rework scene format
authorhgn <hgodden00@gmail.com>
Wed, 13 Jul 2022 01:28:17 +0000 (02:28 +0100)
committerhgn <hgodden00@gmail.com>
Wed, 13 Jul 2022 01:28:17 +0000 (02:28 +0100)
12 files changed:
blender_export.py
character.h
common.h
gate.h
lighting.h
main.c
mesh.h [new file with mode: 0644]
model.h
player.h
scene.h
textures/gradients.png
world.h

index 16b97645b306d758406b4233c8da3ca9b93e0bc3..16d1f381e201f2c9625c335690a4404134d38150 100644 (file)
@@ -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')
 
index c565fc436170fa7d20f5508a62daed0f48eb2f0f..5ce456f24a1648493bd2056aa57156c4efac401b 100644 (file)
@@ -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; 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 );
@@ -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; 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 );
    }
 }
@@ -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;
 
index 1e1ebed3c21aaa8d7dfa65f33fbfeba4943217da..21251546e00336095bbc8b857d3e17d77e4093c4 100644 (file)
--- 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 3151878f25a4f7625c41bb0fe7d7bbe357effdf4..a370d81dde091a61c7c0f34235a158af48df33ef 100644 (file)
--- 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 );
 }
 
index 8f9bdb3115e2bc05d0c05f1bf6459b1851773157..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -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; 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 */
diff --git a/main.c b/main.c
index aa90b02bdc25d39d127155a874fc9971d668ff51..84de4100c203110e5c6da57f5c0512623196bc5b 100644 (file)
--- 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 (file)
index 0000000..e69de29
diff --git a/model.h b/model.h
index 430ed26d7425d684670bddeb0931a9b9b45039de..4ed39d4780500a4d876c19955ed4aea24dbb8f46 100644 (file)
--- 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; i<vg_list_size(regions); i++ )
+   {
+      struct memregion *ri = &regions[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 = &regions[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;
@@ -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
index 3501c72b5d0e39b6c2f9acb434154da38b0816a9..bd7304dc614550c8978345c08cce9fb893a363ae 100644 (file)
--- 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; 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;
@@ -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 76baf547f77b50e69d6c1881b5b24557e411b766..3e3829ecc526c3299cdb9bc8b69db7df09468ac7 100644 (file)
--- 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; 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 );
@@ -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; 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;
@@ -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 );
index 37d3e74434be5b4cf18d7c107ff5c3f2ef291cb1..5118b9c5e5668be2871c6167dbc3043c4c963c93 100644 (file)
Binary files a/textures/gradients.png and b/textures/gradients.png differ
diff --git a/world.h b/world.h
index 20c44011b06486dae764ef86650440220ebddc00..d8b36165c20d2225dcd90621e98d03c5cc7afdd4 100644 (file)
--- 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; 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++ )
    {
@@ -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; 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
     */
@@ -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 );