1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
6 #include "vg/vg_steam_ugc.h"
8 #include "ent_skateshop.h"
13 #include "pointcloud.h"
14 #include "highscores.h"
20 * Checks string equality but does a hash check first
22 static inline int const_str_eq( u32 hash
, const char *str
, const char *cmp
)
24 if( hash
== vg_strdjb2(cmp
) )
25 if( !strcmp( str
, cmp
) )
31 * Get an existing cache instance, allocate a new one to be loaded, or NULL if
34 VG_STATIC
struct cache_board
*skateshop_cache_fetch_board( u32 registry_index
)
36 addon_reg
*reg
= NULL
;
38 if( registry_index
< addon_count( k_workshop_file_type_board
) ){
39 reg
= get_addon_from_index( k_workshop_file_type_board
, registry_index
);
46 SDL_AtomicLock( &addon_system
.sl_cache
);
47 struct cache_board
*min_board
=
48 vg_pool_lru( &addon_system
.board_cache
);
51 if( min_board
->state
== k_cache_board_state_loaded
){
52 player_board_unload( &min_board
->board
);
53 min_board
->reg_ptr
->userdata
= NULL
;
57 vg_info( "Allocating board (reg:%u) '%s'\n",
58 registry_index
, reg
->foldername
);
61 vg_info( "Pre-allocating board (reg:%u) 'null'\n", registry_index
);
64 min_board
->reg_ptr
= reg
;
65 min_board
->reg_index
= registry_index
;
66 min_board
->state
= k_cache_board_state_load_request
;
69 vg_error( "No free boards to load registry!\n" );
72 SDL_AtomicUnlock( &addon_system
.sl_cache
);
76 VG_STATIC
void skateshop_update_viewpage(void)
78 u32 page
= global_skateshop
.selected_board_id
/SKATESHOP_VIEW_SLOT_MAX
;
80 for( u32 i
=0; i
<SKATESHOP_VIEW_SLOT_MAX
; i
++ ){
81 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
82 u32 request_id
= page
*SKATESHOP_VIEW_SLOT_MAX
+ i
;
84 vg_pool
*cache
= &addon_system
.board_cache
;
86 vg_pool_unwatch( cache
, slot
->cache_ptr
);
88 slot
->cache_ptr
= skateshop_cache_fetch_board( request_id
);
90 vg_pool_watch( cache
, slot
->cache_ptr
);
95 * op/subroutine: k_workshop_op_item_load
96 * -----------------------------------------------------------------------------
100 * Reciever for board completion; only promotes the status in the main thread
102 VG_STATIC
void skateshop_async_board_loaded( void *payload
, u32 size
)
104 SDL_AtomicLock( &addon_system
.sl_cache
);
105 struct cache_board
*cache_ptr
= payload
;
106 cache_ptr
->state
= k_cache_board_state_loaded
;
108 cache_ptr
->reg_ptr
->userdata
= cache_ptr
;
109 SDL_AtomicUnlock( &addon_system
.sl_cache
);
110 vg_success( "Async board loaded (%s)\n", cache_ptr
->reg_ptr
->foldername
);
114 * Thread(or subroutine of thread), for checking view slots that weve installed.
115 * Load the model if a view slot wants it
117 VG_STATIC
void workshop_visibile_load_loop(void)
119 vg_info( "Running load loop\n" );
122 for( u32 i
=0; i
<CACHE_BOARD_MAX
; i
++ ){
123 struct cache_board
*cache_ptr
= &addon_system
.boards
[i
];
125 SDL_AtomicLock( &addon_system
.sl_cache
);
126 if( cache_ptr
->state
== k_cache_board_state_load_request
){
127 if( cache_ptr
->reg_index
>= addon_count(k_workshop_file_type_board
) ){
128 /* should maybe have a different value for this case */
129 cache_ptr
->state
= k_cache_board_state_none
;
130 SDL_AtomicUnlock( &addon_system
.sl_cache
);
134 /* continue with the request */
135 SDL_AtomicUnlock( &addon_system
.sl_cache
);
136 addon_reg
*reg
= get_addon_from_index( k_workshop_file_type_board
,
137 cache_ptr
->reg_index
);
138 cache_ptr
->reg_ptr
= reg
;
141 vg_strnull( &folder
, path_buf
, 4096 );
142 if( !addon_get_content_folder( reg
, &folder
) )
146 /* load content files
147 * --------------------------------- */
148 vg_str content_path
= folder
;
151 root
.buf
= reg
->metadata
;
152 root
.len
= reg
->metadata_len
;
153 root
.max
= sizeof(reg
->metadata
);
155 const char *kv_content
= vg_msg_seekkvstr( &root
, "content", 0 );
157 vg_strcat( &content_path
, "/" );
158 vg_strcat( &content_path
, kv_content
);
161 vg_error( "No content paths in metadata\n" );
165 if( !vg_strgood( &content_path
) ) {
166 vg_error( "Metadata path too long\n" );
170 vg_info( "Load content: %s\n", content_path
.buffer
);
171 player_board_load( &cache_ptr
->board
, content_path
.buffer
);
172 vg_async_call( skateshop_async_board_loaded
, cache_ptr
, 0 );
176 SDL_AtomicLock( &addon_system
.sl_cache
);
177 cache_ptr
->state
= k_cache_board_state_none
;
178 SDL_AtomicUnlock( &addon_system
.sl_cache
);
181 SDL_AtomicUnlock( &addon_system
.sl_cache
);
186 VG_STATIC
void world_scan_thread( void *_args
){
187 addon_mount_content_folder( k_workshop_file_type_world
, "maps", ".mdl" );
188 addon_mount_workshop_items();
189 vg_async_call( async_addon_reg_update
, NULL
, 0 );
194 * Asynchronous scan of local disk for worlds
196 VG_STATIC
void skateshop_op_world_scan(void){
197 skaterift_begin_op( k_async_op_world_scan
);
198 vg_loader_start( world_scan_thread
, NULL
);
201 VG_STATIC
void board_processview_thread( void *_args
){
202 workshop_visibile_load_loop();
206 VG_STATIC
void board_scan_thread( void *_args
){
207 addon_mount_content_folder( k_workshop_file_type_board
, "boards", ".mdl" );
208 addon_mount_workshop_items();
209 vg_async_call( async_addon_reg_update
, NULL
, 0 );
211 board_processview_thread(NULL
);
214 VG_STATIC
void skateshop_op_board_scan(void){
215 skaterift_begin_op( k_async_op_board_scan
);
216 vg_loader_start( board_scan_thread
, NULL
);
219 VG_STATIC
void skateshop_op_processview(void){
220 skaterift_begin_op( k_async_op_board_scan
);
221 vg_loader_start( board_processview_thread
, NULL
);
226 * -----------------------------------------------------------------------------
232 VG_STATIC
void skateshop_init(void){
233 u32 cache_size
= sizeof(struct cache_board
)*CACHE_BOARD_MAX
;
234 addon_system
.boards
= vg_linear_alloc( vg_mem
.rtmemory
, cache_size
);
235 memset( addon_system
.boards
, 0, cache_size
);
237 for( i32 i
=0; i
<CACHE_BOARD_MAX
; i
++ ){
238 struct cache_board
*board
= &addon_system
.boards
[i
];
239 board
->state
= k_cache_board_state_none
;
240 board
->reg_ptr
= NULL
;
241 board
->reg_index
= 0xffffffff;
244 vg_pool
*cache
= &addon_system
.board_cache
;
245 cache
->buffer
= addon_system
.boards
;
246 cache
->count
= CACHE_BOARD_MAX
;
247 cache
->stride
= sizeof( struct cache_board
);
248 cache
->offset
= offsetof( struct cache_board
, cachenode
);
249 vg_pool_init( cache
);
252 VG_STATIC
struct cache_board
*skateshop_selected_cache_if_loaded(void)
254 if( addon_count(k_workshop_file_type_board
) ){
255 addon_reg
*reg
= get_addon_from_index(k_workshop_file_type_board
,
256 global_skateshop
.selected_board_id
);
258 SDL_AtomicLock( &addon_system
.sl_cache
);
260 struct cache_board
*cache_ptr
= reg
->userdata
;
261 if( cache_ptr
->state
== k_cache_board_state_loaded
){
262 SDL_AtomicUnlock( &addon_system
.sl_cache
);
266 SDL_AtomicUnlock( &addon_system
.sl_cache
);
272 VG_STATIC
void pointcloud_async_end(void *_
, u32 __
)
274 pointcloud_animate( k_pointcloud_anim_opening
);
277 VG_STATIC
void pointcloud_clear_async(void *_
, u32 __
)
279 pointcloud
.count
= 0;
280 pointcloud_animate( k_pointcloud_anim_opening
);
283 VG_STATIC
void skateshop_preview_loader_thread( void *_data
)
285 addon_reg
*reg
= _data
;
289 vg_strnull( &path
, path_buf
, 4096 );
290 addon_get_content_folder( reg
, &path
);
291 vg_strcat( &path
, "/preview.bin" );
293 vg_linear_clear(vg_mem
.scratch
);
296 void *data
= vg_file_read( vg_mem
.scratch
, path_buf
, &size
);
298 if( size
< sizeof(pointcloud_buffer
) ){
299 vg_async_call( pointcloud_clear_async
, NULL
, 0 );
303 vg_async_item
*call
= vg_async_alloc(size
);
304 pointcloud_buffer
*pcbuf
= call
->payload
;
305 memcpy( pcbuf
, data
, size
);
307 u32 point_count
= (size
-sizeof(pointcloud_buffer
)) /
308 sizeof(struct pointcloud_vert
);
309 pcbuf
->max
= point_count
;
310 pcbuf
->count
= point_count
;
311 pcbuf
->op
= k_pointcloud_op_clear
;
313 vg_async_dispatch( call
, async_pointcloud_sub
);
314 vg_async_call( pointcloud_async_end
, NULL
, 0 );
317 vg_async_call( pointcloud_clear_async
, NULL
, 0 );
321 VG_STATIC
void skateshop_preview_loader_thread_and_end( void *_data
){
322 skateshop_preview_loader_thread( _data
);
326 VG_STATIC
void skateshop_load_world_preview( addon_reg
*reg
)
328 skaterift_begin_op( k_async_op_world_load_preview
);
329 vg_loader_start( skateshop_preview_loader_thread_and_end
, reg
);
335 void temp_update_playermodel(void);
336 VG_STATIC
void global_skateshop_preupdate(void)
338 float rate
= vg_minf( 1.0f
, vg
.time_frame_delta
* 2.0f
);
339 global_skateshop
.factive
= vg_lerpf( global_skateshop
.factive
,
340 global_skateshop
.active
, rate
);
342 if( !global_skateshop
.active
) return;
344 world_instance
*world
= world_current_instance();
345 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
347 /* camera positioning */
348 ent_camera
*ref
= mdl_arritm( &world
->ent_camera
,
349 mdl_entity_id_id(shop
->id_camera
) );
351 v3f dir
= {0.0f
,-1.0f
,0.0f
};
352 mdl_transform_vector( &ref
->transform
, dir
, dir
);
353 m3x3_mulv( localplayer
.invbasis
, dir
, dir
);
354 player_vector_angles( localplayer
.cam_override_angles
, dir
, 1.0f
, 0.0f
);
357 if( shop
->type
== k_skateshop_type_boardshop
||
358 shop
->type
== k_skateshop_type_worldshop
){
359 ent_marker
*display
= mdl_arritm( &world
->ent_marker
,
360 mdl_entity_id_id(shop
->boards
.id_display
) );
362 v3_sub( display
->transform
.co
, localplayer
.rb
.co
, lookat
);
365 else if( shop
->type
== k_skateshop_type_charshop
){
366 v3_sub( ref
->transform
.co
, localplayer
.rb
.co
, lookat
);
369 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
372 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
373 atan2f(lookat
[0],lookat
[2]) );
375 v3_copy( ref
->transform
.co
, localplayer
.cam_override_pos
);
376 localplayer
.cam_override_fov
= ref
->fov
;
377 localplayer
.cam_override_strength
= global_skateshop
.factive
;
380 if( shop
->type
== k_skateshop_type_boardshop
){
381 if( skaterift
.async_op
!= k_async_op_none
) return;
383 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h
), "browse" );
384 gui_helper_action( button_display_string( k_srbind_mback
), "exit" );
386 struct cache_board
*selected_cache
= skateshop_selected_cache_if_loaded();
388 if( selected_cache
){
389 gui_helper_action( button_display_string( k_srbind_maccept
), "pick" );
394 * ----------------------
396 * TODO: Crash if switch page too quick, delist browse if loading....
399 u32 opage
= global_skateshop
.selected_board_id
/SKATESHOP_VIEW_SLOT_MAX
;
401 if( button_down( k_srbind_mleft
) ){
402 if( global_skateshop
.selected_board_id
> 0 ){
403 global_skateshop
.selected_board_id
--;
407 if( button_down( k_srbind_mright
) ){
408 if( global_skateshop
.selected_board_id
+1 <
409 addon_count(k_workshop_file_type_board
) )
411 global_skateshop
.selected_board_id
++;
415 u32 npage
= global_skateshop
.selected_board_id
/SKATESHOP_VIEW_SLOT_MAX
;
417 if( opage
!= npage
){
418 skateshop_update_viewpage();
419 skateshop_op_processview();
421 else if( selected_cache
&& button_down( k_srbind_maccept
) ){
422 vg_info( "chose board from skateshop (%u)\n",
423 global_skateshop
.selected_board_id
);
425 if( localplayer
.board_view_slot
){
426 vg_pool_unwatch( &addon_system
.board_cache
,
427 localplayer
.board_view_slot
);
430 localplayer
.board_view_slot
= selected_cache
;
431 vg_pool_watch( &addon_system
.board_cache
,
432 localplayer
.board_view_slot
);
433 global_skateshop_exit();
434 skaterift_write_savedata();
438 else if( shop
->type
== k_skateshop_type_charshop
){
439 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h
), "browse" );
440 gui_helper_action( button_display_string( k_srbind_mback
), "exit" );
441 gui_helper_action( button_display_string( k_srbind_maccept
), "pick" );
443 if( button_down( k_srbind_mleft
) ){
444 if( k_playermdl_id
> 0 ){
448 k_playermdl_id
= 2; /* HACK */
450 temp_update_playermodel(); /* HACK */
453 if( button_down( k_srbind_mright
) ){
454 if( k_playermdl_id
+1 < 3 ){
458 k_playermdl_id
= 0; /* HACK */
460 temp_update_playermodel(); /* HACK */
464 if( button_down( k_srbind_maccept
) ){
465 global_skateshop_exit();
468 else if( shop
->type
== k_skateshop_type_worldshop
){
472 if( addon_count(k_workshop_file_type_world
) &&
473 ((skaterift
.async_op
== k_async_op_none
)||
474 (skaterift
.async_op
== k_async_op_world_load_preview
))){
475 gui_helper_action( axis_display_string(k_sraxis_mbrowse_h
), "browse" );
479 if( (skaterift
.async_op
== k_async_op_none
) &&
480 global_skateshop
.selected_world_id
> 0 ){
481 gui_helper_action( button_display_string(k_srbind_maccept
),
489 if( button_down( k_srbind_mleft
) ){
490 if( global_skateshop
.selected_world_id
> 0 )
492 global_skateshop
.selected_world_id
--;
497 if( button_down( k_srbind_mright
) ){
498 if( global_skateshop
.selected_world_id
+1 <
499 addon_count(k_workshop_file_type_world
) )
501 global_skateshop
.selected_world_id
++;
507 if( change
&& pointcloud_idle() ){
508 pointcloud_animate( k_pointcloud_anim_hiding
);
511 if( skaterift
.async_op
== k_async_op_none
){
512 addon_reg
*reg
= get_addon_from_index( k_workshop_file_type_world
,
513 global_skateshop
.selected_world_id
);
515 /* automatically load in clouds */
516 if( loadable
&& button_down( k_srbind_maccept
) ){
517 vg_info( "Select rift (%u)\n",
518 global_skateshop
.selected_world_id
);
519 world_loader
.reg
= reg
;
520 world_loader
.override_name
[0] = '\0';
521 skaterift_change_world_start();
525 if( pointcloud
.anim
== k_pointcloud_anim_idle_closed
){
526 if( global_skateshop
.pointcloud_world_id
!=
527 global_skateshop
.selected_world_id
)
529 global_skateshop
.pointcloud_world_id
=
530 global_skateshop
.selected_world_id
;
531 skateshop_load_world_preview( reg
);
534 pointcloud_animate( k_pointcloud_anim_opening
);
537 else if( pointcloud
.anim
== k_pointcloud_anim_idle_open
){
538 if( global_skateshop
.pointcloud_world_id
!=
539 global_skateshop
.selected_world_id
)
541 pointcloud_animate( k_pointcloud_anim_hiding
);
548 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
551 if( button_down( k_srbind_mback
) ){
552 global_skateshop_exit();
557 VG_STATIC
void skateshop_render_boardshop(void)
559 world_instance
*world
= world_current_instance();
560 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
562 u32 slot_count
= vg_list_size(global_skateshop
.shop_view_slots
);
564 ent_marker
*mark_rack
= mdl_arritm( &world
->ent_marker
,
565 mdl_entity_id_id(shop
->boards
.id_rack
)),
566 *mark_display
= mdl_arritm( &world
->ent_marker
,
567 mdl_entity_id_id(shop
->boards
.id_display
));
569 int visibility
[ SKATESHOP_VIEW_SLOT_MAX
];
570 SDL_AtomicLock( &addon_system
.sl_cache
);
571 for( u32 i
=0; i
<SKATESHOP_VIEW_SLOT_MAX
; i
++ ){
572 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
576 if( slot
->cache_ptr
== NULL
) visibility
[i
] = 0;
577 else if( slot
->cache_ptr
->state
!= k_cache_board_state_loaded
)
580 SDL_AtomicUnlock( &addon_system
.sl_cache
);
582 /* Render loaded boards in the view slots */
583 for( u32 i
=0; i
<slot_count
; i
++ ){
584 struct shop_view_slot
*slot
= &global_skateshop
.shop_view_slots
[i
];
585 float selected
= 0.0f
;
587 if( !visibility
[i
] ) goto fade_out
;
590 transform_identity( &xform
);
592 xform
.co
[0] = -((float)i
- ((float)slot_count
)*0.5f
)*0.45f
;
593 mdl_transform_mul( &mark_rack
->transform
, &xform
, &xform
);
595 if( slot
->cache_ptr
->reg_index
== global_skateshop
.selected_board_id
){
599 float t
= slot
->view_blend
;
600 v3_lerp( xform
.co
, mark_display
->transform
.co
, t
, xform
.co
);
601 q_nlerp( xform
.q
, mark_display
->transform
.q
, t
, xform
.q
);
602 v3_lerp( xform
.s
, mark_display
->transform
.s
, t
, xform
.s
);
605 mdl_transform_m4x3( &xform
, mmdl
);
606 render_board( &main_camera
, world
, &slot
->cache_ptr
->board
, mmdl
,
607 k_board_shader_entity
);
610 float rate
= 5.0f
*vg
.time_delta
;
611 slot
->view_blend
= vg_lerpf( slot
->view_blend
, selected
, rate
);
614 ent_marker
*mark_info
= mdl_arritm( &world
->ent_marker
,
615 mdl_entity_id_id(shop
->boards
.id_info
));
617 mdl_transform_m4x3( &mark_info
->transform
, mtext
);
618 mdl_transform_m4x3( &mark_rack
->transform
, mrack
);
621 const char *text_title
= "Fish - Title";
622 const char *text_author
= "by Shaniqua";
626 m4x3_identity( mlocal
);
631 font3d_bind( &gui
.font
, &main_camera
);
632 shader_model_font_uColour( (v4f
){1.0f
,1.0f
,1.0f
,1.0f
} );
635 * ------------------------------------------------------------------ */
637 v3_zero( mlocal
[3] );
638 mlocal
[0][0] = -scale
*2.0f
;
639 mlocal
[1][2] = -scale
*2.0f
;
640 mlocal
[2][1] = -thickness
;
641 mlocal
[3][2] = -0.7f
;
642 m4x3_mul( mrack
, mlocal
, mmdl
);
644 if( addon_count(k_workshop_file_type_board
) ){
647 i
+=highscore_intl( buf
+i
, global_skateshop
.selected_board_id
+1, 3 );
649 i
+=highscore_intl( buf
+i
, addon_count(k_workshop_file_type_board
), 3 );
652 font3d_simple_draw( &gui
.font
, 0, buf
, &main_camera
, mmdl
);
655 font3d_simple_draw( &gui
.font
, 0,
656 "Nothing installed", &main_camera
, mmdl
);
659 struct cache_board
*cache_ptr
= skateshop_selected_cache_if_loaded();
662 global_skateshop
.render
.item_title
= "";
663 global_skateshop
.render
.item_desc
= "";
667 if( global_skateshop
.render
.reg_id
!= global_skateshop
.selected_board_id
){
668 global_skateshop
.render
.item_title
= "";
669 global_skateshop
.render
.item_desc
= "";
670 addon_reg
*reg
= cache_ptr
->reg_ptr
;
672 root
.buf
= reg
->metadata
;
673 root
.len
= reg
->metadata_len
;
674 root
.max
= sizeof(reg
->metadata
);
676 vg_msg workshop
= root
;
677 if( vg_msg_seekframe( &workshop
, "workshop", 0 ) ){
678 const char *title
= vg_msg_seekkvstr( &workshop
, "title", 0 );
679 if( title
) global_skateshop
.render
.item_title
= title
;
681 const char *dsc
= vg_msg_seekkvstr( &workshop
, "author", 0 );
682 if( dsc
) global_skateshop
.render
.item_desc
= dsc
;
685 global_skateshop
.render
.reg_id
= global_skateshop
.selected_board_id
;
688 addon_reg
*reg
= cache_ptr
->reg_ptr
;
691 * ----------------------------------------------------------------- */
693 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale
, scale
, thickness
} );
694 mlocal
[3][0] = -font3d_string_width( &gui
.font
, 0,
695 global_skateshop
.render
.item_title
);
696 mlocal
[3][0] *= scale
*0.5f
;
699 m4x3_mul( mtext
, mlocal
, mmdl
);
700 font3d_simple_draw( &gui
.font
, 0, global_skateshop
.render
.item_title
,
701 &main_camera
, mmdl
);
704 * ----------------------------------------------------------------- */
706 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale
, scale
, thickness
} );
707 mlocal
[3][0] = -font3d_string_width( &gui
.font
, 0,
708 global_skateshop
.render
.item_desc
);
709 mlocal
[3][0] *= scale
*0.5f
;
712 m4x3_mul( mtext
, mlocal
, mmdl
);
713 font3d_simple_draw( &gui
.font
, 0, global_skateshop
.render
.item_desc
,
714 &main_camera
, mmdl
);
717 VG_STATIC
void skateshop_render_charshop(void)
721 VG_STATIC
void skateshop_render_worldshop(void)
723 world_instance
*world
= world_current_instance();
725 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
726 ent_marker
*mark_display
= mdl_arritm( &world
->ent_marker
,
727 mdl_entity_id_id(shop
->worlds
.id_display
)),
728 *mark_info
= mdl_arritm( &world
->ent_marker
,
729 mdl_entity_id_id(shop
->boards
.id_info
));
731 if( global_skateshop
.render
.world_reg
!= global_skateshop
.selected_world_id
){
732 global_skateshop
.render
.world_title
= "";
734 addon_reg
*reg
= get_addon_from_index( k_workshop_file_type_world
,
735 global_skateshop
.selected_world_id
);
737 root
.buf
= reg
->metadata
;
738 root
.len
= reg
->metadata_len
;
739 root
.max
= sizeof(reg
->metadata
);
740 vg_msg workshop
= root
;
741 if( vg_msg_seekframe( &workshop
, "workshop", 0 ) ){
742 global_skateshop
.render
.world_title
= vg_msg_seekkvstr( &workshop
,
745 global_skateshop
.render
.world_loc
= vg_msg_seekkvstr(&root
,"location",0);
746 global_skateshop
.render
.world_reg
= global_skateshop
.selected_world_id
;
750 char buftext
[128], bufsubtext
[128];
751 vg_str info
, subtext
;
752 vg_strnull( &info
, buftext
, 128 );
753 vg_strnull( &subtext
, bufsubtext
, 128 );
755 if( addon_count(k_workshop_file_type_world
) ){
756 addon_reg
*reg
= get_addon_from_index( k_workshop_file_type_world
,
757 global_skateshop
.selected_world_id
);
759 info
.i
+=highscore_intl( info
.buffer
+info
.i
,
760 global_skateshop
.selected_world_id
+1, 3 );
761 info
.buffer
[info
.i
++] = '/';
762 info
.i
+=highscore_intl( info
.buffer
+info
.i
,
763 addon_count(k_workshop_file_type_world
), 3 );
764 info
.buffer
[info
.i
++] = ' ';
765 info
.buffer
[info
.i
] = '\0';
767 vg_strcat( &info
, global_skateshop
.render
.world_title
);
768 if( skaterift
.async_op
== k_async_op_world_loading
||
769 skaterift
.async_op
== k_async_op_world_preloading
){
770 vg_strcat( &subtext
, "Loading..." );
773 addon_reg
*reg
= get_addon_from_index( k_workshop_file_type_world
,
774 global_skateshop
.selected_world_id
);
776 if( reg
->workshop_id
)
777 vg_strcat( &subtext
, "(Workshop) " );
779 vg_strcat( &subtext
, global_skateshop
.render
.world_loc
);
783 vg_strcat( &info
, "No worlds installed" );
787 m4x3f mtext
,mlocal
,mtextmdl
;
788 mdl_transform_m4x3( &mark_info
->transform
, mtext
);
790 font3d_bind( &gui
.font
, &main_camera
);
791 shader_model_font_uColour( (v4f
){1.0f
,1.0f
,1.0f
,1.0f
} );
793 float scale
= 0.2f
, thickness
= 0.015f
, scale1
= 0.08f
;
795 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale
, scale
, thickness
} );
796 mlocal
[3][0] = -font3d_string_width( &gui
.font
, 0, buftext
);
797 mlocal
[3][0] *= scale
*0.5f
;
800 m4x3_mul( mtext
, mlocal
, mtextmdl
);
801 font3d_simple_draw( &gui
.font
, 0, buftext
, &main_camera
, mtextmdl
);
803 m3x3_setdiagonalv3( mlocal
, (v3f
){ scale1
, scale1
, thickness
} );
804 mlocal
[3][0] = -font3d_string_width( &gui
.font
, 0, bufsubtext
);
805 mlocal
[3][0] *= scale1
*0.5f
;
806 mlocal
[3][1] = -scale1
*0.3f
;
807 m4x3_mul( mtext
, mlocal
, mtextmdl
);
808 font3d_simple_draw( &gui
.font
, 0, bufsubtext
, &main_camera
, mtextmdl
);
812 mdl_transform_m4x3( &mark_display
->transform
, mmdl
);
813 m4x3_rotate_y( mmdl
, vg
.time
* 0.2 );
816 glBlendFunc(GL_ONE
, GL_ONE
);
817 glDisable(GL_DEPTH_TEST
);
818 pointcloud_render( world
, &main_camera
, mmdl
);
820 glEnable(GL_DEPTH_TEST
);
824 * World: render event
826 VG_STATIC
void skateshop_render(void)
828 if( !global_skateshop
.active
) return;
830 ent_skateshop
*shop
= global_skateshop
.ptr_ent
;
832 if( shop
->type
== k_skateshop_type_boardshop
){
833 skateshop_render_boardshop();
835 else if( shop
->type
== k_skateshop_type_charshop
){
836 skateshop_render_charshop();
838 else if( shop
->type
== k_skateshop_type_worldshop
){
839 skateshop_render_worldshop();
842 vg_fatal_error( "Unknown store (%u)\n", shop
->type
);
847 * Entity logic: entrance event
849 VG_STATIC
void ent_skateshop_call( world_instance
*world
, ent_call
*call
)
851 u32 index
= mdl_entity_id_id( call
->id
);
852 ent_skateshop
*shop
= mdl_arritm( &world
->ent_skateshop
, index
);
853 vg_info( "skateshop_call\n" );
855 if( menu
.active
) return;
856 if( skaterift
.async_op
!= k_async_op_none
) return;
858 if( call
->function
== k_ent_function_trigger
){
859 if( localplayer
.subsystem
!= k_player_subsystem_walk
){
863 vg_info( "Entering skateshop\n" );
865 localplayer
.immobile
= 1;
866 menu
.disable_open
= 1;
867 global_skateshop
.active
= 1;
869 v3_zero( localplayer
.rb
.v
);
870 v3_zero( localplayer
.rb
.w
);
871 localplayer
._walk
.move_speed
= 0.0f
;
872 global_skateshop
.ptr_ent
= shop
;
874 if( shop
->type
== k_skateshop_type_boardshop
){
875 skateshop_update_viewpage();
876 skateshop_op_board_scan();
878 else if( shop
->type
== k_skateshop_type_worldshop
){
879 pointcloud_animate( k_pointcloud_anim_opening
);
880 skateshop_op_world_scan();
886 * Entity logic: exit event
888 VG_STATIC
void global_skateshop_exit(void)
890 vg_info( "exit skateshop\n" );
891 localplayer
.immobile
= 0;
892 global_skateshop
.active
= 0;
893 menu
.disable_open
= 0;
894 srinput
.ignore_input_frames
= 2;
897 #endif /* ENT_SKATESHOP_C */