POWER
authorhgn <hgodden00@gmail.com>
Sat, 29 Oct 2022 03:50:27 +0000 (04:50 +0100)
committerhgn <hgodden00@gmail.com>
Sat, 29 Oct 2022 03:50:27 +0000 (04:50 +0100)
25 files changed:
blender_export.py
bvh.h
model.h
models_src/ch_jordan.mdl
models_src/ch_new.mdl
models_src/ch_outlaw.mdl
models_src/mp_dev.mdl
models_src/mp_test.mdl
models_src/rs_cars.mdl
models_src/rs_chicken.mdl
models_src/rs_foliage.mdl
models_src/rs_gate.mdl
models_src/rs_menu.mdl
models_src/rs_scoretext.mdl
models_src/rs_skydome.mdl
models_src/rs_vig.mdl
player_audio.h
shaders/terrain.fs
shaders/terrain.h
shaders/water.fs
shaders/water.h
world.h
world_gen.h
world_render.h
world_water.h

index ce4e8264af2fb32dfcdb3efbf73c98fd6733fb7c..4508bca48d8f0f53b3c759ce61bcda421f8297dd 100644 (file)
@@ -17,7 +17,7 @@
 # otherwise
 #
 
-import bpy, math, gpu
+import bpy, math, gpu, os
 import cProfile
 from ctypes import *
 from mathutils import *
@@ -57,10 +57,25 @@ class mdl_submesh(Structure):
                ("material_id",c_uint32)]        # index into the material array
 #}
 
+class mdl_texture(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("pstr_name",c_uint32),
+               ("pack_offset",c_uint32),
+               ("pack_length",c_uint32)]
+#}
+
 class mdl_material(Structure):
 #{
    _pack_ = 1
-   _fields_ = [("pstr_name",c_uint32)]
+   _fields_ = [("pstr_name",c_uint32),
+               ("shader",c_uint32),
+               ("flags",c_uint32),
+               ("colour",c_float*4),
+               ("colour1",c_float*4),
+               ("tex_diffuse",c_uint32),
+               ("tex_decal",c_uint32),
+               ("tex_normal",c_uint32)]
 #}
 
 class mdl_node(Structure):
@@ -95,6 +110,9 @@ class mdl_header(Structure):
                ("material_count",c_uint32),
                ("material_offset",c_uint32),
 
+               ("texture_count",c_uint32),
+               ("texture_offset",c_uint32),
+
                ("anim_count",c_uint32),
                ("anim_offset",c_uint32),
 
@@ -111,7 +129,10 @@ class mdl_header(Structure):
                ("vertex_offset",c_uint32),
 
                ("indice_count",c_uint32),
-               ("indice_offset",c_uint32),]
+               ("indice_offset",c_uint32),
+
+               ("pack_size",c_uint32),
+               ("pack_offset",c_uint32)]
 #}
 
 class mdl_animation(Structure):
@@ -209,11 +230,13 @@ class classtype_gate(Structure):
       indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(7,8)]
 
       for l in indices:
+      #{
          v0 = vs[l[0]]
          v1 = vs[l[1]]
          cv_view_verts += [(v0[0],v0[1],v0[2])]
          cv_view_verts += [(v1[0],v1[1],v1[2])]
          cv_view_colours += [(1,1,0,1),(1,1,0,1)]
+      #}
 
       sw = (0.4,0.4,0.4,0.2)
       if obj.cv_data.target != None:
@@ -747,7 +770,7 @@ g_encoder = None
 
 # Reset encoder
 #
-def encoder_init():
+def encoder_init( collection ):
 #{
    global g_encoder
 
@@ -757,6 +780,10 @@ def encoder_init():
       #
       'header': mdl_header(),
 
+      # Options
+      #
+      'pack_textures': collection.cv_data.pack_textures,
+
       # Compiled data chunks (each can be read optionally by the client)
       #
       'data':
@@ -765,6 +792,7 @@ def encoder_init():
          'node': [],      # Metadata 'chunk'
          'submesh': [],
          'material': [],
+         'texture': [],
          'anim': [],
          'entdata': bytearray(), # variable width
          'strings': bytearray(), # .
@@ -773,6 +801,8 @@ def encoder_init():
          #3---------------------------------
          'vertex': [],    # Mesh data
          'indice': [],
+         #4---------------------------------
+         'pack': bytearray()  # Other generic packed data
       },
 
       # All objects of the model in their final heirachy
@@ -786,16 +816,27 @@ def encoder_init():
       'string_cache':{},
       'mesh_cache': {},
       'material_cache': {},
+      'texture_cache': {}
    }
 
    g_encoder['header'].identifier = 0xABCD0000
    g_encoder['header'].version = 1
 
-   # Add fake NoneID material
+   # Add fake NoneID material and texture
    #
-   none_material = c_uint32(1234)
-   none_material.name = ""
-   encoder_process_material( none_material )
+   none_material = mdl_material()
+   none_material.pstr_name = encoder_process_pstr( "" )
+   none_material.texture_id = 0
+
+   none_texture = mdl_texture()
+   none_texture.pstr_name = encoder_process_pstr( "" )
+   none_texture.pack_offset = 0
+   none_texture.pack_length = 0
+   
+   g_encoder['data']['material'] += [none_material]
+   g_encoder['data']['texture']  += [none_texture]
+
+   g_encoder['data']['pack'].extend( b'datapack\0\0\0\0\0\0\0\0' )
 
    # Add root node
    #
@@ -858,6 +899,164 @@ def encoder_process_pstr( s ):
    return cache[s]
 #}
 
+def get_texture_resource_name( img ):
+#{
+   return os.path.splitext( img.name )[0]
+#}
+
+# Pack a texture
+#
+def encoder_process_texture( img ):
+#{
+   global g_encoder
+
+   if img == None:
+      return 0
+
+   cache = g_encoder['texture_cache']
+   buffer = g_encoder['data']['texture']
+   pack = g_encoder['data']['pack']
+
+   name = get_texture_resource_name( img )
+
+   if name in cache:
+      return cache[name]
+   
+   cache[name] = len( buffer )
+   
+   tex = mdl_texture()
+   tex.pstr_name = encoder_process_pstr( name )
+
+   if g_encoder['pack_textures']:
+   #{
+      tex.pack_offset = len( pack )
+      pack.extend( qoi_encode( img ) )
+      tex.pack_length = len( pack ) - tex.pack_offset
+   #}
+   else:
+      tex.pack_offset = 0
+
+   buffer += [ tex ]
+   return cache[name]
+#}
+
+def material_tex_image(v):
+#{
+    return {
+       "Image Texture":
+       {
+          "image": F"{v}"
+       }
+    }
+#}
+
+cxr_graph_mapping = \
+{
+   # Default shader setup 
+   "Principled BSDF":
+   {
+      "Base Color":
+      {
+         "Image Texture":
+         {
+            "image": "tex_diffuse"
+         },
+         "Mix":
+         {
+            "Color1": material_tex_image("tex_diffuse"),
+            "Color2": material_tex_image("tex_decal")
+         },
+      },
+      "Normal":
+      {
+         "Normal Map":
+         {
+            "Color": material_tex_image("tex_normal")
+         }
+      }
+   }
+}
+
+# https://harrygodden.com/git/?p=convexer.git;a=blob;f=__init__.py;#l1164
+#
+def material_info(mat):
+#{
+   info = {}
+
+   # Using the cv_graph_mapping as a reference, go through the shader
+   # graph and gather all $props from it.
+   #
+   def _graph_read( node_def, node=None, depth=0 ):
+   #{
+      nonlocal mat
+      nonlocal info
+      
+      # Find rootnodes
+      #
+      if node == None:
+      #{
+         _graph_read.extracted = []
+
+         for node_idname in node_def:
+         #{
+            for n in mat.node_tree.nodes:
+            #{
+               if n.name == node_idname:
+               #{
+                  node_def = node_def[node_idname]
+                  node = n
+                  break
+               #}
+            #}
+         #}
+      #}
+
+      for link in node_def:
+      #{
+         link_def = node_def[link]
+
+         if isinstance( link_def, dict ):
+         #{
+            node_link = node.inputs[link]
+
+            if node_link.is_linked:
+            #{
+               # look for definitions for the connected node type
+               #
+               from_node = node_link.links[0].from_node
+               
+               node_name = from_node.name.split('.')[0]
+               if node_name in link_def:
+               #{
+                  from_node_def = link_def[ node_name ]
+
+                  _graph_read( from_node_def, from_node, depth+1 )
+               #}
+               
+               # No definition! :(
+               #  TODO: Make a warning for this?
+            #}
+            else:
+            #{
+               if "default" in link_def:
+               #{
+                  prop = link_def['default']
+                  info[prop] = node_link.default_value
+               #}
+            #}
+         #}
+         else:
+         #{
+            prop = link_def
+            info[prop] = getattr( node, link )
+         #}
+      #}
+   #}
+
+   _graph_read( cxr_graph_mapping )
+   return info
+#}
+
 # Add a material to the material buffer. Returns 0 (None ID) if invalid
 #
 def encoder_process_material( mat ):
@@ -877,8 +1076,61 @@ def encoder_process_material( mat ):
 
    dest = mdl_material()
    dest.pstr_name = encoder_process_pstr( mat.name )
-   buffer += [dest]
+   
+   flags = 0x00
+   if mat.cv_data.skate_surface: flags |= 0x1
+   if mat.cv_data.collision: flags |= 0x2
+   dest.flags = flags
+
+   if mat.cv_data.shader == 'standard': dest.shader = 0
+   if mat.cv_data.shader == 'standard_cutout': dest.shader = 1
+   if mat.cv_data.shader == 'terrain_blend': 
+   #{
+      dest.shader = 2
+
+      dest.colour[0] = pow( mat.cv_data.sand_colour[0], 1.0/2.2 )
+      dest.colour[1] = pow( mat.cv_data.sand_colour[1], 1.0/2.2 )
+      dest.colour[2] = pow( mat.cv_data.sand_colour[2], 1.0/2.2 )
+      dest.colour[3] = 1.0
+
+      dest.colour1[0] = mat.cv_data.blend_offset[0]
+      dest.colour1[1] = mat.cv_data.blend_offset[1]
+   #}
 
+   if mat.cv_data.shader == 'vertex_blend':
+   #{
+      dest.shader = 3
+
+      dest.colour1[0] = mat.cv_data.uv_offset[0]
+      dest.colour1[1] = mat.cv_data.uv_offset[1]
+   #}
+
+   if mat.cv_data.shader == 'water':
+   #{
+      dest.shader = 4
+
+      dest.colour[0]  = pow( mat.cv_data.shore_colour[0], 1.0/2.2 )
+      dest.colour[1]  = pow( mat.cv_data.shore_colour[1], 1.0/2.2 )
+      dest.colour[2]  = pow( mat.cv_data.shore_colour[2], 1.0/2.2 )
+      dest.colour[3]  = 1.0
+      dest.colour1[0] = pow( mat.cv_data.ocean_colour[0], 1.0/2.2 )
+      dest.colour1[1] = pow( mat.cv_data.ocean_colour[1], 1.0/2.2 )
+      dest.colour1[2] = pow( mat.cv_data.ocean_colour[2], 1.0/2.2 )
+      dest.colour1[3] = 1.0
+   #}
+   
+   inf = material_info( mat )
+   
+   if mat.cv_data.shader == 'standard' or \
+      mat.cv_data.shader == 'standard_cutout' or \
+      mat.cv_data.shader == 'terrain_blend' or \
+      mat.cv_data.shader == 'vertex_blend':
+   #{
+      if 'tex_diffuse' in inf: 
+         dest.tex_diffuse = encoder_process_texture(inf['tex_diffuse'])
+   #}
+
+   buffer += [dest]
    return cache[mat.name]
 #}
 
@@ -1128,9 +1380,6 @@ def encoder_compile_mesh( node, node_def ):
    node.submesh_start = len( g_encoder['data']['submesh'] )
    node.submesh_count = 0
 
-   default_mat = c_uint32(12345)
-   default_mat.name = ""
-
    dgraph = bpy.context.evaluated_depsgraph_get()
    data = obj.evaluated_get(dgraph).data
    data.calc_loop_triangles()
@@ -1138,7 +1387,7 @@ def encoder_compile_mesh( node, node_def ):
    
    # Mesh is split into submeshes based on their material
    #
-   mat_list = data.materials if len(data.materials) > 0 else [default_mat]
+   mat_list = data.materials if len(data.materials) > 0 else [None]
    for material_id, mat in enumerate(mat_list):
    #{
       mref = {}
@@ -1646,7 +1895,7 @@ def write_model(collection_name):
    
    collection = bpy.data.collections[collection_name]
 
-   encoder_init()
+   encoder_init( collection )
    encoder_build_scene_graph( collection )
 
    # Compile 
@@ -2137,6 +2386,109 @@ class CV_BONE_PANEL(bpy.types.Panel):
 class CV_SCENE_SETTINGS(bpy.types.PropertyGroup):
 #{
    use_hidden: bpy.props.BoolProperty( name="use hidden", default=False )
+   export_dir: bpy.props.StringProperty( name="Export Dir", subtype='DIR_PATH' )
+#}
+
+class CV_COLLECTION_SETTINGS(bpy.types.PropertyGroup):
+#{
+   pack_textures: bpy.props.BoolProperty( name="Pack Textures", default=False )
+#}
+
+class CV_MATERIAL_SETTINGS(bpy.types.PropertyGroup):
+#{
+   shader: bpy.props.EnumProperty( 
+      name="Format", 
+      items = [
+      ('standard',"standard","",0),
+      ('standard_cutout', "standard_cutout", "", 1),
+      ('terrain_blend', "terrain_blend", "", 2),
+      ('vertex_blend', "vertex_blend", "", 3),
+      ('water',"water","",4),
+      ])
+   
+   collision: bpy.props.BoolProperty( \
+         name="Collisions Enabled",\
+         default=True,\
+         description = "Can the player collide with this material"\
+   )
+   skate_surface: bpy.props.BoolProperty( \
+         name="Skate Surface", \
+         default=True,\
+         description = "Should the game try to target this surface?" \
+   )
+   blend_offset: bpy.props.FloatVectorProperty( \
+         name="Blend Offset", \
+         size=2, \
+         default=Vector((0.5,0.0)),\
+         description="When surface is more than 45 degrees, add this vector " +\
+                     "to the UVs" \
+   )
+   sand_colour: bpy.props.FloatVectorProperty( \
+         name="Sand Colour",\
+         subtype='COLOR',\
+         min=0.0,max=1.0,\
+         default=Vector((0.79,0.63,0.48)),\
+         description="Blend to this colour near the 0 coordinate on UP axis"\
+   )
+   shore_colour: bpy.props.FloatVectorProperty( \
+         name="Shore Colour",\
+         subtype='COLOR',\
+         min=0.0,max=1.0,\
+         default=Vector((0.03,0.32,0.61)),\
+         description="Water colour at the shoreline"\
+   )
+   ocean_colour: bpy.props.FloatVectorProperty( \
+         name="Ocean Colour",\
+         subtype='COLOR',\
+         min=0.0,max=1.0,\
+         default=Vector((0.0,0.006,0.03)),\
+         description="Water colour in the deep bits"\
+   )
+#}
+
+class CV_MATERIAL_PANEL(bpy.types.Panel):
+#{
+   bl_label="Skate Rift material"
+   bl_idname="MATERIAL_PT_cv_material"
+   bl_space_type='PROPERTIES'
+   bl_region_type='WINDOW'
+   bl_context="material"
+   
+   def draw(_,context):
+   #{
+      active_object = bpy.context.active_object
+      if active_object == None: return
+      active_mat = active_object.active_material
+      if active_mat == None: return
+
+      info = material_info( active_mat )
+
+      _.layout.prop( active_mat.cv_data, "shader" )
+      _.layout.prop( active_mat.cv_data, "collision" )
+
+      if active_mat.cv_data.collision:
+         _.layout.prop( active_mat.cv_data, "skate_surface" )
+
+      if active_mat.cv_data.shader == "terrain_blend":
+      #{
+         box = _.layout.box()
+         box.prop( active_mat.cv_data, "blend_offset" )
+         box.prop( active_mat.cv_data, "sand_colour" )
+      #}
+      elif active_mat.cv_data.shader == "vertex_blend":
+      #{
+         box = _.layout.box()
+         box.label( icon='INFO', text="Uses vertex colours, the R channel" )
+         box.prop( active_mat.cv_data, "blend_offset" )
+      #}
+      elif active_mat.cv_data.shader == "water":
+      #{
+         box = _.layout.box()
+         box.label( icon='INFO', text="Depth scale of 16 meters" )
+         box.prop( active_mat.cv_data, "shore_colour" )
+         box.prop( active_mat.cv_data, "ocean_colour" )
+      #}
+   #}
 #}
 
 class CV_OBJ_PANEL(bpy.types.Panel):
@@ -2175,49 +2527,99 @@ class CV_OBJ_PANEL(bpy.types.Panel):
    #}
 #}
 
-class CV_INTERFACE(bpy.types.Panel):
+class CV_COMPILE(bpy.types.Operator):
 #{
-   bl_idname = "VIEW3D_PT_carve"
-   bl_label = "Carve"
-   bl_space_type = 'VIEW_3D'
-   bl_region_type = 'UI'
-   bl_category = "Carve"
+   bl_idname="carve.compile_all"
+   bl_label="Compile All"
 
-   def draw(_, context):
+   def execute(_,context):
    #{
-      layout = _.layout
-      layout.prop( context.scene.cv_data, "use_hidden")
-      layout.operator( "carve.compile_all" )
+      view_layer = bpy.context.view_layer
+      for col in view_layer.layer_collection.children["export"].children:
+         if not col.hide_viewport or bpy.context.scene.cv_data.use_hidden:
+            write_model( col.name )
+
+      return {'FINISHED'}
    #}
 #}
 
-def test_compile():
+class CV_COMPILE_THIS(bpy.types.Operator):
 #{
-   view_layer = bpy.context.view_layer
-   for col in view_layer.layer_collection.children["export"].children:
-      if not col.hide_viewport or bpy.context.scene.cv_data.use_hidden:
-         write_model( col.name )
+   bl_idname="carve.compile_this"
+   bl_label="Compile This collection"
+
+   def execute(_,context):
+   #{
+      col = bpy.context.collection
+      write_model( col.name )
+
+      return {'FINISHED'}
+   #}
 #}
 
-class CV_COMPILE(bpy.types.Operator):
+class CV_INTERFACE(bpy.types.Panel):
 #{
-   bl_idname="carve.compile_all"
-   bl_label="Compile All"
+   bl_idname = "VIEW3D_PT_carve"
+   bl_label = "Skate Rift"
+   bl_space_type = 'VIEW_3D'
+   bl_region_type = 'UI'
+   bl_category = "Skate Rift"
 
-   def execute(_,context):
+   def draw(_, context):
    #{
-      test_compile()
-      #cProfile.runctx("test_compile()",globals(),locals(),sort=1)
-      #for col in bpy.data.collections["export"].children:
-      #   write_model( col.name )
+      layout = _.layout
+      layout.prop( context.scene.cv_data, "export_dir" )
+      
+      col = bpy.context.collection
+      
+      found_in_export = False
+      export_count = 0
+      view_layer = bpy.context.view_layer
+      for c1 in view_layer.layer_collection.children["export"].children:
+      #{
+         if not c1.hide_viewport or bpy.context.scene.cv_data.use_hidden:
+            export_count += 1
 
-      return {'FINISHED'}
+         if c1.name == col.name:
+         #{
+            found_in_export = True
+         #}
+      #}
+
+      box = layout.box()
+      if found_in_export:
+      #{
+         box.label( text=col.name + ".mdl" )
+         box.prop( col.cv_data, "pack_textures" )
+         box.operator( "carve.compile_this" )
+      #}
+      else:
+      #{
+         row = box.row()
+         row.enabled=False
+         row.label( text=col.name )
+         box.label( text="This collection is not in the export group" )
+      #}
+
+      box = layout.box()
+      row = box.row()
+
+      split = row.split( factor = 0.3, align=True )
+      split.prop( context.scene.cv_data, "use_hidden", text="hidden" )
+      
+      row1 = split.row()
+      if export_count == 0:
+         row1.enabled=False
+      row1.operator( "carve.compile_all", \
+                        text=F"Compile all ({export_count} collections)" )
    #}
 #}
 
+
 classes = [CV_OBJ_SETTINGS,CV_OBJ_PANEL,CV_COMPILE,CV_INTERFACE,\
            CV_MESH_SETTINGS, CV_SCENE_SETTINGS, CV_BONE_SETTINGS,\
-           CV_BONE_PANEL]
+           CV_BONE_PANEL, CV_COLLECTION_SETTINGS, CV_COMPILE_THIS,\
+           CV_MATERIAL_SETTINGS, CV_MATERIAL_PANEL ]
 
 def register():
 #{
@@ -2230,6 +2632,10 @@ def register():
    bpy.types.Mesh.cv_data = bpy.props.PointerProperty(type=CV_MESH_SETTINGS)
    bpy.types.Scene.cv_data = bpy.props.PointerProperty(type=CV_SCENE_SETTINGS)
    bpy.types.Bone.cv_data = bpy.props.PointerProperty(type=CV_BONE_SETTINGS)
+   bpy.types.Collection.cv_data = \
+         bpy.props.PointerProperty(type=CV_COLLECTION_SETTINGS)
+   bpy.types.Material.cv_data = \
+         bpy.props.PointerProperty(type=CV_MATERIAL_SETTINGS)
 
    cv_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
       cv_draw,(),'WINDOW','POST_VIEW')
@@ -2244,3 +2650,187 @@ def unregister():
 
    bpy.types.SpaceView3D.draw_handler_remove(cv_view_draw_handler,'WINDOW')
 #}
+
+# ---------------------------------------------------------------------------- #
+#                                                                              #
+#                                 QOI encoder                                  #
+#                                                                              #
+# ---------------------------------------------------------------------------- #
+#                                                                              #
+# Transliteration of:                                                          #
+#    https://github.com/phoboslab/qoi/blob/master/qoi.h                        #
+#                                                                              #
+# Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org               #
+# SPDX-License-Identifier: MIT                                                 #
+# QOI - The "Quite OK Image" format for fast, lossless image compression       #
+#                                                                              #
+# ---------------------------------------------------------------------------- #
+
+class qoi_rgba_t(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("r",c_uint8),
+               ("g",c_uint8),
+               ("b",c_uint8),
+               ("a",c_uint8)]
+#}
+
+QOI_OP_INDEX  = 0x00 # 00xxxxxx
+QOI_OP_DIFF   = 0x40 # 01xxxxxx
+QOI_OP_LUMA   = 0x80 # 10xxxxxx
+QOI_OP_RUN    = 0xc0 # 11xxxxxx
+QOI_OP_RGB    = 0xfe # 11111110
+QOI_OP_RGBA   = 0xff # 11111111
+
+QOI_MASK_2    = 0xc0 # 11000000
+
+def qoi_colour_hash( c ):
+#{
+   return c.r*3 + c.g*5 + c.b*7 + c.a*11
+#}
+
+def qoi_eq( a, b ):
+#{
+   return (a.r==b.r) and (a.g==b.g) and (a.b==b.b) and (a.a==b.a)
+#}
+
+def qoi_32bit( v ):
+#{
+   return bytearray([ (0xff000000 & v) >> 24, \
+                      (0x00ff0000 & v) >> 16, \
+                      (0x0000ff00 & v) >> 8, \
+                      (0x000000ff & v) ])
+#}
+
+def qoi_encode( img ):
+#{
+   data = bytearray()
+   
+   print(F"            . Encoding {img.name}.qoi[{img.size[0]},{img.size[1]}]")
+
+   index = [ qoi_rgba_t() for _ in range(64) ]
+
+   # Header
+   #
+   data.extend( bytearray(c_uint32(0x66696f71)) )
+   data.extend( qoi_32bit( img.size[0] ) )
+   data.extend( qoi_32bit( img.size[1] ) )
+   data.extend( bytearray(c_uint8(4)) )
+   data.extend( bytearray(c_uint8(0)) )
+
+   run = 0
+   px_prev = qoi_rgba_t()
+   px_prev.r = c_uint8(0)
+   px_prev.g = c_uint8(0)
+   px_prev.b = c_uint8(0)
+   px_prev.a = c_uint8(255)
+
+   px = qoi_rgba_t()
+   px.r = c_uint8(0)
+   px.g = c_uint8(0)
+   px.b = c_uint8(0)
+   px.a = c_uint8(255)
+
+   px_len = img.size[0] * img.size[1]
+
+   paxels = [ int(min(max(_,0),1)*255) for _ in img.pixels ]
+
+   for px_pos in range( px_len ):
+   #{
+      idx = px_pos * img.channels
+      nc = img.channels-1
+
+      px.r = paxels[idx+min(0,nc)]
+      px.g = paxels[idx+min(1,nc)]
+      px.b = paxels[idx+min(2,nc)]
+      px.a = paxels[idx+min(3,nc)]
+
+      if qoi_eq( px, px_prev ):
+      #{
+         run += 1
+
+         if (run == 62) or (px_pos == px_len-1):
+         #{
+            data.extend( bytearray( c_uint8(QOI_OP_RUN | (run-1))) )
+            run = 0
+         #}
+      #}
+      else:
+      #{
+         if run > 0:
+         #{
+            data.extend( bytearray( c_uint8(QOI_OP_RUN | (run-1))) )
+            run = 0
+         #}
+
+         index_pos = qoi_colour_hash(px) % 64
+
+         if qoi_eq( index[index_pos], px ):
+         #{
+            data.extend( bytearray( c_uint8(QOI_OP_INDEX | index_pos)) )
+         #}
+         else:
+         #{
+            index[ index_pos ].r = px.r
+            index[ index_pos ].g = px.g
+            index[ index_pos ].b = px.b
+            index[ index_pos ].a = px.a
+
+            if px.a == px_prev.a:
+            #{
+               vr = int(px.r) - int(px_prev.r)
+               vg = int(px.g) - int(px_prev.g)
+               vb = int(px.b) - int(px_prev.b)
+
+               vg_r = vr - vg
+               vg_b = vb - vg
+
+               if (vr > -3) and (vr < 2) and\
+                  (vg > -3) and (vg < 2) and\
+                  (vb > -3) and (vb < 2):
+               #{
+                  op = QOI_OP_DIFF | (vr+2) << 4 | (vg+2) << 2 | (vb+2)
+                  data.extend( bytearray( c_uint8(op) ))
+               #}
+               elif (vg_r > -9) and (vg_r < 8) and\
+                    (vg  > -33) and (vg < 32 ) and\
+                    (vg_b > -9) and (vg_b < 8):
+               #{
+                  op = QOI_OP_LUMA | (vg+32)
+                  delta = (vg_r+8) << 4 | (vg_b + 8)
+                  data.extend( bytearray( c_uint8(op) ) )
+                  data.extend( bytearray( c_uint8(delta) ))
+               #}
+               else:
+               #{
+                  data.extend( bytearray( c_uint8(QOI_OP_RGB) ) )
+                  data.extend( bytearray( c_uint8(px.r) ))
+                  data.extend( bytearray( c_uint8(px.g) ))
+                  data.extend( bytearray( c_uint8(px.b) ))
+               #}
+            #}
+            else:
+            #{
+               data.extend( bytearray( c_uint8(QOI_OP_RGBA) ) )
+               data.extend( bytearray( c_uint8(px.r) ))
+               data.extend( bytearray( c_uint8(px.g) ))
+               data.extend( bytearray( c_uint8(px.b) ))
+               data.extend( bytearray( c_uint8(px.a) ))
+            #}
+         #}
+      #}
+
+      px_prev.r = px.r
+      px_prev.g = px.g
+      px_prev.b = px.b
+      px_prev.a = px.a
+   #}
+   
+   # Padding
+   for i in range(7):
+      data.extend( bytearray( c_uint8(0) ))
+   data.extend( bytearray( c_uint8(1) ))
+   bytearray_align_to( data, 16, 0 )
+
+   return data
+#}
diff --git a/bvh.h b/bvh.h
index 9fdbe985040f51e0cadfd0a183b921240c82a036..84f4c6b7d675c7b1cfdf9f914722b572424aa347 100644 (file)
--- a/bvh.h
+++ b/bvh.h
@@ -137,6 +137,15 @@ VG_STATIC void bh_subdivide( bh_tree *bh, u32 inode )
 VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system, 
                               void *user, u32 item_count )
 {
+   if( item_count == 0 )
+   {
+      bh_tree *bh = vg_linear_alloc( lin_alloc, sizeof(bh_tree) );
+      bh->node_count = 0;
+      bh->system = system;
+      bh->user = user;
+      return bh;
+   }
+
    u32 totsize = sizeof(bh_tree) + sizeof(bh_node)*(item_count*2-1);
    bh_tree *bh = vg_linear_alloc( lin_alloc, totsize );
    bh->system = system;
@@ -192,6 +201,9 @@ VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour )
 
 VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit )
 {
+   if( bh->node_count < 2 )
+      return 0;
+
    int count = 0;
    u32 stack[100];
    u32 depth = 2;
@@ -243,6 +255,9 @@ VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit )
 
 VG_STATIC int bh_select( bh_tree *bh, boxf box, u32 *buffer, int len )
 {
+   if( bh->node_count < 2 )
+      return 0;
+
    int count = 0;
    u32 stack[100];
    u32 depth = 2;
diff --git a/model.h b/model.h
index fb33e0bbad88bbaa45f7c1f61e708148c8a95d0b..ea34a6ddf974f5769f1482a2672e4d0975d21581 100644 (file)
--- a/model.h
+++ b/model.h
@@ -16,6 +16,7 @@ typedef struct mdl_node mdl_node;
 typedef struct mdl_file_header mdl_file_header;
 typedef struct mdl_animation mdl_animation;
 typedef struct mdl_keyframe mdl_keyframe;
+typedef struct mdl_texture mdl_texture;
 typedef struct mdl_context mdl_context;
 
 #define MDL_SIZE_MAX          0x1000000
@@ -43,6 +44,15 @@ enum classtype
    k_classtype_logic_relay = 102
 };
 
+enum mdl_shader
+{
+   k_shader_standard                = 0,
+   k_shader_standard_cutout         = 1,
+   k_shader_terrain_blend           = 2,
+   k_shader_standard_vertex_blend   = 3,
+   k_shader_water                   = 4
+};
+
 #pragma pack(push,1)
 
 struct mdl_vert
@@ -66,9 +76,25 @@ struct mdl_submesh
    u32 material_id;
 };
 
+struct mdl_texture
+{
+   u32 pstr_name,
+       pack_offset,
+       pack_length;
+};
+
 struct mdl_material
 {
-   u32 pstr_name;
+   u32 pstr_name,
+       shader,
+       flags;
+
+   v4f colour,
+       colour1;
+
+   u32 tex_diffuse,
+       tex_decal,
+       tex_normal;
 };
 
 struct mdl_node
@@ -111,6 +137,7 @@ struct mdl_file_header
        node_count,      node_offset,
        submesh_count,   submesh_offset,
        material_count,  material_offset,
+       texture_count,   texture_offset,
        anim_count,      anim_offset,
        entdata_size,    entdata_offset, 
        strings_size,    strings_offset, 
@@ -118,7 +145,9 @@ struct mdl_file_header
        keyframe_count,  keyframe_offset,
 
        vertex_count,    vertex_offset,
-       indice_count,    indice_offset;
+       indice_count,    indice_offset,
+
+       pack_size,       pack_offset;
 };
 
 /* 
@@ -214,6 +243,7 @@ struct mdl_context
    mdl_node       *node_buffer;     /* mdl_load_metadata() */
    mdl_submesh    *submesh_buffer;
    mdl_material   *material_buffer;
+   mdl_texture    *texture_buffer;
    mdl_animation  *anim_buffer;
    void           *entdata_buffer;
    const char     *string_buffer;
@@ -222,6 +252,8 @@ struct mdl_context
 
    mdl_vert       *vertex_buffer;   /* mdl_load_mesh_data() */
    u32            *index_buffer;
+
+   void           *pack;            /* mdl_load_pack_data() */
 };
 
 /*
@@ -388,6 +420,7 @@ VG_STATIC void mdl_load_metadata( mdl_context *mdl, void *lin_alloc )
    mdl->node_buffer     = all_data + (mdl->info.node_offset     - lheader);
    mdl->submesh_buffer  = all_data + (mdl->info.submesh_offset  - lheader);
    mdl->material_buffer = all_data + (mdl->info.material_offset - lheader);
+   mdl->texture_buffer  = all_data + (mdl->info.texture_offset  - lheader);
    mdl->anim_buffer     = all_data + (mdl->info.anim_offset     - lheader);
    mdl->entdata_buffer  = all_data + (mdl->info.entdata_offset  - lheader);
    mdl->string_buffer   = all_data + (mdl->info.strings_offset  - lheader);
@@ -439,6 +472,26 @@ VG_STATIC void mdl_load_anim_data( mdl_context *mdl, void *lin_alloc )
       mdl_load_fatal_corrupt( mdl );
 }
 
+/*
+ * Load pack contents
+ *
+ * TODO request specific files (low)
+ */
+VG_STATIC void mdl_load_pack_data( mdl_context *mdl, void *lin_alloc )
+{
+   assert( mdl->file );
+
+   if( mdl->info.pack_size == 0 )
+      return;
+   
+   mdl->pack = vg_linear_alloc( lin_alloc, mdl->info.pack_size );
+   fseek( mdl->file, mdl->info.pack_offset, SEEK_SET );
+
+   u64 l = fread( mdl->pack, mdl->info.pack_size, 1, mdl->file );
+   if( l != 1 )
+      mdl_load_fatal_corrupt( mdl );
+}
+
 /*
  * close file handle
  */
@@ -448,7 +501,7 @@ VG_STATIC void mdl_close( mdl_context *mdl )
    mdl->file = NULL;
 }
 
-/* open a model */
+/* open a model. TODO: make this flags ( ANIM_DATA|MESH_DATA ... ) */
 VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path )
 {
    /* Inspect the header by opening it, give us the size needed */
@@ -467,6 +520,7 @@ VG_STATIC mdl_context *mdl_load_full( void *lin_alloc, const char *path )
    mdl_load_metadata( ctx, data );
    mdl_load_anim_data( ctx, data );
    mdl_load_mesh_data( ctx, data );
+   mdl_load_pack_data( ctx, data );
    mdl_close( ctx );
 
    return ctx;
index 1b5b3ae76c0aec403695d3b4c37fb5e3a7a09447..360bf00b36a1a7ff96928d3f4755a6c49e34690b 100644 (file)
Binary files a/models_src/ch_jordan.mdl and b/models_src/ch_jordan.mdl differ
index dec441b0cd65627aa0363ac634c595cd0617451a..464a1277f692ba2b12a8f8b408bacdc3fdedbc70 100644 (file)
Binary files a/models_src/ch_new.mdl and b/models_src/ch_new.mdl differ
index 08349ee0b942b299d3d29e9e03bd6f75c42290da..84d494daa6feb3796f568391014f2ffa916496f2 100644 (file)
Binary files a/models_src/ch_outlaw.mdl and b/models_src/ch_outlaw.mdl differ
index 00eb7e81f7fdea67b776f194609e424b7945e2f3..15d83fa535a31e233a5d8105f3ad4a0ce8e4a043 100644 (file)
Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ
index fb51ca7a0031fcd8c8491b10ef06c94875de4957..c5a891cc77a218086e5bc5837504f581e598afda 100644 (file)
Binary files a/models_src/mp_test.mdl and b/models_src/mp_test.mdl differ
index d5c517a03901676da543a41445b58a2b72061adb..3395b82776a81301b4639a11a6321215c0b8194e 100644 (file)
Binary files a/models_src/rs_cars.mdl and b/models_src/rs_cars.mdl differ
index 006b667c2c705e8d099107d5296e1c510aaa889b..c74de54e35b021afe32bb8dc8264ee15543ed17f 100644 (file)
Binary files a/models_src/rs_chicken.mdl and b/models_src/rs_chicken.mdl differ
index 7c4048c1bddf36ce30f469187e992d8691b5689e..4a119d1473a362392224ec10085a02f5ca6a2d8b 100644 (file)
Binary files a/models_src/rs_foliage.mdl and b/models_src/rs_foliage.mdl differ
index b3742fd12f402970bf635f7dc0866fb91df33c03..7a912d61ec23d534e82a7e8d19caa596426b396c 100644 (file)
Binary files a/models_src/rs_gate.mdl and b/models_src/rs_gate.mdl differ
index ef10b04ba57c484ab62053062b7a4d25597d14f3..272d5375cf479aaf74650bd2bb4b3e49630aa072 100644 (file)
Binary files a/models_src/rs_menu.mdl and b/models_src/rs_menu.mdl differ
index ad59c42f1eb0040460caae16d34dabb3b648494f..c781533b4f583347945b8901cf53cb289797ad33 100644 (file)
Binary files a/models_src/rs_scoretext.mdl and b/models_src/rs_scoretext.mdl differ
index 70fbda2928f15aba04a415a79d26127b937eed75..62ceac4d275de301622d4a20645995493a20b07e 100644 (file)
Binary files a/models_src/rs_skydome.mdl and b/models_src/rs_skydome.mdl differ
index d4794cb4640966ed37e72c243e034c973cf25038..e498f34dcd2f94dd64c8cc27e34516164bffe81d 100644 (file)
Binary files a/models_src/rs_vig.mdl and b/models_src/rs_vig.mdl differ
index 298ce0f0dab5994bcdd6e0d1f62e70a996983b78..50616048156b1e71978ca657c25a62c0a328b178 100644 (file)
@@ -103,7 +103,8 @@ VG_STATIC void player_audio(void)
          }
          else if( sprite_type == k_audio_sprite_type_water )
          {
-            audio_player_playclip( avail, &audio_water[rand()%6] );
+            if( world.water.enabled )
+               audio_player_playclip( avail, &audio_water[rand()%6] );
          }
       }
    }
index de8958d2d31847c7e587e803b4cd4c70f3754d7a..f093904b0f46ce5538bf9e78479cb992a877b5a4 100644 (file)
@@ -3,6 +3,8 @@ out vec4 FragColor;
 uniform sampler2D uTexGarbage;
 uniform sampler2D uTexGradients;
 uniform vec3 uCamera;
+uniform vec3 uSandColour;
+uniform vec2 uBlendOffset;
 
 in vec4 aColour;
 in vec2 aUv;
@@ -32,9 +34,9 @@ void main()
    // Colour blending
    float amtgrass = step(qnorm.y,0.6);
    float amtsand = min(max((aCo.y - 10.0) * -0.1,0.0)*qnorm.y,1.0);
-   vec2 uvgradients = aUv + vec2( amtgrass*0.5 + rgarbage.a*0.4, 0.0 );
+   vec2 uvgradients = aUv + vec2( amtgrass + rgarbage.a*0.8 )*uBlendOffset;
    vfrag = texture( uTexGradients, uvgradients ).rgb;
-   vfrag = mix( vfrag, vec3(1.0,0.9,0.8)*0.9, amtsand );
+   vfrag = mix( vfrag, uSandColour, amtsand );
 
    qnorm = mix( qnorm, aNorm, amtsand );
    
index 5ebef38e970aa36c7488362763fa31013e4d30d5..92143b1aaef9e67f50b33a661513ae019791efbb 100644 (file)
@@ -47,6 +47,8 @@ static struct vg_shader _shader_terrain = {
 "uniform sampler2D uTexGarbage;\n"
 "uniform sampler2D uTexGradients;\n"
 "uniform vec3 uCamera;\n"
+"uniform vec3 uSandColour;\n"
+"uniform vec2 uBlendOffset;\n"
 "\n"
 "in vec4 aColour;\n"
 "in vec2 aUv;\n"
@@ -152,7 +154,7 @@ static struct vg_shader _shader_terrain = {
 "   return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n"
 "}\n"
 "\n"
-"#line     14        0 \n"
+"#line     16        0 \n"
 "\n"
 "void main()\n"
 "{\n"
@@ -174,9 +176,9 @@ static struct vg_shader _shader_terrain = {
 "   // Colour blending\n"
 "   float amtgrass = step(qnorm.y,0.6);\n"
 "   float amtsand = min(max((aCo.y - 10.0) * -0.1,0.0)*qnorm.y,1.0);\n"
-"   vec2 uvgradients = aUv + vec2( amtgrass*0.5 + rgarbage.a*0.4, 0.0 );\n"
+"   vec2 uvgradients = aUv + vec2( amtgrass + rgarbage.a*0.8 )*uBlendOffset;\n"
 "   vfrag = texture( uTexGradients, uvgradients ).rgb;\n"
-"   vfrag = mix( vfrag, vec3(1.0,0.9,0.8)*0.9, amtsand );\n"
+"   vfrag = mix( vfrag, uSandColour, amtsand );\n"
 "\n"
 "   qnorm = mix( qnorm, aNorm, amtsand );\n"
 "   \n"
@@ -205,6 +207,8 @@ static GLuint _uniform_terrain_uPv;
 static GLuint _uniform_terrain_uTexGarbage;
 static GLuint _uniform_terrain_uTexGradients;
 static GLuint _uniform_terrain_uCamera;
+static GLuint _uniform_terrain_uSandColour;
+static GLuint _uniform_terrain_uBlendOffset;
 static GLuint _uniform_terrain_g_world_depth;
 static void shader_terrain_uMdl(m4x3f m){
    glUniformMatrix4x3fv( _uniform_terrain_uMdl, 1, GL_FALSE, (float *)m );
@@ -221,6 +225,12 @@ static void shader_terrain_uTexGradients(int i){
 static void shader_terrain_uCamera(v3f v){
    glUniform3fv( _uniform_terrain_uCamera, 1, v );
 }
+static void shader_terrain_uSandColour(v3f v){
+   glUniform3fv( _uniform_terrain_uSandColour, 1, v );
+}
+static void shader_terrain_uBlendOffset(v2f v){
+   glUniform2fv( _uniform_terrain_uBlendOffset, 1, v );
+}
 static void shader_terrain_g_world_depth(int i){
    glUniform1i( _uniform_terrain_g_world_depth, i );
 }
@@ -234,6 +244,8 @@ static void shader_terrain_link(void){
    _uniform_terrain_uTexGarbage = glGetUniformLocation( _shader_terrain.id, "uTexGarbage" );
    _uniform_terrain_uTexGradients = glGetUniformLocation( _shader_terrain.id, "uTexGradients" );
    _uniform_terrain_uCamera = glGetUniformLocation( _shader_terrain.id, "uCamera" );
+   _uniform_terrain_uSandColour = glGetUniformLocation( _shader_terrain.id, "uSandColour" );
+   _uniform_terrain_uBlendOffset = glGetUniformLocation( _shader_terrain.id, "uBlendOffset" );
    _uniform_terrain_g_world_depth = glGetUniformLocation( _shader_terrain.id, "g_world_depth" );
 }
 #endif /* SHADER_terrain_H */
index 9f9e8be54e5dc41302173050a2711a999a46eb28..938c6d1e04d04493226bdaa895d8bdf8a3990322 100644 (file)
@@ -9,6 +9,9 @@ uniform float uTime;
 uniform vec3 uCamera;
 uniform float uSurfaceY;
 
+uniform vec3 uShoreColour;
+uniform vec3 uOceanColour;
+
 in vec4 aColour;
 in vec2 aUv;
 in vec3 aNorm;
@@ -20,9 +23,7 @@ in vec3 aWorldCo;
 vec4 water_surf( vec3 halfview, vec3 vnorm, float depthvalue, 
       vec4 beneath, vec4 above )
 {
-   vec3 colour_shore = vec3( 0.21, 0.6, 0.8 );
-   vec3 colour_ocean = vec3( 0.01, 0.1, 0.2 );
-   vec3 surface_tint = mix(colour_shore, colour_ocean, depthvalue);
+   vec3 surface_tint = mix(uShoreColour, uOceanColour, depthvalue);
 
    float ffresnel = pow(1.0-dot( vnorm, halfview ),5.0);
 
index ca3ab47340ffdb343247e88a65d8c3d312083aa3..e334a5c74e38d635a6b519261f69369104a6cde7 100644 (file)
@@ -53,6 +53,9 @@ static struct vg_shader _shader_water = {
 "uniform vec3 uCamera;\n"
 "uniform float uSurfaceY;\n"
 "\n"
+"uniform vec3 uShoreColour;\n"
+"uniform vec3 uOceanColour;\n"
+"\n"
 "in vec4 aColour;\n"
 "in vec2 aUv;\n"
 "in vec3 aNorm;\n"
@@ -157,14 +160,12 @@ static struct vg_shader _shader_water = {
 "   return mix( vfrag, vec3(0.55,0.76,1.0), min( 1.0, dist ) );\n"
 "}\n"
 "\n"
-"#line     19        0 \n"
+"#line     22        0 \n"
 "\n"
 "vec4 water_surf( vec3 halfview, vec3 vnorm, float depthvalue, \n"
 "      vec4 beneath, vec4 above )\n"
 "{\n"
-"   vec3 colour_shore = vec3( 0.21, 0.6, 0.8 );\n"
-"   vec3 colour_ocean = vec3( 0.01, 0.1, 0.2 );\n"
-"   vec3 surface_tint = mix(colour_shore, colour_ocean, depthvalue);\n"
+"   vec3 surface_tint = mix(uShoreColour, uOceanColour, depthvalue);\n"
 "\n"
 "   float ffresnel = pow(1.0-dot( vnorm, halfview ),5.0);\n"
 "\n"
@@ -229,6 +230,8 @@ static GLuint _uniform_water_uInvRes;
 static GLuint _uniform_water_uTime;
 static GLuint _uniform_water_uCamera;
 static GLuint _uniform_water_uSurfaceY;
+static GLuint _uniform_water_uShoreColour;
+static GLuint _uniform_water_uOceanColour;
 static GLuint _uniform_water_g_world_depth;
 static void shader_water_uMdl(m4x3f m){
    glUniformMatrix4x3fv( _uniform_water_uMdl, 1, GL_FALSE, (float *)m );
@@ -257,6 +260,12 @@ static void shader_water_uCamera(v3f v){
 static void shader_water_uSurfaceY(float f){
    glUniform1f( _uniform_water_uSurfaceY, f );
 }
+static void shader_water_uShoreColour(v3f v){
+   glUniform3fv( _uniform_water_uShoreColour, 1, v );
+}
+static void shader_water_uOceanColour(v3f v){
+   glUniform3fv( _uniform_water_uOceanColour, 1, v );
+}
 static void shader_water_g_world_depth(int i){
    glUniform1i( _uniform_water_g_world_depth, i );
 }
@@ -274,6 +283,8 @@ static void shader_water_link(void){
    _uniform_water_uTime = glGetUniformLocation( _shader_water.id, "uTime" );
    _uniform_water_uCamera = glGetUniformLocation( _shader_water.id, "uCamera" );
    _uniform_water_uSurfaceY = glGetUniformLocation( _shader_water.id, "uSurfaceY" );
+   _uniform_water_uShoreColour = glGetUniformLocation( _shader_water.id, "uShoreColour" );
+   _uniform_water_uOceanColour = glGetUniformLocation( _shader_water.id, "uOceanColour" );
    _uniform_water_g_world_depth = glGetUniformLocation( _shader_water.id, "g_world_depth" );
 }
 #endif /* SHADER_water_H */
diff --git a/world.h b/world.h
index 8b650a5e0c169d336cd0b2a872fe640408c7d29d..e5c039a495113f8ae528ed8b7e4890d1e3ad7064 100644 (file)
--- a/world.h
+++ b/world.h
@@ -46,6 +46,19 @@ enum logic_type
    k_logic_type_achievement   = 3
 };
 
+enum geo_type
+{
+   k_geo_type_solid = 0,
+   k_geo_type_nonsolid = 1,
+   k_geo_type_water = 2
+};
+
+enum material_flag
+{
+   k_material_flag_skate_surface = 0x1,
+   k_material_flag_collision = 0x2
+};
+
 VG_STATIC struct gworld
 {
    /*
@@ -135,6 +148,22 @@ VG_STATIC struct gworld
     */
    mdl_context *meta;
 
+   /*
+    * Materials / textures 
+    */
+
+   GLuint *textures;
+   u32 texture_count;
+
+   struct world_material
+   {
+      mdl_material info;
+      mdl_submesh sm_geo,
+                  sm_no_collide;
+   }
+   * materials;
+   u32 material_count;
+
    /*
     * Named safe places to respawn
     */
@@ -289,19 +318,14 @@ VG_STATIC struct gworld
            *geo_bh;
 
    /* graphics */
+   glmesh mesh_route_lines;
+
    glmesh mesh_geo, 
           mesh_no_collide,
-          mesh_route_lines,
           mesh_water;
 
+   mdl_submesh sm_foliage_main;
    rigidbody rb_geo;
-
-   /* TODO Maybe make this less hardcoded...
-    *      im on it, boss*/
-   mdl_submesh sm_geo_std_oob,   sm_geo_std, sm_geo_vb,
-               sm_foliage_main,  sm_foliage_alphatest,
-               sm_graffiti, sm_subworld, sm_terrain;
-
 }
 world;
 
@@ -627,20 +651,26 @@ VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
 
 VG_STATIC int ray_hit_is_terrain( ray_hit *hit )
 {
+   return 0;
+#if 0
    u32 valid_start = 0,
        valid_end   = world.sm_terrain.vertex_count;
 
    return (hit->tri[0] >= valid_start) &&
           (hit->tri[0]  < valid_end);
+#endif
 }
 
 VG_STATIC int ray_hit_is_ramp( ray_hit *hit )
 {
+   return 1;
+#if 0
    u32 valid_start = world.sm_geo_std.vertex_start,
        valid_end   = world.sm_geo_vb.vertex_start;
 
    return (hit->tri[0] >= valid_start) &&
           (hit->tri[0]  < valid_end);
+#endif
 }
 
 #endif /* WORLD_H */
index 16d64fdefdf8a53af2a1cbb98b28eed71d43702a..c87112afd6ed15887c648239bd590d00b2f38a9d 100644 (file)
@@ -323,36 +323,6 @@ VG_STATIC void world_generate(void)
     * Compile meshes into the world scenes
     */
    world.scene_geo = scene_init( world.dynamic_vgl, 350000, 1200000 );
-   
-   /*
-    * TODO: System to dynamically allocate these 
-    */
-   u32 mat_surf         = 0,
-       mat_surf_oob     = 0,
-       mat_vertex_blend = 0,
-       mat_alphatest    = 0,
-       mat_graffiti     = 0,
-       mat_subworld     = 0,
-       mat_terrain      = 0;
-
-   for( int i=1; i<world.meta->info.material_count; i++ )
-   {
-      mdl_material *mat = &world.meta->material_buffer[ i ];
-      const char *mat_name = mdl_pstr( world.meta, mat->pstr_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;
-      else if( !strcmp( "alphatest", mat_name ))
-         mat_alphatest = i;
-      else if( !strcmp( "graffitibox", mat_name ))
-         mat_graffiti = i;
-      else if( !strcmp( "terrain", mat_name ) )
-         mat_terrain = i;
-   }
 
    m4x3f midentity;
    m4x3_identity( midentity );
@@ -363,36 +333,23 @@ VG_STATIC void world_generate(void)
     */
 
    vg_info( "Generating collidable geometry\n" );
-   vg_info( "terrain...\n" );
-   /* terrain */
-   if( mat_terrain )
-      world_add_all_if_material( midentity, world.scene_geo, 
-                                 world.meta, mat_terrain );
-   scene_copy_slice( world.scene_geo, &world.sm_terrain );
-
-   /* oob */
-   vg_info( "oob...\n" );
-   if( mat_surf_oob )
-      world_add_all_if_material( midentity, world.scene_geo, 
-                                 world.meta, mat_surf_oob );
-   else
-      vg_warn( "No OOB surface\n" );
-   scene_copy_slice( world.scene_geo, &world.sm_geo_std_oob );
-
-
-   /* surface */
-   vg_info( "surface...\n" );
-   if( mat_surf )
-      world_add_all_if_material( midentity, world.scene_geo, 
-                                 world.meta, mat_surf );
-   scene_copy_slice( world.scene_geo, &world.sm_geo_std );
-
-   /* vertex_blend */
-   vg_info( "vertex blend...\n" );
-   if( mat_vertex_blend )
-      world_add_all_if_material( midentity, world.scene_geo,
-                                 world.meta, mat_vertex_blend);
-   scene_copy_slice( world.scene_geo, &world.sm_geo_vb );
+   
+
+   for( int i=0; i<world.material_count; i++ )
+   {
+      struct world_material *mat = &world.materials[ i ];
+
+      if( mat->info.flags & k_material_flag_collision )
+      {
+         world_add_all_if_material( midentity, world.scene_geo, world.meta, i );
+         scene_copy_slice( world.scene_geo, &mat->sm_geo );
+      }
+   }
+
+
+
+
+
    
    /* compress that bad boy */
    world.scene_geo = scene_fix( world.dynamic_vgl, world.scene_geo );
@@ -422,20 +379,13 @@ VG_STATIC void world_generate(void)
 
    world.scene_no_collide = scene_init( world.dynamic_vgl, 200000, 500000 );
 
+#if 0
    vg_info( "Applying foliage\n" );
    srand(0);
    world_apply_procedural_foliage();
    scene_copy_slice( world.scene_no_collide, &world.sm_foliage_main );
+#endif
 
-   vg_info( "alphatest...\n" );
-   world_add_all_if_material( midentity, world.scene_no_collide,
-                              world.meta, mat_alphatest );
-   scene_copy_slice( world.scene_no_collide, &world.sm_foliage_alphatest );
-
-   vg_info( "graffiti...\n" );
-   world_add_all_if_material( midentity, world.scene_no_collide, 
-                              world.meta, mat_graffiti );
-   scene_copy_slice( world.scene_no_collide, &world.sm_graffiti );
 
 
    /* upload and free that */
@@ -546,13 +496,71 @@ VG_STATIC void world_post_process(void)
    reset_player( 1, (const char *[]){"start"} );
 }
 
+VG_STATIC void world_process_resources(void)
+{
+   vg_info( "Loading textures\n" );
+   world.texture_count = world.meta->info.texture_count;
+   world.textures = 
+      vg_linear_alloc( world.dynamic_vgl, sizeof(GLuint)*world.texture_count );
+
+   vg_acquire_thread_sync();
+   {
+      /* error texture */
+      world.textures[0] = vg_tex2d_new();
+      vg_tex2d_set_error();
+      vg_tex2d_nearest();
+      vg_tex2d_repeat();
+
+      for( int i=1; i<world.texture_count; i++ )
+      {
+         mdl_texture *tex = &world.meta->texture_buffer[i];
+
+         if( !tex->pack_offset )
+         {
+            vg_release_thread_sync();
+            vg_fatal_exit_loop( "World models must have packed textures!" );
+         }
+
+         vg_linear_clear( vg_mem.scratch );
+         world.textures[i] = vg_tex2d_new();
+         vg_tex2d_set_error();
+         vg_tex2d_qoi( world.meta->pack + tex->pack_offset, tex->pack_length,
+                       mdl_pstr( world.meta, tex->pstr_name ));
+         vg_tex2d_nearest();
+         vg_tex2d_repeat();
+      }
+   }
+   vg_release_thread_sync();
+
+   vg_info( "Loading materials\n" );
+
+   u32 size = sizeof(struct world_material) * world.meta->info.material_count;
+   world.materials = vg_linear_alloc( world.dynamic_vgl, size );
+                       
+   world.material_count = world.meta->info.material_count;
+   memset( world.materials, 0, size );
+
+   for( int i=1; i<world.material_count; i++ )
+      world.materials[i].info = world.meta->material_buffer[i];
+
+   /* error material */
+   struct world_material *errmat = &world.materials[0];
+   v4_copy( (v4f){ 1.0f,0.0f,0.0f,1.0f }, errmat->info.colour );
+   v4_copy( (v4f){ 1.0f,0.0f,0.0f,1.0f }, errmat->info.colour1 );
+   errmat->info.flags = 0x00;
+   errmat->info.pstr_name = 0; /* useless? */
+   errmat->info.shader = -1;
+   errmat->info.tex_decal = 0;
+   errmat->info.tex_diffuse = 0;
+   errmat->info.tex_normal = 0;
+}
 
 VG_STATIC void world_unload(void)
 {
    /* free meshes */
+   mesh_free( &world.mesh_route_lines );
    mesh_free( &world.mesh_geo );
    mesh_free( &world.mesh_no_collide );
-   mesh_free( &world.mesh_route_lines );
    mesh_free( &world.mesh_water );
 
    world.time = 0.0;
@@ -575,16 +583,24 @@ VG_STATIC void world_unload(void)
       uib->xpos = 0.0f;
    }
 
+   /* delete textures and meshes */
+   glDeleteTextures( world.texture_count, world.textures );
+
    /* delete the entire block of memory */
    vg_linear_clear( world.dynamic_vgl );
    vg_linear_clear( world.audio_vgl );
 
    /* clean dangling pointers */
    world.meta = NULL;
+
+   world.textures = NULL;
+   world.texture_count = 0;
+   world.materials = NULL;
+   world.material_count = 0;
    
    world.scene_geo = NULL;
-   world.scene_lines = NULL;
    world.scene_no_collide = NULL;
+   world.scene_lines = NULL;
 
    world.geo_bh = NULL;
    world.trigger_bh = NULL;
@@ -627,6 +643,9 @@ VG_STATIC void world_load(void)
    world.meta = mdl_load_full( world.dynamic_vgl, world.world_name );
    vg_info( "Loading world: %s\n", world.world_name );
 
+   /* process resources from pack */
+   world_process_resources();
+
    /* dynamic allocations */
    world_ents_allocate();
    world_routes_allocate();
index d2e615d2b754d9813b7d97e3846a8e8bd4e1e457..25d72ee5e9df1e99a95932be02259f5a945534cd 100644 (file)
@@ -45,6 +45,48 @@ VG_STATIC void bind_terrain_textures(void)
    vg_tex2d_bind( &tex_terrain_colours, 1 );
 }
 
+VG_STATIC void world_render_if( enum mdl_shader shader, 
+                                enum geo_type geo_type,
+                                void (*bind_point)(struct world_material *mat))
+{
+   
+   for( int i=0; i<world.material_count; i++ )
+   {
+      struct world_material *mat = &world.materials[i];
+
+      if( mat->info.shader == shader )
+      {
+         mdl_submesh *sm;
+
+         if( geo_type == k_geo_type_solid )
+            sm = &mat->sm_geo;
+         else
+            sm = &mat->sm_no_collide;
+
+         if( !sm->indice_count )
+            continue;
+
+         bind_point( mat );
+         mdl_draw_submesh( sm );
+      }
+   }
+}
+
+VG_STATIC void world_render_both_stages( enum mdl_shader shader,
+                                void (*bind_point)(struct world_material *mat))
+{
+   mesh_bind( &world.mesh_geo );
+   world_render_if( shader, k_geo_type_solid, bind_point );
+   mesh_bind( &world.mesh_no_collide );
+   world_render_if( shader, k_geo_type_nonsolid, bind_point );
+}
+
+VG_STATIC void bindpoint_diffuse_texture1( struct world_material *mat )
+{
+   glActiveTexture( GL_TEXTURE1 );
+   glBindTexture( GL_TEXTURE_2D, world.textures[ mat->info.tex_diffuse ] );
+}
+
 VG_STATIC void render_world_vb( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
@@ -54,16 +96,17 @@ VG_STATIC void render_world_vb( m4x4f projection, v3f camera )
    shader_vblend_uTexGarbage(0);
    shader_vblend_uTexGradients(1);
    shader_link_standard_ub( _shader_vblend.id, 2 );
-   bind_terrain_textures();
+   vg_tex2d_bind( &tex_terrain_noise, 0 );
 
    shader_vblend_uPv( projection );
    shader_vblend_uMdl( identity_matrix );
    shader_vblend_uCamera( camera );
 
-   mesh_bind( &world.mesh_geo );
-   mdl_draw_submesh( &world.sm_geo_vb );
+   world_render_both_stages( k_shader_standard_vertex_blend, 
+                             bindpoint_diffuse_texture1 );
 }
 
+
 VG_STATIC void render_world_alphatest( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
@@ -75,22 +118,28 @@ VG_STATIC void render_world_alphatest( m4x4f projection, v3f camera )
    shader_link_standard_ub( _shader_alphatest.id, 2 );
 
    vg_tex2d_bind( &tex_terrain_noise, 0 );
-   vg_tex2d_bind( &tex_alphatest, 1 );
 
    shader_alphatest_uPv( projection );
    shader_alphatest_uMdl( identity_matrix );
    shader_alphatest_uCamera( camera );
 
    glDisable(GL_CULL_FACE);
-   mesh_bind( &world.mesh_no_collide );
-   mdl_draw_submesh( &world.sm_foliage_alphatest );
-
-   vg_tex2d_bind( &tex_graffiti, 1 );
-   mdl_draw_submesh( &world.sm_graffiti );
+   
+   world_render_both_stages( k_shader_standard_cutout,
+                             bindpoint_diffuse_texture1 );
 
    glEnable(GL_CULL_FACE);
 }
 
+VG_STATIC void bindpoint_terrain( struct world_material *mat )
+{
+   glActiveTexture( GL_TEXTURE1 );
+   glBindTexture( GL_TEXTURE_2D, world.textures[ mat->info.tex_diffuse ] );
+
+   shader_terrain_uSandColour( mat->info.colour );
+   shader_terrain_uBlendOffset( mat->info.colour1 );
+}
+
 VG_STATIC void render_terrain( m4x4f projection, v3f camera )
 {
    m4x3f identity_matrix;
@@ -100,23 +149,14 @@ VG_STATIC void render_terrain( m4x4f projection, v3f camera )
    shader_terrain_uTexGarbage(0);
    shader_terrain_uTexGradients(1);
    shader_link_standard_ub( _shader_terrain.id, 2 );
-   bind_terrain_textures();
+
+   vg_tex2d_bind( &tex_terrain_noise, 0 );
 
    shader_terrain_uPv( projection );
    shader_terrain_uMdl( identity_matrix );
    shader_terrain_uCamera( camera );
 
-   mesh_bind( &world.mesh_geo );
-   mdl_draw_submesh( &world.sm_terrain );
-   mdl_draw_submesh( &world.sm_geo_std_oob );
-   mdl_draw_submesh( &world.sm_geo_std );
-   mdl_draw_submesh( &world.sm_subworld );
-
-   /* TODO: Dont draw in reflection */
-   glDisable( GL_CULL_FACE );
-   mesh_bind( &world.mesh_no_collide );
-   mdl_draw_submesh( &world.sm_foliage_main );
-   glEnable( GL_CULL_FACE );
+   world_render_both_stages( k_shader_terrain_blend, bindpoint_terrain );
 }
 
 VG_STATIC void render_lowerdome( m4x3f camera )
index 656f1b2350afa588117d1a80f8a47a3dddab1093..928d36c95175c6d73cbad7bfee03f0b61a67fd93 100644 (file)
@@ -158,7 +158,19 @@ VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera )
    glBlendEquation(GL_FUNC_ADD);
 
    mesh_bind( &world.mesh_water );
-   mesh_draw( &world.mesh_water );
+
+   for( int i=0; i<world.material_count; i++ )
+   {
+      struct world_material *mat = &world.materials[i];
+
+      if( mat->info.shader == k_shader_water )
+      {
+         shader_water_uShoreColour( mat->info.colour );
+         shader_water_uOceanColour( mat->info.colour1 );
+
+         mdl_draw_submesh( &mat->sm_no_collide );
+      }
+   }
 
    glDisable(GL_BLEND);
 }