move texture compiler to native code
[carveJwlIkooP6JGAAIwe30JlM.git] / blender_export.py
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
 #}