X-Git-Url: https://harrygodden.com/git/?p=convexer.git;a=blobdiff_plain;f=__init__.py;fp=__init__.py;h=8d9254e69b49a1ba2e5971712fbc4f2f4bb173a8;hp=9eba53c76808714d79414d3a69485091795a47ea;hb=0d0b6bf37c8a9c4494071973103a89b4aa82574a;hpb=dbd379f76bcb2139fdb5740232511fa789018e10 diff --git a/__init__.py b/__init__.py index 9eba53c..8d9254e 100644 --- a/__init__.py +++ b/__init__.py @@ -53,6 +53,13 @@ cxr_jobs_batch = None cxr_jobs_inf = [] cxr_error_inf = None +cxr_asset_lib = \ +{ + "models": {}, + "materials": {}, + "textures": {} +} + # Shaders cxr_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') @@ -96,7 +103,7 @@ void main() vec3 worldPos = pWorldPos.xyz; gl_Position = viewProjectionMatrix * pWorldPos; - lNormal = aNormal; //mat3(transpose(inverse(modelMatrix))) * aNormal; + lNormal = normalize(mat3(transpose(inverse(modelMatrix))) * aNormal); lPos = worldPos; } """,""" @@ -419,6 +426,33 @@ class cxr_vmf_context(Structure): ("entity_count",c_int32), ("face_count",c_int32)] +# Valve wrapper types +class fs_locator(Structure): + _fields_ = [("vpk_entry",c_void_p), + ("path",c_char_p*1024)] + +class valve_material(Structure): + _fields_ = [("basetexture",c_char_p), + ("bumpmap",c_char_p)] + +class valve_model_batch(Structure): + _fields_ = [("material",c_uint32), + ("ibstart",c_uint32), + ("ibcount",c_uint32)] + +class valve_model(Structure): + _fields_ = [("vertex_data",POINTER(c_float)), + ("indices",POINTER(c_uint32)), + ("indices_count",c_uint32), + ("vertex_count",c_uint32), + ("part_count",c_uint32), + ("material_count",c_uint32), + ("materials",POINTER(c_char_p)), + ("parts",POINTER(valve_model_batch)), + ("studiohdr",c_void_p), + ("vtxhdr",c_void_p), + ("vvdhdr",c_void_p)] + # Convert blenders mesh format into CXR's static format (they are very similar) # def mesh_cxr_format(obj): @@ -593,17 +627,30 @@ libcxr_lightpatch_bsp = extern( "cxr_lightpatch_bsp", [c_char_p], None ) # Binary file formats and FS libcxr_fs_set_gameinfo = extern( "cxr_fs_set_gameinfo", [c_char_p], c_int32 ) libcxr_fs_exit = extern( "cxr_fs_exit", [], None ) -libcxr_fs_get = extern( "cxr_fs_get", [c_char_p], c_char_p ) -libcxr_load_mdl = extern( "cxr_load_mdl", [c_char_p], POINTER(cxr_tri_mesh) ) +libcxr_fs_get = extern( "cxr_fs_get", [c_char_p, c_int32], c_char_p ) +libcxr_fs_find = extern( "cxr_fs_find", [c_char_p, POINTER(fs_locator)],\ + c_int32 ) + +libcxr_valve_load_model = extern( "valve_load_model", [c_char_p], \ + POINTER(valve_model) ) +libcxr_valve_free_model = extern( "valve_free_model", [POINTER(valve_model)],\ + None ) + +libcxr_valve_load_material = extern( "valve_load_material", [c_char_p], \ + POINTER(valve_material) ) +libcxr_valve_free_material = extern( "valve_free_material", \ + [POINTER(valve_material)], 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_put, libcxr_vdf_node, libcxr_vdf_edon, \ libcxr_vdf_kv, libcxr_lightpatch_bsp, libcxr_write_test_data,\ libcxr_world_preview, libcxr_free_tri_mesh, \ libcxr_fs_set_gameinfo, libcxr_fs_exit, libcxr_fs_get, \ - libcxr_load_mdl ] + libcxr_fs_find,\ + libcxr_valve_load_model, libcxr_valve_free_model,\ + libcxr_valve_load_material, libcxr_valve_free_material ] # Callbacks def libcxr_log_callback(logStr): @@ -634,7 +681,8 @@ def libcxr_line_callback( p0,p1,colour ): cxr_line_colours += [(colour[0],colour[1],colour[2],colour[3])] def cxr_reset_all(): - global cxr_jobs_inf, cxr_jobs_batch, cxr_error_inf, cxr_view_mesh + global cxr_jobs_inf, cxr_jobs_batch, cxr_error_inf, cxr_view_mesh, \ + cxr_asset_lib cxr_jobs_inf = None cxr_jobs_batch = None cxr_error_inf = None @@ -643,6 +691,10 @@ def cxr_reset_all(): cxr_batch_lines() cxr_view_mesh = None + cxr_asset_lib['models'] = {} + cxr_asset_lib['materials'] = {} + cxr_asset_lib['textures'] = {} + scene_redraw() # libnbvtf @@ -1718,40 +1770,115 @@ class CXR_INIT_FS_OPERATOR(bpy.types.Operator): return {'FINISHED'} -class CXR_LOAD_MODEL_OPERATOR(bpy.types.Operator): - bl_idname="convexer.model_load" - bl_label="Load model" +def cxr_load_texture( path ): + global cxr_asset_lib - def execute(_,context): - global cxr_mdl_mesh, cxr_mdl_shader + if path in cxr_asset_lib['textures']: + return cxr_asset_lib['textures'][path] - mdlpath = bpy.context.scene.cxr_data.dev_mdl.encode('utf-8') - pmesh = libcxr_load_mdl.call( mdlpath ) + print( F"cxr_load_texture( '{path}' )" ) - if not pmesh: - print( "Failed to load model" ) - return {'FINISHED'} - - mesh = pmesh[0] + # TODO - #TODO: remove code dupe - vertices = mesh.vertices[:mesh.vertex_count] - vertices = [(_[0],_[1],_[2]) for _ in vertices] + tex = cxr_asset_lib['textures'][path] = None + return tex + +def cxr_load_material( path ): + global cxr_asset_lib + + if path in cxr_asset_lib['materials']: + return cxr_asset_lib['materials'][path] + + print( F"cxr_load_material( '{path}' )" ) + + pvmt = libcxr_valve_load_material.call( path.encode( 'utf-8') ) + vmt = pvmt[0] + + mat = cxr_asset_lib['materials'][path] = {} + + if vmt.basetexture: + mat['basetexture'] = cxr_load_texture( vmt.basetexture.decode('utf-8') ) + + if vmt.bumpmap: + mat['bumpmap'] = cxr_load_texture( vmt.bumpmap.decode('utf-8') ) + + libcxr_valve_free_material.call( pvmt ) + + return mat + +def cxr_load_model_full( path ): + global cxr_asset_lib, cxr_mdl_shader + + if path in cxr_asset_lib['models']: + return cxr_asset_lib['models'][path] + + pmdl = libcxr_valve_load_model.call( path.encode( 'utf-8' ) ) + + print( F"cxr_load_model_full( '{path}' )" ) + + if not pmdl: + print( "Failed to load model" ) + cxr_asset_lib['models'][path] = None + return None + + mdl = pmdl[0] + + # Convert our lovely interleaved vertex stream into, whatever this is. + positions = [ (mdl.vertex_data[i*8+0], \ + mdl.vertex_data[i*8+1], \ + mdl.vertex_data[i*8+2]) for i in range(mdl.vertex_count) ] + + normals = [ (mdl.vertex_data[i*8+3], \ + mdl.vertex_data[i*8+4], \ + mdl.vertex_data[i*8+5]) for i in range(mdl.vertex_count) ] - normals = mesh.normals[:mesh.vertex_count] - normals = [(_[0],_[1],_[2]) for _ in normals] + uvs = [ (mdl.vertex_data[i*8+6], \ + mdl.vertex_data[i*8+7]) for i in range(mdl.vertex_count) ] - indices = mesh.indices[:mesh.indices_count] + fmt = gpu.types.GPUVertFormat() + fmt.attr_add(id="aPos", comp_type='F32', len=3, fetch_mode='FLOAT') + fmt.attr_add(id="aNormal", comp_type='F32', len=3, fetch_mode='FLOAT') + fmt.attr_add(id="aUv", comp_type='F32', len=2, fetch_mode='FLOAT') + + vbo = gpu.types.GPUVertBuf(len=mdl.vertex_count, format=fmt) + vbo.attr_fill(id="aPos", data=positions ) + vbo.attr_fill(id="aNormal", data=normals ) + vbo.attr_fill(id="aUv", data=uvs ) + + batches = cxr_asset_lib['models'][path] = [] + + for p in range(mdl.part_count): + part = mdl.parts[p] + indices = mdl.indices[part.ibstart:part.ibstart+part.ibcount] indices = [ (indices[i*3+0],indices[i*3+1],indices[i*3+2]) \ - for i in range(int(mesh.indices_count/3)) ] - - cxr_mdl_mesh = batch_for_shader( - cxr_mdl_shader, 'TRIS', - { "aPos": vertices, "aNormal": normals }, - indices = indices, - ) + for i in range(part.ibcount//3) ] - libcxr_free_tri_mesh.call( pmesh ) + ibo = gpu.types.GPUIndexBuf( type='TRIS', seq=indices ) + + batch = gpu.types.GPUBatch( type='TRIS', buf=vbo, elem=ibo ) + batch.program_set( cxr_mdl_shader ) + + mat_str = cast( mdl.materials[ part.material ], c_char_p ) + batches += [( cxr_load_material( mat_str.value.decode('utf-8') ), batch )] + + libcxr_valve_free_model.call( pmdl ) + + return batches + +class CXR_LOAD_MODEL_OPERATOR(bpy.types.Operator): + bl_idname="convexer.model_load" + bl_label="Load model" + + def execute(_,context): + global cxr_mdl_mesh, cxr_mdl_shader, cxr_asset_lib + + test_mdl = cxr_load_model_full( bpy.context.scene.cxr_data.dev_mdl ) + + if test_mdl != None: + # just draw first batch part for now + cxr_mdl_mesh = test_mdl[0][1] + else: + cxr_mdl_mesh = None scene_redraw() return {'FINISHED'}