# otherwise
#
-import bpy, math, gpu
+import bpy, math, gpu, os
import cProfile
from ctypes import *
from mathutils import *
("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):
("material_count",c_uint32),
("material_offset",c_uint32),
+ ("texture_count",c_uint32),
+ ("texture_offset",c_uint32),
+
("anim_count",c_uint32),
("anim_offset",c_uint32),
("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):
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:
# Reset encoder
#
-def encoder_init():
+def encoder_init( collection ):
#{
global g_encoder
#
'header': mdl_header(),
+ # Options
+ #
+ 'pack_textures': collection.cv_data.pack_textures,
+
# Compiled data chunks (each can be read optionally by the client)
#
'data':
'node': [], # Metadata 'chunk'
'submesh': [],
'material': [],
+ 'texture': [],
'anim': [],
'entdata': bytearray(), # variable width
'strings': bytearray(), # .
#3---------------------------------
'vertex': [], # Mesh data
'indice': [],
+ #4---------------------------------
+ 'pack': bytearray() # Other generic packed data
},
# All objects of the model in their final heirachy
'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
#
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 ):
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]
#}
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()
# 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 = {}
collection = bpy.data.collections[collection_name]
- encoder_init()
+ encoder_init( collection )
encoder_build_scene_graph( collection )
# Compile
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):
#}
#}
-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():
#{
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')
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
+#}
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;
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;
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;
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
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
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
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,
keyframe_count, keyframe_offset,
vertex_count, vertex_offset,
- indice_count, indice_offset;
+ indice_count, indice_offset,
+
+ pack_size, pack_offset;
};
/*
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;
mdl_vert *vertex_buffer; /* mdl_load_mesh_data() */
u32 *index_buffer;
+
+ void *pack; /* mdl_load_pack_data() */
};
/*
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);
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
*/
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 */
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;
}
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] );
}
}
}
uniform sampler2D uTexGarbage;
uniform sampler2D uTexGradients;
uniform vec3 uCamera;
+uniform vec3 uSandColour;
+uniform vec2 uBlendOffset;
in vec4 aColour;
in vec2 aUv;
// 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 );
"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"
" 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"
" // 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"
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 );
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 );
}
_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 */
uniform vec3 uCamera;
uniform float uSurfaceY;
+uniform vec3 uShoreColour;
+uniform vec3 uOceanColour;
+
in vec4 aColour;
in vec2 aUv;
in vec3 aNorm;
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);
"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"
" 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"
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 );
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 );
}
_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 */
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
{
/*
*/
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
*/
*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;
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 */
* 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 );
*/
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 );
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 */
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;
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;
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();
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;
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;
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;
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 )
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);
}