From 2937c186209f5ff766cacc9f17a118744ede7b7a Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 12 Apr 2022 03:22:57 +0100 Subject: [PATCH] Major API revision --- Makefile | 48 +- __init__.py | 417 +++--- src/convexer.c => cxr/cxr.h | 1561 +++++++++++--------- {src => cxr}/cxr_math.h | 0 {src => cxr}/cxr_mem.h | 0 cxr/test.c | 35 + {src/nbvtf => nbvtf}/librgbcx.h | 0 {src/nbvtf => nbvtf}/nbvtf.h | 52 +- {src/nbvtf => nbvtf}/rgbcx.h | 0 {src/nbvtf => nbvtf}/rgbcx_table4.h | 0 {src/nbvtf => nbvtf}/stb/stb_dxt.h | 0 {src/nbvtf => nbvtf}/stb/stb_image.h | 0 {src/nbvtf => nbvtf}/stb/stb_image_write.h | 0 {src/nbvtf => nbvtf}/vtf_cmd.c | 0 src/test.c | 11 - 15 files changed, 1204 insertions(+), 920 deletions(-) rename src/convexer.c => cxr/cxr.h (84%) rename {src => cxr}/cxr_math.h (100%) rename {src => cxr}/cxr_mem.h (100%) create mode 100644 cxr/test.c rename {src/nbvtf => nbvtf}/librgbcx.h (100%) rename {src/nbvtf => nbvtf}/nbvtf.h (91%) rename {src/nbvtf => nbvtf}/rgbcx.h (100%) rename {src/nbvtf => nbvtf}/rgbcx_table4.h (100%) rename {src/nbvtf => nbvtf}/stb/stb_dxt.h (100%) rename {src/nbvtf => nbvtf}/stb/stb_image.h (100%) rename {src/nbvtf => nbvtf}/stb/stb_image_write.h (100%) rename {src/nbvtf => nbvtf}/vtf_cmd.c (100%) delete mode 100644 src/test.c diff --git a/Makefile b/Makefile index 4bafbd0..8d62488 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,42 @@ all: libcxr.so libnbvtf.so -libcxr.so: src/convexer.c src/cxr_math.h src/cxr_mem.h - gcc -ggdb -O1 -Wall -fPIC -shared src/convexer.c -o libcxr.so -lm -Wno-unused-variable -Wno-unused-function -DDEBUG_WRITE_MESH -std=c99 -pedantic +libcxr.so: cxr/cxr.h cxr/cxr_math.h cxr/cxr_mem.h + gcc -O1 -ggdb -fPIC -shared \ + -Wall -Wno-unused-variable -Wno-unused-function -std=c99 -pedantic \ + -DCXR_SO -DCXR_DEBUG -DCXR_VALVE_MAP_FILE \ + -xc cxr/cxr.h \ + -o libcxr.so \ + -lm -tovtf: src/obj/librgbcx.o src/obj/tovtf.o - g++ -O3 src/obj/tovtf.o src/obj/librgbcx.o -o tovtf +tovtf: nbvtf/obj/librgbcx.o nbvtf/obj/tovtf.o + g++ -O3 nbvtf/obj/tovtf.o nbvtf/obj/librgbcx.o -o tovtf -src/obj/librgbcx.o: src/nbvtf/librgbcx.cc src/nbvtf/rgbcx.h - g++ -O3 -c src/nbvtf/librgbcx.cc -o src/obj/librgbcx.o +nbvtf/obj/librgbcx.o: nbvtf/librgbcx.cc nbvtf/rgbcx.h + g++ -O3 -c \ + nbvtf/librgbcx.cc \ + -o nbvtf/obj/librgbcx.o -src/obj/tovtf.o: src/nbvtf/vtf_cmd.c src/nbvtf/nbvtf.h - gcc -O3 -DUSE_LIBRGBCX -c -I./src/nbvtf/ src/nbvtf/vtf_cmd.c -o src/obj/tovtf.o +nbvtf/obj/tovtf.o: nbvtf/vtf_cmd.c nbvtf/nbvtf.h + gcc -O3 -c \ + -DUSE_LIBRGBCX \ + -I./nbvtf/ \ + nbvtf/vtf_cmd.c \ + -o nbvtf/obj/tovtf.o -src/obj/libnbvtf.o: src/nbvtf/nbvtf.h - gcc -O3 -fPIC -x c -c -DNBVTF_AS_SO src/nbvtf/nbvtf.h -o src/obj/libnbvtf.o +nbvtf/obj/libnbvtf.o: nbvtf/nbvtf.h + gcc -O3 -fPIC -c \ + -DUSE_LIBRGBCX -DNBVTF_AS_SO \ + -xc nbvtf/nbvtf.h \ + -o nbvtf/obj/libnbvtf.o -libnbvtf.so: src/obj/librgbcx.o src/obj/libnbvtf.o - g++ -O3 -shared src/obj/librgbcx.o src/obj/libnbvtf.o -o libnbvtf.so +libnbvtf.so: nbvtf/obj/librgbcx.o nbvtf/obj/libnbvtf.o + g++ -O3 -shared \ + nbvtf/obj/librgbcx.o nbvtf/obj/libnbvtf.o \ + -o libnbvtf.so -test: src/convexer.c src/test.c src/cxr_math.h src/solid.h - gcc -ggdb -O1 -Wall src/test.c -o test -lm -Wno-unused-variable -Wno-unused-function -fsanitize=address -Werror=vla +test: cxr/test.c cxr/cxr.h cxr/cxr_math.h cxr/solid.h + gcc -ggdb -O1 -Wall \ + -Wno-unused-variable -Wno-unused-function -fsanitize=address -Werror=vla \ + cxr/test.c \ + -o test \ + -lm diff --git a/__init__.py b/__init__.py index 8cc9638..544d770 100644 --- a/__init__.py +++ b/__init__.py @@ -25,31 +25,135 @@ vmt_param_dynamic_class = None # libcxr interface (TODO: We can probably automate this) # ====================================================== -libcxr = None + +class extern(): + def __init__(_,name,argtypes,restype): + _.name = name + _.argtypes = argtypes + _.restype = restype + _.call = None + + def loadfrom(_,so): + _.call = getattr(so,_.name) + _.call.argtypes = _.argtypes + + if _.restype != None: + _.call.restype = _.restype + libc_dlclose = None libc_dlclose = cdll.LoadLibrary(None).dlclose libc_dlclose.argtypes = [c_void_p] +# Callback ctypes wrapper... +libcxr = None c_libcxr_log_callback = None c_libcxr_line_callback = None -libcxr_write_test_data = None -libcxr_context_reset = None -libcxr_set_offset = None -libcxr_set_scale_factor = None +# Structure definitions +class cxr_edge(Structure): + _fields_ = [("i0",c_int32), + ("i1",c_int32), + ("freestyle",c_int32)] + +class cxr_static_loop(Structure): + _fields_ = [("index",c_int32), + ("edge_index",c_int32), + ("uv",c_double * 2)] + +class cxr_polygon(Structure): + _fields_ = [("loop_start",c_int32), + ("loop_total",c_int32), + ("normal",c_double * 3), + ("center",c_double * 3), + ("material_id",c_int32)] + +class cxr_material(Structure): + _fields_ = [("res",c_int32 * 2), + ("name",c_char_p)] -# Vdf writing interface -libcxr_vdf_open = None -libcxr_vdf_close = None -libcxr_vdf_put = None -libcxr_vdf_node = None -libcxr_vdf_edon = None -libcxr_vdf_kv = None +class cxr_static_mesh(Structure): + _fields_ = [("vertices",POINTER(c_double * 3)), + ("edges",POINTER(cxr_edge)), + ("loops",POINTER(cxr_static_loop)), + ("polys",POINTER(cxr_polygon)), + ("materials",POINTER(cxr_material)), + + ("poly_count",c_int32), + ("vertex_count",c_int32), + ("edge_count",c_int32), + ("loop_count",c_int32), + ("material_count",c_int32)] + +class cxr_tri_mesh(Structure): + _fields_ = [("vertices",POINTER(c_double *3)), + ("colours",POINTER(c_double *4)), + ("indices",POINTER(c_int32)), + ("indices_count",c_int32), + ("vertex_count",c_int32)] + +class cxr_vmf_context(Structure): + _fields_ = [("mapversion",c_int32), + ("skyname",c_char_p), + ("detailvbsp",c_char_p), + ("detailmaterial",c_char_p), + ("scale",c_double), + ("offset",c_double *3), + ("lightmap_scale",c_int32), + ("brush_count",c_int32), + ("entity_count",c_int32), + ("face_count",c_int32)] + +# Public API +libcxr_decompose = extern( "cxr_decompose", \ + [POINTER(cxr_static_mesh)], c_void_p ) + +libcxr_free_world = extern( "cxr_free_world", [c_void_p], None ) +libcxr_write_test_data = extern( "cxr_write_test_data", \ + [POINTER(cxr_static_mesh)], None ) +libcxr_world_preview = extern( "cxr_world_preview", [c_void_p], \ + POINTER(cxr_tri_mesh)) +libcxr_free_tri_mesh = extern( "cxr_free_tri_mesh", [c_void_p], None ) + +# VMF +libcxr_begin_vmf = extern( "cxr_begin_vmf", \ + [POINTER(cxr_vmf_context), c_void_p], None ) + +libcxr_vmf_begin_entities = extern( "cxr_vmf_begin_entities", \ + [POINTER(cxr_vmf_context), c_void_p], None ) + +libcxr_push_world_vmf = extern("cxr_push_world_vmf", \ + [c_void_p,POINTER(cxr_vmf_context),c_void_p], None ) + +libcxr_end_vmf = extern( "cxr_end_vmf", \ + [POINTER(cxr_vmf_context),c_void_p], None ) + +# VDF +libcxr_vdf_open = extern( "cxr_vdf_open", [c_char_p], c_void_p ) +libcxr_vdf_close = extern( "cxr_vdf_close", [c_void_p], None ) +libcxr_vdf_put = extern( "cxr_vdf_put", [c_void_p,c_char_p], None ) +libcxr_vdf_node = extern( "cxr_vdf_node", [c_void_p,c_char_p], None ) +libcxr_vdf_edon = extern( "cxr_vdf_edon", [c_void_p], None ) +libcxr_vdf_kv = extern( "cxr_vdf_kv", [c_void_p,c_char_p,c_char_p], None ) + +# Other +libcxr_lightpatch_bsp = extern( "cxr_lightpatch_bsp", [c_char_p], None ) + +libcxr_funcs = [ libcxr_decompose, libcxr_free_world, libcxr_begin_vmf, \ + libcxr_vmf_begin_entities, libcxr_push_world_vmf, \ + libcxr_end_vmf, libcxr_vdf_open, libcxr_vdf_close, \ + libcxr_vdf_put, libcxr_vdf_node, libcxr_vdf_edon, + libcxr_vdf_kv, libcxr_lightpatch_bsp, libcxr_write_test_data,\ + libcxr_world_preview, libcxr_free_tri_mesh ] # libnbvtf interface # ================== libnbvtf = None -libnbvtf_convert = None + +libnbvtf_convert = extern( "nbvtf_convert", \ + [c_char_p,c_int32,c_int32,c_int32,c_int32,c_int32,c_uint32,c_char_p], + c_int32 ) + +libnbvtf_funcs = [ libnbvtf_convert ] # NBVTF constants # =============== @@ -69,76 +173,34 @@ class vdf_structure(): def __init__(_,path): _.path = path def __enter__(_): - _.fp = libcxr_vdf_open( _.path.encode('utf-8') ) + _.fp = libcxr_vdf_open.call( _.path.encode('utf-8') ) if _.fp == None: print( F"Could not open file {_.path}" ) return None return _ def __exit__(_,type,value,traceback): if _.fp != None: - libcxr_vdf_close(_.fp) + libcxr_vdf_close.call(_.fp) def put(_,s): - libcxr_vdf_put(_.fp, s.encode('utf-8') ) + libcxr_vdf_put.call(_.fp, s.encode('utf-8') ) def node(_,name): - libcxr_vdf_node(_.fp, name.encode('utf-8') ) + libcxr_vdf_node.call(_.fp, name.encode('utf-8') ) def edon(_): - libcxr_vdf_edon(_.fp) + libcxr_vdf_edon.call(_.fp) def kv(_,k,v): - libcxr_vdf_kv(_.fp, k.encode('utf-8'), v.encode('utf-8')) + libcxr_vdf_kv.call(_.fp, k.encode('utf-8'), v.encode('utf-8')) class cxr_object_context(): def __init__(_,scale,offset_z): _.scale=scale _.offset_z=offset_z -libcxr_convert_mesh_to_vmf = None - debug_gpu_lines = None +debug_gpu_mesh = None debug_gpu_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') debug_draw_handler = None -class cxr_settings(Structure): - _fields_ = [("debug",c_int32), - ("lightmap_scale",c_int32), - ("light_scale",c_double)] - -class cxr_input_loop(Structure): - _fields_ = [("index",c_int32), - ("edge_index",c_int32), - ("uv",c_double * 2)] - -class cxr_polygon(Structure): - _fields_ = [("loop_start",c_int32), - ("loop_total",c_int32), - ("normal",c_double * 3), - ("center",c_double * 3), - ("material_id",c_int32)] - -class cxr_edge(Structure): - _fields_ = [("i0",c_int32), - ("i1",c_int32), - ("freestyle",c_int32)] - -class cxr_material(Structure): - _fields_ = [("res",c_int32 * 2), - ("vmt_path",c_char_p)] - -class cxr_input_mesh(Structure): - _fields_ = [("vertices",POINTER(c_double * 3)), - ("edges",POINTER(cxr_edge)), - ("loops",POINTER(cxr_input_loop)), - ("polys",POINTER(cxr_polygon)), - ("materials",POINTER(cxr_material)), - - ("poly_count",c_int32), - ("vertex_count",c_int32), - ("edge_count",c_int32), - ("loop_count",c_int32), - ("material_count",c_int32)] - -class cxr_output_mesh(Structure): - _fields_ = [] def libcxr_log_callback(logStr): print( F"{logStr.decode('utf-8')}",end='' ) @@ -184,35 +246,36 @@ def libcxr_line_callback(p0,p1,colour): def cxr_draw(): global debug_gpu_lines global debug_gpu_shader - + global debug_gpu_mesh + + debug_gpu_shader.bind() + + gpu.state.depth_test_set('LESS_EQUAL') + gpu.state.depth_mask_set(False) + gpu.state.line_width_set(1.5) + gpu.state.face_culling_set('BACK') + gpu.state.blend_set('ALPHA') if debug_gpu_lines != None: debug_gpu_lines.draw(debug_gpu_shader) + gpu.state.blend_set('ADDITIVE') + if debug_gpu_mesh != None: + debug_gpu_mesh.draw(debug_gpu_shader) + class CXR_RELOAD(bpy.types.Operator): bl_idname="convexer.reload" bl_label="Reload convexer" def execute(_,context): - global libcxr, libnbvtf, libnbvtf_convert + global libcxr, libnbvtf, libcxr_funcs, libnbvtf_funcs # Load vtf library libnbvtf = cdll.LoadLibrary( os.path.dirname(__file__)+'/libnbvtf.so') - libnbvtf_convert = libnbvtf.nbvtf_convert - libnbvtf_convert.argtypes = [\ - c_char_p, \ - c_int32, \ - c_int32, \ - c_int32, \ - c_int32, \ - c_uint32, \ - c_char_p ] - libnbvtf_convert.restype = c_int32 if libcxr != None: _handle = libcxr._handle - # TODO: Find a propper way to do this for i in range(10): libc_dlclose( _handle ) del libcxr @@ -222,62 +285,14 @@ class CXR_RELOAD(bpy.types.Operator): build_time = c_char_p.in_dll(libcxr,'cxr_build_time') print( F"libcxr build time: {build_time.value}" ) - # Public API - global libcxr_write_test_data, libcxr_convert_mesh_to_vmf - - libcxr_write_test_data = libcxr.cxr_write_test_data - libcxr_write_test_data.argtypes = [\ - POINTER(cxr_input_mesh) - ] - libcxr_write_test_data.restype = c_int32 - - libcxr_convert_mesh_to_vmf = libcxr.cxr_convert_mesh_to_vmf - libcxr_convert_mesh_to_vmf.argtypes = [\ - POINTER(cxr_input_mesh),\ - c_void_p,\ - ] - libcxr_convert_mesh_to_vmf.restype = c_int32 - - global libcxr_context_reset, libcxr_set_offset,\ - libcxr_set_scale_factor - libcxr_context_reset = libcxr.cxr_context_reset - - libcxr_set_offset = libcxr.cxr_set_offset - libcxr_set_offset.argtypes = [ c_double ] - - libcxr_set_scale_factor = libcxr.cxr_set_scale_factor - libcxr_set_scale_factor.argtypes = [ c_double ] - - # VDF - global libcxr_vdf_open, \ - libcxr_vdf_close, \ - libcxr_vdf_put, \ - libcxr_vdf_node, \ - libcxr_vdf_edon, \ - libcxr_vdf_kv - - libcxr_vdf_open = libcxr.cxr_vdf_open - libcxr_vdf_open.argtypes = [ c_char_p ] - libcxr_vdf_open.restype = c_void_p - - libcxr_vdf_close = libcxr.cxr_vdf_close - libcxr_vdf_close.argtypes = [ c_void_p ] - - libcxr_vdf_put = libcxr.cxr_vdf_put - libcxr_vdf_put.argtypes = [ c_void_p, c_char_p ] - - libcxr_vdf_node = libcxr.cxr_vdf_node - libcxr_vdf_node.argtypes = [ c_void_p, c_char_p ] + for fd in libnbvtf_funcs: + fd.loadfrom( libnbvtf ) - libcxr_vdf_edon = libcxr.cxr_vdf_edon - libcxr_vdf_edon.argtypes = [ c_void_p ] - - libcxr_vdf_kv = libcxr.cxr_vdf_kv - libcxr_vdf_kv.argtypes = [ c_void_p, c_char_p, c_char_p ] + for fd in libcxr_funcs: + fd.loadfrom( libcxr ) # Callbacks - global c_libcxr_log_callback - global c_libcxr_line_callback + global c_libcxr_log_callback, c_libcxr_line_callback LOG_FUNCTION_TYPE = CFUNCTYPE(None,c_char_p) c_libcxr_log_callback = LOG_FUNCTION_TYPE(libcxr_log_callback) @@ -295,20 +310,6 @@ def libcxr_use(): if libcxr == None: bpy.ops.convexer.reload() - - def _bool_int(b): - return 1 if b else 0 - - scene = bpy.context.scene - cxr = scene.cxr_data - - settings=cxr_settings() - settings.debug=_bool_int(cxr.debug) - - settings.lightmap_scale=cxr.lightmap_scale - settings.light_scale=cxr.light_scale - - libcxr.cxr_settings_update(pointer(settings)) def to_aeiou( v ): ret = "" @@ -817,7 +818,7 @@ def mesh_cxr_format(obj): _,mtx_rot,_ = obj.matrix_world.decompose() - mesh = cxr_input_mesh() + mesh = cxr_static_mesh() vertex_data = ((c_double*3)*len(data.vertices))() for i, vert in enumerate(data.vertices): @@ -826,7 +827,7 @@ def mesh_cxr_format(obj): vertex_data[i][1] = c_double(v[1]) vertex_data[i][2] = c_double(v[2]) - loop_data = (cxr_input_loop*len(data.loops))() + loop_data = (cxr_static_loop*len(data.loops))() polygon_data = (cxr_polygon*len(data.polygons))() for i, poly in enumerate(data.polygons): @@ -874,7 +875,7 @@ def mesh_cxr_format(obj): mesh.edges = cast(edge_data, POINTER(cxr_edge)) mesh.vertices = cast(vertex_data, POINTER(c_double*3)) - mesh.loops = cast(loop_data,POINTER(cxr_input_loop)) + mesh.loops = cast(loop_data,POINTER(cxr_static_loop)) mesh.polys = cast(polygon_data, POINTER(cxr_polygon)) mesh.materials = cast(material_data, POINTER(cxr_material)) @@ -909,41 +910,24 @@ class CXR_WRITE_VMF(bpy.types.Operator): # States material_info.references = set() - libcxr_context_reset() output_vmf = F"{directory}/{settings.project_name}.vmf" with vdf_structure(output_vmf) as m: print( F"Write: {output_vmf}" ) - m.node('versioninfo') - m.kv('editorversion','400') - m.kv('editorbuild','8456') - m.kv('mapversion','4') - m.kv('formatversion','100') - m.kv('prefab','0') - m.edon() - - m.node('visgroups') - m.edon() - - m.node('viewsettings') - m.kv('bSnapToGrid','1') - m.kv('bShowGrid','1') - m.kv('bShowLogicalGrid','0') - m.kv('nGridSpacing','64') - m.kv('bShow3DGrid','0') - m.edon() - - m.node('world') - m.kv('id','1') - m.kv('mapversion','1') - m.kv('classname','worldspawn') - m.kv('skyname','sky_csgo_night02b') - m.kv('maxpropscreenwidth','-1') - m.kv('detailvbsp','detail.vbsp') - m.kv('detailmaterial','detail/detailsprites') + vmfinfo = cxr_vmf_context() + vmfinfo.mapversion = 4 + vmfinfo.skyname = b"sky_csgo_night02b" + vmfinfo.detailvbsp = b"detail.vbsp" + vmfinfo.detailmaterial = b"detail/detailsprites" + vmfinfo.lightmap_scale = 12 + vmfinfo.brush_count = 0 + vmfinfo.entity_count = 0 + vmfinfo.face_count = 0 + libcxr_begin_vmf.call( pointer(vmfinfo), m.fp ) + # Make sure all of our asset types have a unique ID def _uid_prepare(objtype): used_ids = [0] @@ -1007,13 +991,31 @@ class CXR_WRITE_VMF(bpy.types.Operator): if 'skybox' in bpy.data.collections: _collect( bpy.data.collections['skybox'], transform_sky ) + def _buildsolid( obj, ctx ): + nonlocal m + + baked = mesh_cxr_format( brush[0] ) + world = libcxr_decompose.call( baked ) + + if world == None: + return False + + vmfinfo.scale = brush[1].scale + vmfinfo.offset[0] = 0.0 + vmfinfo.offset[1] = 0.0 + vmfinfo.offset[2] = brush[1].offset_z + + libcxr_push_world_vmf.call( world, pointer(vmfinfo), m.fp ) + libcxr_free_world.call( world ) + + return True + # World geometry for brush in _collect.geo: - baked = mesh_cxr_format( brush[0] ) - libcxr_set_scale_factor( brush[1].scale ) - libcxr_set_offset( brush[1].offset_z ) - libcxr_convert_mesh_to_vmf(baked,m.fp) - + if not _buildsolid( brush[0], brush[1] ): + print( "error" ) + return {'CANCELLED'} + m.edon() # Entities @@ -1031,11 +1033,8 @@ class CXR_WRITE_VMF(bpy.types.Operator): m.kv( kv[0], ' '.join([str(_) for _ in kv[2]]) ) else: m.kv( kv[0], str(kv[2]) ) - if obj.type == 'MESH': - baked = mesh_cxr_format( obj ) - libcxr_set_scale_factor( ctx.scale ) - libcxr_set_offset( ctx.offset_z ) - libcxr_convert_mesh_to_vmf(baked,m.fp) + if not _buildsolid( obj, ctx ): + return {'CANCELLED'} m.edon() @@ -1062,12 +1061,57 @@ class CXR_DEV_OPERATOR(bpy.types.Operator): mesh_src = mesh_cxr_format(context.active_object) libcxr_reset_debug_lines() - libcxr_write_test_data( pointer(mesh_src) ) + libcxr_write_test_data.call( pointer(mesh_src) ) libcxr_batch_debug_lines() scene_redraw() return {'FINISHED'} +class CXR_PREVIEW_OPERATOR(bpy.types.Operator): + bl_idname="convexer.preview" + bl_label="Preview" + + def execute(_,context): + libcxr_use() + + libcxr_reset_debug_lines() + + mesh_src = mesh_cxr_format(context.active_object) + world = libcxr_decompose.call( mesh_src ) + + global debug_gpu_shader, debug_gpu_mesh + + if world == None: + debug_gpu_mesh = None + libcxr_batch_debug_lines() + return {'CANCELLED'} + + ptrpreview = libcxr_world_preview.call( world ) + preview = ptrpreview[0] + + vertices = preview.vertices[:preview.vertex_count] + vertices = [(_[0],_[1],_[2]) for _ in vertices] + + colours = preview.colours[:preview.vertex_count] + colours = [(_[0],_[1],_[2],_[3]) for _ in colours] + + indices = preview.indices[:preview.indices_count] + indices = [ (indices[i*3+0],indices[i*3+1],indices[i*3+2]) \ + for i in range(int(preview.indices_count/3)) ] + + debug_gpu_mesh = batch_for_shader( + debug_gpu_shader, 'TRIS', + { "pos": vertices, "color": colours }, + indices = indices, + ) + + libcxr_free_tri_mesh.call( ptrpreview ) + libcxr_free_world.call( world ) + + libcxr_batch_debug_lines() + scene_redraw() + return {'FINISHED'} + class CXR_INTERFACE(bpy.types.Panel): bl_label="Convexer" bl_idname="SCENE_PT_convexer" @@ -1078,6 +1122,7 @@ class CXR_INTERFACE(bpy.types.Panel): def draw(_,context): _.layout.operator("convexer.reload") _.layout.operator("convexer.dev_test") + _.layout.operator("convexer.preview") _.layout.operator("convexer.write_vmf") settings = context.scene.cxr_data @@ -1137,7 +1182,7 @@ def compile_image(img,flags): flags_full |= NBVTF_TEXTUREFLAGS_CLAMPS flags_full |= NBVTF_TEXTUREFLAGS_CLAMPT - if libnbvtf_convert(src,dims[0],dims[1],mipmap,fmt,flags_full,dst): + if libnbvtf_convert.call(src,dims[0],dims[1],mipmap,fmt,0,flags_full,dst): img.cxr_data.last_hash = comphash return name @@ -1542,7 +1587,7 @@ classes = [ CXR_RELOAD, CXR_DEV_OPERATOR, CXR_INTERFACE, \ CXR_WRITE_VMF, CXR_MATERIAL_PANEL, CXR_IMAGE_SETTINGS,\ CXR_MODEL_SETTINGS, CXR_ENTITY_SETTINGS, CXR_CUBEMAP_SETTINGS,\ CXR_LIGHT_SETTINGS, CXR_SCENE_SETTINGS, CXR_DETECT_COMPILERS,\ - CXR_ENTITY_PANEL, CXR_LIGHT_PANEL ] + CXR_ENTITY_PANEL, CXR_LIGHT_PANEL, CXR_PREVIEW_OPERATOR ] def register(): global debug_draw_handler, vmt_param_dynamic_class diff --git a/src/convexer.c b/cxr/cxr.h similarity index 84% rename from src/convexer.c rename to cxr/cxr.h index fd750d6..5a4542a 100644 --- a/src/convexer.c +++ b/cxr/cxr.h @@ -1,5 +1,5 @@ /* - CONVEXER v0.8 + CONVEXER v0.9 A GNU/Linux-first Source1 Hammer replacement built with Blender, for mapmakers @@ -18,18 +18,42 @@ Program structure: File/folder Lang Purpose - src/ - __init__.py Python Blender plugin interface - convexer.c C Heavy lifting; brush decomp, mesh processing + + __init__.py Python Blender plugin interface + + cxr/ + cxr.h C Heavy lifting; brush decomp, mesh processing cxr_math.h C Vector maths and other handy things cxr_mem.h C Automatic resizing buffers - nbvtf/ - nbvtf.h C VTF processing interface - librgcx.h C++ Rich Geldreich's DXT1/DXT5 compressors - stb/ C Sean Barrets image I/O + libcxr.c C Compile as SO + + nbvtf/ + nbvtf.h C VTF processing interface + librgcx.h C++ Rich Geldreich's DXT1/DXT5 compressors + stb/ C Sean Barrets image I/O + + + HEADER + MACROS + STD INCLUDE + TYPEDEFS + INCLUDE + STRUCTURE DEFS + + API + + IMPLEMENTATION */ -const char *cxr_build_time = __DATE__ " @" __TIME__; +#define CXR_API +#define CXR_EPSILON 0.001 +#define CXR_PLANE_SIMILARITY_MAX 0.998 +#define CXR_BIG_NUMBER 1e300 +#define CXR_INTERIOR_ANGLE_MAX 0.998 + +#ifdef CXR_SO + #define CXR_IMPLEMENTATION +#endif #include #include @@ -56,55 +80,66 @@ typedef v3f m3x3f[3]; typedef v3f m4x3f[4]; typedef v3f boxf[2]; -#define CXR_EPSILON 0.001 -#define CXR_PLANE_SIMILARITY_MAX 0.998 -#define CXR_BIG_NUMBER 1e300 -#define CXR_INTERIOR_ANGLE_MAX 0.998 -#define CXR_API -#define CXR_DIRTY_OPTIMISATION 1 -#define CXR_DEBUG_WRITE_MESH 1 -#define CXR_DEBUG_ALLOCATORS 1 -#define CXR_MANIFOLD_DEBUG 0 - -#define CXR_ERROR_DEGEN_IMPLICIT 0x1 -#define CXR_ERROR_BAD_MANIFOLD 0x2 -#define CXR_ERROR_NO_SOLIDS 0x4 - #include "cxr_math.h" #include "cxr_mem.h" -static v4f colours_random[] = -{ - { 0.863, 0.078, 0.235, 0.4 }, - { 0.000, 0.980, 0.604, 0.4 }, - { 0.118, 0.565, 1.000, 0.4 }, - { 0.855, 0.439, 0.839, 0.4 }, - { 0.824, 0.412, 0.118, 0.4 }, - { 0.125, 0.698, 0.667, 0.4 }, - { 0.541, 0.169, 0.886, 0.4 }, - { 1.000, 0.843, 0.000, 0.4 } -}; - -static int cxr_range(int x, int bound) -{ - if( x < 0 ) - x += bound * (x/bound + 1); - - return x % bound; -} +typedef struct cxr_world cxr_world; +typedef struct cxr_solid cxr_solid; +typedef struct cxr_mesh cxr_mesh; typedef struct cxr_edge cxr_edge; -typedef struct cxr_input_mesh cxr_input_mesh; -typedef struct cxr_input_loop cxr_input_loop; typedef struct cxr_polygon cxr_polygon; -typedef struct cxr_material cxr_material; +typedef struct cxr_static_mesh cxr_static_mesh; typedef struct cxr_loop cxr_loop; -typedef struct cxr_solid cxr_solid; -typedef struct cxr_mesh cxr_mesh; -typedef struct cxr_texinfo cxr_texinfo; -typedef struct cxr_vdf cxr_vdf; +typedef struct cxr_static_loop cxr_static_loop; +typedef struct cxr_material cxr_material; +typedef struct cxr_tri_mesh cxr_tri_mesh; + +#ifdef CXR_VALVE_MAP_FILE + typedef struct cxr_vdf cxr_vdf; + typedef struct cxr_texinfo cxr_texinfo; + typedef struct cxr_vmf_context cxr_vmf_context; +#endif /* CXR_VALVE_MAP_FILE */ + +/* + * Public API + */ + +/* Main convexer algorithms */ +/* Convex decomp from mesh */ +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ); +CXR_API void cxr_free_world( cxr_world *world ); +CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world ); +CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ); + +#ifdef CXR_VALVE_MAP_FILE +/* VMF interface */ +CXR_API void cxr_begin_vmf( cxr_vmf_context *ctx, cxr_vdf *vdf ); +CXR_API void cxr_vmf_begin_entities( cxr_vmf_context *ctx, cxr_vdf *vdf ); +CXR_API void cxr_push_world_vmf( + cxr_world *world, cxr_vmf_context *ctx, cxr_vdf *vdf); +CXR_API void cxr_end_vmf( cxr_vmf_context *ctx, cxr_vdf *vdf ); + +/* VDF interface */ +CXR_API cxr_vdf *cxr_vdf_open( const char *path ); +CXR_API void cxr_vdf_close( cxr_vdf *vdf ); +CXR_API void cxr_vdf_put( cxr_vdf *vdf, const char *str ); +CXR_API void cxr_vdf_node( cxr_vdf *vdf, const char *str ); +CXR_API void cxr_vdf_edon( cxr_vdf *vdf ); +CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv ); + +/* Other tools */ +CXR_API int cxr_lightpatch_bsp( const char *path ); +#endif /* CXR_VALVE_MAP_FILE */ + +#ifdef CXR_DEBUG +/* Debugging */ +CXR_API void cxr_set_log_function( void (*func)(const char *str) ); +CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) ); +CXR_API void cxr_write_test_data( cxr_static_mesh *src ); +#endif /* CXR_DEBUG */ -struct cxr_input_mesh +struct cxr_static_mesh { v3f *vertices; @@ -115,7 +150,7 @@ struct cxr_input_mesh } *edges; - struct cxr_input_loop + struct cxr_static_loop { i32 index, edge_index; @@ -135,7 +170,7 @@ struct cxr_input_mesh struct cxr_material { i32 res[2]; - const char *vmt_path; + const char *name; } *materials; @@ -157,7 +192,18 @@ struct cxr_loop struct cxr_solid { - i32 *polygons; + cxr_mesh *pmesh; + int displacement, + invalid; +}; + +struct cxr_world +{ + cxr_abuffer abverts, + absolids; + + cxr_material *materials; + int material_count; }; struct cxr_mesh @@ -177,6 +223,17 @@ struct cxr_mesh struct cxr_loop *loops; }; +/* Simple mesh type mainly for debugging */ +struct cxr_tri_mesh +{ + v3f *vertices; + v4f *colours; + i32 *indices, + indices_count, + vertex_count; +}; + +#ifdef CXR_VALVE_MAP_FILE struct cxr_texinfo { v3f uaxis, vaxis; @@ -193,42 +250,55 @@ struct cxr_vdf i32 level; }; -static struct cxr_settings -{ - i32 debug, - lightmap_scale; - - double light_scale; -} -cxr_settings = { - .debug = 0, - .lightmap_scale = 12, - - .light_scale = 1.0/5.0 -}; - -static struct cxr_context +struct cxr_vmf_context { + /* File info */ + i32 mapversion; + const char *skyname, + *detailvbsp, + *detailmaterial; + + /* Transform settings */ + double scale; + v3f offset; + i32 lightmap_scale; + + /* Current stats */ i32 brush_count, entity_count, face_count; - - double scale_factor; - double offset_z; -} -cxr_context = { - .brush_count = 0, - .entity_count = 0, - .face_count = 0, - .scale_factor = 32.0, - .offset_z = 0.0 }; +#endif /* CXR_VALVE_MAP_FILE */ -static struct cxr_material cxr_nodraw = { - .res = { 512, 512 }, - .vmt_path = "tools/toolsnodraw" +enum cxr_soliderr +{ + k_soliderr_none = 0, + k_soliderr_non_manifold, + k_soliderr_bad_manifold, + k_soliderr_no_solids, + k_soliderr_degenerate_implicit }; +/* + * Implementation + * ----------------------------------------------------------------------------- + */ +#ifdef CXR_IMPLEMENTATION + #ifdef CXR_SO + const char *cxr_build_time = __DATE__ " @" __TIME__; + #endif + +static void (*cxr_log_func)(const char *str); +static void (*cxr_line_func)( v3f p0, v3f p1, v4f colour ); + +static int cxr_range(int x, int bound) +{ + if( x < 0 ) + x += bound * (x/bound + 1); + + return x % bound; +} + /* * This should be called after appending any data to those buffers */ @@ -239,12 +309,61 @@ static void cxr_mesh_update( cxr_mesh *mesh ) mesh->loops = cxr_ab_ptr(&mesh->abloops, 0); } +static v4f colours_random[] = +{ + { 0.863, 0.078, 0.235, 0.4 }, + { 0.000, 0.980, 0.604, 0.4 }, + { 0.118, 0.565, 1.000, 0.4 }, + { 0.855, 0.439, 0.839, 0.4 }, + { 0.824, 0.412, 0.118, 0.4 }, + { 0.125, 0.698, 0.667, 0.4 }, + { 0.541, 0.169, 0.886, 0.4 }, + { 1.000, 0.843, 0.000, 0.4 } +}; + +static v4f colours_solids[] = +{ + { 100, 143, 255, 200 }, + { 120, 94, 240, 200 }, + { 220, 38, 127, 200 }, + { 254, 97, 0, 200 }, + { 255, 176, 0, 200 } +}; + +static v4f colour_entity = { 37, 241, 122, 255 }; +static v4f colour_displacement_solid = { 146, 146, 146, 120 }; static v4f colour_error = { 1.0f, 0.0f, 0.0f, 1.0f }; static v4f colour_face_graph = { 1.0f, 1.0f, 1.0f, 0.03f }; static v4f colour_success = { 0.0f, 1.0f, 0.0f, 1.0f }; -static void (*cxr_log_func)(const char *str); -static void (*cxr_line_func)( v3f p0, v3f p1, v4f colour ); +static void value_random(int n, v4f colour) +{ + double val = cxr_range(n,8); + val /= 16.0; + val += 0.75; + + v3_muls( colour, val, colour ); +} + +static void colour_random_brush(int n, v4f colour) +{ +#if 1 + int value_n = n / 5; + int colour_n = cxr_range( n, 5 ); + v4_muls( colours_solids[ colour_n ], 1.0/255.0, colour ); + value_random( value_n, colour ); +#else + int colour_n = cxr_range( n, 8 ); + v4_copy( colours_random[ colour_n ], colour ); +#endif +} + +/* + * Debugging and diagnostic utilities + * ----------------------------------------------------------------------------- + */ + +#ifdef CXR_DEBUG static void cxr_log( const char *fmt, ... ) { @@ -261,278 +380,174 @@ static void cxr_log( const char *fmt, ... ) fputs(buf,stdout); } -/* - * Public API - */ - -/* - * Main function - * Breaks up geometry into solid pieces - * Turns marked mesh segments into displacements - */ -CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output); - -/* Context management */ -CXR_API void cxr_context_reset(void); -CXR_API void cxr_set_offset(double offset); -CXR_API void cxr_set_scale_factor(double scale); -CXR_API void cxr_settings_update( struct cxr_settings *settings ); - -/* VDF interface */ -CXR_API cxr_vdf *cxr_vdf_open(const char *path); -CXR_API void cxr_vdf_close(cxr_vdf *vdf); -CXR_API void cxr_vdf_put(cxr_vdf *vdf, const char *str); -CXR_API void cxr_vdf_node(cxr_vdf *vdf, const char *str); -CXR_API void cxr_vdf_edon( cxr_vdf *vdf ); -CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv ); - -/* Debugging */ -CXR_API void cxr_set_log_function( void (*func)(const char *str) ); -CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) ); -CXR_API cxr_input_mesh *cxr_write_test_data( cxr_input_mesh *src ); - -/* Other tools */ -CXR_API int cxr_lightpatch_bsp( const char *path ); - -/* - * Implementation - */ - -CXR_API void cxr_context_reset(void) +static void cxr_debug_line( v3f p0, v3f p1, v4f colour ) { - cxr_context.brush_count = 0; - cxr_context.entity_count = 0; - cxr_context.face_count = 0; - cxr_context.offset_z = 0.0; - cxr_context.scale_factor = 32.0; + if( cxr_line_func ) + cxr_line_func( p0, p1, colour ); } -CXR_API void cxr_set_offset(double offset) +static void cxr_debug_box( v3f p0, double sz, v4f colour ) { - cxr_context.offset_z = offset; -} + v3f a,b,c,d, + a1,b1,c1,d1; + v3_add(p0, (v3f){-sz,-sz,-sz}, a); + v3_add(p0, (v3f){-sz, sz,-sz}, b); + v3_add(p0, (v3f){ sz, sz,-sz}, c); + v3_add(p0, (v3f){ sz,-sz,-sz}, d); + v3_add(p0, (v3f){-sz,-sz,sz}, a1); + v3_add(p0, (v3f){-sz, sz,sz}, b1); + v3_add(p0, (v3f){ sz, sz,sz}, c1); + v3_add(p0, (v3f){ sz,-sz,sz}, d1); -CXR_API void cxr_set_scale_factor(double scale) -{ - cxr_context.scale_factor = scale; + cxr_debug_line( a,b, colour ); + cxr_debug_line( b,c, colour ); + cxr_debug_line( c,d, colour ); + cxr_debug_line( d,a, colour ); + cxr_debug_line( a1,b1, colour ); + cxr_debug_line( b1,c1, colour ); + cxr_debug_line( c1,d1, colour ); + cxr_debug_line( d1,a1, colour ); + cxr_debug_line( a,a1, colour ); + cxr_debug_line( b,b1, colour ); + cxr_debug_line( c,c1, colour ); + cxr_debug_line( d,d1, colour ); } -CXR_API cxr_vdf *cxr_vdf_open(const char *path) +/* + * Draw arrow with the tips oriented along normal + */ +static void cxr_debug_arrow( v3f p0, v3f p1, v3f normal, double sz, v4f colour ) { - cxr_vdf *vdf = malloc(sizeof(cxr_vdf)); - - vdf->level = 0; - vdf->fp = fopen( path, "w" ); - - if( !vdf->fp ) - { - free( vdf ); - return NULL; - } + v3f dir, tan, p2, p3; + v3_sub(p1,p0,dir); + v3_normalize(dir); - return vdf; + v3_cross(dir,normal,tan); + v3_muladds( p1,dir, -sz, p2 ); + v3_muladds( p2,tan,sz,p3 ); + cxr_debug_line( p1, p3, colour ); + v3_muladds( p2,tan,-sz,p3 ); + cxr_debug_line( p1, p3, colour ); + cxr_debug_line( p0, p1, colour ); } -CXR_API void cxr_vdf_close(cxr_vdf *vdf) +/* + * Draw arrows CCW around polygon, draw normal vector from center + */ +static void cxr_debug_poly( cxr_mesh *mesh, cxr_polygon *poly, v4f colour ) { - fclose( vdf->fp ); - free( vdf ); -} + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); -CXR_API void cxr_vdf_put(cxr_vdf *vdf, const char *str) -{ - for( int i=0; ilevel; i++ ) - fputs( " ", vdf->fp ); + for( int i=0; iloop_total; i++ ) + { + int lp0 = poly->loop_start+i, + lp1 = poly->loop_start+cxr_range(i+1,poly->loop_total); - fputs( str, vdf->fp ); -} + int i0 = mesh->loops[ lp0 ].index, + i1 = mesh->loops[ lp1 ].index; -static void cxr_vdf_printf( cxr_vdf *vdf, const char *fmt, ... ) -{ - cxr_vdf_put(vdf,""); + v3f p0, p1; + + v3_lerp( verts[i0], poly->center, 0.0075, p0 ); + v3_lerp( verts[i1], poly->center, 0.0075, p1 ); + v3_muladds( p0, poly->normal, 0.01, p0 ); + v3_muladds( p1, poly->normal, 0.01, p1 ); - va_list args; - va_start( args, fmt ); - vfprintf( vdf->fp, fmt, args ); - va_end(args); -} + cxr_debug_arrow( p0, p1, poly->normal, 0.05, colour ); + } -CXR_API void cxr_vdf_node(cxr_vdf *vdf, const char *str) -{ - cxr_vdf_put( vdf, str ); - putc( (u8)'\n', vdf->fp ); - cxr_vdf_put( vdf, "{\n" ); + v3f nrm0; + v3_muladds( poly->center, poly->normal, 0.3, nrm0 ); - vdf->level ++; + cxr_debug_line( poly->center, nrm0, colour ); } -CXR_API void cxr_vdf_edon( cxr_vdf *vdf ) +static void cxr_debug_mesh(cxr_mesh *mesh, v4f colour ) { - vdf->level --; - cxr_vdf_put( vdf, "}\n" ); + for( int i=0; iabpolys.count; i++ ) + { + cxr_polygon *poly = &mesh->polys[i]; + cxr_debug_poly( mesh, poly, colour ); + } } -CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv ) +CXR_API void cxr_write_test_data( cxr_static_mesh *src ) { - cxr_vdf_printf( vdf, "\"%s\" \"%s\"\n", strk, strv ); -} - -/* - * Data-type specific Keyvalues - */ -static void cxr_vdf_ki32( cxr_vdf *vdf, const char *strk, i32 val ) -{ - cxr_vdf_printf( vdf, "\"%s\" \"%d\"\n", strk, val ); -} - -static void cxr_vdf_kdouble( cxr_vdf *vdf, const char *strk, double val ) -{ - cxr_vdf_printf( vdf, "\"%s\" \"%f\"\n", strk, val ); -} - -static void cxr_vdf_kaxis( cxr_vdf *vdf, const char *strk, - v3f normal, double offset, double scale -){ - cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n", - strk, normal[0], normal[1],normal[2], offset, scale ); -} - -static void cxr_vdf_kv3f( cxr_vdf *vdf, const char *strk, v3f v ) -{ - cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f]\"\n", strk, v[0], v[1], v[2] ); -} - -static void cxr_vdf_karrdouble( cxr_vdf *vdf, const char *strk, - int id, double *doubles, int count -){ - cxr_vdf_put(vdf,""); - fprintf( vdf->fp, "\"%s%d\" \"", strk, id ); - for( int i=0; ivertex_count; i ++ ) { - if( i == count-1 ) fprintf( vdf->fp, "%f", doubles[i] ); - else fprintf( vdf->fp, "%f ", doubles[i] ); + fprintf( fp, " { %f, %f, %f },\n", + src->vertices[i][0], + src->vertices[i][1], + src->vertices[i][2] ); } - fprintf( vdf->fp, "\"\n" ); -} + fprintf( fp, "};\n" ); -static void cxr_vdf_karrv3f( cxr_vdf *vdf, const char *strk, - int id, v3f *vecs, int count -){ - cxr_vdf_put(vdf,""); - fprintf( vdf->fp, "\"%s%d\" \"", strk, id ); - for( int i=0; iloop_count; i ++ ) { - const char *format = i == count-1? "%f %f %f": "%f %f %f "; - fprintf( vdf->fp, format, vecs[i][0], vecs[i][1], vecs[i][2] ); + fprintf( fp, " {%d, %d},\n", + src->loops[i].index, + src->loops[i].edge_index); } - fprintf( vdf->fp, "\"\n" ); -} + fprintf( fp, "};\n" ); -static void cxr_vdf_plane( cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c ) -{ - cxr_vdf_printf( vdf, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n", - strk, a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2] ); -} + fprintf( fp, "struct cxr_polygon test_polys[] = {\n" ); + for( int i=0; i poly_count; i++ ) + { + fprintf( fp, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n", + src->polys[i].loop_start, + src->polys[i].loop_total, + src->polys[i].normal[0], + src->polys[i].normal[1], + src->polys[i].normal[2], + src->polys[i].center[0], + src->polys[i].center[1], + src->polys[i].center[2] ); + } + fprintf( fp, "};\n" ); -static void cxr_vdf_colour255(cxr_vdf *vdf, const char *strk, v4f colour) -{ - v4f scale; - v4_muls( colour, 255.0, scale ); - cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n", - strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]); -} + fprintf( fp, "struct cxr_edge test_edges[] = {\n" ); + for( int i=0; iedge_count; i++ ) + { + fprintf( fp, " {%d, %d, %d},\n", + src->edges[i].i0, + src->edges[i].i1, + src->edges[i].freestyle + ); + } + fprintf( fp, "};\n" ); -/* - * Debugging line drawing - */ -static void cxr_debug_line( v3f p0, v3f p1, v4f colour ) -{ - if( cxr_line_func ) - cxr_line_func( p0, p1, colour ); + fprintf( fp, "struct cxr_static_mesh test_mesh = {\n" ); + fprintf( fp, " .vertices = test_verts,\n" ); + fprintf( fp, " .loops = test_loops,\n" ); + fprintf( fp, " .edges = test_edges,\n" ); + fprintf( fp, " .polys = test_polys,\n" ); + fprintf( fp, " .poly_count=%d,\n", src->poly_count ); + fprintf( fp, " .vertex_count=%d,\n", src->vertex_count ); + fprintf( fp, " .edge_count=%d,\n",src->edge_count ); + fprintf( fp, " .loop_count=%d\n", src->loop_count ); + fprintf( fp, "};\n" ); + + fclose( fp ); } -static void cxr_debug_box( v3f p0, double sz, v4f colour ) +CXR_API void cxr_set_log_function( void (*func)(const char *str) ) { - v3f a,b,c,d, - a1,b1,c1,d1; - v3_add(p0, (v3f){-sz,-sz,-sz}, a); - v3_add(p0, (v3f){-sz, sz,-sz}, b); - v3_add(p0, (v3f){ sz, sz,-sz}, c); - v3_add(p0, (v3f){ sz,-sz,-sz}, d); - v3_add(p0, (v3f){-sz,-sz,sz}, a1); - v3_add(p0, (v3f){-sz, sz,sz}, b1); - v3_add(p0, (v3f){ sz, sz,sz}, c1); - v3_add(p0, (v3f){ sz,-sz,sz}, d1); - - cxr_debug_line( a,b, colour ); - cxr_debug_line( b,c, colour ); - cxr_debug_line( c,d, colour ); - cxr_debug_line( d,a, colour ); - cxr_debug_line( a1,b1, colour ); - cxr_debug_line( b1,c1, colour ); - cxr_debug_line( c1,d1, colour ); - cxr_debug_line( d1,a1, colour ); - cxr_debug_line( a,a1, colour ); - cxr_debug_line( b,b1, colour ); - cxr_debug_line( c,c1, colour ); - cxr_debug_line( d,d1, colour ); + cxr_log_func = func; } -/* - * Draw arrow with the tips oriented along normal - */ -static void cxr_debug_arrow( v3f p0, v3f p1, v3f normal, double sz, v4f colour ) +CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) ) { - v3f dir, tan, p2, p3; - v3_sub(p1,p0,dir); - v3_normalize(dir); - - v3_cross(dir,normal,tan); - v3_muladds( p1,dir, -sz, p2 ); - v3_muladds( p2,tan,sz,p3 ); - cxr_debug_line( p1, p3, colour ); - v3_muladds( p2,tan,-sz,p3 ); - cxr_debug_line( p1, p3, colour ); - cxr_debug_line( p0, p1, colour ); + cxr_line_func = func; } -/* - * Draw arrows CCW around polygon, draw normal vector from center - */ -static void cxr_debug_poly( cxr_mesh *mesh, cxr_polygon *poly, v4f colour ) -{ - v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); - - for( int i=0; iloop_total; i++ ) - { - int lp0 = poly->loop_start+i, - lp1 = poly->loop_start+cxr_range(i+1,poly->loop_total); - - int i0 = mesh->loops[ lp0 ].index, - i1 = mesh->loops[ lp1 ].index; - - v3f p0, p1; - - v3_lerp( verts[i0], poly->center, 0.02, p0 ); - v3_lerp( verts[i1], poly->center, 0.02, p1 ); +#endif /* CXR_DEBUG */ - cxr_debug_arrow( p0, p1, poly->normal, 0.05, colour ); - } - - v3f nrm0; - v3_muladds( poly->center, poly->normal, 0.3, nrm0 ); - - cxr_debug_line( poly->center, nrm0, colour ); -} - -static void cxr_debug_mesh(cxr_mesh *mesh, v4f colour ) -{ - for( int i=0; iabpolys.count; i++ ) - { - cxr_polygon *poly = &mesh->polys[i]; - cxr_debug_poly( mesh, poly, colour ); - } -} /* * abverts is a pointer to an existing vertex buffer @@ -738,7 +753,9 @@ static int cxr_create_poly( cxr_mesh *mesh, int loop_count ) if( loop_count < 3 ) { +#ifdef CXR_DEBUG cxr_log( "tried to add new poly with length %d!\n", loop_count ); +#endif return 0; } @@ -1086,9 +1103,8 @@ tag_vert: static int cxr_solid_overlap( cxr_mesh *mesh, cxr_polygon *pa, cxr_polygon *pb, - int common_edge_index, - int debug ) -{ + int common_edge_index +){ v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); cxr_edge *common_edge = &mesh->edges[common_edge_index]; @@ -1122,9 +1138,6 @@ static int cxr_solid_overlap( cxr_mesh *mesh, int i0 = unique_verts[i], i1 = unique_verts[j]; - if( debug ) - cxr_debug_line( verts[i0], verts[i1], colours_random[2] ); - for( int k=0; kabedges.count; k++ ) { cxr_edge *edge = &mesh->edges[k]; @@ -1141,32 +1154,13 @@ static int cxr_solid_overlap( cxr_mesh *mesh, if( dist < 0.025 ) { - if( debug ) - { - cxr_debug_box( ca, 0.025, colour_error ); - cxr_debug_box( cb, 0.025, colour_error ); - cxr_debug_line( a0, a1, colour_error ); - cxr_debug_line( b0, b1, colour_error ); - - continue; - } - else - { - free( unique_verts ); - return 1; - } + free( unique_verts ); + return 1; } } } } - if( debug ) - { - cxr_debug_line( verts[mesh->edges[common_edge_index].i0], - verts[mesh->edges[common_edge_index].i1], - colour_success ); - } - free( unique_verts ); return 0; } @@ -1209,7 +1203,7 @@ search_iterate:; /* Check for dodgy edges */ cxr_polygon *newpoly = &mesh->polys[loop->poly_right]; - if( cxr_solid_overlap(mesh,poly,newpoly,loop->edge_index,0)) + if( cxr_solid_overlap(mesh,poly,newpoly,loop->edge_index)) goto skip_plane; /* Looking ahead by one step gives us an early out for invalid @@ -1322,8 +1316,7 @@ static void cxr_link_manifold( struct csolid *solid, int *solid_buffer, struct temp_manifold *manifold - ) -{ +){ cxr_loop **edge_list = malloc( sizeof(*edge_list) * solid->edge_count ); int init_reverse = 0; @@ -1471,12 +1464,14 @@ static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start ) if( plane_polarity( planel, intersect ) > 0.01 ) { +#ifdef CXR_DEBUG cxr_log( "degen vert, planes %d, %d, %d [max:%d]\n", i,j,k, new_polys ); - + cxr_debug_poly( mesh, ptri, colours_random[3] ); cxr_debug_poly( mesh, ptrj, colours_random[1] ); cxr_debug_poly( mesh, ptrk, colours_random[2] ); +#endif return 0; } @@ -1552,13 +1547,17 @@ static int cxr_build_implicit_geo( cxr_mesh *mesh, int new_polys, int start ) static cxr_mesh *cxr_pull_best_solid( cxr_mesh *mesh, int preserve_more_edges, - u32 *error ) + enum cxr_soliderr *err ) { + *err = k_soliderr_none; + if( !cxr_mesh_link_loops(mesh) ) { +#ifdef CXR_DEBUG cxr_log( "non-manifold edges are in the mesh: " "implicit internal geometry does not have full support\n" ); - +#endif + *err = k_soliderr_non_manifold; return NULL; } @@ -1678,7 +1677,8 @@ static cxr_mesh *cxr_pull_best_solid( if( manifold.status == k_manifold_err ) { - *error = CXR_ERROR_BAD_MANIFOLD; + *err = k_soliderr_bad_manifold; + free(solid_buffer); free(candidates); free(manifold.loops); @@ -1705,7 +1705,7 @@ static cxr_mesh *cxr_pull_best_solid( if( max_solid_faces < 2 ) { - *error = CXR_ERROR_NO_SOLIDS; + *err = k_soliderr_no_solids; free(solid_buffer); free(candidates); free(best_manifold.loops); @@ -1784,7 +1784,9 @@ static cxr_mesh *cxr_pull_best_solid( if( new_polys > best_manifold.loop_count ) { +#ifdef CXR_DEBUG cxr_log( "Programming error: Too many new polys!\n" ); +#endif exit(1); } @@ -1853,7 +1855,7 @@ static cxr_mesh *cxr_pull_best_solid( free(best_manifold.loops); cxr_free_mesh( pullmesh ); - *error = CXR_ERROR_DEGEN_IMPLICIT; + *err = k_soliderr_degenerate_implicit; return NULL; } } @@ -1916,7 +1918,7 @@ static cxr_mesh *cxr_pull_best_solid( * with auto buffers. */ static cxr_mesh *cxr_to_internal_format( - cxr_input_mesh *src, + cxr_static_mesh *src, cxr_abuffer *abverts ){ cxr_mesh *mesh = cxr_alloc_mesh( src->edge_count, src->loop_count, @@ -1946,6 +1948,426 @@ static cxr_mesh *cxr_to_internal_format( return mesh; } +static int cxr_solid_checkerr( cxr_mesh *mesh ) +{ + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + int err_count = 0; + + for( int i=0; iabpolys.count; i++ ) + { + int plane_err = 0; + + cxr_polygon *poly = &mesh->polys[i]; + v4f plane; + + normal_to_plane( poly->normal, poly->center, plane ); + + for( int j=0; jloop_total; j++ ) + { + cxr_loop *loop = &mesh->loops[ poly->loop_start+j ]; + double *vert = verts[ loop->index ]; + + if( fabs(plane_polarity(plane,vert)) > 0.0025 ) + { + err_count ++; + plane_err ++; + + v3f ref; + plane_project_point( plane, vert, ref ); + +#ifdef CXR_DEBUG + cxr_debug_line( ref, vert, colour_error ); + cxr_debug_box( vert, 0.1, colour_error ); +#endif + } + } + +#ifdef CXR_DEBUG + if( plane_err ) + cxr_debug_poly( mesh, poly, colour_error ); +#endif + } + + return err_count; +} + +CXR_API void cxr_free_world( cxr_world *world ) +{ + for( int i=0; iabsolids.count; i++ ) + { + cxr_solid *solid = cxr_ab_ptr( &world->absolids, i ); + cxr_free_mesh( solid->pmesh ); + } + + cxr_ab_free( &world->abverts ); + cxr_ab_free( &world->absolids ); + free( world->materials ); + free( world ); +} + +CXR_API cxr_tri_mesh *cxr_world_preview( cxr_world *world ) +{ + cxr_tri_mesh *out = malloc( sizeof(cxr_tri_mesh) ); + out->vertex_count = 0; + out->indices_count = 0; + + for( int i=0; iabsolids.count; i++ ) + { + cxr_solid *solid = cxr_ab_ptr( &world->absolids, i ); + cxr_mesh *mesh = solid->pmesh; + + for( int j=0; jabpolys.count; j ++ ) + { + cxr_polygon *poly = &mesh->polys[j]; + + out->vertex_count += poly->loop_total * 3; /* Polygon, edge strip */ + out->indices_count += (poly->loop_total -2) * 3; /* Polygon */ + out->indices_count += poly->loop_total * 2 * 3; /* Edge strip */ + } + } + + out->colours = malloc( sizeof(v4f)*out->vertex_count ); + out->vertices = malloc( sizeof(v3f)*out->vertex_count ); + out->indices = malloc( sizeof(i32)*out->indices_count ); + + v3f *overts = out->vertices; + v4f *colours = out->colours; + i32 *indices = out->indices; + + int vi = 0, + ii = 0; + + for( int i=0; iabsolids.count; i++ ) + { + cxr_solid *solid = cxr_ab_ptr( &world->absolids, i ); + cxr_mesh *mesh = solid->pmesh; + + v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); + v4f colour; + + colour_random_brush( i, colour ); + + for( int j=0; jabpolys.count; j ++ ) + { + cxr_polygon *poly = &mesh->polys[j]; + + int istart = vi; + + for( int k=0; kloop_total-2; k++ ) + { + int i0 = 0, + i1 = (k+1)*3, + i2 = (k+2)*3; + + indices[ ii ++ ] = istart+i0; + indices[ ii ++ ] = istart+i1; + indices[ ii ++ ] = istart+i2; + } + + for( int k=0; kloop_total; k++ ) + { + cxr_loop *lp = &mesh->loops[poly->loop_start+k]; + + int i0r = k*3+1, + i1r = cxr_range(k+1,poly->loop_total)*3+1, + i0i = k*3+2, + i1i = cxr_range(k+1,poly->loop_total)*3+2; + + indices[ ii ++ ] = istart+i0i; + indices[ ii ++ ] = istart+i1i; + indices[ ii ++ ] = istart+i1r; + + indices[ ii ++ ] = istart+i0i; + indices[ ii ++ ] = istart+i1r; + indices[ ii ++ ] = istart+i0r; + + /* Main */ + v3_muladds( verts[lp->index], poly->normal, 0.02, overts[vi] ); + v4_copy( colour, colours[ vi ] ); + vi ++; + + /* Trim */ + v3f inner; + v3_lerp( verts[lp->index], poly->center, 0.2, inner ); + v3_muladds( inner, poly->normal, 0.015, overts[ vi ] ); + v4_copy( colour, colours[ vi ] ); + v4_copy( (v4f){ 0.0, 0.0, 0.0, 0.0 }, colours[vi] ); + vi ++; + + v3_muladds(verts[lp->index], poly->normal, 0.0, overts[ vi ] ); + v4_copy( colour, colours[ vi ] ); + v4_copy( (v4f){ 1.0, 1.0, 1.0, 0.125 }, colours[vi] ); + vi ++; + } + } + } + + return out; +} + +CXR_API void cxr_free_tri_mesh( cxr_tri_mesh *mesh ) +{ + free( mesh->colours ); + free( mesh->indices ); + free( mesh->vertices ); + free( mesh ); +} + +CXR_API cxr_world *cxr_decompose( cxr_static_mesh *src ) +{ + cxr_world *world = malloc( sizeof(*world) ); + + /* Copy data to internal formats */ + cxr_mesh *main_mesh = cxr_to_internal_format( src, &world->abverts ); + cxr_ab_init( &world->absolids, sizeof(cxr_solid), 2 ); + + if( src->material_count ) + { + size_t dsize = sizeof(cxr_material) * src->material_count; + world->materials = malloc( dsize ); + memcpy( world->materials, src->materials, dsize ); + } + else world->materials = NULL; + + int invalid_count = 0; + + /* + * Preprocessor 1: Island seperation + */ + while(1) + { + cxr_mesh *res = cxr_pull_island( main_mesh ); + if( res ) + { + cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 }); + } + else break; + } + cxr_ab_push( &world->absolids, &(cxr_solid){ main_mesh, 0, 0 } ); + + /* + * Preprocessor 2: Displacement processing & error checks + */ + for( int i=0; iabsolids.count; i++ ) + { + cxr_solid *pinf = cxr_ab_ptr(&world->absolids,i); + + for( int j=0; jpmesh->abpolys.count; j++ ) + { + cxr_polygon *poly = &pinf->pmesh->polys[ j ]; + + for( int k=0; kloop_total; k++ ) + { + cxr_loop *lp = &pinf->pmesh->loops[ poly->loop_start+k ]; + cxr_edge *edge = &pinf->pmesh->edges[ lp->edge_index ]; + + if( edge->freestyle ) + goto displacement; + } + } + + if( cxr_solid_checkerr( pinf->pmesh ) ) + { + pinf->invalid = 1; + invalid_count ++; + } + + continue; + + displacement: + pinf->displacement = 1; + } + + /* + * Main convex decomp algorithm + */ + int sources_count = world->absolids.count; + u32 error = 0x00; + + if( invalid_count ) + goto decomp_failed; + + for( int i=0; iabsolids, i); + + if( pinf.displacement || pinf.invalid ) + continue; + + while(1) + { + cxr_mesh *res = cxr_pull_best_solid( pinf.pmesh, 0, &error ); + + if( res ) + { + cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 } ); + } + else + { + if( error == k_soliderr_no_solids ) + { + /* Retry if non-critical error, with extra edges */ + res = cxr_pull_best_solid(pinf.pmesh, 1, &error); + + if( res ) + cxr_ab_push( &world->absolids, &(cxr_solid){ res, 0, 0 } ); + else + goto decomp_failed; + } + else + if( error ) + goto decomp_failed; + else + break; + } + } + } + + return world; + +decomp_failed: + cxr_log( "Error %d\n", error ); + cxr_free_world( world ); + return NULL; +} + +/* + * format specific functions: vdf, vmf, (v)bsp + * ---------------------------------------------------------------------------- + */ +#ifdef CXR_VALVE_MAP_FILE + +CXR_API cxr_vdf *cxr_vdf_open(const char *path) +{ + cxr_vdf *vdf = malloc(sizeof(cxr_vdf)); + + vdf->level = 0; + vdf->fp = fopen( path, "w" ); + + if( !vdf->fp ) + { + free( vdf ); + return NULL; + } + + return vdf; +} + +CXR_API void cxr_vdf_close(cxr_vdf *vdf) +{ + fclose( vdf->fp ); + free( vdf ); +} + +CXR_API void cxr_vdf_put(cxr_vdf *vdf, const char *str) +{ + for( int i=0; ilevel; i++ ) + fputs( " ", vdf->fp ); + + fputs( str, vdf->fp ); +} + +static void cxr_vdf_printf( cxr_vdf *vdf, const char *fmt, ... ) +{ + cxr_vdf_put(vdf,""); + + va_list args; + va_start( args, fmt ); + vfprintf( vdf->fp, fmt, args ); + va_end(args); +} + +CXR_API void cxr_vdf_node(cxr_vdf *vdf, const char *str) +{ + cxr_vdf_put( vdf, str ); + putc( (u8)'\n', vdf->fp ); + cxr_vdf_put( vdf, "{\n" ); + + vdf->level ++; +} + +CXR_API void cxr_vdf_edon( cxr_vdf *vdf ) +{ + vdf->level --; + cxr_vdf_put( vdf, "}\n" ); +} + +CXR_API void cxr_vdf_kv( cxr_vdf *vdf, const char *strk, const char *strv ) +{ + cxr_vdf_printf( vdf, "\"%s\" \"%s\"\n", strk, strv ); +} + +/* + * Data-type specific Keyvalues + */ +static void cxr_vdf_ki32( cxr_vdf *vdf, const char *strk, i32 val ) +{ + cxr_vdf_printf( vdf, "\"%s\" \"%d\"\n", strk, val ); +} + +static void cxr_vdf_kdouble( cxr_vdf *vdf, const char *strk, double val ) +{ + cxr_vdf_printf( vdf, "\"%s\" \"%f\"\n", strk, val ); +} + +static void cxr_vdf_kaxis( cxr_vdf *vdf, const char *strk, + v3f normal, double offset, double scale +){ + cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f %f] %f\"\n", + strk, normal[0], normal[1],normal[2], offset, scale ); +} + +static void cxr_vdf_kv3f( cxr_vdf *vdf, const char *strk, v3f v ) +{ + cxr_vdf_printf( vdf, "\"%s\" \"[%f %f %f]\"\n", strk, v[0], v[1], v[2] ); +} + +static void cxr_vdf_karrdouble( cxr_vdf *vdf, const char *strk, + int id, double *doubles, int count +){ + cxr_vdf_put(vdf,""); + fprintf( vdf->fp, "\"%s%d\" \"", strk, id ); + for( int i=0; ifp, "%f", doubles[i] ); + else fprintf( vdf->fp, "%f ", doubles[i] ); + } + fprintf( vdf->fp, "\"\n" ); +} + +static void cxr_vdf_karrv3f( cxr_vdf *vdf, const char *strk, + int id, v3f *vecs, int count +){ + cxr_vdf_put(vdf,""); + fprintf( vdf->fp, "\"%s%d\" \"", strk, id ); + for( int i=0; ifp, format, vecs[i][0], vecs[i][1], vecs[i][2] ); + } + fprintf( vdf->fp, "\"\n" ); +} + +static void cxr_vdf_plane( cxr_vdf *vdf, const char *strk, v3f a, v3f b, v3f c ) +{ + cxr_vdf_printf( vdf, "\"%s\" \"(%f %f %f) (%f %f %f) (%f %f %f)\"\n", + strk, a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2] ); +} + +static void cxr_vdf_colour255(cxr_vdf *vdf, const char *strk, v4f colour) +{ + v4f scale; + v4_muls( colour, 255.0, scale ); + cxr_vdf_printf( vdf, "\"%s\" \"%d %d %d %d\"\n", + strk,(int)scale[0], (int)scale[1], (int)scale[2], (int)scale[3]); +} + +static struct cxr_material cxr_nodraw = +{ + .res = { 512, 512 }, + .name = "tools/toolsnodraw" +}; + /* * Find most extreme point along a given direction */ @@ -2069,73 +2491,10 @@ static void cxr_calculate_axis( cxr_texinfo *transform, v3f verts[3], transform->winding = winding; } -CXR_API cxr_input_mesh *cxr_write_test_data( cxr_input_mesh *src ) -{ - FILE *fp = fopen( - "/home/harry/Documents/blender_addons_remote/addons/convexer/src/solid.h", - "w" ); - - fprintf( fp, "v3f test_verts[] = {\n" ); - for( int i=0; ivertex_count; i ++ ) - { - fprintf( fp, " { %f, %f, %f },\n", - src->vertices[i][0], - src->vertices[i][1], - src->vertices[i][2] ); - } - fprintf( fp, "};\n" ); - - fprintf( fp, "struct cxr_input_loop test_loops[] = {\n" ); - for( int i=0; iloop_count; i ++ ) - { - fprintf( fp, " {%d, %d},\n", - src->loops[i].index, - src->loops[i].edge_index); - } - fprintf( fp, "};\n" ); - - fprintf( fp, "struct cxr_polygon test_polys[] = {\n" ); - for( int i=0; i poly_count; i++ ) - { - fprintf( fp, " {%d, %d, {%f, %f, %f}, {%f, %f, %f}},\n", - src->polys[i].loop_start, - src->polys[i].loop_total, - src->polys[i].normal[0], - src->polys[i].normal[1], - src->polys[i].normal[2], - src->polys[i].center[0], - src->polys[i].center[1], - src->polys[i].center[2] ); - } - fprintf( fp, "};\n" ); - - fprintf( fp, "struct cxr_edge test_edges[] = {\n" ); - for( int i=0; iedge_count; i++ ) - { - fprintf( fp, " {%d, %d, %d},\n", - src->edges[i].i0, - src->edges[i].i1, - src->edges[i].freestyle - ); - } - fprintf( fp, "};\n" ); - - fprintf( fp, "struct cxr_input_mesh test_mesh = {\n" ); - fprintf( fp, " .vertices = test_verts,\n" ); - fprintf( fp, " .loops = test_loops,\n" ); - fprintf( fp, " .edges = test_edges,\n" ); - fprintf( fp, " .polys = test_polys,\n" ); - fprintf( fp, " .poly_count=%d,\n", src->poly_count ); - fprintf( fp, " .vertex_count=%d,\n", src->vertex_count ); - fprintf( fp, " .edge_count=%d,\n",src->edge_count ); - fprintf( fp, " .loop_count=%d\n", src->loop_count ); - fprintf( fp, "};\n" ); - - fclose( fp ); - - return NULL; -} - +/* + * Get the maximal direction of a vector, while also ignoring an axis + * specified + */ static int cxr_cardinal( v3f a, int ignore ) { int component = 0; @@ -2161,8 +2520,8 @@ static int cxr_cardinal( v3f a, int ignore ) /* * Convert contiguous mesh to displacement patch */ -static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, - cxr_vdf *output +static int cxr_write_disp( cxr_mesh *mesh, cxr_world *world, + cxr_vmf_context *ctx, cxr_vdf *output ){ v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); @@ -2206,26 +2565,9 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, } } - /* - * Find best normal for brush patch. VBSP uses the original brush as an - * reference for decal projection in-game - */ - - v3f avg_normal, refv, refu, refn; + v3f refv, refu, refn; v3_zero(refv); v3_zero(refu); v3_zero(refn); - for( int i=0; iabpolys.count; i++ ) - { - cxr_polygon *poly = &mesh->polys[i]; - v3_add( poly->normal, avg_normal, avg_normal ); - } - v3_divs( avg_normal, mesh->abpolys.count, avg_normal ); - - if( v3_length( avg_normal ) <= 1e-6 ) - v3_copy( (v3f){ 0.0, 0.0, 1.0 }, avg_normal ); - else - v3_normalize( avg_normal ); - /* * Approximately match the area of the result brush faces to the actual * area. @@ -2347,9 +2689,9 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, int corner_count = 1; cxr_material *matptr = - basepoly->material_id < 0 || inputmesh->material_count == 0? + basepoly->material_id < 0 || !world->materials? &cxr_nodraw: - &inputmesh->materials[ basepoly->material_id ]; + &world->materials[ basepoly->material_id ]; dispedge_count = 2; dispedge[0] = l0->index; @@ -2425,9 +2767,7 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, if( !newvert ) { - cxr_debug_box( verts[dispedge[dispedge_count-1]], 0.1, - colour_error); - break; + return 0; } } @@ -2489,10 +2829,12 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, } } +#ifdef CXR_DEBUG cxr_log( "Broken displacement!\n" ); +#endif free( graph ); free( vertinfo ); - return; + return 0; next_cell:; } @@ -2541,17 +2883,6 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, v3_muladds( face_center, refn, 1.5, pn ); v3_muladds( face_center, refv, 1.5, pv ); v3_muladds( face_center, refu, 1.5, pu ); - - /* Draw reference vectors */ - if( cxr_settings.debug ) - { - cxr_debug_line( p0, pn, (v4f){0.0,0.0,1.0,1.0}); - cxr_debug_line( p0, pv, (v4f){0.0,1.0,0.0,1.0}); - cxr_debug_line( p0, pu, (v4f){1.0,0.0,0.0,1.0}); - cxr_debug_line(tri_ref[0],tri_ref[1],(v4f){1.0,1.0,1.0,1.0}); - cxr_debug_line(tri_ref[1],tri_ref[2],(v4f){1.0,1.0,1.0,1.0}); - cxr_debug_line(tri_ref[2],tri_ref[0],(v4f){1.0,1.0,1.0,1.0}); - } } /* Create world coordinates */ @@ -2575,24 +2906,12 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, for( int j=0; j<4; j++ ) v3_muladds( world_corners[j], refn, -1.0, world_corners[j+4] ); - if( cxr_settings.debug ) - { - for( int j=0; j<4; j++ ) - { - double *p0 = world_corners[j], - *p1 = world_corners[cxr_range(j+1,4)]; - - cxr_debug_arrow( p0, p1, avg_normal, 0.1, colour ); - } - } - /* Apply world transform */ for( int j=0; j<8; j++ ) { double *p0 = world_corners[j]; - v3_muls( p0, cxr_context.scale_factor, p0 ); - - p0[2] += cxr_context.offset_z; + v3_muls( p0, ctx->scale, p0 ); + v3_add( p0, ctx->offset, p0 ); } cxr_texinfo texinfo_shared; @@ -2601,7 +2920,7 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, /* Write brush */ cxr_vdf_node( output, "solid" ); - cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count ); + cxr_vdf_ki32( output, "id", ++ ctx->brush_count ); int sides[6][3] = {{ 0, 1, 2 }, @@ -2630,8 +2949,8 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, tx = (double)k/(double)(5-1); v3_lerp( lside0, lside1, tx, lref ); - v3_muls( verts[grid[index]], cxr_context.scale_factor, vworld ); - vworld[2] += cxr_context.offset_z; + v3_muls( verts[grid[index]], ctx->scale, vworld ); + v3_add( ctx->offset, vworld, ctx->offset ); v3_sub( vworld, lref, vdelta ); v3_copy( vdelta, normals[index] ); @@ -2645,12 +2964,12 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, int *side = sides[j]; cxr_vdf_node( output, "side" ); - cxr_vdf_ki32( output, "id", ++ cxr_context.face_count ); + cxr_vdf_ki32( output, "id", ++ ctx->face_count ); cxr_vdf_plane( output, "plane", world_corners[side[2]], world_corners[side[1]], world_corners[side[0]] ); - cxr_vdf_kv( output, "material", matptr->vmt_path ); + cxr_vdf_kv( output, "material", matptr->name ); cxr_vdf_kaxis( output, "uaxis", texinfo_shared.uaxis, @@ -2662,7 +2981,7 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, texinfo_shared.scale[1] ); cxr_vdf_kdouble( output, "rotation", 0.0 ); - cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale); + cxr_vdf_ki32( output, "lightmapscale", ctx->lightmap_scale); cxr_vdf_ki32( output, "smoothing_groups", 0 ); if( j == 0 ) @@ -2727,7 +3046,7 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, cxr_vdf_node( output, "editor"); cxr_vdf_colour255( output, "color", - colours_random[cxr_range(cxr_context.brush_count,8)]); + colours_random[cxr_range(ctx->brush_count,8)]); cxr_vdf_ki32( output, "visgroupshown",1); cxr_vdf_ki32( output, "visgroupautoshown",1); @@ -2740,192 +3059,75 @@ static void cxr_write_disp( cxr_mesh *mesh, cxr_input_mesh *inputmesh, free( graph ); free( vertinfo ); + + return 1; } -static int cxr_solid_checkerr( cxr_mesh *mesh ) +/* + * Write header information for a vmf to vdf + */ +CXR_API void cxr_begin_vmf( cxr_vmf_context *ctx, cxr_vdf *output ) { - v3f *verts = cxr_ab_ptr( mesh->p_abverts, 0 ); - int err_count = 0; - - for( int i=0; iabpolys.count; i++ ) - { - int plane_err = 0; - - cxr_polygon *poly = &mesh->polys[i]; - v4f plane; - - normal_to_plane( poly->normal, poly->center, plane ); - - for( int j=0; jloop_total; j++ ) - { - cxr_loop *loop = &mesh->loops[ poly->loop_start+j ]; - double *vert = verts[ loop->index ]; - - if( fabs(plane_polarity(plane,vert)) > 0.0025 ) - { - err_count ++; - plane_err ++; - - v3f ref; - plane_project_point( plane, vert, ref ); - - cxr_debug_line( ref, vert, colour_error ); - cxr_debug_box( vert, 0.1, colour_error ); - } - } - - if( plane_err ) - cxr_debug_poly( mesh, poly, colour_error ); - } - - return err_count; + cxr_vdf_node( output, "versioninfo" ); + cxr_vdf_ki32( output, "editorversion", 400 ); + cxr_vdf_ki32( output, "editorbuild", 8456 ); + cxr_vdf_ki32( output, "mapversion", ctx->mapversion ); + cxr_vdf_ki32( output, "formatversion", 100 ); + cxr_vdf_ki32( output, "prefab", 0 ); + cxr_vdf_edon( output ); + + cxr_vdf_node( output, "visgroups" ); + cxr_vdf_edon( output ); + + cxr_vdf_node( output, "viewsettings" ); + cxr_vdf_ki32( output, "bSnapToGrid", 1 ); + cxr_vdf_ki32( output, "bShowGrid", 1 ); + cxr_vdf_ki32( output, "bShowLogicalGrid", 0 ); + cxr_vdf_ki32( output, "nGridSpacing", 64 ); + cxr_vdf_ki32( output, "bShow3DGrid", 0 ); + cxr_vdf_edon( output ); + + cxr_vdf_node( output, "world" ); + cxr_vdf_ki32( output, "id", 1 ); + cxr_vdf_ki32( output, "mapversion", 1 ); /* ?? */ + cxr_vdf_kv( output, "classname", "worldspawn" ); + cxr_vdf_kv( output, "skyname", ctx->skyname ); + cxr_vdf_ki32( output, "maxpropscreenwidth", -1 ); + cxr_vdf_kv( output, "detailvbsp", ctx->detailvbsp ); + cxr_vdf_kv( output, "detailmaterial", ctx->detailmaterial ); } -CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output) +/* Fairly useless but might need in the future */ +CXR_API void cxr_vmf_begin_entities( cxr_vmf_context *ctx, cxr_vdf *vdf ) { - cxr_abuffer abverts; - cxr_mesh *main_mesh = cxr_to_internal_format(src, &abverts); - - u32 error = 0x00; - int invalid_count = 0; + cxr_vdf_edon( vdf ); +} - struct solidinf - { - cxr_mesh *pmesh; - int is_displacement, invalid; - }; +CXR_API void cxr_end_vmf( cxr_vmf_context *ctx, cxr_vdf *vdf ) +{ +} - cxr_abuffer solids; - cxr_ab_init( &solids, sizeof(struct solidinf), 2 ); +/* + * Write solids (and displacements) to VMF file + */ +CXR_API void cxr_push_world_vmf( cxr_world *world, cxr_vmf_context *ctx, + cxr_vdf *output +){ + v3f *verts = cxr_ab_ptr( &world->abverts, 0 ); - /* - * Preprocessor 1: Island seperation - */ - while(1) - { - cxr_mesh *res = cxr_pull_island( main_mesh ); - if( res ) - { - cxr_ab_push( &solids, &(struct solidinf){ res, 0 }); - } - else break; - } - cxr_ab_push( &solids, &(struct solidinf){main_mesh,0} ); - - /* - * Preprocessor 2: Displacement processing & error checks - */ - for( int i=0; iabsolids.count; i++ ) { - struct solidinf *pinf = cxr_ab_ptr(&solids,i); - - for( int j=0; jpmesh->abpolys.count; j++ ) - { - cxr_polygon *poly = &pinf->pmesh->polys[ j ]; - - for( int k=0; kloop_total; k++ ) - { - cxr_loop *lp = &pinf->pmesh->loops[ poly->loop_start+k ]; - cxr_edge *edge = &pinf->pmesh->edges[ lp->edge_index ]; + cxr_solid *solid = cxr_ab_ptr(&world->absolids,i); - if( edge->freestyle ) - goto IL_SOLID_IS_DISPLACEMENT; - } - } - - if( cxr_solid_checkerr( pinf->pmesh ) ) + if( solid->displacement ) { - pinf->invalid = 1; - invalid_count ++; - } - - continue; - IL_SOLID_IS_DISPLACEMENT:; - - pinf->is_displacement = 1; - cxr_write_disp( pinf->pmesh, src, output ); - } - - /* - * Main convex decomp algorithm - */ - int sources_count = solids.count; - - for( int i=0; ipmesh, world, ctx, output ); continue; - - while(1) - { - cxr_mesh *res = cxr_pull_best_solid( pinf.pmesh, 0, &error ); - - if( res ) - { - cxr_ab_push( &solids, &(struct solidinf){res,0} ); - if( error ) - break; - } - else - { - if( error ) - { - /* Retry if non-critical error, with extra edges */ - - if( error & CXR_ERROR_NO_SOLIDS ) - { - error = 0x00; - res = cxr_pull_best_solid(pinf.pmesh, 1, &error); - - if( res ) cxr_ab_push( &solids, &(struct solidinf){res,0} ); - else break; - - if( error ) break; - } - else - break; - } - else - break; - } - } - } - - if( cxr_settings.debug ) - { - for( int i=0; iis_displacement ) - cxr_debug_mesh( solid->pmesh, colours_random[cxr_range(i,8)] ); - } - } - - if( error ) - { - for( int i=0; ipmesh ); } - - cxr_ab_free( &abverts ); - cxr_ab_free( &solids ); - return error; - } - - /* Write all solids as VMF brushes */ - for( int i=0; iis_displacement ) continue; - + cxr_vdf_node( output, "solid" ); - cxr_vdf_ki32( output, "id", ++ cxr_context.brush_count ); + cxr_vdf_ki32( output, "id", ++ ctx->brush_count ); for( int j=0; jpmesh->abpolys.count; j++ ) { @@ -2933,43 +3135,43 @@ CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output) cxr_loop *ploops = &solid->pmesh->loops[poly->loop_start]; cxr_material *matptr = - poly->material_id < 0 || src->material_count == 0? + poly->material_id < 0 || !world->materials? &cxr_nodraw: - &src->materials[ poly->material_id ]; + &world->materials[ poly->material_id ]; cxr_vdf_node( output, "side" ); - cxr_vdf_ki32( output, "id", ++ cxr_context.face_count ); + cxr_vdf_ki32( output, "id", ++ ctx->face_count ); - v3f verts[3]; v2f uvs[3]; + v3f tri[3]; v2f uvs[3]; int i0 = ploops[0].index, i1 = ploops[1].index, i2 = ploops[2].index; - v3_muls( cxr_ab_ptr(&abverts,i0), cxr_context.scale_factor, verts[0] ); - v3_muls( cxr_ab_ptr(&abverts,i1), cxr_context.scale_factor, verts[1] ); - v3_muls( cxr_ab_ptr(&abverts,i2), cxr_context.scale_factor, verts[2] ); - - verts[0][2] += cxr_context.offset_z; - verts[1][2] += cxr_context.offset_z; - verts[2][2] += cxr_context.offset_z; + v3_muls( verts[i0], ctx->scale, tri[0] ); + v3_muls( verts[i1], ctx->scale, tri[1] ); + v3_muls( verts[i2], ctx->scale, tri[2] ); + + v3_add( ctx->offset, tri[0], tri[0] ); + v3_add( ctx->offset, tri[1], tri[1] ); + v3_add( ctx->offset, tri[2], tri[2] ); v2_copy( ploops[0].uv, uvs[0] ); v2_copy( ploops[1].uv, uvs[1] ); v2_copy( ploops[2].uv, uvs[2] ); - cxr_vdf_plane( output, "plane", verts[2], verts[1], verts[0] ); - cxr_vdf_kv( output, "material", matptr->vmt_path ); + cxr_vdf_plane( output, "plane", tri[2], tri[1], tri[0] ); + cxr_vdf_kv( output, "material", matptr->name ); cxr_texinfo tx; - cxr_calculate_axis( &tx, verts, uvs, + cxr_calculate_axis( &tx, tri, uvs, (double[2]){ matptr->res[0], matptr->res[1] }); cxr_vdf_kaxis( output, "uaxis", tx.uaxis, tx.offset[0], tx.scale[0]); cxr_vdf_kaxis( output, "vaxis", tx.vaxis, tx.offset[1], tx.scale[1]); cxr_vdf_kdouble( output, "rotation", 0.0 ); - cxr_vdf_ki32( output, "lightmapscale", cxr_settings.lightmap_scale ); + cxr_vdf_ki32( output, "lightmapscale", ctx->lightmap_scale ); cxr_vdf_ki32( output, "smoothing_groups", 0); cxr_vdf_edon( output ); @@ -2977,7 +3179,7 @@ CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output) cxr_vdf_node( output, "editor" ); cxr_vdf_colour255( output, "color", - colours_random[cxr_range(cxr_context.brush_count,8)]); + colours_random[cxr_range(ctx->brush_count,8)]); cxr_vdf_ki32( output, "visgroupshown", 1 ); cxr_vdf_ki32( output, "visgroupautoshown", 1 ); @@ -2985,32 +3187,6 @@ CXR_API i32 cxr_convert_mesh_to_vmf(cxr_input_mesh *src, cxr_vdf *output) cxr_vdf_edon( output ); } - - for( int i=0; ipmesh ); - } - - cxr_ab_free( &abverts ); - cxr_ab_free( &solids ); - return 0; -} - - -CXR_API void cxr_set_log_function( void (*func)(const char *str) ) -{ - cxr_log_func = func; -} - -CXR_API void cxr_set_line_function( void (*func)(v3f p0, v3f p1, v4f colour) ) -{ - cxr_line_func = func; -} - -CXR_API void cxr_settings_update( struct cxr_settings *settings ) -{ - cxr_settings = *settings; } /* @@ -3076,7 +3252,9 @@ CXR_API int cxr_lightpatch_bsp( const char *path ) if( !fp ) { +#ifdef CXR_DEBUG cxr_log( "Could not open BSP file for editing (r+b)\n" ); +#endif return 0; } @@ -3105,10 +3283,15 @@ CXR_API int cxr_lightpatch_bsp( const char *path ) fwrite( lights, lump->filelen, 1, fp ); fseek( fp, 0, SEEK_SET ); fwrite( &header, sizeof(struct header), 1, fp ); + +#ifdef CXR_DEBUG cxr_log( "removed %d marked lights\n", light_count-new_count ); +#endif fclose( fp ); free( lights ); return 1; } +#endif /* CXR_VALVE_MAP_FILE */ +#endif /* CXR_IMPLEMENTATION */ diff --git a/src/cxr_math.h b/cxr/cxr_math.h similarity index 100% rename from src/cxr_math.h rename to cxr/cxr_math.h diff --git a/src/cxr_mem.h b/cxr/cxr_mem.h similarity index 100% rename from src/cxr_mem.h rename to cxr/cxr_mem.h diff --git a/cxr/test.c b/cxr/test.c new file mode 100644 index 0000000..4529b98 --- /dev/null +++ b/cxr/test.c @@ -0,0 +1,35 @@ +#include "convexer.c" +#include "solid.h" + +int main(int arc, const char *argv[]) +{ + cxr_vdf *vdo = cxr_vdf_open( + "/home/harry/Documents/blender_addons_remote/addons/convexer/test.vmf" ); + + cxr_vmf_context ctx = + { + .brush_count = 0, + .entity_count = 0, + .face_count = 0, + .detailvbsp = "", + .detailmaterial = "", + .lightmap_scale = 12, + .mapversion = 4, + .offset = { 0.0, 0.0, 0.0 }, + .scale = 32.0, + .skyname = "vertigoblue" + }; + + cxr_world *world = cxr_decompose( &test_mesh ); + if( world ) + { + cxr_push_world_vmf( world, &ctx, vdo ); + cxr_free_world( world ); + } + + cxr_vmf_begin_entities( &ctx, vdo ); + cxr_end_vmf( &ctx, vdo ); + + cxr_vdf_close(vdo); + return 0; +} diff --git a/src/nbvtf/librgbcx.h b/nbvtf/librgbcx.h similarity index 100% rename from src/nbvtf/librgbcx.h rename to nbvtf/librgbcx.h diff --git a/src/nbvtf/nbvtf.h b/nbvtf/nbvtf.h similarity index 91% rename from src/nbvtf/nbvtf.h rename to nbvtf/nbvtf.h index 3ed8536..c0071c9 100644 --- a/src/nbvtf/nbvtf.h +++ b/nbvtf/nbvtf.h @@ -1,4 +1,4 @@ -// nbvtf.h - v1.02 - Writer for Valve Texture Format - public domain +// nbvtf.h - v1.03 - Writer for Valve Texture Format - public domain // Written by Harry 'hgn' Godden // // Credits: @@ -26,12 +26,14 @@ // format - Choose from: k_EImageFormat_DXT1, compressedk_EImageFormat_DXT5, k_EImageFormat_BGR888, k_EImageFormat_ABGR8888 // usr_flags - You can append any flags but only really need TEXTUREFLAGS_NORMAL if texture is normal map // dest - file path to write vtf to +// qual - Image quality 0-18 (rgbcx, stb always highqual) // // Convert specific: // src - file path of source image to convert // w, h - MAXIMUM image dimentions of final product. Set as 0 to be automatic // // version history: +// v1.03 - Added quality switch // v1.02 - Improved box filtering, small bug fixes // v1.01 - switch to OpenGL normal format for input // v1.00 - (hgn) first release @@ -448,7 +450,7 @@ uint32_t nbvtf_sizeimg( int w, int h, EImageFormat_t format ) return 0; } -void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha ) +void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha, int qual ) { #ifdef USE_LIBRGBCX // TODO: move this somewehre else @@ -461,18 +463,19 @@ void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha ) if( alpha ) { - rgbcx__encode_bc3( 12, dest, src ); + rgbcx__encode_bc3( qual, dest, src ); } else { - rgbcx__encode_bc1( 12, dest, src, 0, 0 ); + rgbcx__encode_bc1( qual, dest, src, 0, 0 ); } #else stb_compress_dxt_block( dest, src, alpha, STB_DXT_HIGHQUAL ); #endif } -void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, uint8_t *dest ) +void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual, + uint8_t *dest ) { uint32_t blocks_x, blocks_y; @@ -499,14 +502,14 @@ void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, uint8_t *dest ) memcpy( working_block + i*4*4, src_begin + w*4*i, 4*4 ); } - nbvtf_dxt_block( dest_block, working_block, alpha ); + nbvtf_dxt_block( dest_block, working_block, alpha, qual ); dest_block += block_size; } if( padx ) { nbvtf_dxt_pad( src, blocks_x, y, w, h, working_block ); - nbvtf_dxt_block( dest_block, working_block, alpha ); + nbvtf_dxt_block( dest_block, working_block, alpha, qual ); dest_block += block_size; } } @@ -517,7 +520,7 @@ void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, uint8_t *dest ) for( int x = 0; x < blocks_x; x ++ ) { nbvtf_dxt_pad( src, x, blocks_y, w, h, working_block ); - nbvtf_dxt_block( dest_block, working_block, alpha ); + nbvtf_dxt_block( dest_block, working_block, alpha, qual ); dest_block += block_size; } } @@ -526,7 +529,7 @@ void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, uint8_t *dest ) if( padx && pady ) { nbvtf_dxt_pad( src, blocks_x, blocks_y, w, h, working_block ); - nbvtf_dxt_block( dest_block, working_block, alpha ); + nbvtf_dxt_block( dest_block, working_block, alpha, qual ); } } @@ -541,16 +544,17 @@ void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest ) } } -void nbvtf_write_img_data( uint8_t *src, int w, int h, EImageFormat_t format, uint8_t *wb, FILE *file ) +void nbvtf_write_img_data( uint8_t *src, int w, int h, + EImageFormat_t format, int qual, uint8_t *wb, FILE *file ) { switch( format ) { case k_EImageFormat_DXT1: - nbvtf_compress_dxt( src, w, h, 0, wb ); + nbvtf_compress_dxt( src, w, h, 0, qual, wb ); fwrite( wb, nbvtf_dxt_sizeimg( w, h, 0 ), 1, file ); break; case k_EImageFormat_DXT5: - nbvtf_compress_dxt( src, w, h, 1, wb ); + nbvtf_compress_dxt( src, w, h, 1, qual, wb ); fwrite( wb, nbvtf_dxt_sizeimg( w, h, 1 ), 1, file ); break; case k_EImageFormat_ABGR8888: @@ -570,7 +574,8 @@ void nbvtf_write_img_data( uint8_t *src, int w, int h, EImageFormat_t format, ui #ifdef NBVTF_AS_SO __attribute__((visibility("default"))) #endif -int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest ) +int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, + EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest ) { if( !nbvtf_power2x(w,h) ) { @@ -668,9 +673,11 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t fo } uint32_t size_highres = nbvtf_sizeimg( w, h, format ); - uint32_t size_lowres = nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 ); + uint32_t size_lowres = + nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 ); - uint8_t *working_buffer = (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) ); + uint8_t *working_buffer = + (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) ); if( !working_buffer ) { @@ -703,7 +710,8 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t fo // Write low res nbvtf_write_img_data( - lr_src, header.lowResImageWidth, header.lowResImageHeight, k_EImageFormat_DXT1, working_buffer, file + lr_src, header.lowResImageWidth, header.lowResImageHeight, + k_EImageFormat_DXT1, qual, working_buffer, file ); // Write texture data @@ -715,12 +723,13 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t fo for( int i = start; i < num_mips; i ++ ) { mipimg_t *mip = mip_offsets + (num_mips - i -1); - nbvtf_write_img_data( mip_data + mip->src_offset, mip->w, mip->h, format, working_buffer, file ); + nbvtf_write_img_data( mip_data + mip->src_offset, mip->w, mip->h, + format, qual, working_buffer, file ); } } // Write high resolution - nbvtf_write_img_data( src, w, h, format, working_buffer, file ); + nbvtf_write_img_data( src, w, h, format, qual, working_buffer, file ); fclose( file ); @@ -736,7 +745,8 @@ int nbvtf_write( uint8_t *reference, int w, int h, int mipmap, EImageFormat_t fo #ifdef NBVTF_AS_SO __attribute__((visibility("default"))) #endif -int nbvtf_convert( const char *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest ) +int nbvtf_convert( const char *src, int w, int h, int mipmap, + EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest ) { if( (w && h) && !nbvtf_power2x(w,h) ) { @@ -760,7 +770,9 @@ int nbvtf_convert( const char *src, int w, int h, int mipmap, EImageFormat_t for if( (w && h) && ( x > w || y > h ) ) nbvtf_downscale( data, x, y, w, h, data ); - int status = nbvtf_write( data, w, h, mipmap, format, usr_flags, dest ); + int status = nbvtf_write( data, w, h, mipmap, format, qual, + usr_flags, dest ); + stbi_image_free( data ); return status; diff --git a/src/nbvtf/rgbcx.h b/nbvtf/rgbcx.h similarity index 100% rename from src/nbvtf/rgbcx.h rename to nbvtf/rgbcx.h diff --git a/src/nbvtf/rgbcx_table4.h b/nbvtf/rgbcx_table4.h similarity index 100% rename from src/nbvtf/rgbcx_table4.h rename to nbvtf/rgbcx_table4.h diff --git a/src/nbvtf/stb/stb_dxt.h b/nbvtf/stb/stb_dxt.h similarity index 100% rename from src/nbvtf/stb/stb_dxt.h rename to nbvtf/stb/stb_dxt.h diff --git a/src/nbvtf/stb/stb_image.h b/nbvtf/stb/stb_image.h similarity index 100% rename from src/nbvtf/stb/stb_image.h rename to nbvtf/stb/stb_image.h diff --git a/src/nbvtf/stb/stb_image_write.h b/nbvtf/stb/stb_image_write.h similarity index 100% rename from src/nbvtf/stb/stb_image_write.h rename to nbvtf/stb/stb_image_write.h diff --git a/src/nbvtf/vtf_cmd.c b/nbvtf/vtf_cmd.c similarity index 100% rename from src/nbvtf/vtf_cmd.c rename to nbvtf/vtf_cmd.c diff --git a/src/test.c b/src/test.c deleted file mode 100644 index 1042c3a..0000000 --- a/src/test.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "convexer.c" -#include "solid.h" - -int main(int arc, const char *argv[]) -{ - cxr_vdf *vdo = cxr_vdf_open( "/home/harry/Documents/blender_addons_remote/addons/convexer/test.vmf" ); - - cxr_convert_mesh_to_vmf( &test_mesh, vdo ); - cxr_vdf_close(vdo); - return 0; -} -- 2.25.1