From: hgn Date: Tue, 11 Apr 2023 02:35:51 +0000 (+0100) Subject: text3d X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;ds=sidebyside;h=d6171f1c56789b2ca79efa3313fbbf74a13bda7a;hp=b888cce683d95cc01d0b4be9bbe92a0dd47452ac;p=carveJwlIkooP6JGAAIwe30JlM.git text3d --- diff --git a/blender_export.py b/blender_export.py index cbd2a19..f9b225d 100644 --- a/blender_export.py +++ b/blender_export.py @@ -3,6 +3,7 @@ import cProfile from ctypes import * from mathutils import * from gpu_extras.batch import batch_for_shader +from bpy_extras import mesh_utils bl_info = { "name":"Skaterift .mdl exporter", @@ -24,7 +25,8 @@ sr_entity_alias = { 'ent_water': 5, 'ent_volume': 6, 'ent_audio': 7, - 'ent_marker': 8 + 'ent_marker': 8, + 'ent_glyph': 9 } class mdl_vert(Structure): # 48 bytes. Quite large. Could compress @@ -171,7 +173,8 @@ class ent_gate(Structure): ("transport",(c_float*3)*4), ("_anonymous_union",version_refcount_union), ("timing_time",c_double), - ("routes",c_uint16*4)] + ("routes",c_uint16*4), + ("route_count",c_uint8)] #} class ent_route_node(Structure): @@ -289,6 +292,29 @@ class ent_marker(Structure): ("name",c_uint32)] #} +class ent_glyph(Structure): +#{ + _fields_ = [("size",c_float*2), + ("indice_start",c_uint32), + ("indice_count",c_uint32)] +#} + +class ent_font_variant(Structure): +#{ + _fields_ = [("name",c_uint32), + ("material_id",c_uint32)] +#} + +class ent_font(Structure): +#{ + _fields_ = [("alias",c_uint32), + ("variant_start",c_uint32), + ("variant_count",c_uint32), + ("glyph_start",c_uint32), + ("glyph_count",c_uint32), + ("glyph_utf32_base",c_uint32)] +#} + def obj_ent_type( obj ): #{ if obj.type == 'ARMATURE': return 'mdl_armature' @@ -688,8 +714,7 @@ def sr_compile_mesh( obj ): # Write the vertex / indice data # for tri_index, tri in enumerate(data.loop_triangles):#{ - if tri.material_index != material_id: - continue + if tri.material_index != material_id: continue for j in range(3):#{ vert = data.vertices[tri.vertices[j]] @@ -852,6 +877,136 @@ def sr_compile_mesh( obj ): sr_compile.mesh_data.extend(bytearray(node)) #} +def sr_compile_fonts( collection ): +#{ + print( F"[SR] Compiling fonts" ) + + glyph_count = 0 + variant_count = 0 + + for obj in collection.all_objects:#{ + if obj_ent_type(obj) != 'ent_font': continue + + data = obj.SR_data.ent_font[0] + + font=ent_font() + font.alias = sr_compile_string( data.alias ) + font.variant_start = variant_count + font.variant_count = 0 + font.glyph_start = glyph_count + + glyph_base = data.glyphs[0].utf32 + glyph_range = data.glyphs[-1].utf32 - glyph_base + + font.glyph_utf32_base = glyph_base + font.glyph_count = glyph_range + + for i in range(len(data.variants)):#{ + data_var = data.variants[i] + if not data_var.mesh: continue + + mesh = data_var.mesh.data + + variant = ent_font_variant() + variant.name = sr_compile_string( data_var.tipo ) + + # fonts (variants) only support one material each + mat = None + if len(mesh.materials) != 0: + mat = mesh.materials[0] + variant.material_id = sr_compile_material( mat ) + + font.variant_count += 1 + + islands = mesh_utils.mesh_linked_triangles(mesh) + centroids = [Vector((0,0)) for _ in range(len(islands))] + + for j in range(len(islands)):#{ + for tri in islands[j]:#{ + centroids[j].x += tri.center[0] + centroids[j].y += tri.center[2] + #} + + centroids[j] /= len(islands[j]) + #} + + for j in range(glyph_range):#{ + data_glyph = data.glyphs[j] + glyph = ent_glyph() + glyph.indice_start = len(sr_compile.indice_data)//sizeof(c_uint32) + glyph.indice_count = 0 + glyph.size[0] = data_glyph.bounds[2] + glyph.size[1] = data_glyph.bounds[3] + + vertex_reference = {} + + for k in range(len(islands)):#{ + if centroids[k].x < data_glyph.bounds[0] or \ + centroids[k].x > data_glyph.bounds[0]+data_glyph.bounds[2] or\ + centroids[k].y < data_glyph.bounds[1] or \ + centroids[k].y > data_glyph.bounds[1]+data_glyph.bounds[3]: + #{ + continue + #} + + for l in range(len(islands[k])):#{ + tri = islands[k][l] + for m in range(3):#{ + vert = mesh.vertices[tri.vertices[m]] + li = tri.loops[m] + vi = mesh.loops[li].vertex_index + + # Gather vertex information + # + co = [vert.co[_] for _ in range(3)] + co[0] -= data_glyph.bounds[0] + co[2] -= data_glyph.bounds[1] + norm = mesh.loops[li].normal + uv = (0,0) + if mesh.uv_layers: uv = mesh.uv_layers.active.data[li].uv + + TOLERENCE = float(10**4) + key = (int(co[0]*TOLERENCE+0.5), + int(co[1]*TOLERENCE+0.5), + int(co[2]*TOLERENCE+0.5), + int(norm[0]*TOLERENCE+0.5), + int(norm[1]*TOLERENCE+0.5), + int(norm[2]*TOLERENCE+0.5), + int(uv[0]*TOLERENCE+0.5), + int(uv[1]*TOLERENCE+0.5)) + + if key in vertex_reference: + index = vertex_reference[key] + else:#{ + vindex = len(sr_compile.vertex_data)//sizeof(mdl_vert) + index = bytearray(c_uint32(vindex)) + vertex_reference[key] = index + v = mdl_vert() + v.co[0] = co[0] + v.co[1] = co[2] + v.co[2] = -co[1] + v.norm[0] = norm[0] + v.norm[1] = norm[2] + v.norm[2] = -norm[1] + v.uv[0] = uv[0] + v.uv[1] = uv[1] + + sr_compile.vertex_data.extend(bytearray(v)) + #} + + glyph.indice_count += 1 + sr_compile.indice_data.extend( index ) + #} + #} + #} + sr_ent_push( glyph ) + #} + sr_ent_push( variant ) + #} + sr_ent_push( font ) + #} +#} + def sr_compile_armature( obj ): #{ node = mdl_armature() @@ -1252,6 +1407,8 @@ def sr_compile( collection ): #} #} + sr_compile_fonts(collection) + def _children( col ):#{ yield col for c in col.children:#{ @@ -1609,6 +1766,10 @@ class SR_INTERFACE(bpy.types.Panel): active_object = context.active_object if not active_object: return + _.layout.operator( 'skaterift.copy_entity_data', \ + text=F'Copy entity data to {len(context.selected_objects)-1} '+\ + F'other objects' ) + box = _.layout.box() row = box.row() row.alignment = 'CENTER' @@ -1789,15 +1950,86 @@ class SR_UL_ROUTE_NODE_LIST(bpy.types.UIList): #} #} +def internal_listdel_execute(self,context,ent_name,collection_name): +#{ + active_object = context.active_object + data = getattr(active_object.SR_data,ent_name)[0] + lista = getattr(data,collection_name) + index = getattr(data,F'{collection_name}_index') + + lista.remove(index) + + setattr(data,F'{collection_name}_index', min(max(0,index-1), len(lista)-1)) + return{'FINISHED'} +#} + +def internal_listadd_execute(self,context,ent_name,collection_name): +#{ + active_object = context.active_object + getattr(getattr(active_object.SR_data,ent_name)[0],collection_name).add() + return{'FINISHED'} +#} + +def copy_propgroup( de, to ): +#{ + for a in de.__annotations__:#{ + if isinstance(getattr(de,a), bpy.types.bpy_prop_collection):#{ + ca = getattr(de,a) + cb = getattr(to,a) + + while len(cb) != len(ca):#{ + if len(cb) < len(ca): cb.add() + else: cb.remove(0) + #} + for i in range(len(ca)):#{ + copy_propgroup(ca[i],cb[i]) + #} + #} + else:#{ + setattr(to,a,getattr(de,a)) + #} + #} +#} + +class SR_OT_COPY_ENTITY_DATA(bpy.types.Operator): +#{ + bl_idname = "skaterift.copy_entity_data" + bl_label = "Copy entity data" + + def execute(self, context):#{ + data = context.active_object.SR_data + new_type = data.ent_type + print( F"Copy entity data from: {context.active_object.name}" ) + + for obj in context.selected_objects:#{ + if obj != context.active_object:#{ + print( F" To: {obj.name}" ) + + obj.SR_data.ent_type = new_type + + if active_object.type == 'MESH':#{ + col = getattr( obj.data.SR_data, new_type, None ) + if col != None and len(col)==0: col.add() + mdata = context.active_object.data.SR_data + copy_propgroup( getattr(mdata,new_type)[0], col[0] ) + #} + + col = getattr( obj.SR_data, new_type, None ) + if col != None and len(col)==0: col.add() + copy_propgroup( getattr(data,new_type)[0], col[0] ) + #} + #} + return{'FINISHED'} + #} +#} + class SR_OT_ROUTE_LIST_NEW_ITEM(bpy.types.Operator): #{ bl_idname = "skaterift.new_entry" bl_label = "Add gate" def execute(self, context):#{ - active_object = context.active_object - active_object.SR_data.ent_route[0].gates.add() - return{'FINISHED'} + return internal_listadd_execute(self,context,'ent_route','gates') #} #} @@ -1816,13 +2048,7 @@ class SR_OT_ROUTE_LIST_DEL_ITEM(bpy.types.Operator): #} def execute(self, context):#{ - active_object = context.active_object - lista = active_object.SR_data.ent_route[0].gates - index = active_object.SR_data.ent_route[0].gates_index - lista.remove(index) - active_object.SR_data.ent_route[0].gates_index = \ - min(max(0, index-1), len(lista) - 1) - return{'FINISHED'} + return internal_listdel_execute(self,context,'ent_route','gates') #} #} @@ -1832,9 +2058,7 @@ class SR_OT_AUDIO_LIST_NEW_ITEM(bpy.types.Operator): bl_label = "Add file" def execute(self, context):#{ - active_object = context.active_object - active_object.SR_data.ent_audio[0].files.add() - return{'FINISHED'} + return internal_listadd_execute(self,context,'ent_audio','files') #} #} @@ -1853,16 +2077,115 @@ class SR_OT_AUDIO_LIST_DEL_ITEM(bpy.types.Operator): #} def execute(self, context):#{ + return internal_listdel_execute(self,context,'ent_audio','files') + return{'FINISHED'} + #} +#} + +class SR_OT_GLYPH_LIST_NEW_ITEM(bpy.types.Operator): +#{ + bl_idname = "skaterift.gl_new_entry" + bl_label = "Add glyph" + + def execute(self, context):#{ + active_object = context.active_object + + font = active_object.SR_data.ent_font[0] + font.glyphs.add() + + if len(font.glyphs) > 1:#{ + prev = font.glyphs[-2] + cur = font.glyphs[-1] + + cur.bounds = prev.bounds + cur.utf32 = prev.utf32+1 + #} + + return{'FINISHED'} + #} +#} + +class SR_OT_GLYPH_LIST_DEL_ITEM(bpy.types.Operator): +#{ + bl_idname = "skaterift.gl_del_entry" + bl_label = "Remove Glyph" + + @classmethod + def poll(cls, context):#{ + active_object = context.active_object + if obj_ent_type(active_object) == 'ent_font':#{ + return active_object.SR_data.ent_font[0].glyphs + #} + else: return False + #} + + def execute(self, context):#{ + return internal_listdel_execute(self,context,'ent_font','glyphs') + #} +#} + +class SR_OT_GLYPH_LIST_MOVE_ITEM(bpy.types.Operator): +#{ + bl_idname = "skaterift.gl_move_item" + bl_label = "aa" + direction: bpy.props.EnumProperty(items=(('UP', 'Up', ""), + ('DOWN', 'Down', ""),)) + + @classmethod + def poll(cls, context):#{ + active_object = context.active_object + if obj_ent_type(active_object) == 'ent_font':#{ + return active_object.SR_data.ent_font[0].glyphs + #} + else: return False + #} + + def execute(_, context):#{ active_object = context.active_object - lista = active_object.SR_data.ent_audio[0].files - index = active_object.SR_data.ent_audio[0].file_index - lista.remove(index) - active_object.SR_data.ent_audio[0].file_index = \ - min(max(0, index-1), len(lista) - 1) + data = active_object.SR_data.ent_font[0] + + index = data.glyphs_index + neighbor = index + (-1 if _.direction == 'UP' else 1) + data.glyphs.move( neighbor, index ) + + list_length = len(data.glyphs) - 1 + new_index = index + (-1 if _.direction == 'UP' else 1) + + data.glyphs_index = max(0, min(new_index, list_length)) + return{'FINISHED'} #} #} +class SR_OT_FONT_VARIANT_LIST_NEW_ITEM(bpy.types.Operator): +#{ + bl_idname = "skaterift.fv_new_entry" + bl_label = "Add variant" + + def execute(self, context):#{ + return internal_listadd_execute(self,context,'ent_font','variants') + #} +#} + +class SR_OT_FONT_VARIANT_LIST_DEL_ITEM(bpy.types.Operator): +#{ + bl_idname = "skaterift.fv_del_entry" + bl_label = "Remove variant" + + @classmethod + def poll(cls, context):#{ + active_object = context.active_object + if obj_ent_type(active_object) == 'ent_font':#{ + return active_object.SR_data.ent_font[0].variants + #} + else: return False + #} + + def execute(self, context):#{ + return internal_listdel_execute(self,context,'ent_font','variants') + #} +#} + class SR_OBJECT_ENT_AUDIO_FILE_ENTRY(bpy.types.PropertyGroup): #{ path: bpy.props.StringProperty( name="Path" ) @@ -1883,6 +2206,37 @@ class SR_UL_AUDIO_LIST(bpy.types.UIList): #} #} +class SR_UL_FONT_VARIANT_LIST(bpy.types.UIList): +#{ + bl_idname = 'SR_UL_FONT_VARIANT_LIST' + + def draw_item(_,context,layout,data,item,icon,active_data,active_propname): + #{ + layout.prop( item, 'mesh', emboss=False ) + layout.prop( item, 'tipo' ) + #} +#} + +class SR_UL_FONT_GLYPH_LIST(bpy.types.UIList): +#{ + bl_idname = 'SR_UL_FONT_GLYPH_LIST' + + def draw_item(_,context,layout,data,item,icon,active_data,active_propname): + #{ + s0 = layout.split(factor=0.3) + c = s0.column() + s1 = c.split(factor=0.3) + c = s1.column() + row = c.row() + lbl = chr(item.utf32) if item.utf32 >= 32 and item.utf32 <= 126 else 'ERR' + row.label(text=lbl) + c = s1.column() + c.prop( item, 'utf32', text='', emboss=True ) + c = s0.column() + row = c.row() + row.prop( item, 'bounds', text='', emboss=False ) + #} +#} class SR_OBJECT_ENT_ROUTE(bpy.types.PropertyGroup): #{ @@ -1941,7 +2295,7 @@ class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup): class SR_OBJECT_ENT_AUDIO(bpy.types.PropertyGroup): #{ files: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_AUDIO_FILE_ENTRY) - file_index: bpy.props.IntProperty() + files_index: bpy.props.IntProperty() flag_3d: bpy.props.BoolProperty( name="3D audio",default=True ) flag_loop: bpy.props.BoolProperty( name="Loop",default=False ) @@ -2020,6 +2374,59 @@ class SR_OBJECT_ENT_MARKER(bpy.types.PropertyGroup): alias: bpy.props.StringProperty() #} +class SR_OBJECT_ENT_GLYPH(bpy.types.PropertyGroup): +#{ + mini: bpy.props.FloatVectorProperty(size=2) + maxi: bpy.props.FloatVectorProperty(size=2) + utf32: bpy.props.IntProperty() +#} + +class SR_OBJECT_ENT_GLYPH_ENTRY(bpy.types.PropertyGroup): +#{ + bounds: bpy.props.FloatVectorProperty(size=4,subtype='NONE') + utf32: bpy.props.IntProperty() +#} + +class SR_OBJECT_ENT_FONT_VARIANT(bpy.types.PropertyGroup): +#{ + mesh: bpy.props.PointerProperty(type=bpy.types.Object) + tipo: bpy.props.StringProperty() +#} + +class SR_OBJECT_ENT_FONT(bpy.types.PropertyGroup): +#{ + variants: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_FONT_VARIANT) + glyphs: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GLYPH_ENTRY) + alias: bpy.props.StringProperty() + + glyphs_index: bpy.props.IntProperty() + variants_index: bpy.props.IntProperty() + + @staticmethod + def sr_inspector( layout, data ): + #{ + layout.prop( data[0], 'alias' ) + + layout.label( text='Variants' ) + layout.template_list('SR_UL_FONT_VARIANT_LIST', 'Variants', \ + data[0], 'variants', data[0], 'variants_index',\ + rows=5 ) + row = layout.row() + row.operator( 'skaterift.fv_new_entry', text='Add' ) + row.operator( 'skaterift.fv_del_entry', text='Remove' ) + + layout.label( text='ASCII Glyphs' ) + layout.template_list('SR_UL_FONT_GLYPH_LIST', 'Glyphs', \ + data[0], 'glyphs', data[0], 'glyphs_index', rows=5) + + row = layout.row() + row.operator( 'skaterift.gl_new_entry', text='Add' ) + row.operator( 'skaterift.gl_del_entry', text='Remove' ) + row.operator( 'skaterift.gl_move_item', text='^' ).direction='UP' + row.operator( 'skaterift.gl_move_item', text='v' ).direction='DOWN' + #} +#} + class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): #{ ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE) @@ -2028,7 +2435,8 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): ent_volume: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_VOLUME) ent_audio: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_AUDIO) ent_marker: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MARKER) - + ent_glyph: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GLYPH) + ent_font: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_FONT) ent_type: bpy.props.EnumProperty( name="Type", items=[('none', 'None', '', 0), @@ -2039,7 +2447,9 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup): ('ent_water', 'Water Surface', '', 5), ('ent_volume', 'Volume', '', 6 ), ('ent_audio', 'Audio Files', '', 7), - ('ent_marker', 'Marker', '', 8)], + ('ent_marker', 'Marker', '', 8), + ('ent_font', 'Font', '', 9), + ('ent_font_variant','Font variant','',10)], update=sr_on_type_change ) #} @@ -2962,6 +3372,29 @@ def cv_draw(): if obj.SR_data.ent_audio[0].flag_3d: cv_draw_sphere( obj.location, obj.scale[0], (1,1,0) ) #} + elif ent_type == 'ent_font':#{ + data = obj.SR_data.ent_font[0] + + for i in range(len(data.variants)):#{ + sub = data.variants[i].mesh + if not sub: continue + + for ch in data.glyphs:#{ + mini = (ch.bounds[0],ch.bounds[1]) + maxi = (ch.bounds[2]+mini[0],ch.bounds[3]+mini[1]) + p0 = sub.matrix_world @ Vector((mini[0],0.0,mini[1])) + p1 = sub.matrix_world @ Vector((maxi[0],0.0,mini[1])) + p2 = sub.matrix_world @ Vector((maxi[0],0.0,maxi[1])) + p3 = sub.matrix_world @ Vector((mini[0],0.0,maxi[1])) + + if i == data.variants_index: cc = (0.5,0.5,0.5) + else: cc = (0,0,0) + + cv_view_verts += [p0,p1,p1,p2,p2,p3,p3,p0] + cv_view_colours += [cc,cc,cc,cc,cc,cc,cc,cc] + #} + #} + #} #} #} @@ -2983,11 +3416,19 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\ SR_OBJECT_ENT_GATE, SR_MESH_ENT_GATE, SR_OBJECT_ENT_SPAWN, \ SR_OBJECT_ENT_ROUTE_ENTRY, SR_UL_ROUTE_NODE_LIST, \ SR_OBJECT_ENT_ROUTE, SR_OT_ROUTE_LIST_NEW_ITEM,\ + SR_OT_GLYPH_LIST_NEW_ITEM, SR_OT_GLYPH_LIST_DEL_ITEM,\ + SR_OT_GLYPH_LIST_MOVE_ITEM,\ SR_OT_AUDIO_LIST_NEW_ITEM,SR_OT_AUDIO_LIST_DEL_ITEM,\ - SR_OBJECT_ENT_VOLUME, + SR_OT_FONT_VARIANT_LIST_NEW_ITEM,SR_OT_FONT_VARIANT_LIST_DEL_ITEM,\ + SR_OT_COPY_ENTITY_DATA, \ + SR_OBJECT_ENT_VOLUME, \ SR_UL_AUDIO_LIST, SR_OBJECT_ENT_AUDIO_FILE_ENTRY,\ SR_OT_ROUTE_LIST_DEL_ITEM,\ - SR_OBJECT_ENT_AUDIO,SR_OBJECT_ENT_MARKER,\ + SR_OBJECT_ENT_AUDIO,SR_OBJECT_ENT_MARKER,SR_OBJECT_ENT_GLYPH,\ + SR_OBJECT_ENT_FONT_VARIANT, + SR_OBJECT_ENT_GLYPH_ENTRY,\ + SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\ + SR_OBJECT_ENT_FONT,\ \ SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \ diff --git a/build.c b/build.c index f791927..73ba1b7 100644 --- a/build.c +++ b/build.c @@ -133,6 +133,7 @@ void build_shaders(void) _S( "model_menu", "model.vs", "model_menu.fs" ); _S( "model_character_view", "model_skinned.vs", "model_character_view.fs" ); _S( "model_gate", "model_gate.vs", "model_gate_lq.fs" ); + _S( "model_font", "model_font.vs", "model_font.fs" ); /* 2D */ _S( "blit", "blit.vs", "blit.fs" ); diff --git a/common.h b/common.h index 9eda6f6..0aaab5d 100644 --- a/common.h +++ b/common.h @@ -17,6 +17,9 @@ #define RESET_MAX_TIME 45.0 VG_STATIC v3f TEMP_BOARD_0, TEMP_BOARD_1; +#include "font.h" +VG_STATIC font3d test_font; + enum menu_controller_type { k_menu_controller_type_keyboard, diff --git a/entity.h b/entity.h index e437d3d..143ad0d 100644 --- a/entity.h +++ b/entity.h @@ -18,6 +18,9 @@ typedef struct ent_volume ent_volume; typedef struct ent_audio ent_audio; typedef struct ent_index ent_index; typedef struct ent_marker ent_marker; +typedef struct ent_font ent_font; +typedef struct ent_font_variant ent_font_variant; +typedef struct ent_glyph ent_glyph; enum entity_alias{ k_ent_gate = 1, @@ -87,12 +90,13 @@ struct ent_gate{ u32 timing_version; struct{ - u8 ref_count, ref_total; + u8 ref_count; }; }; double timing_time; u16 routes[4]; /* routes that pass through this gate */ + u8 route_count; }; struct ent_route_node{ @@ -124,11 +128,13 @@ struct ent_route{ v4f colour; /* runtime */ - u32 active_checkpoint; + u16 active_checkpoint, + valid_checkpoints; + float factive; m4x3f board_transform; mdl_submesh sm; - double latest_pass; + double timing_base; }; struct ent_water{ @@ -189,6 +195,20 @@ struct ent_marker{ u32 pstr_alias; }; +VG_STATIC ent_marker *ent_find_marker( mdl_context *mdl, + mdl_array_ptr *arr, const char *alias ) +{ + for( u32 i=0; ipstr_alias ), alias ) ){ + return marker; + } + } + + return NULL; +} + enum channel_behaviour{ k_channel_behaviour_unlimited = 0, k_channel_behaviour_discard_if_full = 1, @@ -201,18 +221,24 @@ enum probability_curve{ k_probability_curve_wildlife_night = 2 }; -VG_STATIC ent_marker *ent_find_marker( mdl_context *mdl, - mdl_array_ptr *arr, const char *alias ) -{ - for( u32 i=0; ipstr_alias ), alias ) ){ - return marker; - } - } +struct ent_font_variant{ + u32 name, + material_id; +}; - return NULL; -} +struct ent_glyph{ + v2f size; + u32 indice_start, + indice_count; +}; #endif /* ENTITY_H */ diff --git a/font.h b/font.h new file mode 100644 index 0000000..4c7d8f4 --- /dev/null +++ b/font.h @@ -0,0 +1,146 @@ +#ifndef FONT_H +#define FONT_H + +#include "model.h" +#include "entity.h" +#include "camera.h" +#include "shaders/model_font.h" + +typedef struct font3d font3d; +struct font3d{ + mdl_context mdl; + GLuint texture; + glmesh mesh; + + ent_font info; + mdl_array_ptr font_variants, + glyphs; +}; + +VG_STATIC void font3d_load( font3d *font, const char *mdl_path, void *alloc ) +{ + mdl_open( &font->mdl, mdl_path, alloc ); + mdl_load_metadata_block( &font->mdl, alloc ); + + vg_linear_clear( vg_mem.scratch ); + mdl_array_ptr fonts; + mdl_load_array( &font->mdl, &fonts, "ent_font", vg_mem.scratch ); + font->info = *((ent_font *)mdl_arritm(&fonts,0)); + + mdl_load_array( &font->mdl, &font->font_variants, "ent_font_variant", alloc); + mdl_load_array( &font->mdl, &font->glyphs, "ent_glyph", alloc ); + + vg_linear_clear( vg_mem.scratch ); + mdl_load_mesh_block( &font->mdl, vg_mem.scratch ); + mdl_load_pack_block( &font->mdl, vg_mem.scratch ); + mdl_close( &font->mdl ); + + vg_acquire_thread_sync(); + { + /* upload mesh */ + mesh_upload( &font->mesh, + font->mdl.verts.data, font->mdl.verts.count, + font->mdl.indices.data, font->mdl.indices.count ); + + /* upload first texture */ + font->texture = vg_tex2d_new(); + mdl_texture *tex0 = mdl_arritm( &font->mdl.textures, 0 ); + + vg_tex2d_set_error(); + vg_tex2d_qoi( mdl_arritm( &font->mdl.pack, tex0->file.pack_offset ), + tex0->file.pack_size, + mdl_pstr( &font->mdl, tex0->file.pstr_path )); + vg_tex2d_nearest(); + vg_tex2d_repeat(); + } + vg_release_thread_sync(); +} + +VG_STATIC void font3d_init(void) +{ + shader_model_font_register(); +} + +VG_STATIC u32 font3d_find_variant( font3d *font, const char *name ) +{ + for( u32 i=0; ifont_variants ); i ++ ){ + ent_font_variant *variant = mdl_arritm( &font->font_variants, i ); + + if( !strcmp( mdl_pstr( &font->mdl, variant->name ), name ) ){ + return i; + } + } + + return 0; +} + +VG_STATIC void font3d_bind( font3d *font, camera *cam ) +{ + shader_model_font_use(); + shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} ); + shader_model_font_uTexMain( 1 ); + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, font->texture ); + + shader_model_font_uPv( cam->mtx.pv ); + mesh_bind( &font->mesh ); +} + +VG_STATIC +void font3d_simple_draw( font3d *font, u32 variant_id, const char *text, + camera *cam, m4x3f transform ) +{ + v3f offset; + v3_zero( offset ); + + m4x4f prev_mtx; + + m4x3_expand( transform, prev_mtx ); + m4x4_mul( cam->mtx_prev.pv, prev_mtx, prev_mtx ); + + shader_model_font_uPvmPrev( prev_mtx ); + shader_model_font_uMdl( transform ); + + for( int i=0;; i++ ){ + u32 c = text[i]; + if(!c) break; + + if( c < font->info.glyph_utf32_base ) continue; + if( c >= font->info.glyph_utf32_base+font->info.glyph_count) continue; + + u32 index = c - font->info.glyph_utf32_base; + index += font->info.glyph_start; + index += font->info.glyph_count * variant_id; + ent_glyph *glyph = mdl_arritm( &font->glyphs, index ); + + if( glyph->indice_count ){ + shader_model_font_uOffset( offset ); + mesh_drawn( glyph->indice_start, glyph->indice_count ); + } + offset[0] += glyph->size[0]; + } +} + +VG_STATIC +float font3d_string_width( font3d *font, u32 variant_id, const char *text ) +{ + float width = 0.0f; + for( int i=0;; i++ ){ + u32 c = text[i]; + if(!c) break; + + if( c < font->info.glyph_utf32_base ) continue; + if( c >= font->info.glyph_utf32_base+font->info.glyph_count) continue; + + u32 index = c - font->info.glyph_utf32_base; + index += font->info.glyph_start; + index += font->info.glyph_count * variant_id; + ent_glyph *glyph = mdl_arritm( &font->glyphs, index ); + + width += glyph->size[0]; + } + + return width; +} + +#endif /* FONT_H */ diff --git a/maps_src/mp_gridmap.mdl b/maps_src/mp_gridmap.mdl index a1c0ef4..484e165 100644 Binary files a/maps_src/mp_gridmap.mdl and b/maps_src/mp_gridmap.mdl differ diff --git a/maps_src/mp_mtzero.mdl b/maps_src/mp_mtzero.mdl index 1b58c56..29b4aff 100644 Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ diff --git a/menu.h b/menu.h index 4318e62..7a00846 100644 --- a/menu.h +++ b/menu.h @@ -826,7 +826,7 @@ VG_STATIC void menu_render_fg( camera *cam ) mdl_transform_m4x3( &btn->mesh->transform, mtx ); m4x3_mul( menu_mdl_mtx, mtx, mtx ); m4x3_identity( mtx_size ); - m4x3_scale( mtx_size, expSustainedImpulse( btn->fsize, 0.5f, 8.7f) ); + m3x3_scalef( mtx_size, expSustainedImpulse( btn->fsize, 0.5f, 8.7f) ); m4x3_mul( mtx, mtx_size, mtx ); shader_model_menu_uMdl( mtx ); diff --git a/models_src/rs_font.mdl b/models_src/rs_font.mdl new file mode 100644 index 0000000..1c84117 Binary files /dev/null and b/models_src/rs_font.mdl differ diff --git a/player.c b/player.c index 8d6429f..ea29b4c 100644 --- a/player.c +++ b/player.c @@ -377,7 +377,7 @@ VG_STATIC void player__pre_render( player_instance *player ) player->rewind_total_length = 0.0f; player->rewind_accum = 0.0f; world_global.sky_target_rate = 1.0; - world_global.last_use = world_global.time; + world_global.time = world_global.last_use; } else{ world_global.sky_target_rate = -100.0; diff --git a/shaders/model_font.fs b/shaders/model_font.fs new file mode 100644 index 0000000..673238c --- /dev/null +++ b/shaders/model_font.fs @@ -0,0 +1,18 @@ +out vec4 FragColor; + +uniform sampler2D uTexMain; +uniform vec4 uColour; + +in vec4 aColour; +in vec2 aUv; +in vec3 aNorm; +in vec3 aCo; + +#include "motion_vectors_fs.glsl" + +void main() +{ + compute_motion_vectors(); + vec4 diffuse = texture( uTexMain, aUv ); + FragColor = vec4( diffuse.rgb, 1.0 ) * uColour; +} diff --git a/shaders/model_font.h b/shaders/model_font.h new file mode 100644 index 0000000..7de7971 --- /dev/null +++ b/shaders/model_font.h @@ -0,0 +1,147 @@ +#ifndef SHADER_model_font_H +#define SHADER_model_font_H +static void shader_model_font_link(void); +static void shader_model_font_register(void); +static struct vg_shader _shader_model_font = { + .name = "model_font", + .link = shader_model_font_link, + .vs = +{ +.orig_file = "shaders/model_font.vs", +.static_src = +"layout (location=0) in vec3 a_co;\n" +"layout (location=1) in vec3 a_norm;\n" +"layout (location=2) in vec2 a_uv;\n" +"layout (location=3) in vec4 a_colour;\n" +"layout (location=4) in vec4 a_weights;\n" +"layout (location=5) in ivec4 a_groups;\n" +"\n" +"#line 1 1 \n" +"const float k_motion_lerp_amount = 0.01;\n" +"\n" +"#line 2 0 \n" +"\n" +"out vec3 aMotionVec0;\n" +"out vec3 aMotionVec1;\n" +"\n" +"void vs_motion_out( vec4 vproj0, vec4 vproj1 )\n" +"{\n" +" // This magically solves some artifacting errors!\n" +" //\n" +" vproj1 = vproj0*(1.0-k_motion_lerp_amount) + vproj1*k_motion_lerp_amount;\n" +"\n" +" aMotionVec0 = vec3( vproj0.xy, vproj0.w );\n" +" aMotionVec1 = vec3( vproj1.xy, vproj1.w );\n" +"}\n" +"\n" +"#line 9 0 \n" +"\n" +"uniform mat4x3 uMdl;\n" +"uniform mat4 uPv;\n" +"uniform mat4 uPvmPrev;\n" +"uniform vec3 uOffset;\n" +"\n" +"out vec4 aColour;\n" +"out vec2 aUv;\n" +"out vec3 aNorm;\n" +"out vec3 aCo;\n" +"out vec3 aWorldCo;\n" +"\n" +"void main()\n" +"{\n" +" vec3 co = a_co+uOffset;\n" +" vec3 world_pos0 = uMdl * vec4( co, 1.0 );\n" +" vec4 vproj0 = uPv * vec4( world_pos0, 1.0 );\n" +" vec4 vproj1 = uPvmPrev * vec4( co, 1.0 );\n" +"\n" +" vs_motion_out( vproj0, vproj1 );\n" +"\n" +" gl_Position = vproj0;\n" +" aWorldCo = world_pos0;\n" +" aColour = a_colour;\n" +" aUv = a_uv;\n" +" aNorm = mat3(uMdl) * a_norm;\n" +" aCo = a_co;\n" +"}\n" +""}, + .fs = +{ +.orig_file = "shaders/model_font.fs", +.static_src = +"out vec4 FragColor;\n" +"\n" +"uniform sampler2D uTexMain;\n" +"uniform vec4 uColour;\n" +"\n" +"in vec4 aColour;\n" +"in vec2 aUv;\n" +"in vec3 aNorm;\n" +"in vec3 aCo;\n" +"\n" +"#line 1 1 \n" +"const float k_motion_lerp_amount = 0.01;\n" +"\n" +"#line 2 0 \n" +"\n" +"layout (location = 1) out vec2 oMotionVec;\n" +"\n" +"in vec3 aMotionVec0;\n" +"in vec3 aMotionVec1;\n" +"\n" +"void compute_motion_vectors()\n" +"{\n" +" // Write motion vectors\n" +" vec2 vmotion0 = aMotionVec0.xy / aMotionVec0.z;\n" +" vec2 vmotion1 = aMotionVec1.xy / aMotionVec1.z;\n" +"\n" +" oMotionVec = (vmotion1-vmotion0) * (1.0/k_motion_lerp_amount);\n" +"}\n" +"\n" +"#line 12 0 \n" +"\n" +"void main()\n" +"{\n" +" compute_motion_vectors();\n" +" vec4 diffuse = texture( uTexMain, aUv );\n" +" FragColor = vec4( diffuse.rgb, 1.0 ) * uColour;\n" +"}\n" +""}, +}; + +static GLuint _uniform_model_font_uMdl; +static GLuint _uniform_model_font_uPv; +static GLuint _uniform_model_font_uPvmPrev; +static GLuint _uniform_model_font_uOffset; +static GLuint _uniform_model_font_uTexMain; +static GLuint _uniform_model_font_uColour; +static void shader_model_font_uMdl(m4x3f m){ + glUniformMatrix4x3fv(_uniform_model_font_uMdl,1,GL_FALSE,(float*)m); +} +static void shader_model_font_uPv(m4x4f m){ + glUniformMatrix4fv(_uniform_model_font_uPv,1,GL_FALSE,(float*)m); +} +static void shader_model_font_uPvmPrev(m4x4f m){ + glUniformMatrix4fv(_uniform_model_font_uPvmPrev,1,GL_FALSE,(float*)m); +} +static void shader_model_font_uOffset(v3f v){ + glUniform3fv(_uniform_model_font_uOffset,1,v); +} +static void shader_model_font_uTexMain(int i){ + glUniform1i(_uniform_model_font_uTexMain,i); +} +static void shader_model_font_uColour(v4f v){ + glUniform4fv(_uniform_model_font_uColour,1,v); +} +static void shader_model_font_register(void){ + vg_shader_register( &_shader_model_font ); +} +static void shader_model_font_use(void){ glUseProgram(_shader_model_font.id); } +static void shader_model_font_link(void){ + _uniform_model_font_uMdl = glGetUniformLocation( _shader_model_font.id, "uMdl" ); + _uniform_model_font_uPv = glGetUniformLocation( _shader_model_font.id, "uPv" ); + _uniform_model_font_uPvmPrev = glGetUniformLocation( _shader_model_font.id, "uPvmPrev" ); + _uniform_model_font_uOffset = glGetUniformLocation( _shader_model_font.id, "uOffset" ); + _uniform_model_font_uTexMain = glGetUniformLocation( _shader_model_font.id, "uTexMain" ); + _uniform_model_font_uColour = glGetUniformLocation( _shader_model_font.id, "uColour" ); +} +#endif /* SHADER_model_font_H */ diff --git a/shaders/model_font.vs b/shaders/model_font.vs new file mode 100644 index 0000000..764f008 --- /dev/null +++ b/shaders/model_font.vs @@ -0,0 +1,36 @@ +layout (location=0) in vec3 a_co; +layout (location=1) in vec3 a_norm; +layout (location=2) in vec2 a_uv; +layout (location=3) in vec4 a_colour; +layout (location=4) in vec4 a_weights; +layout (location=5) in ivec4 a_groups; + +#include "motion_vectors_vs.glsl" + +uniform mat4x3 uMdl; +uniform mat4 uPv; +uniform mat4 uPvmPrev; +uniform vec3 uOffset; + +out vec4 aColour; +out vec2 aUv; +out vec3 aNorm; +out vec3 aCo; +out vec3 aWorldCo; + +void main() +{ + vec3 co = a_co+uOffset; + vec3 world_pos0 = uMdl * vec4( co, 1.0 ); + vec4 vproj0 = uPv * vec4( world_pos0, 1.0 ); + vec4 vproj1 = uPvmPrev * vec4( co, 1.0 ); + + vs_motion_out( vproj0, vproj1 ); + + gl_Position = vproj0; + aWorldCo = world_pos0; + aColour = a_colour; + aUv = a_uv; + aNorm = mat3(uMdl) * a_norm; + aCo = a_co; +} diff --git a/skaterift.c b/skaterift.c index f0fb218..3033277 100644 --- a/skaterift.c +++ b/skaterift.c @@ -18,6 +18,7 @@ #include "render.h" #include "audio.h" #include "world.h" +#include "font.h" @@ -217,6 +218,10 @@ VG_STATIC void vg_load(void) vg_loader_step( render_init, NULL ); vg_loader_step( menu_init, NULL ); vg_loader_step( world_init, NULL ); + vg_loader_step( font3d_init, NULL ); + + font3d_load( &test_font, "models/rs_font.mdl", vg_mem.rtmemory ); + //vg_loader_step( player_init, NULL ); //vg_loader_step( vehicle_init, NULL ); // @@ -241,8 +246,8 @@ VG_STATIC void vg_load(void) /* 'systems' are completely loaded now */ /* load home world */ - //world_load( &world_global.worlds[0], "maps/mp_gridmap.mdl" ); - world_load( &world_global.worlds[0], "maps/mp_mtzero.mdl" ); + world_load( &world_global.worlds[0], "maps/mp_gridmap.mdl" ); + //world_load( &world_global.worlds[0], "maps/mp_mtzero.mdl" ); #if 0 world_load( &world_global.worlds[1], "maps/mp_gridmap.mdl" ); diff --git a/world_gate.h b/world_gate.h index ad87ed1..a073b26 100644 --- a/world_gate.h +++ b/world_gate.h @@ -27,8 +27,8 @@ VG_STATIC void gate_transform_update( ent_gate *gate ) v3_copy( gate->co[1], recv_to_world[3] ); m4x3_mul( recv_to_world, to_local, gate->transport ); - m4x3_scalev( gate->to_world, (v3f){ gate->dimensions[0], - gate->dimensions[1], 1.0f } ); + m3x3_scale( gate->to_world, (v3f){ gate->dimensions[0], + gate->dimensions[1], 1.0f } ); } VG_STATIC void world_gates_init(void) diff --git a/world_routes.h b/world_routes.h index 61aa86c..5a81d0c 100644 --- a/world_routes.h +++ b/world_routes.h @@ -8,6 +8,7 @@ #include #include "world.h" #include "world_gate.h" +#include "font.h" #if 0 #include "shaders/vblend.h" @@ -59,7 +60,7 @@ VG_STATIC void world_routes_clear( world_instance *world ) { for( u32 i=0; ient_route ); i++ ){ ent_route *route = mdl_arritm( &world->ent_route, i ); - route->active_checkpoint = 0xffffffff; + route->active_checkpoint = 0xffff; } for( u32 i=0; ient_gate ); i++ ){ @@ -77,9 +78,10 @@ VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route ) vg_info( "------- time lap %s -------\n", mdl_pstr(&world->meta,route->pstr_name) ); - double total_time = 0.0; + double start_time = 0.0; u32 last_version=0; - int validated = 1; + + u32 valid_count=0; for( u32 i=0; icheckpoints_count; i++ ){ u32 cpid = route->checkpoints_start+(i+route->active_checkpoint); @@ -90,22 +92,34 @@ VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route ) rg = mdl_arritm( &world->ent_gate, rg->target ); if( i == 0 ) - total_time = rg->timing_time; + start_time = rg->timing_time; else{ - if( last_version+1 != rg->timing_version ) - validated = 0; + if( last_version+1 == rg->timing_version ) + valid_count ++; + else + valid_count = 0; } last_version = rg->timing_version; vg_info( "%u %f\n", rg->timing_version, rg->timing_time ); } + if( world_global.current_run_version == last_version+1 ) + valid_count ++; + else + valid_count = 0; + vg_info( "%u %f\n", world_global.current_run_version, world_global.time ); - if( validated && (world_global.current_run_version == last_version+1)){ - total_time = world_global.time - total_time; - world_routes_local_set_record( world, route, total_time ); + if( valid_count==route->checkpoints_count ){ + double lap_time = world_global.time - start_time; + world_routes_local_set_record( world, route, lap_time ); } + + route->valid_checkpoints = valid_count+1; + route->timing_base = start_time; + + vg_info( "valid: %u\n", valid_count ); vg_info( "----------------------------\n" ); } @@ -123,7 +137,7 @@ VG_STATIC void world_routes_activate_entry_gate( world_instance *world, ent_route *route = mdl_arritm( &world->ent_route, i ); u32 active_prev = route->active_checkpoint; - route->active_checkpoint = 0xffffffff; + route->active_checkpoint = 0xffff; for( u32 j=0; j<4; j++ ){ if( dest->routes[j] == i ){ @@ -165,7 +179,7 @@ VG_STATIC void world_routes_debug( world_instance *world ) 0xff5442f5 }; u32 cc = 0xffcccccc; - if( route->active_checkpoint != 0xffffffff ){ + if( route->active_checkpoint != 0xffff ){ cc = colours[i%vg_list_size(colours)]; } @@ -337,7 +351,7 @@ VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id ) v3_add( (v3f){0.0f,0.1f,0.0f}, start_gate->co[0], p[0] ); p[0][3] = start_gate->ref_count; - p[0][3] -= (float)start_gate->ref_total * 0.5f; + p[0][3] -= (float)start_gate->route_count * 0.5f; start_gate->ref_count ++; if( !c0->path_count ) @@ -401,7 +415,7 @@ VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id ) if( i == route->checkpoints_count-1) p[2][3] -= 1.0f; - p[2][3] -= (float)collector->ref_total * 0.5f; + p[2][3] -= (float)collector->route_count * 0.5f; //collector->ref_count ++; } @@ -441,7 +455,7 @@ VG_STATIC void world_routes_generate( world_instance *world ) for( u32 i=0; ient_gate); i++ ){ ent_gate *gate = mdl_arritm( &world->ent_gate, i ); gate->ref_count = 0; - gate->ref_total = 0; + gate->route_count = 0; } for( u32 i=0; ient_route_node); i++ ){ @@ -462,7 +476,7 @@ VG_STATIC void world_routes_generate( world_instance *world ) ent_gate *start_gate = mdl_arritm( &world->ent_gate, c0->gate_index ); start_gate = mdl_arritm( &world->ent_gate, start_gate->target ); - start_gate->ref_total ++; + start_gate->route_count ++; if( !c0->path_count ) continue; @@ -579,7 +593,7 @@ VG_STATIC void world_routes_update( world_instance *world ) for( u32 i=0; ient_route); i++ ){ ent_route *route = mdl_arritm( &world->ent_route, i ); - int target = route->active_checkpoint == 0xffffffff? 0: 1; + int target = route->active_checkpoint == 0xffff? 0: 1; route->factive = vg_lerpf( route->factive, target, 0.6f*vg.time_delta ); } } @@ -629,6 +643,83 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam, mdl_draw_submesh( &route->sm ); } + /* timers + * ---------------------------------------------------- */ + if( layer_depth == 0 ){ + font3d_bind( &test_font, cam ); + + for( u32 i=0; ient_route); i++ ){ + ent_route *route = mdl_arritm( &world->ent_route, i ); + + if( route->active_checkpoint != 0xffff ){ + v4f colour; + float brightness = 0.3f + world->ub_lighting.g_day_phase; + v3_muls( route->colour, brightness, colour ); + colour[3] = 1.0f-route->factive; + + shader_model_font_uColour( colour ); + + u32 next = route->active_checkpoint+1+layer_depth; + next = next % route->checkpoints_count; + next += route->checkpoints_start; + + ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, next ); + ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index ); + + + u32 j=0; + for( ; j<4; j++ ){ + if( gate->routes[j] == i ){ + break; + } + } + float h0 = 0.8f, + h1 = 1.2f, + depth = 0.4f, + size = 0.4f; + + char text[256]; + + if( route->valid_checkpoints >= route->checkpoints_count ){ + double lap_time = world_global.time - route->timing_base; + snprintf( text, 255, "%.1f", lap_time ); + } + else{ + snprintf( text, 255, "%hu/%hu", route->valid_checkpoints, + route->checkpoints_count ); + } + + float align_r = font3d_string_width( &test_font, 0, text ) * size; + + v3f positions[] = { + { -0.92f, h0, depth }, + { 0.92f - align_r, h0, depth }, + { -0.92f, h1, depth }, + { 0.92f - align_r, h1, depth }, + }; + + ent_gate *dest = mdl_arritm( &world->ent_gate, gate->target ); + + if( dest->route_count == 1 ){ + positions[0][0] = -align_r*0.5f; + positions[0][1] = h1; + } + + m4x3f model; + m3x3_copy( gate->to_world, model ); + float ratio = v3_length(model[0]) / v3_length(model[1]); + + m3x3_scale( model, (v3f){ size, size*ratio, 0.1f } ); + m4x3_mulv( gate->to_world, positions[j], model[3] ); + + font3d_simple_draw( &test_font, 0, text, cam, model ); + } + } + } + + /* gate markers + * ---------------------------------------------------- */ + shader_model_gate_use(); shader_model_gate_uPv( cam->mtx.pv ); shader_model_gate_uCam( cam->pos ); @@ -645,7 +736,7 @@ VG_STATIC void render_world_routes( world_instance *world, camera *cam, for( u32 i=0; ient_route); i++ ){ ent_route *route = mdl_arritm( &world->ent_route, i ); - if( route->active_checkpoint != 0xffffffff ){ + if( route->active_checkpoint != 0xffff ){ v4f colour; float brightness = 0.3f + world->ub_lighting.g_day_phase; v3_muls( route->colour, brightness, colour );