import bpy, math, gpu
from ctypes import *
+from mathutils import *
from gpu_extras.batch import batch_for_shader
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()
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
#
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]
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
# ------------------------------------------------------------------------------
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
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', \
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="" )
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):
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"
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
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')
{
glmesh mesh;
- submodel parts[ PART_COUNT ];
+ mdl_submesh parts[ PART_COUNT ];
+ v3f origins[ PART_COUNT ];
m4x3f matrices[ PART_COUNT ];
/* Auxillary information */
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 ] );
}
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; i<PART_COUNT; i++ )
{
snprintf( buf, sizeof(buf)-1, "%s_%s", name, character_part_strings[i] );
- submodel *sm = submodel_get( src, buf );
+ mdl_node *pnode = mdl_node_from_name( src, buf );
- if( !sm )
+ memset( &ch->parts[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 );
*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];
#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++ )
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] );
}
}
}
{
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; i<PART_COUNT; i++ )
{
- float *pivot = ch->parts[i].pivot;
+ float *pivot = ch->origins[i];
v3_sub( ch->ragdoll[i].co, pivot, ch->ragdoll[i].delta );
}
}
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 );
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 */
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;
#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 */
{
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 );
}
-#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; z<gi->pt_dims[2]; z++ )
- {
- for( int y=0; y<gi->pt_dims[1]; y++ )
- {
- for( int x=0; x<gi->pt_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; i<sc->vertex_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 */
world_load();
- reset_player( 1, (const char *[]){ "tutorial" } );
+ reset_player( 1, (const char *[]){ "start" } );
player_transform_update();
}
#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,
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;
};
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 );
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();
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; i<vg_list_size(regions); i++ )
+ {
+ struct memregion *ri = ®ions[i];
+
+ if( ri->count == 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; j<vg_list_size(regions); j++ )
+ {
+ struct memregion *rj = ®ions[j];
+ if( rj->count == 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; i<mdl->node_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; i<mdl->layer_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; i<mdl->marker_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; i<model->layer_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; j<sm->indice_count; j++ )
indices[j] += offset;
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
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; i<world.spawn_count; i++ )
+ {
+ r = &world.spawns[i];
+ if( !strcmp( r->name, 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; i<world.spawn_count; i++ )
+ {
+ r = &world.spawns[i];
+ float d = v3_dist2( r->co, 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;
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)
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
{
glmesh mesh;
- model_vert *verts;
+ mdl_vert *verts;
u32 *indices;
bh_tree bhtris;
u32 shadower_count,
shadower_cap;
- submodel submesh;
+ mdl_submesh submesh;
};
+#if 0
GLuint tex_dual_noise;
+#endif
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 )
{
free( buf );
}
+#endif
}
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; i<submodel->vertex_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; i<submodel->indice_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; i<submodel->vertex_count; i++ )
+ for( u32 i=0; i<sm->vertex_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 );
v2_copy( src->uv, pvert->uv );
}
- for( u32 i=0; i<submodel->indice_count; i++ )
+ for( u32 i=0; i<sm->indice_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;
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,
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)
{
}
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 );
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);
}
{
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 );
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;
/* 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;
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)
}
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; i<mworld->layer_count; i++ )
+static void add_all_if_material( scene *pscene, mdl_header *mdl, u32 id )
+{
+ for( int i=0; i<mdl->node_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; i<mworld->layer_count; i++ )
- {
- submodel *sm = model_get_submodel( mworld, i );
- if( !strcmp( sm->material, "vertex_blend" ) )
+ for( int j=0; j<pnode->submesh_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; i<mworld->layer_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; i<mworld->marker_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; i<mworld->layer_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; i<mworld->layer_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++ )
{
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; i<mworld->layer_count; i++ )
+
+ /*
+ * Compile meshes into the world scenes
+ */
+ u32 mat_surf = 0,
+ mat_surf_oob = 0,
+ mat_vertex_blend = 0;
+
+ for( int i=1; i<mworld->material_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; i<mworld->node_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
*/
&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);
}
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)
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 );