quite a lot of changes
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_skateshop.c
1 #ifndef ENT_SKATESHOP_C
2 #define ENT_SKATESHOP_C
3
4 #define VG_GAME
5 #include "vg/vg.h"
6 #include "vg/vg_steam_ugc.h"
7 #include "vg/vg_msg.h"
8 #include "ent_skateshop.h"
9 #include "world.h"
10 #include "player.h"
11 #include "gui.h"
12 #include "menu.h"
13 #include "pointcloud.h"
14 #include "highscores.h"
15 #include "steam.h"
16 #include "addon.h"
17 #include "save.h"
18
19 /*
20 * Checks string equality but does a hash check first
21 */
22 static inline int const_str_eq( u32 hash, const char *str, const char *cmp )
23 {
24 if( hash == vg_strdjb2(cmp) )
25 if( !strcmp( str, cmp ) )
26 return 1;
27 return 0;
28 }
29
30 VG_STATIC void skateshop_update_viewpage(void){
31 u32 page = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
32
33 for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ ){
34 u32 j = SKATESHOP_VIEW_SLOT_MAX-1-i;
35 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[j];
36 addon_cache_unwatch( k_addon_type_board, slot->cache_id );
37 }
38
39 for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ ){
40 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
41 u32 request_id = page*SKATESHOP_VIEW_SLOT_MAX + i;
42 slot->cache_id = addon_cache_create_viewer( k_addon_type_board,
43 request_id );
44 }
45 }
46
47 /*
48 * op/subroutine: k_workshop_op_item_load
49 * -----------------------------------------------------------------------------
50 */
51
52 VG_STATIC void world_scan_thread( void *_args ){
53 addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
54 addon_mount_workshop_items();
55 vg_async_call( async_addon_reg_update, NULL, 0 );
56 skaterift_end_op();
57 }
58
59 /*
60 * Asynchronous scan of local disk for worlds
61 */
62 VG_STATIC void skateshop_op_world_scan(void){
63 skaterift_begin_op( k_async_op_world_scan );
64 vg_loader_start( world_scan_thread, NULL );
65 }
66
67 VG_STATIC void board_processview_thread( void *_args ){
68 addon_cache_load_loop();
69 skaterift_end_op();
70 }
71
72 VG_STATIC void board_scan_thread( void *_args ){
73 addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
74 addon_mount_workshop_items();
75 vg_async_call( async_addon_reg_update, NULL, 0 );
76 vg_async_stall();
77 board_processview_thread(NULL);
78 }
79
80 VG_STATIC void skateshop_op_board_scan(void){
81 skaterift_begin_op( k_async_op_board_scan );
82 vg_loader_start( board_scan_thread, NULL );
83 }
84
85 VG_STATIC void skateshop_op_processview(void){
86 skaterift_begin_op( k_async_op_board_scan );
87 vg_loader_start( board_processview_thread, NULL );
88 }
89
90 /*
91 * Regular stuff
92 * -----------------------------------------------------------------------------
93 */
94
95 /*
96 * VG event init
97 */
98 VG_STATIC void skateshop_init(void){
99 }
100
101 static u16 skateshop_selected_cache_id(void){
102 if( addon_count(k_addon_type_board) ){
103 addon_reg *reg = get_addon_from_index(k_addon_type_board,
104 global_skateshop.selected_board_id);
105 return reg->cache_id;
106 }
107 else return 0;
108 }
109
110 VG_STATIC void pointcloud_async_end(void *_, u32 __)
111 {
112 pointcloud_animate( k_pointcloud_anim_opening );
113 }
114
115 VG_STATIC void pointcloud_clear_async(void *_, u32 __)
116 {
117 pointcloud.count = 0;
118 pointcloud_animate( k_pointcloud_anim_opening );
119 }
120
121 VG_STATIC void skateshop_world_preview_loader_thread( void *_data )
122 {
123 addon_reg *reg = _data;
124
125 char path_buf[4096];
126 vg_str path;
127 vg_strnull( &path, path_buf, 4096 );
128 addon_get_content_folder( reg, &path );
129 vg_strcat( &path, "/preview.bin" );
130
131 vg_linear_clear(vg_mem.scratch);
132 u32 size;
133
134 void *data = vg_file_read( vg_mem.scratch, path_buf, &size );
135 if( data ){
136 if( size < sizeof(pointcloud_buffer) ){
137 vg_async_call( pointcloud_clear_async, NULL, 0 );
138 return;
139 }
140
141 vg_async_item *call = vg_async_alloc(size);
142 pointcloud_buffer *pcbuf = call->payload;
143 memcpy( pcbuf, data, size );
144
145 u32 point_count = (size-sizeof(pointcloud_buffer)) /
146 sizeof(struct pointcloud_vert);
147 pcbuf->max = point_count;
148 pcbuf->count = point_count;
149 pcbuf->op = k_pointcloud_op_clear;
150
151 vg_async_dispatch( call, async_pointcloud_sub );
152 vg_async_call( pointcloud_async_end, NULL, 0 );
153 }
154 else{
155 vg_async_call( pointcloud_clear_async, NULL, 0 );
156 }
157 }
158
159 VG_STATIC void skateshop_world_preview_loader_thread_and_end( void *_data ){
160 skateshop_world_preview_loader_thread( _data );
161 skaterift_end_op();
162 }
163
164 VG_STATIC void skateshop_load_world_preview( addon_reg *reg )
165 {
166 skaterift_begin_op( k_async_op_world_load_preview );
167 vg_loader_start( skateshop_world_preview_loader_thread_and_end, reg );
168 }
169
170 /*
171 * VG event preupdate
172 */
173 void temp_update_playermodel(void);
174 VG_STATIC void global_skateshop_preupdate(void)
175 {
176 float rate = vg_minf( 1.0f, vg.time_frame_delta * 2.0f );
177 global_skateshop.factive = vg_lerpf( global_skateshop.factive,
178 global_skateshop.active, rate );
179
180 if( !global_skateshop.active ) return;
181
182 world_instance *world = world_current_instance();
183 ent_skateshop *shop = global_skateshop.ptr_ent;
184
185 /* camera positioning */
186 ent_camera *ref = mdl_arritm( &world->ent_camera,
187 mdl_entity_id_id(shop->id_camera) );
188
189 v3f dir = {0.0f,-1.0f,0.0f};
190 mdl_transform_vector( &ref->transform, dir, dir );
191 m3x3_mulv( localplayer.invbasis, dir, dir );
192 player_vector_angles( localplayer.cam_override_angles, dir, 1.0f, 0.0f );
193
194 v3f lookat;
195 if( shop->type == k_skateshop_type_boardshop ||
196 shop->type == k_skateshop_type_worldshop ){
197 ent_marker *display = mdl_arritm( &world->ent_marker,
198 mdl_entity_id_id(shop->boards.id_display) );
199
200 v3_sub( display->transform.co, localplayer.rb.co, lookat );
201
202 }
203 else if( shop->type == k_skateshop_type_charshop ){
204 v3_sub( ref->transform.co, localplayer.rb.co, lookat );
205 }
206 else{
207 vg_fatal_error( "Unknown store (%u)\n", shop->type );
208 }
209
210 q_axis_angle( localplayer.rb.q, (v3f){0.0f,1.0f,0.0f},
211 atan2f(lookat[0],lookat[2]) );
212
213 v3_copy( ref->transform.co, localplayer.cam_override_pos );
214 localplayer.cam_override_fov = ref->fov;
215 localplayer.cam_override_strength = global_skateshop.factive;
216
217 /* input */
218 if( shop->type == k_skateshop_type_boardshop ){
219 if( skaterift.async_op != k_async_op_none ) return;
220
221 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h ), "browse" );
222 gui_helper_action( button_display_string( k_srbind_mback ), "exit" );
223
224 u16 cache_id = skateshop_selected_cache_id();
225 if( cache_id ){
226 gui_helper_action( button_display_string( k_srbind_maccept ), "pick" );
227 }
228
229 /*
230 * Controls
231 * ----------------------
232 */
233 u32 opage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
234
235 if( button_down( k_srbind_mleft ) ){
236 if( global_skateshop.selected_board_id > 0 ){
237 global_skateshop.selected_board_id --;
238 }
239 }
240
241 if( button_down( k_srbind_mright ) ){
242 if( global_skateshop.selected_board_id+1 <
243 addon_count(k_addon_type_board) )
244 {
245 global_skateshop.selected_board_id ++;
246 }
247 }
248
249 u32 npage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
250
251 if( opage != npage ){
252 skateshop_update_viewpage();
253 skateshop_op_processview();
254 }
255 else if( cache_id && button_down( k_srbind_maccept )){
256 vg_info( "chose board from skateshop (%u)\n",
257 global_skateshop.selected_board_id );
258
259 addon_cache_unwatch( k_addon_type_board, localplayer.board_view_slot );
260 addon_cache_watch( k_addon_type_board, cache_id );
261 localplayer.board_view_slot = cache_id;
262
263 global_skateshop_exit();
264 skaterift_write_savedata();
265 return;
266 }
267 }
268 else if( shop->type == k_skateshop_type_charshop ){
269 if( skaterift.async_op != k_async_op_none ) return;
270
271 gui_helper_action( axis_display_string( k_sraxis_mbrowse_h ), "browse" );
272 gui_helper_action( button_display_string( k_srbind_mback ), "exit" );
273 gui_helper_action( button_display_string( k_srbind_maccept ), "pick" );
274
275 int changed = 0;
276
277 if( button_down( k_srbind_mleft ) ){
278 if( global_skateshop.selected_player_id > 0 ){
279 global_skateshop.selected_player_id --;
280 }
281 else{
282 global_skateshop.selected_player_id =
283 addon_count(k_addon_type_player) -1;
284 }
285
286 changed = 1;
287 }
288
289 if( button_down( k_srbind_mright ) ){
290 if( global_skateshop.selected_player_id+1 <
291 addon_count(k_addon_type_player) ){
292 global_skateshop.selected_player_id ++;
293 }
294 else{
295 global_skateshop.selected_player_id = 0;
296 }
297
298 changed = 1;
299 }
300
301 if( changed ){
302 player__use_model( &localplayer, global_skateshop.selected_player_id );
303 skateshop_op_processview();
304 }
305
306 if( button_down( k_srbind_maccept ) ){
307 global_skateshop_exit();
308 }
309 }
310 else if( shop->type == k_skateshop_type_worldshop ){
311 int browseable = 0,
312 loadable = 0;
313
314 if( addon_count(k_addon_type_world) &&
315 ((skaterift.async_op == k_async_op_none)||
316 (skaterift.async_op == k_async_op_world_load_preview))){
317 gui_helper_action( axis_display_string(k_sraxis_mbrowse_h), "browse" );
318 browseable = 1;
319 }
320
321 if( (skaterift.async_op == k_async_op_none) &&
322 global_skateshop.selected_world_id > 0 ){
323 gui_helper_action( button_display_string(k_srbind_maccept),
324 "open rift" );
325 loadable = 1;
326 }
327
328 int change = 0;
329
330 if( browseable ){
331 if( button_down( k_srbind_mleft ) ){
332 if( global_skateshop.selected_world_id > 0 )
333 {
334 global_skateshop.selected_world_id --;
335 change = 1;
336 }
337 }
338
339 if( button_down( k_srbind_mright ) ){
340 if( global_skateshop.selected_world_id+1 <
341 addon_count(k_addon_type_world) )
342 {
343 global_skateshop.selected_world_id ++;
344 change = 1;
345 }
346 }
347 }
348
349 if( change && pointcloud_idle() ){
350 pointcloud_animate( k_pointcloud_anim_hiding );
351 }
352
353 if( skaterift.async_op == k_async_op_none ){
354 addon_reg *reg = get_addon_from_index( k_addon_type_world,
355 global_skateshop.selected_world_id );
356
357 /* automatically load in clouds */
358 if( loadable && button_down( k_srbind_maccept ) ){
359 vg_info( "Select rift (%u)\n",
360 global_skateshop.selected_world_id );
361 world_loader.reg = reg;
362 world_loader.override_name[0] = '\0';
363 skaterift_change_world_start();
364 return;
365 }
366 else{
367 if( pointcloud.anim == k_pointcloud_anim_idle_closed ){
368 if( global_skateshop.pointcloud_world_id !=
369 global_skateshop.selected_world_id )
370 {
371 global_skateshop.pointcloud_world_id =
372 global_skateshop.selected_world_id;
373 skateshop_load_world_preview( reg );
374 }
375 else{
376 pointcloud_animate( k_pointcloud_anim_opening );
377 }
378 }
379 else if( pointcloud.anim == k_pointcloud_anim_idle_open ){
380 if( global_skateshop.pointcloud_world_id !=
381 global_skateshop.selected_world_id )
382 {
383 pointcloud_animate( k_pointcloud_anim_hiding );
384 }
385 }
386 }
387 }
388 }
389 else{
390 vg_fatal_error( "Unknown store (%u)\n", shop->type );
391 }
392
393 if( button_down( k_srbind_mback ) ){
394 global_skateshop_exit();
395 return;
396 }
397 }
398
399 VG_STATIC void skateshop_render_boardshop(void)
400 {
401 world_instance *world = world_current_instance();
402 ent_skateshop *shop = global_skateshop.ptr_ent;
403
404 u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
405
406 ent_marker *mark_rack = mdl_arritm( &world->ent_marker,
407 mdl_entity_id_id(shop->boards.id_rack)),
408 *mark_display = mdl_arritm( &world->ent_marker,
409 mdl_entity_id_id(shop->boards.id_display));
410
411 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
412 struct addon_cache *cache = &addon_system.cache[k_addon_type_board];
413
414 /* Render loaded boards in the view slots */
415 for( u32 i=0; i<slot_count; i++ ){
416 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
417 float selected = 0.0f;
418
419 if( !slot->cache_id )
420 goto fade_out;
421
422 addon_cache_entry *entry = vg_pool_item( &cache->pool, slot->cache_id );
423
424 if( entry->state != k_addon_cache_state_loaded )
425 goto fade_out;
426
427 struct player_board *board =
428 addon_cache_item( k_addon_type_board, slot->cache_id );
429
430 mdl_transform xform;
431 transform_identity( &xform );
432
433 xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
434 mdl_transform_mul( &mark_rack->transform, &xform, &xform );
435
436
437 if( entry->reg_index == global_skateshop.selected_board_id ){
438 selected = 1.0f;
439 }
440
441 float t = slot->view_blend;
442 v3_lerp( xform.co, mark_display->transform.co, t, xform.co );
443 q_nlerp( xform.q, mark_display->transform.q, t, xform.q );
444 v3_lerp( xform.s, mark_display->transform.s, t, xform.s );
445
446 m4x3f mmdl;
447 mdl_transform_m4x3( &xform, mmdl );
448 render_board( &main_camera, world, board, mmdl, k_board_shader_entity );
449
450 fade_out:;
451 float rate = 5.0f*vg.time_delta;
452 slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
453 }
454
455 ent_marker *mark_info = mdl_arritm( &world->ent_marker,
456 mdl_entity_id_id(shop->boards.id_info));
457 m4x3f mtext, mrack;
458 mdl_transform_m4x3( &mark_info->transform, mtext );
459 mdl_transform_m4x3( &mark_rack->transform, mrack );
460
461 #if 0
462 const char *text_title = "Fish - Title";
463 const char *text_author = "by Shaniqua";
464 #endif
465
466 m4x3f mlocal, mmdl;
467 m4x3_identity( mlocal );
468
469 float scale = 0.2f,
470 thickness = 0.03f;
471
472 font3d_bind( &gui.font, &main_camera );
473 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
474
475 /* Selection counter
476 * ------------------------------------------------------------------ */
477 m3x3_zero( mlocal );
478 v3_zero( mlocal[3] );
479 mlocal[0][0] = -scale*2.0f;
480 mlocal[1][2] = -scale*2.0f;
481 mlocal[2][1] = -thickness;
482 mlocal[3][2] = -0.7f;
483 m4x3_mul( mrack, mlocal, mmdl );
484
485 if( addon_count(k_addon_type_board) ){
486 char buf[16];
487 int i=0;
488 i+=highscore_intl( buf+i, global_skateshop.selected_board_id+1, 3 );
489 buf[i++] = '/';
490 i+=highscore_intl( buf+i, addon_count(k_addon_type_board), 3 );
491 buf[i++] = '\0';
492
493 font3d_simple_draw( &gui.font, 0, buf, &main_camera, mmdl );
494 }
495 else{
496 font3d_simple_draw( &gui.font, 0,
497 "Nothing installed", &main_camera, mmdl );
498 }
499
500 u16 cache_id = skateshop_selected_cache_id();
501 struct addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
502 addon_reg *reg = NULL;
503
504 if( entry ) reg = entry->reg_ptr;
505
506 if( !reg ){
507 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
508 global_skateshop.render.item_title = "";
509 global_skateshop.render.item_desc = "";
510 return;
511 }
512
513 if( global_skateshop.render.reg_id != global_skateshop.selected_board_id ){
514 global_skateshop.render.item_title = "";
515 global_skateshop.render.item_desc = "";
516 vg_msg root = {0};
517 root.buf = reg->metadata;
518 root.len = reg->metadata_len;
519 root.max = sizeof(reg->metadata);
520
521 vg_msg workshop = root;
522 if( vg_msg_seekframe( &workshop, "workshop", 0 ) ){
523 const char *title = vg_msg_seekkvstr( &workshop, "title", 0 );
524 if( title ) global_skateshop.render.item_title = title;
525
526 const char *dsc = vg_msg_seekkvstr( &workshop, "author", 0 );
527 if( dsc ) global_skateshop.render.item_desc = dsc;
528 }
529
530 global_skateshop.render.reg_id = global_skateshop.selected_board_id;
531 }
532
533 /* Skin title
534 * ----------------------------------------------------------------- */
535 m3x3_zero( mlocal );
536 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
537 mlocal[3][0] = -font3d_string_width( &gui.font, 0,
538 global_skateshop.render.item_title );
539 mlocal[3][0] *= scale*0.5f;
540 mlocal[3][1] = 0.1f;
541 mlocal[3][2] = 0.0f;
542 m4x3_mul( mtext, mlocal, mmdl );
543 font3d_simple_draw( &gui.font, 0, global_skateshop.render.item_title,
544 &main_camera, mmdl );
545
546 /* Author name
547 * ----------------------------------------------------------------- */
548 scale *= 0.4f;
549 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
550 mlocal[3][0] = -font3d_string_width( &gui.font, 0,
551 global_skateshop.render.item_desc );
552 mlocal[3][0] *= scale*0.5f;
553 mlocal[3][1] = 0.0f;
554 mlocal[3][2] = 0.0f;
555 m4x3_mul( mtext, mlocal, mmdl );
556 font3d_simple_draw( &gui.font, 0, global_skateshop.render.item_desc,
557 &main_camera, mmdl );
558
559 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
560 }
561
562 VG_STATIC void skateshop_render_charshop(void)
563 {
564 }
565
566 VG_STATIC void skateshop_render_worldshop(void)
567 {
568 world_instance *world = world_current_instance();
569
570 ent_skateshop *shop = global_skateshop.ptr_ent;
571 ent_marker *mark_display = mdl_arritm( &world->ent_marker,
572 mdl_entity_id_id(shop->worlds.id_display)),
573 *mark_info = mdl_arritm( &world->ent_marker,
574 mdl_entity_id_id(shop->boards.id_info));
575
576 if( global_skateshop.render.world_reg != global_skateshop.selected_world_id){
577 global_skateshop.render.world_title = "";
578
579 addon_reg *reg = get_addon_from_index( k_addon_type_world,
580 global_skateshop.selected_world_id );
581 vg_msg root = {0};
582 root.buf = reg->metadata;
583 root.len = reg->metadata_len;
584 root.max = sizeof(reg->metadata);
585 vg_msg workshop = root;
586 if( vg_msg_seekframe( &workshop, "workshop", 0 ) ){
587 global_skateshop.render.world_title = vg_msg_seekkvstr( &workshop,
588 "title", 0 );
589 }
590 global_skateshop.render.world_loc = vg_msg_seekkvstr(&root,"location",0);
591 global_skateshop.render.world_reg = global_skateshop.selected_world_id;
592 }
593
594 /* Text */
595 char buftext[128], bufsubtext[128];
596 vg_str info, subtext;
597 vg_strnull( &info, buftext, 128 );
598 vg_strnull( &subtext, bufsubtext, 128 );
599
600 if( addon_count(k_addon_type_world) ){
601 addon_reg *reg = get_addon_from_index( k_addon_type_world,
602 global_skateshop.selected_world_id );
603
604 info.i+=highscore_intl( info.buffer+info.i,
605 global_skateshop.selected_world_id+1, 3 );
606 info.buffer[info.i++] = '/';
607 info.i+=highscore_intl( info.buffer+info.i,
608 addon_count(k_addon_type_world), 3 );
609 info.buffer[info.i++] = ' ';
610 info.buffer[info.i] = '\0';
611
612 vg_strcat( &info, global_skateshop.render.world_title );
613 if( skaterift.async_op == k_async_op_world_loading ||
614 skaterift.async_op == k_async_op_world_preloading ){
615 vg_strcat( &subtext, "Loading..." );
616 }
617 else{
618 addon_reg *reg = get_addon_from_index( k_addon_type_world,
619 global_skateshop.selected_world_id );
620
621 if( reg->alias.workshop_id )
622 vg_strcat( &subtext, "(Workshop) " );
623
624 vg_strcat( &subtext, global_skateshop.render.world_loc );
625 }
626 }
627 else{
628 vg_strcat( &info, "No worlds installed" );
629 }
630
631
632 m4x3f mtext,mlocal,mtextmdl;
633 mdl_transform_m4x3( &mark_info->transform, mtext );
634
635 font3d_bind( &gui.font, &main_camera );
636 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
637
638 float scale = 0.2f, thickness = 0.015f, scale1 = 0.08f;
639 m3x3_zero( mlocal );
640 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
641 mlocal[3][0] = -font3d_string_width( &gui.font, 0, buftext );
642 mlocal[3][0] *= scale*0.5f;
643 mlocal[3][1] = 0.1f;
644 mlocal[3][2] = 0.0f;
645 m4x3_mul( mtext, mlocal, mtextmdl );
646 font3d_simple_draw( &gui.font, 0, buftext, &main_camera, mtextmdl );
647
648 m3x3_setdiagonalv3( mlocal, (v3f){ scale1, scale1, thickness } );
649 mlocal[3][0] = -font3d_string_width( &gui.font, 0, bufsubtext );
650 mlocal[3][0] *= scale1*0.5f;
651 mlocal[3][1] = -scale1*0.3f;
652 m4x3_mul( mtext, mlocal, mtextmdl );
653 font3d_simple_draw( &gui.font, 0, bufsubtext, &main_camera, mtextmdl );
654
655 /* pointcloud */
656 m4x3f mmdl;
657 mdl_transform_m4x3( &mark_display->transform, mmdl );
658 m4x3_rotate_y( mmdl, vg.time * 0.2 );
659
660 glEnable(GL_BLEND);
661 glBlendFunc(GL_ONE, GL_ONE);
662 glDisable(GL_DEPTH_TEST);
663 pointcloud_render( world, &main_camera, mmdl );
664 glDisable(GL_BLEND);
665 glEnable(GL_DEPTH_TEST);
666 }
667
668 /*
669 * World: render event
670 */
671 VG_STATIC void skateshop_render(void)
672 {
673 if( !global_skateshop.active ) return;
674
675 ent_skateshop *shop = global_skateshop.ptr_ent;
676
677 if( shop->type == k_skateshop_type_boardshop ){
678 skateshop_render_boardshop();
679 }
680 else if( shop->type == k_skateshop_type_charshop ){
681 skateshop_render_charshop();
682 }
683 else if( shop->type == k_skateshop_type_worldshop ){
684 skateshop_render_worldshop();
685 }
686 else{
687 vg_fatal_error( "Unknown store (%u)\n", shop->type );
688 }
689 }
690
691 /*
692 * Entity logic: entrance event
693 */
694 VG_STATIC void ent_skateshop_call( world_instance *world, ent_call *call )
695 {
696 u32 index = mdl_entity_id_id( call->id );
697 ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, index );
698 vg_info( "skateshop_call\n" );
699
700 if( menu.active ) return;
701 if( skaterift.async_op != k_async_op_none ) return;
702
703 if( call->function == k_ent_function_trigger ){
704 if( localplayer.subsystem != k_player_subsystem_walk ){
705 return;
706 }
707
708 vg_info( "Entering skateshop\n" );
709
710 localplayer.immobile = 1;
711 menu.disable_open = 1;
712 global_skateshop.active = 1;
713
714 v3_zero( localplayer.rb.v );
715 v3_zero( localplayer.rb.w );
716 localplayer._walk.move_speed = 0.0f;
717 global_skateshop.ptr_ent = shop;
718
719 if( shop->type == k_skateshop_type_boardshop ){
720 skateshop_update_viewpage();
721 skateshop_op_board_scan();
722 }
723 else if( shop->type == k_skateshop_type_charshop ){
724
725 }
726 else if( shop->type == k_skateshop_type_worldshop ){
727 pointcloud_animate( k_pointcloud_anim_opening );
728 skateshop_op_world_scan();
729 }
730 }
731 }
732
733 /*
734 * Entity logic: exit event
735 */
736 VG_STATIC void global_skateshop_exit(void)
737 {
738 vg_info( "exit skateshop\n" );
739 localplayer.immobile = 0;
740 global_skateshop.active = 0;
741 menu.disable_open = 0;
742 srinput.ignore_input_frames = 2;
743 }
744
745 #endif /* ENT_SKATESHOP_C */