From b440efbe5785d114d08bb3f5ec0e09cad943006d Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 12 Mar 2024 10:19:29 +0000 Subject: [PATCH] move texture compiler to native code --- blender_export.py | 198 ++++++++-------------------------------------- build.c | 19 ++++- qoi_lib.c | 28 +++++++ 3 files changed, 79 insertions(+), 166 deletions(-) create mode 100644 qoi_lib.c diff --git a/blender_export.py b/blender_export.py index b1e7677..19e68f0 100644 --- a/blender_export.py +++ b/blender_export.py @@ -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 68e485a..94869b4 100644 --- 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 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