From: hgn Date: Sat, 29 Oct 2022 03:50:27 +0000 (+0100) Subject: POWER X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=1f0e3292c021e8263716e5f4544a1efcedf3f03d;hp=be6707a307bfeec1b45cca8b3fb647e81262be87;p=carveJwlIkooP6JGAAIwe30JlM.git POWER --- diff --git a/blender_export.py b/blender_export.py index ce4e826..4508bca 100644 --- a/blender_export.py +++ b/blender_export.py @@ -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 9fdbe98..84f4c6b 100644 --- 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 fb33e0b..ea34a6d 100644 --- 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; diff --git a/models_src/ch_jordan.mdl b/models_src/ch_jordan.mdl index 1b5b3ae..360bf00 100644 Binary files a/models_src/ch_jordan.mdl and b/models_src/ch_jordan.mdl differ diff --git a/models_src/ch_new.mdl b/models_src/ch_new.mdl index dec441b..464a127 100644 Binary files a/models_src/ch_new.mdl and b/models_src/ch_new.mdl differ diff --git a/models_src/ch_outlaw.mdl b/models_src/ch_outlaw.mdl index 08349ee..84d494d 100644 Binary files a/models_src/ch_outlaw.mdl and b/models_src/ch_outlaw.mdl differ diff --git a/models_src/mp_dev.mdl b/models_src/mp_dev.mdl index 00eb7e8..15d83fa 100644 Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ diff --git a/models_src/mp_test.mdl b/models_src/mp_test.mdl index fb51ca7..c5a891c 100644 Binary files a/models_src/mp_test.mdl and b/models_src/mp_test.mdl differ diff --git a/models_src/rs_cars.mdl b/models_src/rs_cars.mdl index d5c517a..3395b82 100644 Binary files a/models_src/rs_cars.mdl and b/models_src/rs_cars.mdl differ diff --git a/models_src/rs_chicken.mdl b/models_src/rs_chicken.mdl index 006b667..c74de54 100644 Binary files a/models_src/rs_chicken.mdl and b/models_src/rs_chicken.mdl differ diff --git a/models_src/rs_foliage.mdl b/models_src/rs_foliage.mdl index 7c4048c..4a119d1 100644 Binary files a/models_src/rs_foliage.mdl and b/models_src/rs_foliage.mdl differ diff --git a/models_src/rs_gate.mdl b/models_src/rs_gate.mdl index b3742fd..7a912d6 100644 Binary files a/models_src/rs_gate.mdl and b/models_src/rs_gate.mdl differ diff --git a/models_src/rs_menu.mdl b/models_src/rs_menu.mdl index ef10b04..272d537 100644 Binary files a/models_src/rs_menu.mdl and b/models_src/rs_menu.mdl differ diff --git a/models_src/rs_scoretext.mdl b/models_src/rs_scoretext.mdl index ad59c42..c781533 100644 Binary files a/models_src/rs_scoretext.mdl and b/models_src/rs_scoretext.mdl differ diff --git a/models_src/rs_skydome.mdl b/models_src/rs_skydome.mdl index 70fbda2..62ceac4 100644 Binary files a/models_src/rs_skydome.mdl and b/models_src/rs_skydome.mdl differ diff --git a/models_src/rs_vig.mdl b/models_src/rs_vig.mdl index d4794cb..e498f34 100644 Binary files a/models_src/rs_vig.mdl and b/models_src/rs_vig.mdl differ diff --git a/player_audio.h b/player_audio.h index 298ce0f..5061604 100644 --- a/player_audio.h +++ b/player_audio.h @@ -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] ); } } } diff --git a/shaders/terrain.fs b/shaders/terrain.fs index de8958d..f093904 100644 --- a/shaders/terrain.fs +++ b/shaders/terrain.fs @@ -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 ); diff --git a/shaders/terrain.h b/shaders/terrain.h index 5ebef38..92143b1 100644 --- a/shaders/terrain.h +++ b/shaders/terrain.h @@ -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 */ diff --git a/shaders/water.fs b/shaders/water.fs index 9f9e8be..938c6d1 100644 --- a/shaders/water.fs +++ b/shaders/water.fs @@ -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); diff --git a/shaders/water.h b/shaders/water.h index ca3ab47..e334a5c 100644 --- a/shaders/water.h +++ b/shaders/water.h @@ -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 8b650a5..e5c039a 100644 --- 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 */ diff --git a/world_gen.h b/world_gen.h index 16d64fd..c87112a 100644 --- a/world_gen.h +++ b/world_gen.h @@ -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; iinfo.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; iinfo.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; itexture_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; imaterial_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(); diff --git a/world_render.h b/world_render.h index d2e615d..25d72ee 100644 --- a/world_render.h +++ b/world_render.h @@ -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; iinfo.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 ) diff --git a/world_water.h b/world_water.h index 656f1b2..928d36c 100644 --- a/world_water.h +++ b/world_water.h @@ -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; iinfo.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); }