From: hgn Date: Wed, 13 Jul 2022 01:28:17 +0000 (+0100) Subject: rework scene format X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=9c85e110fa8b965195438d96625ff9753af362a6;p=carveJwlIkooP6JGAAIwe30JlM.git rework scene format --- diff --git a/blender_export.py b/blender_export.py index 16b9764..16d1f38 100644 --- a/blender_export.py +++ b/blender_export.py @@ -1,5 +1,6 @@ import bpy, math, gpu from ctypes import * +from mathutils import * from gpu_extras.batch import batch_for_shader bl_info = { @@ -14,168 +15,246 @@ bl_info = { "category":"Import/Export", } -class model(Structure): +class mdl_vert(Structure): _pack_ = 1 - _fields_ = [("identifier",c_uint32), - ("vertex_count",c_uint32), - ("indice_count",c_uint32), - ("layer_count",c_uint32), - ("marker_count",c_uint32)] + _fields_ = [("co",c_float*3), + ("norm",c_float*3), + ("colour",c_float*4), + ("uv",c_float*2)] -class submodel(Structure): +class mdl_submesh(Structure): _pack_ = 1 _fields_ = [("indice_start",c_uint32), ("indice_count",c_uint32), ("vertex_start",c_uint32), ("vertex_count",c_uint32), ("bbx",(c_float*3)*2), - ("pivot",c_float*3), - ("q",c_float*4), - ("name",c_char*32), - ("material",c_char*32)] + ("material_id",c_uint32)] # index into the material array -class classtype_gate(Structure): +class mdl_material(Structure): _pack_ = 1 - _fields_ = [("target",c_uint32)] + _fields_ = [("pstr_name",c_uint32)] -class marker(Structure): +class mdl_node(Structure): _pack_ = 1 _fields_ = [("co",c_float*3), ( "q",c_float*4), ( "s",c_float*3), + ("submesh_start",c_uint32), + ("submesh_count",c_uint32), ("classtype",c_uint32), ("offset",c_uint32), - ("name",c_char*32)] + ("pstr_name",c_uint32)] -class model_vert(Structure): +class mdl_header(Structure): _pack_ = 1 - _fields_ = [("co",c_float*3), - ("norm",c_float*3), - ("colour",c_float*4), - ("uv",c_float*2)] + _fields_ = [("identifier",c_uint32), + ("version",c_uint32), + ("file_length",c_uint32), + ("vertex_count",c_uint32), + ("vertex_offset",c_uint32), + + ("indice_count",c_uint32), + ("indice_offset",c_uint32), + + ("submesh_count",c_uint32), + ("submesh_offset",c_uint32), + + ("material_count",c_uint32), + ("material_offset",c_uint32), + + ("node_count",c_uint32), + ("node_offset",c_uint32), + + ("strings_offset",c_uint32), + ("entdata_offset",c_uint32) + ] + +# Entity types +# ========================================== + +class classtype_gate(Structure): + _pack_ = 1 + _fields_ = [("target",c_uint32)] + +class classtype_block(Structure): + _pack_ = 1 + _fields_ = [("bbx",(c_float*3)*2)] -def submesh_set_transform( sm, obj ): - sm.pivot[0] = obj.matrix_world.translation[0] - sm.pivot[1] = obj.matrix_world.translation[2] - sm.pivot[2] = -obj.matrix_world.translation[1] +class classtype_spawn(Structure): + _pack_ = 1 + _fields_ = [("temp",c_uint32)] + +class classtype_water(Structure): + _pack_ = 1 + _fields_ = [("temp",c_uint32)] - quat = obj.matrix_world.to_quaternion() - sm.q[0] = quat[1] - sm.q[1] = quat[3] - sm.q[2] = -quat[2] - sm.q[3] = quat[0] +# Exporter +# ============================================================================== def write_model(name): - fp = open(F"/home/harry/Documents/carve/models/{name}.mdl", "wb") + print( F"Create mode {name}" ) + collection = bpy.data.collections[name] - header = model() + header = mdl_header() header.identifier = 0xABCD0000 + header.version = 0 header.vertex_count = 0 header.indice_count = 0 - header.layer_count = 0 - header.marker_count = 1 + header.submesh_count = 0 + header.node_count = 0 + header.material_count = 0 + header.file_length = 0 mesh_cache = {} - layers = [] + string_cache = {} + material_cache = {} + + strings_buffer = b'' + + material_buffer = [] + submesh_buffer = [] vertex_buffer = [] indice_buffer = [] + node_buffer = [] + entdata_buffer = [] + entdata_length = 0 + + def emplace_string( s ): + nonlocal string_cache, strings_buffer + + if s in string_cache: + return string_cache[s] + + string_cache[s] = len( strings_buffer ) + strings_buffer += (s+'\0').encode('utf-8') + return string_cache[s] + + def emplace_material( mat ): + nonlocal material_cache, material_buffer + + if mat.name in material_cache: + return material_cache[mat.name] + + material_cache[mat.name] = header.material_count + dest = mdl_material() + dest.pstr_name = emplace_string( mat.name ) + material_buffer += [dest] + + header.material_count += 1 + return material_cache[mat.name] + + # Create root or empty node and materials + # + none_material = c_uint32(69) + none_material.name = "" + emplace_material( none_material ) + + root = mdl_node() + root.co[0] = 0 + root.co[1] = 0 + root.co[2] = 0 + root.q[0] = 0 + root.q[1] = 0 + root.q[2] = 0 + root.q[3] = 1 + root.s[0] = 1 + root.s[1] = 1 + root.s[2] = 1 + root.pstr_name = emplace_string('') + root.submesh_start = 0 + root.submesh_count = 0 + root.offset = 0 + root.classtype = 0 + node_buffer += [root] + + # Do exporting + # + print( " assigning ids" ) + header.node_count = 1 + for obj in collection.all_objects: + obj.cv_data.uid = header.node_count + header.node_count += 1 + + print( " compiling data" ) + for obj in collection.all_objects: + print( F" [{obj.cv_data.uid}/{header.node_count-1}] {obj.name}" ) + + node = mdl_node() + node.co[0] = obj.location[0] + node.co[1] = obj.location[2] + node.co[2] = -obj.location[1] + + # Convert rotation quat to our space type + quat = obj.matrix_world.to_quaternion() + node.q[0] = quat[1] + node.q[1] = quat[3] + node.q[2] = -quat[2] + node.q[3] = quat[0] + + node.s[0] = obj.scale[0] + node.s[1] = obj.scale[2] + node.s[2] = obj.scale[1] + node.pstr_name = emplace_string( obj.name ) + + # Process entity data + # + node.offset = entdata_length + classtype = obj.cv_data.classtype + + if classtype == 'k_classtype_none': + node.classtype = 0 + node.offset = 0 + + elif classtype == 'k_classtype_gate': + node.classtype = 1 + entdata_length += sizeof( classtype_gate ) + + gate = classtype_gate() + gate.target = 0 + if obj.cv_data.target != None: + gate.target = obj.cv_data.target.cv_data.uid - print( F"Create mode {name}" ) - - rootmarker = marker() - rootmarker.co[0] = 0 - rootmarker.co[1] = 0 - rootmarker.co[2] = 0 - rootmarker.q[0] = 0 - rootmarker.q[1] = 0 - rootmarker.q[2] = 0 - rootmarker.q[3] = 1 - rootmarker.s[0] = 1 - rootmarker.s[1] = 1 - rootmarker.s[2] = 1 - rootmarker.name = "".encode('utf-8') - rootmarker.offset = 0 - rootmarker.classtype = 0 - - markers = [ rootmarker ] # aka entities - entdata_structs = [] - entdata_offset = 0 - - entity_count = 1 - - for obj in collection.objects: - if obj.type == 'EMPTY': - obj.cv_data.uid = entity_count - entity_count += 1 - - for obj in collection.objects: - if obj.type == 'EMPTY': - mk = marker() - mk.co[0] = obj.location[0] - mk.co[1] = obj.location[2] - mk.co[2] = -obj.location[1] - - # Convert rotation quat to our space type - quat = obj.matrix_world.to_quaternion() - mk.q[0] = quat[1] - mk.q[1] = quat[3] - mk.q[2] = -quat[2] - mk.q[3] = quat[0] - - mk.s[0] = obj.scale[0] - mk.s[1] = obj.scale[2] - mk.s[2] = obj.scale[1] - mk.name = obj.name.encode('utf-8') - mk.offset = entdata_offset + entdata_buffer += [gate] - classtype = obj.cv_data.classtype + elif classtype == 'k_classtype_block': + node.classtype = 2 + entdata_length += sizeof( classtype_block ) - if classtype == 'k_classtype_gate': - mk.classtype = 1 - entdata_offset += sizeof( classtype_gate ) + source = obj.data.cv_data - gate = classtype_gate() - gate.target = 0 - if obj.cv_data.target != None: - gate.target = obj.cv_data.target.cv_data.uid + block = classtype_block() + block.bbx[0][0] = source.v0[0] + block.bbx[0][1] = source.v0[2] + block.bbx[0][2] = -source.v0[1] + block.bbx[1][0] = source.v1[0] + block.bbx[1][1] = source.v1[2] + block.bbx[1][2] = -source.v1[1] + entdata_buffer += [block] - entdata_structs += [gate] + elif classtype == 'k_classtype_spawn': + node.classtype = 3 - elif classtype == 'k_thingummybob': - pass + elif classtype == 'k_classtype_water': + node.classtype = 4 - markers += [mk] - header.marker_count += 1 + # Process meshes + # + node.submesh_start = header.submesh_count + node.submesh_count = 0 - elif obj.type == 'MESH': + if obj.type == 'MESH': default_mat = c_uint32(69) default_mat.name = "" if obj.data.name in mesh_cache: ref = mesh_cache[obj.data.name] - for material_id, mref in enumerate(ref['sm']): - print(F" Link submesh({ref['users']}) '{obj.name}:{mat.name}'") - - sm = submodel() - sm.indice_start = mref['indice_start'] - sm.indice_count = mref['indice_count'] - sm.vertex_start = mref['vertex_start'] - sm.vertex_count = mref['vertex_count'] - sm.name = obj.name.encode('utf-8') - sm.material = mref['material'] - sm.bbx = mref['bbx'] - submesh_set_transform( sm, obj ) - layers += [sm] - header.layer_count += 1 - - ref['users'] += 1 + node.submesh_start = ref.submesh_start + node.submesh_count = ref.submesh_count + node_buffer += [node] continue - ref = mesh_cache[obj.data.name] = {} - ref['users'] = 0 - ref['sm'] = [] - dgraph = bpy.context.evaluated_depsgraph_get() data = obj.evaluated_get(dgraph).data data.calc_loop_triangles() @@ -185,24 +264,18 @@ def write_model(name): for material_id, mat in enumerate(mat_list): mref = {} - sm = submodel() + sm = mdl_submesh() sm.indice_start = header.indice_count sm.vertex_start = header.vertex_count sm.vertex_count = 0 sm.indice_count = 0 - submesh_set_transform( sm, obj ) + sm.material_id = emplace_material( mat ) for i in range(3): sm.bbx[0][i] = 999999 sm.bbx[1][i] = -999999 - - sm.name = obj.name.encode('utf-8') - sm.material = mat.name.encode('utf-8') - print( F" Creating submesh '{obj.name}:{mat.name}'" ) + boffa = {} - - hit_count = 0 - miss_count = 0 # Write the vertex / indice data # @@ -231,17 +304,14 @@ def write_model(name): if key in boffa: indice_buffer += [boffa[key]] - hit_count += 1 else: - miss_count += 1 index = c_uint32(sm.vertex_count) sm.vertex_count += 1 boffa[key] = index - indice_buffer += [index] - v = model_vert() + v = mdl_vert() v.co[0] = co[0] v.co[1] = co[2] v.co[2] = -co[1] @@ -267,35 +337,63 @@ def write_model(name): for i in range(3): sm.bbx[j][i] = 0 - layers += [sm] - header.layer_count += 1 + submesh_buffer += [sm] + node.submesh_count += 1 + header.submesh_count += 1 header.vertex_count += sm.vertex_count header.indice_count += sm.indice_count - mref['indice_start'] = sm.indice_start - mref['indice_count'] = sm.indice_count - mref['vertex_start'] = sm.vertex_start - mref['vertex_count'] = sm.vertex_count - mref['bbx'] = sm.bbx - print( F"{sm.bbx[0][0]},{sm.bbx[0][1]},{sm.bbx[0][2]}" ) + mesh_cache[obj.data.name] = node + node_buffer += [node] + + # Write data arrays + # + print( "Writing data" ) + fpos = sizeof(header) + + header.node_offset = fpos + fpos += sizeof(mdl_node)*header.node_count + + header.submesh_offset = fpos + fpos += sizeof(mdl_submesh)*header.submesh_count + + header.material_offset = fpos + fpos += sizeof(mdl_material)*header.material_count - mref['material'] = sm.material - ref['sm'] += [mref] + header.entdata_offset = fpos + fpos += entdata_length + header.vertex_offset = fpos + fpos += sizeof(mdl_vert)*header.vertex_count + + header.indice_offset = fpos + fpos += sizeof(c_uint32)*header.indice_count + + header.strings_offset = fpos + fpos += len(strings_buffer) + + header.file_length = fpos + + fp = open(F"/home/harry/Documents/carve/models/{name}.mdl", "wb") fp.write( bytearray( header ) ) - for l in layers: - fp.write( bytearray(l) ) - for m in markers: - fp.write( bytearray(m) ) + + for node in node_buffer: + fp.write( bytearray(node) ) + for sm in submesh_buffer: + fp.write( bytearray(sm) ) + for mat in material_buffer: + fp.write( bytearray(mat) ) + for ed in entdata_buffer: + fp.write( bytearray(ed) ) for v in vertex_buffer: fp.write( bytearray(v) ) for i in indice_buffer: fp.write( bytearray(i) ) - for ed in entdata_structs: - fp.write( bytearray(ed) ) - + fp.write( strings_buffer ) fp.close() + print( F"Completed {name}.mdl" ) + # Clicky clicky GUI # ------------------------------------------------------------------------------ @@ -314,7 +412,7 @@ def cv_draw(): verts = [] colours = [] - for obj in bpy.context.collection.all_objects: + for obj in bpy.context.collection.objects: if obj.cv_data.classtype == 'k_classtype_gate': if obj.cv_data.target != None: p0 = obj.location @@ -322,6 +420,29 @@ def cv_draw(): verts += [(p0[0],p0[1],p0[2])] verts += [(p1[0],p1[1],p1[2])] colours += [(0,1,0,1.0),(1,0,0,1.0)] + elif obj.cv_data.classtype == 'k_classtype_block': + a = obj.data.cv_data.v0 + b = obj.data.cv_data.v1 + + vs = [None]*8 + vs[0] = obj.matrix_world @ Vector((a[0], a[1], a[2])) + vs[1] = obj.matrix_world @ Vector((a[0], b[1], a[2])) + vs[2] = obj.matrix_world @ Vector((b[0], b[1], a[2])) + vs[3] = obj.matrix_world @ Vector((b[0], a[1], a[2])) + vs[4] = obj.matrix_world @ Vector((a[0], a[1], b[2])) + vs[5] = obj.matrix_world @ Vector((a[0], b[1], b[2])) + vs[6] = obj.matrix_world @ Vector((b[0], b[1], b[2])) + vs[7] = obj.matrix_world @ Vector((b[0], a[1], b[2])) + + indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\ + (0,4),(1,5),(2,6),(3,7)] + + for l in indices: + v0 = vs[l[0]] + v1 = vs[l[1]] + verts += [(v0[0],v0[1],v0[2])] + verts += [(v1[0],v1[1],v1[2])] + colours += [(1,1,0,1),(1,1,0,1)] lines = batch_for_shader(\ cv_view_shader, 'LINES', \ @@ -336,6 +457,12 @@ def cv_poll_target(scene, obj): return False return True +class CV_MESH_SETTINGS(bpy.types.PropertyGroup): + v0: bpy.props.FloatVectorProperty(name="v0",size=3) + v1: bpy.props.FloatVectorProperty(name="v1",size=3) + v2: bpy.props.FloatVectorProperty(name="v2",size=3) + v3: bpy.props.FloatVectorProperty(name="v3",size=3) + class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): uid: bpy.props.IntProperty( name="" ) @@ -347,6 +474,9 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): items = [ ('k_classtype_none', "k_classtype_none", "", 0), ('k_classtype_gate', "k_classtype_gate", "", 1), + ('k_classtype_block', "k_classtype_block", "", 2), + ('k_classtype_spawn', "k_classtype_spawn", "", 3), + ('k_classtype_water', "k_classtype_water", "", 4) ]) class CV_OBJ_PANEL(bpy.types.Panel): @@ -360,7 +490,17 @@ class CV_OBJ_PANEL(bpy.types.Panel): active_object = bpy.context.active_object if active_object == None: return _.layout.prop( active_object.cv_data, "classtype" ) - _.layout.prop( active_object.cv_data, "target" ) + + if active_object.cv_data.classtype == 'k_classtype_gate': + _.layout.prop( active_object.cv_data, "target" ) + elif active_object.cv_data.classtype == 'k_classtype_block': + mesh = active_object.data + + _.layout.label( text=F"(i) Data is stored in {mesh.name}" ) + _.layout.prop( mesh.cv_data, "v0" ) + _.layout.prop( mesh.cv_data, "v1" ) + _.layout.prop( mesh.cv_data, "v2" ) + _.layout.prop( mesh.cv_data, "v3" ) class CV_INTERFACE(bpy.types.Panel): bl_idname = "VIEW3D_PT_carve" @@ -383,7 +523,8 @@ class CV_COMPILE(bpy.types.Operator): return {'FINISHED'} -classes = [CV_OBJ_SETTINGS,CV_OBJ_PANEL,CV_COMPILE,CV_INTERFACE] +classes = [CV_OBJ_SETTINGS,CV_OBJ_PANEL,CV_COMPILE,CV_INTERFACE,\ + CV_MESH_SETTINGS] def register(): global cv_view_draw_handler @@ -392,6 +533,8 @@ def register(): bpy.utils.register_class(c) bpy.types.Object.cv_data = bpy.props.PointerProperty(type=CV_OBJ_SETTINGS) + bpy.types.Mesh.cv_data = bpy.props.PointerProperty(type=CV_MESH_SETTINGS) + cv_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\ cv_draw,(),'WINDOW','POST_VIEW') diff --git a/character.h b/character.h index c565fc4..5ce456f 100644 --- a/character.h +++ b/character.h @@ -63,7 +63,8 @@ struct character { glmesh mesh; - submodel parts[ PART_COUNT ]; + mdl_submesh parts[ PART_COUNT ]; + v3f origins[ PART_COUNT ]; m4x3f matrices[ PART_COUNT ]; /* Auxillary information */ @@ -96,7 +97,7 @@ struct character static void character_offset( struct character *ch, enum character_part parent, enum character_part child ) { - v3_sub( ch->parts[ child ].pivot, ch->parts[ parent ].pivot, + v3_sub( ch->origins[ child ], ch->origins[ parent ], ch->offsets[ child ] ); } @@ -105,35 +106,44 @@ static int character_load( struct character *ch, const char *name ) char buf[64]; snprintf( buf, sizeof(buf)-1, "models/%s.mdl", name ); - model *src = vg_asset_read( buf ); + mdl_header *src = mdl_load( buf ); if( !src ) - { - vg_error( "Could not open 'models/%s.mdl'", name ); return 0; - } int error_count = 0; for( int i=0; iparts[i], 0, sizeof(mdl_submesh) ); + v3_zero( ch->origins[i] ); + + if( !pnode ) { vg_warn( "Character file does not contain an '_%s' part.\n", character_part_strings[i] ); error_count ++; - - memset( &ch->parts[i], 0, sizeof(submodel) ); + continue; + } + + mdl_submesh *sm = mdl_node_submesh( src, pnode, 0 ); + + if( !sm ) + { + vg_warn( "Character file's '_%s' part has no mesh.\n", + character_part_strings[i] ); + error_count ++; continue; } ch->parts[i] = *sm; + v3_copy( pnode->co, ch->origins[i] ); } - model_unpack( src, &ch->mesh ); + mdl_unpack_glmesh( src, &ch->mesh ); if( !error_count ) vg_success( "Loaded character file '%s' with no errors\n", name ); @@ -489,7 +499,7 @@ static void character_testpose( struct character *ch, float t ) *pole = ch->ik_body.pole; hips[0] = cosf(t*1.325f)*0.25f; - hips[1] = (sinf(t)*0.2f+0.6f) * ch->parts[ k_chpart_body0 ].pivot[1]; + hips[1] = (sinf(t)*0.2f+0.6f) * ch->origins[ k_chpart_body0 ][1]; hips[2] = 0.0f; collar[0] = hips[0]; @@ -568,7 +578,7 @@ static void character_draw( struct character *ch, float temp ) #endif shader_character_uMdl( ch->matrices[i] ); - submodel_draw( &ch->parts[i] ); + mdl_draw_submesh( &ch->parts[i] ); } for( int i=0; i<2; i++ ) @@ -576,14 +586,14 @@ static void character_draw( struct character *ch, float temp ) if( ch->shoes[i] ) { shader_character_uMdl( ch->matrices[i] ); - submodel_draw( &ch->parts[i] ); + mdl_draw_submesh( &ch->parts[i] ); } else { shader_character_uMdl( ch->matrices[i+2] ); - submodel_draw( &ch->parts[i] ); + mdl_draw_submesh( &ch->parts[i] ); shader_character_uMdl( ch->matrices[i] ); - submodel_draw( &ch->parts[i+2] ); + mdl_draw_submesh( &ch->parts[i+2] ); } } } @@ -676,14 +686,14 @@ static void character_init_ragdoll_joints( struct character *ch ) { struct rd_joint *joint = &rd_joints[i]; - float *hinge = ch->parts[joint->ib].pivot; + float *hinge = ch->origins[joint->ib]; v3_sub( hinge, ch->ragdoll[joint->ia].co, joint->lca ); v3_sub( hinge, ch->ragdoll[joint->ib].co, joint->lcb ); } for( int i=0; iparts[i].pivot; + float *pivot = ch->origins[i]; v3_sub( ch->ragdoll[i].co, pivot, ch->ragdoll[i].delta ); } } @@ -700,27 +710,27 @@ static void character_init_ragdoll( struct character *ch ) v3f chest_dims = { chest_depth, chest_height, chest_width }; character_rd_box( ch, k_chpart_body1, chest_dims ); - v3_copy( ch->parts[k_chpart_body1].pivot, rbs[k_chpart_body1].co ); + v3_copy( ch->origins[k_chpart_body1], rbs[k_chpart_body1].co ); rbs[k_chpart_body1].co[1] += chest_height*0.5f; /* Torso */ v3f torso_dims = { chest_depth, offs[k_chpart_body1][1]-offs[k_chpart_leg_l0][1], chest_width*0.85f }; - v3_copy( ch->parts[k_chpart_body0].pivot, rbs[k_chpart_body0].co ); + v3_copy( ch->origins[k_chpart_body0], rbs[k_chpart_body0].co ); character_rd_box( ch, k_chpart_body0, torso_dims ); /* Neck */ v3f neck_dims = { chest_depth*0.5f, offs[k_chpart_head][1], chest_depth*0.5f }; - v3_copy( ch->parts[k_chpart_neck].pivot, rbs[k_chpart_neck].co ); + v3_copy( ch->origins[k_chpart_neck], rbs[k_chpart_neck].co ); rbs[k_chpart_neck].co[1] += neck_dims[1]*0.5f; character_rd_box( ch, k_chpart_neck, neck_dims ); /* Head */ v3f head_dims = { chest_width*0.5f, chest_width*0.5f, chest_width*0.5f }; - v3_copy( ch->parts[k_chpart_head].pivot, rbs[k_chpart_head].co ); + v3_copy( ch->origins[k_chpart_head], rbs[k_chpart_head].co ); rbs[k_chpart_head].co[1] += head_dims[1]*0.5f; character_rd_box( ch, k_chpart_head, head_dims ); @@ -738,18 +748,18 @@ static void character_init_ragdoll( struct character *ch ) character_rd_box( ch, k_chpart_hand_l, hand_dims ); character_rd_box( ch, k_chpart_hand_r, hand_dims ); - v3_copy( ch->parts[k_chpart_arm_l0].pivot, rbs[k_chpart_arm_l0].co ); + v3_copy( ch->origins[k_chpart_arm_l0], rbs[k_chpart_arm_l0].co ); rbs[k_chpart_arm_l0].co[2] += ua_dims[2] * 0.5f; - v3_copy( ch->parts[k_chpart_arm_l1].pivot, rbs[k_chpart_arm_l1].co ); + v3_copy( ch->origins[k_chpart_arm_l1], rbs[k_chpart_arm_l1].co ); rbs[k_chpart_arm_l1].co[2] += la_dims[2] * 0.5f; - v3_copy( ch->parts[k_chpart_hand_l].pivot, rbs[k_chpart_hand_l].co ); + v3_copy( ch->origins[k_chpart_hand_l], rbs[k_chpart_hand_l].co ); rbs[k_chpart_hand_l].co[2] += hand_dims[2] * 0.5f; - v3_copy( ch->parts[k_chpart_arm_r0].pivot, rbs[k_chpart_arm_r0].co ); + v3_copy( ch->origins[k_chpart_arm_r0], rbs[k_chpart_arm_r0].co ); rbs[k_chpart_arm_r0].co[2] -= ua_dims[2] * 0.5f; - v3_copy( ch->parts[k_chpart_arm_r1].pivot, rbs[k_chpart_arm_r1].co ); + v3_copy( ch->origins[k_chpart_arm_r1], rbs[k_chpart_arm_r1].co ); rbs[k_chpart_arm_r1].co[2] -= la_dims[2] * 0.5f; - v3_copy( ch->parts[k_chpart_hand_r].pivot, rbs[k_chpart_hand_r].co ); + v3_copy( ch->origins[k_chpart_hand_r], rbs[k_chpart_hand_r].co ); rbs[k_chpart_hand_r].co[2] -= hand_dims[2] * 0.5f; /* LEgs */ @@ -766,19 +776,19 @@ static void character_init_ragdoll( struct character *ch ) character_rd_box( ch, k_chpart_foot_l, foot_dims ); character_rd_box( ch, k_chpart_foot_r, foot_dims ); - v3_copy( ch->parts[k_chpart_leg_l0].pivot, rbs[k_chpart_leg_l0].co ); + v3_copy( ch->origins[k_chpart_leg_l0], rbs[k_chpart_leg_l0].co ); rbs[k_chpart_leg_l0].co[1] -= ul_dims[1] * 0.5f; - v3_copy( ch->parts[k_chpart_leg_l1].pivot, rbs[k_chpart_leg_l1].co ); + v3_copy( ch->origins[k_chpart_leg_l1], rbs[k_chpart_leg_l1].co ); rbs[k_chpart_leg_l1].co[1] -= ll_dims[1] * 0.5f; - v3_copy( ch->parts[k_chpart_foot_l].pivot, rbs[k_chpart_foot_l].co ); + v3_copy( ch->origins[k_chpart_foot_l], rbs[k_chpart_foot_l].co ); rbs[k_chpart_foot_l].co[1] -= foot_dims[1] * 0.5f; rbs[k_chpart_foot_l].co[0] -= foot_dims[0] * 0.5f; - v3_copy( ch->parts[k_chpart_leg_r0].pivot, rbs[k_chpart_leg_r0].co ); + v3_copy( ch->origins[k_chpart_leg_r0], rbs[k_chpart_leg_r0].co ); rbs[k_chpart_leg_r0].co[1] -= ul_dims[1] * 0.5f; - v3_copy( ch->parts[k_chpart_leg_r1].pivot, rbs[k_chpart_leg_r1].co ); + v3_copy( ch->origins[k_chpart_leg_r1], rbs[k_chpart_leg_r1].co ); rbs[k_chpart_leg_r1].co[1] -= ll_dims[1] * 0.5f; - v3_copy( ch->parts[k_chpart_foot_r].pivot, rbs[k_chpart_foot_r].co ); + v3_copy( ch->origins[k_chpart_foot_r], rbs[k_chpart_foot_r].co ); rbs[k_chpart_foot_r].co[1] -= foot_dims[1] * 0.5f; rbs[k_chpart_foot_r].co[0] -= foot_dims[0] * 0.5f; diff --git a/common.h b/common.h index 1e1ebed..2125154 100644 --- a/common.h +++ b/common.h @@ -5,12 +5,17 @@ #define VG_FRAMEBUFFER_RESIZE 1 #include "vg/vg.h" +/* TODO: he needs a home somewhere */ static float ktimestep = 1.0f/60.0f; +/* TODO: he needs a home somewhere */ enum classtype { k_classtype_none = 0, - k_classtype_gate = 1 + k_classtype_gate = 1, + k_classtype_block = 2, + k_classtype_spawn = 3, + k_classtype_water = 4 }; /* TODO: he needs a home somewhere */ diff --git a/gate.h b/gate.h index 3151878..a370d81 100644 --- a/gate.h +++ b/gate.h @@ -62,8 +62,8 @@ static void gate_init(void) { fb_init( &grender.fb ); - model *mgate = vg_asset_read( "models/rs_gate.mdl" ); - model_unpack( mgate, &grender.mdl ); + mdl_header *mgate = mdl_load( "models/rs_gate.mdl" ); + mdl_unpack_glmesh( mgate, &grender.mdl ); free( mgate ); } diff --git a/lighting.h b/lighting.h index 8f9bdb3..e69de29 100644 --- a/lighting.h +++ b/lighting.h @@ -1,104 +0,0 @@ -#ifndef LIGHTING_H -#define LIGHTING_H - -#include "common.h" -#include "scene.h" - -static int ray_world( v3f pos, v3f dir, ray_hit *hit ); - -typedef struct voxel_gi voxel_gi; - -struct voxel_gi -{ - GLuint hw_texture, - pt_texture; - - v3i pt_dims; /* Page table dimentions */ - i32 page_size; - - v3f origin; -}; - -static void voxel_gi_setup( voxel_gi *gi, scene *sc, - i32 page_size, float voxel_res ) -{ - v3_copy( sc->bbx[0], gi->origin ); - gi->page_size = page_size; - - v3f extent; - v3_sub( sc->bbx[1], sc->bbx[0], extent ); - - float fpage_size = voxel_res * (float)page_size; - - for( int i=0; i<3; i++ ) - { - i32 voxel_count = extent[i] / voxel_res; - gi->pt_dims[i] = (voxel_count+page_size-1) / page_size; - } - - i32 pt_capacity = gi->pt_dims[0]*gi->pt_dims[1]*gi->pt_dims[2]; - vg_info( "Page table size: %dkb\n", (pt_capacity*2*2)/1024 ); - - u16 *page_table = malloc( pt_capacity*sizeof(u16)*3 ); - - - u32 active_count = 0; - - for( int z=0; zpt_dims[2]; z++ ) - { - for( int y=0; ypt_dims[1]; y++ ) - { - for( int x=0; xpt_dims[0]; x++ ) - { - v3f base = {x,y,z}, - end = {x+1,y+1,z+1}; - - boxf page_region; - - v3_muladds( sc->bbx[0], base, ((float)page_size)*voxel_res, base ); - v3_muladds( sc->bbx[0], end, ((float)page_size)*voxel_res, end ); - v3_copy( base, page_region[0] ); - v3_copy( end, page_region[1] ); - - u32 nothing[2]; - if( bh_select( &sc->bhtris, page_region, nothing, 2 )) - { - active_count ++; - - /* Calculate lighting */ - } - } - } - } - - /* Calculate physical storage size */ - vg_info( "Hardware texture required size: %dmb\n", - ((active_count*page_size*page_size*page_size*1)/1024)/1024 ); - vg_info( "Required physical blocks: %d\n", active_count ); - - free( page_table ); -} - -static void compute_lighting_vertex( scene *sc ) -{ - v3f light_dir = { 0.2f, 1.0f, 1.0f }; - v3_normalize( light_dir ); - - for( int i=0; ivertex_count; i++ ) - { - model_vert *mv = &sc->verts[i]; - - ray_hit hit; - hit.dist = 100.0f; - - ray_world( mv->co, light_dir, &hit ); - float amt = hit.dist / 100.0f; - - mv->colour[0] = amt; - mv->colour[1] = amt; - mv->colour[2] = amt; - mv->colour[3] = 1.0f; - } -} - -#endif /* LIGHTING_H */ diff --git a/main.c b/main.c index aa90b02..84de410 100644 --- a/main.c +++ b/main.c @@ -151,7 +151,7 @@ void vg_start(void) world_load(); - reset_player( 1, (const char *[]){ "tutorial" } ); + reset_player( 1, (const char *[]){ "start" } ); player_transform_update(); } diff --git a/mesh.h b/mesh.h new file mode 100644 index 0000000..e69de29 diff --git a/model.h b/model.h index 430ed26..4ed39d4 100644 --- a/model.h +++ b/model.h @@ -1,28 +1,35 @@ #ifndef MODEL_H #define MODEL_H -#include "vg/vg.h" +#include "common.h" -typedef struct model model; typedef struct glmesh glmesh; -typedef struct submodel submodel; -typedef struct model_vert model_vert; -typedef struct model_marker model_marker; -typedef struct sdf_primative sdf_primative; -typedef enum esdf_type esdf_type; + +typedef struct mdl_vert mdl_vert; +typedef struct mdl_submesh mdl_submesh; +typedef struct mdl_material mdl_material; +typedef struct mdl_node mdl_node; +typedef struct mdl_header mdl_header; + +#define MDL_SIZE_MAX 0x1000000 +#define MDL_VERT_MAX 1000000 +#define MDL_INDICE_MAX 1000000 +#define MDL_MATERIAL_MAX 500 +#define MDL_NODE_MAX 4000 +#define MDL_SUBMESH_MAX 8000 +#define MDL_STRING_LENGTH_MAX 64 #pragma pack(push,1) -struct model -{ - u32 identifier; - u32 vertex_count, - indice_count, - layer_count, - marker_count; +struct mdl_vert +{ + v3f co, + norm; + v4f colour; + v2f uv; }; -struct submodel +struct mdl_submesh { u32 indice_start, indice_count, @@ -30,36 +37,69 @@ struct submodel vertex_count; boxf bbx; - v3f pivot; /* same as co? */ - v4f q; - char name[32]; - char material[32]; + u32 material_id; }; -struct classtype_gate +struct mdl_material { - u32 target; + u32 pstr_name; }; -struct model_marker +struct mdl_node { v3f co; v4f q; v3f s; - u32 classtype; - u32 offset; - char name[32]; + + u32 submesh_start, + submesh_count, + classtype, + offset, + pstr_name; }; -struct model_vert +struct mdl_header { - v3f co, - norm; - v4f colour; - v2f uv; + u32 identifier, version, file_length; + + u32 vertex_count, vertex_offset, + indice_count, indice_offset, + submesh_count, submesh_offset, + material_count, material_offset, + node_count, node_offset, + strings_offset, entdata_offset; +}; + +/* + * Entity data structures + */ + +struct classtype_block +{ + boxf bbx; +}; + +struct classtype_gate +{ + u32 target; +}; + +struct classtype_spawn +{ + u32 target; +}; + +struct classtype_water +{ + u32 temp; }; + #pragma pack(pop) +/* + * Simple mesh interface for OpenGL + */ + struct glmesh { GLuint vao, vbo, ebo; @@ -67,7 +107,7 @@ struct glmesh }; static void mesh_upload( glmesh *mesh, - model_vert *verts, u32 vert_count, + mdl_vert *verts, u32 vert_count, u32 *indices, u32 indice_count ) { glGenVertexArrays( 1, &mesh->vao ); @@ -75,29 +115,29 @@ static void mesh_upload( glmesh *mesh, glGenBuffers( 1, &mesh->ebo ); glBindVertexArray( mesh->vao ); + size_t stride = sizeof(mdl_vert); + glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo ); - glBufferData( GL_ARRAY_BUFFER, vert_count*sizeof(model_vert), - verts, GL_STATIC_DRAW ); + glBufferData( GL_ARRAY_BUFFER, vert_count*stride, verts, GL_STATIC_DRAW ); glBindVertexArray( mesh->vao ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo ); glBufferData( GL_ELEMENT_ARRAY_BUFFER, indice_count*sizeof(u32), indices, GL_STATIC_DRAW ); - glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void*)0 ); + glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 ); glEnableVertexAttribArray( 0 ); glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, norm) ); + stride, (void *)offsetof(mdl_vert, norm) ); glEnableVertexAttribArray( 1 ); glVertexAttribPointer( 2, 4, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, colour) ); + stride, (void *)offsetof(mdl_vert, colour) ); glEnableVertexAttribArray( 2 ); glVertexAttribPointer( 3, 2, GL_FLOAT, GL_FALSE, - sizeof(model_vert), (void *)offsetof(model_vert, uv) ); + stride, (void *)offsetof(mdl_vert, uv) ); glEnableVertexAttribArray( 3 ); VG_CHECK_GL(); @@ -120,92 +160,227 @@ static void mesh_draw( glmesh *mesh ) mesh_drawn( 0, mesh->indice_count ); } +static void mesh_free( glmesh *mesh ) +{ + glDeleteVertexArrays( 1, &mesh->vao ); + glDeleteBuffers( 1, &mesh->ebo ); + glDeleteBuffers( 1, &mesh->vbo ); +} + + /* - * Helper functions for file offsets - * TODO: Revise this + * Model implementation */ -static submodel *model_get_submodel( model *mdl, int id ) + +static mdl_header *mdl_load( const char *path ) { - return ((submodel*)(mdl+1)) + id; + i64 size; + mdl_header *header = vg_asset_read_s( path, &size ); + + /* + * Check file is valid + */ + if( !header ) + { + vg_error( "Could not open '%s'\n", path ); + return NULL; + } + + if( size < sizeof(mdl_header) ) + { + free( header ); + vg_error( "Invalid file '%s' (too small for header)\n", path ); + return NULL; + } + + if( header->file_length != size ) + { + vg_error( "Invalid file '%s'" + "(wrong .file_length, %ub != real file size %ub)\n", + path, header->file_length, size ); + free( header ); + return NULL; + } + + /* + * Validate offsets and memory sections, to ensure all arrays are in-bounds, + * and that they do not overlap. + */ + + struct memregion + { + const char *desc; + u32 count, max_count, size, offset; + } + regions[] = { + { + "Vertices", + header->vertex_count, MDL_VERT_MAX, + sizeof(mdl_vert), header->vertex_offset + }, + { + "Indices", + header->indice_count, MDL_INDICE_MAX, + sizeof(u32), header->indice_offset + }, + { + "Submesh", + header->submesh_count, MDL_SUBMESH_MAX, + sizeof(mdl_submesh), header->submesh_offset + }, + { + "Materials", + header->material_count, MDL_MATERIAL_MAX, + sizeof(mdl_material), header->material_offset + }, + { + "Nodes", + header->node_count, MDL_NODE_MAX, + sizeof(mdl_node), header->node_count + } + }; + + for( int i=0; icount == 0 ) + continue; + + if( ri->count > ri->max_count ) + { + free( header ); + vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n", + path, ri->desc, ri->count, ri->max_count ); + return NULL; + } + + if( ri->offset >= header->file_length ) + { + free( header ); + vg_error( "'%s': '%s' buffer offset is out of range\n", + path, ri->desc ); + return NULL; + } + + if( ri->offset + ri->size*ri->count > header->file_length ) + { + free( header ); + vg_error( "'%s': '%s' buffer size is out of range\n", + path, ri->desc ); + return NULL; + } + + for( int j=0; jcount == 0 ) + continue; + + if( ri->offset >= rj->offset && + (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count)) + { + free( header ); + vg_error( "'%s': '%s' buffer overlaps '%s'\n", + path, ri->desc, rj->desc ); + return NULL; + } + } + } + + /* + * Pointer validation TODO(workshop) + */ + + /* + * strings TODO(workshop) + */ + + return header; } -static model_marker *model_get_marker( model *mdl, int id ) +static void *mdl_baseptr( mdl_header *mdl, u32 offset ) { - return ((model_marker*)model_get_submodel(mdl,mdl->layer_count)) + id; + return (void *)mdl + offset; } -static model_vert *model_vertex_base( model *mdl ) +static const char *mdl_pstr( mdl_header *mdl, u32 pstr ) { - return (model_vert *)model_get_marker( mdl, mdl->marker_count ); + return (const char *)(mdl_baseptr( mdl, mdl->strings_offset )) + pstr; } -static u32 *model_indice_base( model *mdl ) +static mdl_node *mdl_node_from_id( mdl_header *mdl, u32 id ) { - return (u32 *)(model_vertex_base( mdl ) + mdl->vertex_count); + return ((mdl_node *)mdl_baseptr( mdl, mdl->node_offset )) + id; } -static model_vert *submodel_vert_data( model *mdl, submodel *sub ) +static mdl_node *mdl_node_from_name( mdl_header *mdl, const char *name ) { - return model_vertex_base(mdl) + sub->vertex_start; + for( int i=0; inode_count; i++ ) + { + mdl_node *pnode = mdl_node_from_id( mdl, i ); + + if( !strcmp( name, mdl_pstr( mdl, pnode->pstr_name )) ) + return pnode; + } + + return NULL; } -static u32 *submodel_indice_data( model *mdl, submodel *sub ) +static mdl_submesh *mdl_submesh_from_id( mdl_header *mdl, u32 id ) { - return model_indice_base(mdl) + sub->indice_start; + if( id >= mdl->submesh_count ) + return NULL; + + return ((mdl_submesh *)mdl_baseptr( mdl, mdl->submesh_offset )) + id; } -static void *get_entdata_raw( model *mdl, model_marker *marker ) +static mdl_submesh *mdl_node_submesh( mdl_header *mdl, mdl_node *node, u32 i ) { - return ((void *)(model_indice_base(mdl) + mdl->indice_count)) + - marker->offset; + if( i >= node->submesh_count ) + return NULL; + + return mdl_submesh_from_id( mdl, node->submesh_start+i ); } -static submodel *submodel_get( model *mdl, const char *name ) +static u32 *mdl_submesh_indices( mdl_header *mdl, mdl_submesh *sm ) { - for( int i=0; ilayer_count; i++ ) - { - submodel *pmdl =model_get_submodel(mdl,i); - - if( !strcmp( pmdl->name, name ) ) - return pmdl; - } - - return NULL; + return ((u32 *)mdl_baseptr( mdl, mdl->indice_offset )) + sm->indice_start; } -static model_marker *model_marker_get( model *mdl, const char *name ) +static mdl_vert *mdl_submesh_vertices( mdl_header *mdl, mdl_submesh *sm ) { - for( int i=0; imarker_count; i++ ) - { - model_marker *mk = model_get_marker( mdl,i ); + return ((mdl_vert *)mdl_baseptr(mdl,mdl->vertex_offset)) + sm->vertex_start; +} - if( !strcmp( mk->name, name ) ) - return mk; - } - - return NULL; +static mdl_material *mdl_material_from_id( mdl_header *mdl, u32 id ) +{ + return ((mdl_material *)mdl_baseptr(mdl,mdl->material_offset)) + id; } -static void submodel_draw( submodel *sm ) +static void mdl_node_transform( mdl_node *pnode, m4x3f transform ) { - mesh_drawn( sm->indice_start, sm->indice_count ); + q_m3x3( pnode->q, transform ); + transform[0][0] *= pnode->s[0]; + transform[1][1] *= pnode->s[1]; + transform[2][2] *= pnode->s[2]; + v3_copy( pnode->co, transform[3] ); } -static void model_unpack_submodel( model *model, glmesh *mesh, submodel *sm ) +static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm ) { - mesh_upload( mesh, - model_vertex_base( model ) + sm->vertex_start, sm->vertex_count, - model_indice_base( model ) + sm->indice_start, sm->indice_count ); + mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count, + mdl_submesh_indices( mdl, sm ), sm->indice_count ); } -static void model_unpack( model *model, glmesh *mesh ) +static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) { - u32 offset = model_get_submodel( model, 0 )->vertex_count; + u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count; - for( int i=1; ilayer_count; i++ ) + for( int i=1; i< mdl->submesh_count; i++ ) { - submodel *sm = model_get_submodel( model, i ); - u32 *indices = submodel_indice_data( model, sm ); + mdl_submesh *sm = mdl_submesh_from_id( mdl, i ); + u32 *indices = mdl_submesh_indices( mdl, sm ); for( u32 j=0; jindice_count; j++ ) indices[j] += offset; @@ -213,15 +388,22 @@ static void model_unpack( model *model, glmesh *mesh ) offset += sm->vertex_count; } - mesh_upload( mesh, model_vertex_base( model ), model->vertex_count, - model_indice_base( model ), model->indice_count ); + mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset ); + u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset ); + + mesh_upload( mesh, vertex_base, mdl->vertex_count, + indice_base, mdl->indice_count ); } -static void mesh_free( glmesh *mesh ) +static void mdl_draw_submesh( mdl_submesh *sm ) { - glDeleteVertexArrays( 1, &mesh->vao ); - glDeleteBuffers( 1, &mesh->ebo ); - glDeleteBuffers( 1, &mesh->vbo ); + mesh_drawn( sm->indice_start, sm->indice_count ); } +static void *mdl_get_entdata( mdl_header *mdl, mdl_node *pnode ) +{ + return mdl_baseptr( mdl, mdl->entdata_offset ) + pnode->offset; +} + + #endif diff --git a/player.h b/player.h index 3501c72..bd7304d 100644 --- a/player.h +++ b/player.h @@ -66,15 +66,49 @@ static void player_transform_update(void) static int reset_player( int argc, char const *argv[] ) { - v3_copy( world.tutorial, player.co ); - if( argc == 1 ) + struct respawn_point *rp = NULL, *r; + + if( argc > 1 ) { - if( !strcmp( argv[0], "tutorial" )) - v3_copy( world.tutorial, player.co ); + for( int i=0; iname, argv[0] ) ) + { + rp = r; + break; + } + } + + if( !rp ) + vg_warn( "No spawn named '%s'\n", argv[0] ); } - v3_copy( (v3f){ 0.0f, 0.0f, -0.2f }, player.v ); - q_identity( player.rot ); + if( !rp ) + { + float min_dist = INFINITY; + for( int i=0; ico, player.co ); + + if( d < min_dist ) + { + min_dist = d; + rp = r; + } + } + } + + if( !rp ) + { + vg_error( "No spawn found\n" ); + return 0; + } + + v4_copy( r->q, player.rot ); + v3_copy( r->co, player.co ); + player.vswitch = 1.0f; player.slip_last = 0.0f; player.is_dead = 0; @@ -85,7 +119,8 @@ static int reset_player( int argc, char const *argv[] ) player.mdl.shoes[1] = 1; player_transform_update(); - return 0; + m3x3_mulv( player.to_world, (v3f){ 0.0f, 0.0f, -0.2f }, player.v ); + return 1; } static void player_mouseview(void) @@ -597,7 +632,7 @@ static void player_do_motion(void) static int player_walkgrid_tri_walkable( u32 tri[3] ) { - return tri[0] < world.sm_road.vertex_count; + return tri[0] < world.sm_surface.vertex_count; } #define WALKGRID_SIZE 16 diff --git a/scene.h b/scene.h index 76baf54..3e3829e 100644 --- a/scene.h +++ b/scene.h @@ -11,7 +11,7 @@ struct scene { glmesh mesh; - model_vert *verts; + mdl_vert *verts; u32 *indices; bh_tree bhtris; @@ -25,10 +25,12 @@ struct scene u32 shadower_count, shadower_cap; - submodel submesh; + mdl_submesh submesh; }; +#if 0 GLuint tex_dual_noise; +#endif static void scene_init( scene *pscene ) { @@ -44,6 +46,7 @@ static void scene_init( scene *pscene ) v3_fill( pscene->bbx[0], 999999.9f ); v3_fill( pscene->bbx[1], -999999.9f ); +#if 0 static int noise_ready = 0; if( !noise_ready ) { @@ -78,6 +81,7 @@ static void scene_init( scene *pscene ) free( buf ); } +#endif } static void *buffer_reserve( void *buffer, u32 count, u32 *cap, u32 amount, @@ -93,85 +97,37 @@ static void *buffer_reserve( void *buffer, u32 count, u32 *cap, u32 amount, return buffer; } +static void *buffer_fix( void *buffer, u32 count, u32 *cap, size_t emsize ) +{ + *cap = count; + return realloc( buffer, (*cap) * emsize ); +} + /* * Append a model into the scene with a given transform */ -static void scene_add_model( scene *pscene, model *mdl, submodel *submodel, - v3f pos, float yaw, float scale ) -{ - pscene->verts = buffer_reserve( pscene->verts, pscene->vertex_count, - &pscene->vertex_cap, submodel->vertex_count, sizeof(model_vert) ); - pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count, - &pscene->indice_cap, submodel->indice_count, sizeof(u32) ); - - /* Transform and place vertices */ - model_vert *src_verts = submodel_vert_data( mdl, submodel ); - u32 *src_indices = submodel_indice_data( mdl, submodel ); - - m4x3f mtx; - m4x3_identity( mtx ); - m4x3_translate( mtx, pos ); - m4x3_rotate_y( mtx, yaw ); - m4x3_scale( mtx, scale ); - - boxf bbxnew; - box_copy( submodel->bbx, bbxnew ); - m4x3_transform_aabb( mtx, bbxnew ); - box_concat( pscene->bbx, bbxnew ); - - m3x3f rotation; - m4x3_to_3x3( mtx, rotation ); - float rand_hue = vg_randf(); - - for( u32 i=0; ivertex_count; i++ ) - { - model_vert *pvert = &pscene->verts[ pscene->vertex_count+i ], - *src = &src_verts[ i ]; - - m4x3_mulv( mtx, src->co, pvert->co ); - m3x3_mulv( rotation, src->norm, pvert->norm ); - - v4_copy( src->colour, pvert->colour ); - v2_copy( src->uv, pvert->uv ); - - float rel_y = src->co[1] / submodel->bbx[1][1]; - pvert->colour[0] = rel_y; - pvert->colour[2] = rand_hue; - } - - for( u32 i=0; iindice_count; i++ ) - { - u32 *pidx = &pscene->indices[ pscene->indice_count+i ]; - *pidx = src_indices[i] + pscene->vertex_count; - } - - pscene->vertex_count += submodel->vertex_count; - pscene->indice_count += submodel->indice_count; -} - -static void scene_add_foliage( scene *pscene, model *mdl, submodel *submodel, - m4x3f transform ) +static void scene_add_submesh( scene *pscene, mdl_header *mdl, + mdl_submesh *sm, m4x3f transform ) { pscene->verts = buffer_reserve( pscene->verts, pscene->vertex_count, - &pscene->vertex_cap, submodel->vertex_count, sizeof(model_vert) ); + &pscene->vertex_cap, sm->vertex_count, sizeof(mdl_vert) ); pscene->indices = buffer_reserve( pscene->indices, pscene->indice_count, - &pscene->indice_cap, submodel->indice_count, sizeof(u32) ); + &pscene->indice_cap, sm->indice_count, sizeof(u32) ); /* Transform and place vertices */ - model_vert *src_verts = submodel_vert_data( mdl, submodel ); - u32 *src_indices = submodel_indice_data( mdl, submodel ); + mdl_vert *src_verts = mdl_submesh_vertices( mdl, sm ); + u32 *src_indices = mdl_submesh_indices( mdl, sm ); boxf bbxnew; - box_copy( submodel->bbx, bbxnew ); + box_copy( sm->bbx, bbxnew ); m4x3_transform_aabb( transform, bbxnew ); box_concat( pscene->bbx, bbxnew ); - float rand_hue = vg_randf(); - for( u32 i=0; ivertex_count; i++ ) + for( u32 i=0; ivertex_count; i++ ) { - model_vert *pvert = &pscene->verts[ pscene->vertex_count+i ], - *src = &src_verts[ i ]; + mdl_vert *pvert = &pscene->verts[ pscene->vertex_count+i ], + *src = &src_verts[ i ]; m4x3_mulv( transform, src->co, pvert->co ); m3x3_mulv( transform, src->norm, pvert->norm ); @@ -180,17 +136,17 @@ static void scene_add_foliage( scene *pscene, model *mdl, submodel *submodel, v2_copy( src->uv, pvert->uv ); } - for( u32 i=0; iindice_count; i++ ) + for( u32 i=0; iindice_count; i++ ) { u32 *pidx = &pscene->indices[ pscene->indice_count+i ]; *pidx = src_indices[i] + pscene->vertex_count; } - pscene->vertex_count += submodel->vertex_count; - pscene->indice_count += submodel->indice_count; + pscene->vertex_count += sm->vertex_count; + pscene->indice_count += sm->indice_count; } -static void scene_copy_slice( scene *pscene, submodel *sm ) +static void scene_copy_slice( scene *pscene, mdl_submesh *sm ) { sm->indice_start = pscene->submesh.indice_start; sm->indice_count = pscene->indice_count - sm->indice_start; @@ -202,6 +158,15 @@ static void scene_copy_slice( scene *pscene, submodel *sm ) pscene->submesh.vertex_start = pscene->vertex_count; } +static void scene_fix( scene *pscene ) +{ + buffer_fix( pscene->verts, pscene->vertex_count, + &pscene->vertex_cap, sizeof( mdl_vert )); + + buffer_fix( pscene->indices, pscene->indice_count, + &pscene->indice_cap, sizeof( mdl_vert )); +} + static void scene_upload( scene *pscene ) { mesh_upload( &pscene->mesh, @@ -223,6 +188,14 @@ static void scene_draw( scene *pscene ) mesh_drawn( 0, pscene->indice_count ); } +static void scene_free( scene *pscene ) +{ + free( pscene->verts ); + free( pscene->indices ); + + /* TODO: bvh */ +} + static void scene_register(void) { } @@ -234,9 +207,9 @@ static void scene_register(void) static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index ) { scene *s = user; - model_vert *pa = &s->verts[ s->indices[item_index*3+0] ], - *pb = &s->verts[ s->indices[item_index*3+1] ], - *pc = &s->verts[ s->indices[item_index*3+2] ]; + mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ], + *pb = &s->verts[ s->indices[item_index*3+1] ], + *pc = &s->verts[ s->indices[item_index*3+2] ]; box_addpt( bound, pa->co ); box_addpt( bound, pb->co ); @@ -246,9 +219,9 @@ static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index ) static float scene_bh_centroid( void *user, u32 item_index, int axis ) { scene *s = user; - model_vert *pa = &s->verts[ s->indices[item_index*3+0] ], - *pb = &s->verts[ s->indices[item_index*3+1] ], - *pc = &s->verts[ s->indices[item_index*3+2] ]; + mdl_vert *pa = &s->verts[ s->indices[item_index*3+0] ], + *pb = &s->verts[ s->indices[item_index*3+1] ], + *pc = &s->verts[ s->indices[item_index*3+2] ]; return (pa->co[axis] + pb->co[axis] + pc->co[axis]) * (1.0f/3.0f); } @@ -278,9 +251,9 @@ static void scene_bh_debug( void *user, u32 item_index ) { scene *s = user; u32 idx = item_index*3; - model_vert *pa = &s->verts[ s->indices[ idx+0 ] ], - *pb = &s->verts[ s->indices[ idx+1 ] ], - *pc = &s->verts[ s->indices[ idx+2 ] ]; + mdl_vert *pa = &s->verts[ s->indices[ idx+0 ] ], + *pb = &s->verts[ s->indices[ idx+1 ] ], + *pc = &s->verts[ s->indices[ idx+2 ] ]; vg_line( pa->co, pb->co, 0xff0000ff ); vg_line( pb->co, pc->co, 0xff0000ff ); diff --git a/textures/gradients.png b/textures/gradients.png index 37d3e74..5118b9c 100644 Binary files a/textures/gradients.png and b/textures/gradients.png differ diff --git a/world.h b/world.h index 20c4401..d8b3616 100644 --- a/world.h +++ b/world.h @@ -26,7 +26,15 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); static struct gworld { /* gameplay */ - v3f tutorial; + struct respawn_point + { + v3f co; + v4f q; + char name[32]; + } + spawns[32]; + u32 spawn_count; + teleport_gate gates[64]; u32 gate_count; @@ -37,11 +45,10 @@ static struct gworld /* Rendering & geometry */ scene geo, foliage, props; - submodel sm_road, sm_terrain; + mdl_submesh sm_surface; glmesh skybox, skydome; - submodel dome_upper, - dome_lower; + mdl_submesh dome_upper, dome_lower; } world; @@ -64,7 +71,7 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ) static int ray_hit_is_ramp( ray_hit *hit ) { - return hit->tri[0] < world.sm_road.vertex_count; + return hit->tri[0] < world.sm_surface.vertex_count; } static void world_register(void) @@ -82,146 +89,39 @@ static void world_free(void) } static void render_world_depth( m4x4f projection, m4x3f camera ); -static void world_load(void) -{ - /* - * Setup scene - * - * TODO: Call world_free when its ready here - * - */ - scene_init( &world.geo ); - model *mworld = vg_asset_read( "models/mp_dev.mdl" ); - for( int i=0; ilayer_count; i++ ) +static void add_all_if_material( scene *pscene, mdl_header *mdl, u32 id ) +{ + for( int i=0; inode_count; i++ ) { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "surf" ) ) - scene_add_model( &world.geo, mworld, sm, sm->pivot, 0.0f, 1.0f ); + mdl_node *pnode = mdl_node_from_id( mdl, i ); - } - for( int i=0; ilayer_count; i++ ) - { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "vertex_blend" ) ) + for( int j=0; jsubmesh_count; j++ ) { - m4x3f transform; - q_m3x3( sm->q, transform ); - v3_copy( sm->pivot, transform[3] ); - scene_add_foliage( &world.geo, mworld, sm, transform ); - } - } - scene_copy_slice( &world.geo, &world.sm_road ); + mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j ); - for( int i=0; ilayer_count; i++ ) - { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "terrain" ) ) - scene_add_model( &world.geo, mworld, sm, sm->pivot, 0.0f, 1.0f ); - } - - - scene_copy_slice( &world.geo, &world.sm_terrain ); - - /* - * TODO: Parametric marker import - */ - v3_copy( model_marker_get( mworld, "start" )->co, world.tutorial ); - - /* - * Initialize gates - */ - - world.gate_count = 0; - for( int i=0; imarker_count; i++ ) - { - model_marker *ga = model_get_marker( mworld, i ); - - if( ga->classtype == k_classtype_gate ) - { - struct classtype_gate *data = get_entdata_raw( mworld, ga ); - - if( data->target ) + if( sm->material_id == id ) { - model_marker *gb = model_get_marker( mworld, data->target ); - - teleport_gate *gate = &world.gates[ world.gate_count ++ ]; - - v3_copy( ga->co, gate->co[0] ); - v3_copy( gb->co, gate->co[1] ); - v4_copy( ga->q, gate->q[0] ); - v4_copy( gb->q, gate->q[1] ); - v2_copy( ga->s, gate->dims ); - - gate_transform_update( gate ); + m4x3f transform; + mdl_node_transform( pnode, transform ); + scene_add_submesh( pscene, mdl, sm, transform ); } } } +} - /* - * Load water mesh (1 per world) - */ - for( int i=0; ilayer_count; i++ ) - { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "water" ) ) - { - glmesh surf; - model_unpack_submodel( mworld, &surf, sm ); - - water_init(); - water_set_surface( &surf, sm->pivot[1] ); - - vg_info( "%.3f\n", sm->pivot[1] ); - - break; - } - } - - scene_bh_create( &world.geo ); - scene_upload( &world.geo ); - +static void world_apply_foliage(void) +{ scene_init( &world.foliage ); - model *mfoliage = vg_asset_read("models/rs_foliage.mdl"); - - /* - * TODO: Load any other meshes into the foliage scene, and create rbs for - * them. - * - * then compute bvh - */ - - for( int i=0; ilayer_count; i++ ) - { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "surf" ) || - !strcmp( sm->material, "terrain" ) || - !strcmp( sm->material, "water" ) || - !strcmp( sm->material, "vertex_blend") ) - continue; - - m4x3f transform; - q_m3x3( sm->q, transform ); - v3_copy( sm->pivot, transform[3] ); - scene_add_foliage( &world.foliage, mworld, sm, transform ); - - rigidbody *rb = &world.temp_rbs[ world.rb_count ++ ]; - - box_copy( sm->bbx, rb->bbx ); - v3_copy( sm->pivot, rb->co ); - rb_init( rb ); - v4_copy( sm->q, rb->q ); - rb_update_transform( rb ); - } + mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl"); v3f volume; v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume ); volume[1] = 1.0f; m4x3f transform; - - submodel *sm_blob = submodel_get( mfoliage, "blob" ), - *sm_tree = submodel_get( mfoliage, "tree" ); + mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" ); + mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 ); for( int i=0;i<100000;i++ ) { @@ -250,41 +150,142 @@ static void world_load(void) q_m3x3( qsurface, transform ); v3_copy( hit.pos, transform[3] ); - - if( vg_randf() < 0.0006f ) - { - m3x3_identity( transform ); - scene_add_foliage( &world.foliage, mfoliage, sm_tree, transform); - } - else - scene_add_foliage( &world.foliage, mfoliage, sm_blob, transform); + scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform); } } } - free( mfoliage ); scene_upload( &world.foliage ); - - - /* Prop layer */ + free( mfoliage ); +} + +static void world_load(void) +{ + mdl_header *mworld = mdl_load( "models/mp_dev.mdl" ); + + world.spawn_count = 0; + world.gate_count = 0; + world.rb_count = 0; + + scene_init( &world.geo ); scene_init( &world.props ); - for( int i=0; ilayer_count; i++ ) + + /* + * Compile meshes into the world scenes + */ + u32 mat_surf = 0, + mat_surf_oob = 0, + mat_vertex_blend = 0; + + for( int i=1; imaterial_count; i++ ) + { + mdl_material *mat = mdl_material_from_id( mworld, i ); + const char *mat_name = mdl_pstr( mworld, mat->pstr_name ); + + vg_info( "%d %s\n", mat->pstr_name, mat_name ); + + if( !strcmp( "surf", mat_name )) + mat_surf = i; + else if( !strcmp( "surf_oob", mat_name )) + mat_surf_oob = i; + else if( !strcmp( "vertex_blend", mat_name )) + mat_vertex_blend = i; + } + + if( mat_surf ) + add_all_if_material( &world.geo, mworld, mat_surf ); + + scene_copy_slice( &world.geo, &world.sm_surface ); + + if( mat_surf_oob ) + add_all_if_material( &world.geo, mworld, mat_surf_oob ); + else + vg_warn( "No OOB surface\n" ); + + scene_bh_create( &world.geo ); + scene_upload( &world.geo ); + + if( mat_vertex_blend ) + add_all_if_material( &world.props, mworld, mat_vertex_blend ); + + /* TODO bvh? */ + + /* + * Process entities + */ + for( int i=0; inode_count; i++ ) { - submodel *sm = model_get_submodel( mworld, i ); - if( !strcmp( sm->material, "vertex_blend" ) ) + mdl_node *pnode = mdl_node_from_id( mworld, i ); + + if( pnode->classtype == k_classtype_none ) + {} + else if( pnode->classtype == k_classtype_gate ) + { + struct classtype_gate *entgate = mdl_get_entdata( mworld, pnode ); + mdl_node *pother = mdl_node_from_id( mworld, entgate->target ); + + teleport_gate *gate = &world.gates[ world.gate_count ++ ]; + + v3_copy( pnode->co, gate->co[0] ); + v3_copy( pother->co, gate->co[1] ); + v4_copy( pnode->q, gate->q[0] ); + v4_copy( pother->q, gate->q[1] ); + v2_copy( pnode->s, gate->dims ); + + gate_transform_update( gate ); + } + else if( pnode->classtype == k_classtype_block ) { + struct classtype_block *block = mdl_get_entdata( mworld, pnode ); + m4x3f transform; - q_m3x3( sm->q, transform ); - v3_copy( sm->pivot, transform[3] ); - scene_add_foliage( &world.props, mworld, sm, transform ); + mdl_node_transform( pnode, transform ); + + rigidbody *rb = &world.temp_rbs[ world.rb_count ++ ]; + + box_copy( block->bbx, rb->bbx ); /* TODO: apply scale */ + v3_copy( pnode->co, rb->co ); + rb_init( rb ); + v4_copy( pnode->q, rb->q ); + rb_update_transform( rb ); + } + else if( pnode->classtype == k_classtype_spawn ) + { + struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ]; + + v3_copy( pnode->co, rp->co ); + v4_copy( pnode->q, rp->q ); + strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) ); + } + else if( pnode->classtype == k_classtype_water ) + { + if( wrender.enabled ) + { + vg_warn( "Multiple water surfaces in level! ('%s')\n", + mdl_pstr( mworld, pnode->pstr_name )); + continue; + } + + mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 ); + + if( sm ) + { + glmesh surf; + mdl_unpack_submesh( mworld, &surf, sm ); + water_init(); + water_set_surface( &surf, pnode->co[1] ); + } } } scene_upload( &world.props ); - free( mworld ); + bh_create( &world.bhcubes, &bh_system_rigidbodies, world.temp_rbs, world.rb_count ); - + + world_apply_foliage(); + free( mworld ); + /* * Rendering the depth map */ @@ -346,12 +347,14 @@ static void world_init(void) &tex_terrain_noise }, 2 ); - model *msky = vg_asset_read("models/rs_skydome.mdl"); - model_unpack( msky, &world.skydome ); - - world.dome_lower = *submodel_get( msky, "dome_lower" ); - world.dome_upper = *submodel_get( msky, "dome_upper" ); + mdl_header *msky = mdl_load("models/rs_skydome.mdl"); + mdl_unpack_glmesh( msky, &world.skydome ); + mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ), + *nupper = mdl_node_from_name( msky, "dome_upper" ); + + world.dome_lower = *mdl_node_submesh( msky, nlower, 0 ); + world.dome_upper = *mdl_node_submesh( msky, nupper, 0 ); free(msky); } @@ -427,8 +430,8 @@ static void render_lowerdome( m4x3f camera ) shader_planeinf_uPv(full); shader_planeinf_uCamera(camera[3]); shader_planeinf_uPlane( (v4f){0.0f,1.0f,0.0f, water_height()} ); - - submodel_draw( &world.dome_lower ); + + mdl_draw_submesh( &world.dome_lower ); } static void render_sky(m4x3f camera) @@ -457,7 +460,7 @@ static void render_sky(m4x3f camera) glDisable( GL_DEPTH_TEST ); mesh_bind( &world.skydome ); - submodel_draw( &world.dome_upper ); + mdl_draw_submesh( &world.dome_upper ); glEnable( GL_DEPTH_TEST ); glDepthMask( GL_TRUE );