('ent_challenge', 'Challenge', '', 19 ),
('ent_relay', 'Relay', '', 20 ),
('ent_miniworld', 'Mini World', '', 22 ),
- ('ent_prop', 'Prop', '', 23 )
+ ('ent_prop', 'Prop', '', 23 ),
+ ('ent_list', 'Entity List', '', 24 ),
+ ('ent_region', 'Region', '', 25 )
]
MDL_VERSION_NR = 104
SR_TRIGGERABLE = [ 'ent_audio', 'ent_ccmd', 'ent_gate', 'ent_challenge', \
'ent_relay', 'ent_skateshop', 'ent_objective', 'ent_route',\
- 'ent_miniworld' ]
+ 'ent_miniworld', 'ent_region' ]
def get_entity_enum_id( alias ):
#{
sr_functions = { 0: 'view' }
#}
+class ent_list(Structure):#{
+ _fields_ = [("start",c_uint16),("count",c_uint16)]
+#}
+
class ent_water(Structure):
#{
_fields_ = [("transform",mdl_transform),
1: 'view/reset' }
#}
+class ent_region(Structure):#{
+ _fields_ = [("transform",mdl_transform),
+ ("submesh_start",c_uint32), ("submesh_count",c_uint32),
+ ("pstr_title",c_uint32),
+ ("flags",c_uint32),
+ ("zone_volume",c_uint32)]
+ sr_functions = { 0: 'enter', 1: 'leave' }
+#}
+
class ent_relay(Structure):#{
_fields_ = [("targets",(c_uint32*2)*4),
("targets_events",c_uint32*4)]
if ent_type == 'ent_font_variant': continue
if ent_type == 'ent_menuitem': continue
if ent_type == 'ent_objective': continue
+ if ent_type == 'ent_region': continue
#TODO: This is messy.
if ent_type == 'ent_gate':#{
challenge.status = 0
sr_ent_push( challenge )
#}
+ elif ent_type == 'ent_region':#{
+ region = ent_region()
+ obj_data = obj.SR_data.ent_region[0]
+ compile_obj_transform( obj, region.transform )
+ region.submesh_start, region.submesh_count, _ = \
+ sr_compile_mesh_internal( obj )
+ region.pstr_title = sr_compile_string( obj_data.title )
+ region.zone_volume = sr_entity_id( obj_data.zone_volume )
+ sr_ent_push( region )
+ #}
elif ent_type == 'ent_relay':#{
relay = ent_relay()
obj_data = obj.SR_data.ent_relay[0]
#}
#}
+
+class SR_OT_ENT_LIST_NEW_ITEM(bpy.types.Operator):#{
+ bl_idname = "skaterift.ent_list_new_entry"
+ bl_label = "Add entity"
+
+ def execute(self, context):#{
+ return internal_listadd_execute(self,context,'ent_list','entities')
+ #}
+#}
+
+class SR_OT_ENT_LIST_DEL_ITEM(bpy.types.Operator):#{
+ bl_idname = "skaterift.ent_list_del_entry"
+ bl_label = "Remove entity"
+
+ @classmethod
+ def poll(cls, context):#{
+ active_object = context.active_object
+ if obj_ent_type(active_object) == 'ent_list':#{
+ return active_object.SR_data.ent_list[0].entities
+ #}
+ else: return False
+ #}
+
+ def execute(self, context):#{
+ return internal_listdel_execute(self,context,'ent_list','entities')
+ #}
+#}
+
+class SR_OBJECT_ENT_LIST_ENTRY(bpy.types.PropertyGroup):
+#{
+ target: bpy.props.PointerProperty( \
+ type=bpy.types.Object, name='target' )
+#}
+
+class SR_UL_ENT_LIST(bpy.types.UIList):#{
+ bl_idname = 'SR_UL_ENT_LIST'
+
+ def draw_item(_,context,layout,data,item,icon,active_data,active_propname):#{
+ layout.prop( item, 'target', text='', emboss=False )
+ #}
+#}
+
+class SR_OBJECT_ENT_LIST(bpy.types.PropertyGroup):#{
+ entities: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_LIST_ENTRY)
+ entities_index: bpy.props.IntProperty()
+
+ @staticmethod
+ def sr_inspector( layout, data ):#{
+ layout.label( text='Entities' )
+ layout.template_list('SR_UL_ENT_LIST', 'Entities', \
+ data[0], 'entities', data[0], \
+ 'entities_index', rows=5)
+
+ row = layout.row()
+ row.operator( 'skaterift.ent_list_new_entry', text='Add' )
+ row.operator( 'skaterift.ent_list_del_entry', text='Remove' )
+ #}
+#}
+
+
class SR_OBJECT_ENT_VOLUME(bpy.types.PropertyGroup):#{
subtype: bpy.props.EnumProperty(
name="Subtype",
#}
#}
+class SR_OBJECT_ENT_REGION(bpy.types.PropertyGroup):#{
+ title: bpy.props.StringProperty( name="Title" )
+ zone_volume: bpy.props.PointerProperty(
+ type=bpy.types.Object, name="Zone Volume", \
+ poll=lambda self,obj: sr_filter_ent_type(obj,['ent_volume']))
+#}
+
class SR_OBJECT_ENT_RELAY(bpy.types.PropertyGroup):#{
target0: bpy.props.PointerProperty( \
type=bpy.types.Object, name="Target 0", \
ent_ccmd: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_CCMD)
ent_objective: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_OBJECTIVE)
ent_challenge: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_CHALLENGE)
+ ent_region: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_REGION)
ent_relay: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_RELAY)
ent_miniworld: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MINIWORLD)
+ ent_list: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_LIST)
ent_type: bpy.props.EnumProperty(
name="Type",
SR_OBJECT_ENT_WORKSHOP_PREVIEW,SR_OBJECT_ENT_MENU_ITEM,\
SR_OBJECT_ENT_WORLD_INFO,SR_OBJECT_ENT_CCMD,\
SR_OBJECT_ENT_OBJECTIVE,SR_OBJECT_ENT_CHALLENGE,\
+ SR_OBJECT_ENT_REGION,\
SR_OBJECT_ENT_RELAY,SR_OBJECT_ENT_MINIWORLD,\
+ SR_OBJECT_ENT_LIST_ENTRY, SR_UL_ENT_LIST, SR_OBJECT_ENT_LIST, \
+ SR_OT_ENT_LIST_NEW_ITEM, SR_OT_ENT_LIST_DEL_ITEM,\
\
SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES,
SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \
for( u32 i=0; i<mdl_arrcount(&dest_world->ent_route); i++ ){
ent_route *route = mdl_arritm( &dest_world->ent_route, i );
- if( route->achievment_status & 0x2 ){
+ if( route->flags & k_ent_route_flag_achieve_gold ){
miniworld_icon( cam, k_gui_icon_rift_run_gold,
route->board_transform[3],1.0f);
}
- else if( route->achievment_status & 0x1 ){
+ else if( route->flags & k_ent_route_flag_achieve_silver ){
miniworld_icon( cam, k_gui_icon_rift_run_silver,
route->board_transform[3],1.0f);
}
--- /dev/null
+#include "ent_region.h"
+#include "gui.h"
+
+static void ent_region_call( world_instance *world, ent_call *call ){
+ ent_region *region =
+ mdl_arritm( &world->ent_region, mdl_entity_id_id(call->id) );
+
+ if( !region->zone_volume )
+ return;
+
+ ent_volume *volume =
+ mdl_arritm( &world->ent_volume, mdl_entity_id_id(region->zone_volume) );
+
+ if( call->function == 0 ){ /* enter */
+ for( u32 i=0; i<mdl_arrcount(&world->ent_route); i ++ ){
+ ent_route *route = mdl_arritm( &world->ent_route, i );
+
+ v3f local;
+ m4x3_mulv( volume->to_local, route->board_transform[3], local );
+ if( (fabsf(local[0]) <= 1.0f) &&
+ (fabsf(local[1]) <= 1.0f) &&
+ (fabsf(local[2]) <= 1.0f) ){
+ route->flags &= ~k_ent_route_flag_out_of_zone;
+ }
+ else {
+ route->flags |= k_ent_route_flag_out_of_zone;
+ }
+ }
+
+ gui_location_print_ccmd( 1, (const char *[]){
+ mdl_pstr(&world->meta,region->pstr_title)} );
+ }
+ else if( call->function == 1 ){ /* leave */
+ for( u32 i=0; i<mdl_arrcount(&world->ent_route); i ++ ){
+ ent_route *route = mdl_arritm( &world->ent_route, i );
+ route->flags |= k_ent_route_flag_out_of_zone;
+ }
+ }
+}
+
+/*
+ * reevaluate all achievements to calculate the compiled achievement
+ */
+static void ent_region_re_eval( world_instance *world ){
+ for( u32 i=0; i<mdl_arrcount(&world->ent_region); i ++ ){
+ ent_region *region = mdl_arritm(&world->ent_region, i);
+
+ if( !region->zone_volume )
+ continue;
+
+ ent_volume *volume = mdl_arritm(&world->ent_volume,
+ mdl_entity_id_id(region->zone_volume));
+
+ u32 combined = k_ent_route_flag_achieve_gold |
+ k_ent_route_flag_achieve_silver;
+
+ for( u32 j=0; j<mdl_arrcount(&world->ent_route); j ++ ){
+ ent_route *route = mdl_arritm(&world->ent_route, j );
+
+ v3f local;
+ m4x3_mulv( volume->to_local, route->board_transform[3], local );
+ if( !((fabsf(local[0]) <= 1.0f) &&
+ (fabsf(local[1]) <= 1.0f) &&
+ (fabsf(local[2]) <= 1.0f)) ){
+ continue;
+ }
+
+ combined &= route->flags;
+ }
+
+ region->flags = combined;
+
+ /* TODO: Challenges */
+ }
+}
--- /dev/null
+#ifndef ENT_REGION_H
+#define ENT_REGION_H
+
+#include "world_entity.h"
+
+#endif /* ENT_REGION_H */
#include "ent_route.c"
#include "ent_portal.c"
#include "ent_miniworld.c"
+#include "ent_region.c"
typedef void (*fn_entity_call_handler)( world_instance *, ent_call *);
[k_ent_relay] = ent_relay_call,
[k_ent_challenge] = ent_challenge_call,
[k_ent_route] = ent_route_call,
- [k_ent_miniworld] = ent_miniworld_call
+ [k_ent_miniworld] = ent_miniworld_call,
+ [k_ent_region] = ent_region_call
};
if( type >= vg_list_size(table) ){
typedef struct ent_cubemap ent_cubemap;
typedef struct ent_miniworld ent_miniworld;
typedef struct ent_prop ent_prop;
+typedef struct ent_region ent_region;
enum entity_alias{
k_ent_none = 0,
k_ent_challenge = 19,
k_ent_relay = 20,
k_ent_cubemap = 21,
- k_ent_miniworld = 22
+ k_ent_miniworld = 22,
+ k_ent_prop = 23,
+ k_ent_list = 24,
+ k_ent_region = 25
};
static u32 mdl_entity_id_type( u32 entity_id ){
path_count;
};
+enum ent_route_flag {
+ k_ent_route_flag_achieve_silver = 0x1,
+ k_ent_route_flag_achieve_gold = 0x2,
+
+ k_ent_route_flag_out_of_zone = 0x10
+};
+
struct ent_route{
union{
mdl_transform transform;
- u32 official_track_id;
+ u32 official_track_id; /* TODO: remove this */
}
anon;
u32 id_camera; /* v103+ */
/* v104+, but always accessible */
- u32 achievment_status;
+ u32 flags;
f64 best_laptime;
};
u32 submesh_start, submesh_count, flags;
};
+struct ent_region {
+ mdl_transform transform;
+ u32 submesh_start, submesh_count, pstr_title, flags, zone_volume;
+};
+
#include "world.h"
static void entity_call( world_instance *world, ent_call *call );
ent_relay,
ent_cubemap,
ent_miniworld,
- ent_prop;
+ ent_prop,
+ ent_region;
enum skybox {
k_skybox_default,
}
}
- for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
- ent_route *route = mdl_arritm( &world->ent_route, i );
- route->achievment_status = 0;
- route->best_laptime = 0.0;
- }
-
vg_msg routes_block = *sav;
if( vg_msg_seekframe( &routes_block, "routes" ) ){
for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
vg_msg route_info = routes_block;
if( vg_msg_seekframe( &route_info,
mdl_pstr(&world->meta,route->pstr_name) ) ){
- route->achievment_status =
- vg_msg_getkvu32( &route_info, "achivement_status", 0 );
+ route->flags |= vg_msg_getkvu32( &route_info, "flags", 0 );
route->best_laptime =
vg_msg_getkvf64( &route_info, "best_laptime", 0.0 );
}
}
}
+
+ ent_region_re_eval( world );
}
static void world_entity_serialize( world_instance *world, vg_msg *sav ){
vg_msg_frame( sav, mdl_pstr( &world->meta, route->pstr_name ) );
{
- vg_msg_wkvu32( sav, "achivement_status", route->achievment_status );
+ vg_msg_wkvu32( sav, "flags", route->flags );
vg_msg_wkvf64( sav, "best_laptime", route->best_laptime );
}
vg_msg_end_frame( sav );
}
}
+ /* unpack region models */
+ for( u32 i=0; i<mdl_arrcount( &world->ent_region ); i++ ){
+ ent_region *region = mdl_arritm( &world->ent_region, i );
+
+ for( u32 j=0; j<region->submesh_count; j ++ ){
+ mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
+ region->submesh_start+j );
+ world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm );
+ }
+ }
+
/* unpack gate models */
for( u32 i=0; i<mdl_arrcount( &world->ent_gate ); i++ ){
ent_gate *gate = mdl_arritm( &world->ent_gate, i );
MDL_LOAD_ARRAY( meta, &world->ent_cubemap, ent_cubemap, heap );
MDL_LOAD_ARRAY( meta, &world->ent_miniworld, ent_miniworld, heap );
MDL_LOAD_ARRAY( meta, &world->ent_prop, ent_prop, heap );
+ MDL_LOAD_ARRAY( meta, &world->ent_region, ent_region, heap );
mdl_array_ptr infos;
MDL_LOAD_ARRAY( meta, &infos, ent_worldinfo, vg_mem.scratch );
glEnable(GL_CULL_FACE);
}
-static
-void world_render_challenges( world_instance *world, struct world_pass *pass,
- v3f pos ){
+static void world_render_challenges( world_instance *world,
+ struct world_pass *pass, v3f pos ){
if( !world ) return;
if( skaterift.activity == k_skaterift_replay ) return;
if( world != world_current_instance() ) return;
}
}
-static void render_world_fxglow( world_instance *world, camera *cam ){
+static void render_world_fxglow( world_instance *host_world,
+ world_instance *world, camera *cam,
+ m4x3f world_mmdl,
+ int generic, int challenges, int regions ){
shader_scene_fxglow_use();
shader_scene_fxglow_uUvOffset( (v2f){ 0.0f, 0.0f } );
shader_scene_fxglow_uTexMain(1);
shader_scene_fxglow_uPv( cam->mtx.pv );
- world_link_lighting_ub( world, _shader_scene_fxglow.id );
- world_bind_position_texture( world, _shader_scene_fxglow.id,
+ world_link_lighting_ub( host_world, _shader_scene_fxglow.id );
+ world_bind_position_texture( host_world, _shader_scene_fxglow.id,
_uniform_scene_fxglow_g_world_depth, 2 );
- world_bind_light_array( world, _shader_scene_fxglow.id,
+ world_bind_light_array( host_world, _shader_scene_fxglow.id,
_uniform_scene_fxglow_uLightsArray, 3 );
- world_bind_light_index( world, _shader_scene_fxglow.id,
+ world_bind_light_index( host_world, _shader_scene_fxglow.id,
_uniform_scene_fxglow_uLightsIndex, 4 );
shader_scene_fxglow_uCamera( cam->transform[3] );
.fn_set_uPvmPrev = shader_scene_fxglow_uPvmPrev,
};
- world_render_both_stages( world, &pass );
- world_render_challenges( world, &pass, cam->pos );
+ if( generic )
+ world_render_both_stages( world, &pass );
+
+ if( regions ){
+ mesh_bind( &world->mesh_no_collide );
+
+ u32 last_material = 0;
+ for( u32 i=0; i<mdl_arrcount(&world->ent_region); i ++ ){
+ shader_scene_fxglow_uUvOffset( (v2f){ 0.0f, 0.0f } );
+ ent_region *region = mdl_arritm( &world->ent_region, i );
+
+ f32 offset = 0.0f;
+ if( region->flags & k_ent_route_flag_achieve_gold )
+ offset = 2.0f;
+ else if( region->flags & k_ent_route_flag_achieve_silver )
+ offset = 1.0f;
+
+ shader_scene_fxglow_uUvOffset( (v2f){ (8.0f/256.0f)*offset, 0.0f } );
+
+ m4x3f mmdl;
+ mdl_transform_m4x3( ®ion->transform, mmdl );
+ m4x3_mul( world_mmdl, mmdl, mmdl );
+ shader_scene_fxglow_uMdl( mmdl );
+
+ for( u32 j=0; j<region->submesh_count; j++ ){
+ mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
+ region->submesh_start + j );
+
+ if( sm->material_id != last_material ){
+ last_material = sm->material_id;
+ pass.fn_bind_textures(world,&world->surfaces[sm->material_id]);
+ }
+ mdl_draw_submesh( sm );
+ }
+ }
+ }
+
+ if( challenges )
+ world_render_challenges( world, &pass, cam->pos );
glEnable(GL_CULL_FACE);
}
GL_COLOR_ATTACHMENT1 } );
}
- render_world_fxglow( world, cam );
+ render_world_fxglow( world, world, cam, NULL, 1, 1, 0 );
}
if( with_water ){
pass.geo_type = k_world_geo_type_nonsolid;
render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev );
glEnable( GL_CULL_FACE );
+
+ render_world_fxglow( world, world, cam, mmdl, 0, 0, 1 );
}
static void render_cubemap_side( world_instance *world, ent_cubemap *cm,
#include "shaders/scene_route.h"
#include "shaders/routeui.h"
+#include "ent_region.h"
static void world_routes_clear( world_instance *world )
{
if( (route->best_laptime == 0.0) || (lap_time < route->best_laptime) ){
route->best_laptime = lap_time;
- route->achievment_status |= 0x1;
-
- if( clean )
- route->achievment_status |= 0x2;
}
+ route->flags |= k_ent_route_flag_achieve_silver;
+ if( clean ) route->flags |= k_ent_route_flag_achieve_gold;
+ ent_region_re_eval( world );
+
/* for steam achievements. */
if( route->anon.official_track_id != 0xffffffff ){
struct track_info *ti = &track_infos[ route->anon.official_track_id ];
ent_route *route = mdl_arritm(&world->ent_route,i);
mdl_transform_m4x3( &route->anon.transform, route->board_transform );
+ route->flags = 0x00;
+ route->best_laptime = 0.0;
+
+ if( mdl_arrcount(&world->ent_region) )
+ route->flags |= k_ent_route_flag_out_of_zone;
+
route->anon.official_track_id = 0xffffffff;
for( u32 j=0; j<vg_list_size(track_infos); j ++ ){
if( !strcmp(track_infos[j].name,
static void ent_route_imgui( world_instance *world, ent_route *route,
ui_point inout_cursor ){
+ if( route->flags & k_ent_route_flag_out_of_zone )
+ return;
+
u32 last_version=0;
f64 last_time = 0.0;
for( u32 i=0; i<valid_sections; i ++ ){
struct time_block *block = &blocks[ i ];
- ui_px w = block->length * 2.0f;
+ ui_px w = block->length * 6.0f;
ui_rect rect = { x, inout_cursor[1], w, h };
ui_fill( rect, colour );
struct route_ui{
};
+static void ent_region_re_eval( world_instance *world );
#endif /* WORLD_ROUTES_UI_H */