move texture compiler to native code
authorhgn <hgodden00@gmail.com>
Tue, 12 Mar 2024 10:19:29 +0000 (10:19 +0000)
committerhgn <hgodden00@gmail.com>
Tue, 12 Mar 2024 10:19:29 +0000 (10:19 +0000)
blender_export.py
build.c
qoi_lib.c [new file with mode: 0644]

index b1e7677fb232cf5c071a74ff4cff5f6a26af3e21..19e68f0b64c66cc37d8e87bb16d7e1214c129a1e 100644 (file)
@@ -1,5 +1,6 @@
-import bpy, blf, math, gpu, os
+import bpy, blf, math, gpu, os, time
 import cProfile
+import numpy as np
 from ctypes import *
 from mathutils import *
 from gpu_extras.batch import batch_for_shader
@@ -4999,176 +5000,43 @@ def unregister():
    bpy.types.SpaceView3D.draw_handler_remove(cv_view_pixel_handler,'WINDOW')
 #}
 
-# ---------------------------------------------------------------------------- #
-#                                                                              #
-#                                 QOI encoder                                  #
-#                                                                              #
-# ---------------------------------------------------------------------------- #
-#                                                                              #
-# Transliteration of:                                                          #
-#    https://github.com/phoboslab/qoi/blob/master/qoi.h                        #
-#                                                                              #
-# Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org               #
-# SPDX-License-Identifier: MIT                                                 #
-# QOI - The "Quite OK Image" format for fast, lossless image compression       #
-#                                                                              #
-# ---------------------------------------------------------------------------- #
-
-class qoi_rgba_t(Structure):
-#{
-   _pack_ = 1
-   _fields_ = [("r",c_uint8),
-               ("g",c_uint8),
-               ("b",c_uint8),
-               ("a",c_uint8)]
-#}
-
-QOI_OP_INDEX  = 0x00 # 00xxxxxx
-QOI_OP_DIFF   = 0x40 # 01xxxxxx
-QOI_OP_LUMA   = 0x80 # 10xxxxxx
-QOI_OP_RUN    = 0xc0 # 11xxxxxx
-QOI_OP_RGB    = 0xfe # 11111110
-QOI_OP_RGBA   = 0xff # 11111111
-
-QOI_MASK_2    = 0xc0 # 11000000
-
-def qoi_colour_hash( c ):
-#{
-   return c.r*3 + c.g*5 + c.b*7 + c.a*11
-#}
-
-def qoi_eq( a, b ):
-#{
-   return (a.r==b.r) and (a.g==b.g) and (a.b==b.b) and (a.a==b.a)
-#}
-
-def qoi_32bit( v ):
-#{
-   return bytearray([ (0xff000000 & v) >> 24, \
-                      (0x00ff0000 & v) >> 16, \
-                      (0x0000ff00 & v) >> 8, \
-                      (0x000000ff & v) ])
-#}
+qoi_lib = None
+qoi_encode_rgbaf32 = None
+qoi_free = None
 
 def qoi_encode( img ):
 #{
-   data = bytearray()
+   global qoi_lib
+   global qoi_encode_rgbaf32
+   global qoi_free
    
+   if not qoi_lib:
+   #{
+      ext = '.dll' if os.name=='nt' else '.so'
+      path = F'{os.path.dirname(__file__)}/qoi{ext}'
+      qoi_lib = cdll.LoadLibrary( path )
+      qoi_encode_rgbaf32 = qoi_lib.qoi_encode_rgbaf32
+      qoi_encode_rgbaf32.argtypes = \
+         [ np.ctypeslib.ndpointer(dtype=np.float32,\
+                                  ndim=1,\
+                                  flags='C_CONTIGUOUS'), \
+          c_uint32, c_uint32, POINTER(c_int32) ]
+      qoi_encode_rgbaf32.restype = POINTER(c_uint8)
+
+      qoi_free = qoi_lib.qoi_free
+      qoi_free.argtypes = [ POINTER(c_uint8) ]
+   #}
+
    print(F"{' ':<30}",end='\r')
    print(F"[QOI] Encoding {img.name}.qoi[{img.size[0]},{img.size[1]}]",end='\r')
 
-   index = [ qoi_rgba_t() for _ in range(64) ]
-
-   # Header
-   #
-   data.extend( bytearray(c_uint32(0x66696f71)) )
-   data.extend( qoi_32bit( img.size[0] ) )
-   data.extend( qoi_32bit( img.size[1] ) )
-   data.extend( bytearray(c_uint8(4)) )
-   data.extend( bytearray(c_uint8(0)) )
-
-   run = 0
-   px_prev = qoi_rgba_t()
-   px_prev.r = c_uint8(0)
-   px_prev.g = c_uint8(0)
-   px_prev.b = c_uint8(0)
-   px_prev.a = c_uint8(255)
-
-   px = qoi_rgba_t()
-   px.r = c_uint8(0)
-   px.g = c_uint8(0)
-   px.b = c_uint8(0)
-   px.a = c_uint8(255)
-
-   px_len = img.size[0] * img.size[1]
-   paxels = [ int(min(max(_,0),1)*255) for _ in img.pixels ]
-
-   for px_pos in range( px_len ): #{
-      idx = px_pos * img.channels
-      nc = img.channels-1
-
-      px.r = paxels[idx+min(0,nc)]
-      px.g = paxels[idx+min(1,nc)]
-      px.b = paxels[idx+min(2,nc)]
-      px.a = paxels[idx+min(3,nc)]
-
-      if qoi_eq( px, px_prev ): #{
-         run += 1
-
-         if (run == 62) or (px_pos == px_len-1): #{
-            data.extend( bytearray( c_uint8(QOI_OP_RUN | (run-1))) )
-            run = 0
-         #}
-      #}
-      else: #{
-         if run > 0: #{
-            data.extend( bytearray( c_uint8(QOI_OP_RUN | (run-1))) )
-            run = 0
-         #}
-
-         index_pos = qoi_colour_hash(px) % 64
-
-         if qoi_eq( index[index_pos], px ): #{
-            data.extend( bytearray( c_uint8(QOI_OP_INDEX | index_pos)) )
-         #}
-         else: #{
-            index[ index_pos ].r = px.r
-            index[ index_pos ].g = px.g
-            index[ index_pos ].b = px.b
-            index[ index_pos ].a = px.a
-
-            if px.a == px_prev.a: #{
-               vr = int(px.r) - int(px_prev.r)
-               vg = int(px.g) - int(px_prev.g)
-               vb = int(px.b) - int(px_prev.b)
-
-               vg_r = vr - vg
-               vg_b = vb - vg
-
-               if (vr > -3) and (vr < 2) and\
-                  (vg > -3) and (vg < 2) and\
-                  (vb > -3) and (vb < 2):
-               #{
-                  op = QOI_OP_DIFF | (vr+2) << 4 | (vg+2) << 2 | (vb+2)
-                  data.extend( bytearray( c_uint8(op) ))
-               #}
-               elif (vg_r > -9) and (vg_r < 8) and\
-                    (vg  > -33) and (vg < 32 ) and\
-                    (vg_b > -9) and (vg_b < 8):
-               #{
-                  op = QOI_OP_LUMA | (vg+32)
-                  delta = (vg_r+8) << 4 | (vg_b + 8)
-                  data.extend( bytearray( c_uint8(op) ) )
-                  data.extend( bytearray( c_uint8(delta) ))
-               #}
-               else: #{
-                  data.extend( bytearray( c_uint8(QOI_OP_RGB) ) )
-                  data.extend( bytearray( c_uint8(px.r) ))
-                  data.extend( bytearray( c_uint8(px.g) ))
-                  data.extend( bytearray( c_uint8(px.b) ))
-               #}
-            #}
-            else: #{
-               data.extend( bytearray( c_uint8(QOI_OP_RGBA) ) )
-               data.extend( bytearray( c_uint8(px.r) ))
-               data.extend( bytearray( c_uint8(px.g) ))
-               data.extend( bytearray( c_uint8(px.b) ))
-               data.extend( bytearray( c_uint8(px.a) ))
-            #}
-         #}
-      #}
-
-      px_prev.r = px.r
-      px_prev.g = px.g
-      px_prev.b = px.b
-      px_prev.a = px.a
-   #}
-   
-   # Padding
-   for i in range(7):
-      data.extend( bytearray( c_uint8(0) ))
-   data.extend( bytearray( c_uint8(1) ))
-   bytearray_align_to( data, 16, b'\x00' )
+   crab = np.asarray(img.pixels, dtype=np.float32)
+   cock = c_int()
+   comped = qoi_encode_rgbaf32( crab, img.size[0], img.size[1], byref(cock) )
+   end = time.time()
 
-   return data
+   bingo = bytearray(comped[:cock.value])
+   bytearray_align_to( bingo, 16, b'\x00' )
+   qoi_free( comped )
+   return bingo
 #}
diff --git a/build.c b/build.c
index 68e485a80a8376aab728044ece7e3c05fd69ee42..94869b4874606405bdc715fbb3078875c2baedd5 100644 (file)
--- a/build.c
+++ b/build.c
@@ -205,11 +205,25 @@ void compile_server( struct vg_project *proj )
    vg_compile_project( proj );
 }
 
+void compile_tools( struct vg_env *env, struct vg_project *proj )
+{
+   struct vg_env backup = *env;
+   env->optimization = 3; /* force optimization always */
+   env->debug_asan = 0;
+
+   vg_project_new_target( proj, "tools/qoi", k_obj_type_shared );
+   vg_add_source( proj, "qoi_lib.c " );
+   vg_compile_project( proj );
+
+   *env = backup;
+}
+
 /*
  * Scripts
  * -------------------------------------------------------------------------- */
 
-void s_release_all(void){
+void s_release_all(void)
+{
    vg_info( "running script: s_release_all(void)\n" );
 
    struct vg_project content_proj, windows_proj, linux_proj;
@@ -224,12 +238,14 @@ void s_release_all(void){
    env.platform = k_platform_windows;
    vg_project_init( &windows_proj, &env, "skaterift" );
    build_game_bin( &windows_proj );
+   compile_tools( &env, &windows_proj );
 
    /* binaries for linux */
    env = vg_release_env;
    env.platform = k_platform_linux;
    vg_project_init( &linux_proj, &env, "skaterift" );
    build_game_bin( &linux_proj );
+   compile_tools( &env, &linux_proj );
 
    /* package them up for storage */
    vg_tarball_project( &content_proj );
@@ -250,6 +266,7 @@ void s_testing_build(void)
    vg_project_init( &test_proj, &vg_test_env, "skaterift-test" );
 
    build_game_bin( &test_proj );
+   compile_tools( &vg_test_env, &test_proj );
    build_game_content( &test_proj );
    vg_add_blob( &test_proj, "steam_appid.txt", "" );
 }
diff --git a/qoi_lib.c b/qoi_lib.c
new file mode 100644 (file)
index 0000000..238e50a
--- /dev/null
+++ b/qoi_lib.c
@@ -0,0 +1,28 @@
+#define QOI_IMPLEMENTATION
+#include "vg/submodules/qoi/qoi.h"
+#include "vg/vg_platform.h"
+#include "vg/vg_m.h"
+
+u8 *qoi_encode_rgbaf32( f32 *data, u32 width, u32 height, int *length )
+{
+   u8 *buf = (u8 *)data;
+   for( u32 i=0; i<width*height*4; i ++ )
+   {
+      buf[i] = vg_clampf( data[i] * 255.0f, 0.0f, 255.0f );
+   }
+
+   qoi_desc desc = 
+   {
+      .channels=4,  
+      .colorspace=0, 
+      .width=width, 
+      .height=height
+   };
+
+   return qoi_encode( buf, &desc, length );
+}
+
+void qoi_free( u8 *ptr )
+{
+   free( ptr );
+}