chaos pt 1
[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 "highscores.h"
14 #include "steam.h"
15 #include "addon.h"
16 #include "save.h"
17 #include "network.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 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 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 }
57
58 /*
59 * Asynchronous scan of local disk for worlds
60 */
61 static void skateshop_op_world_scan(void){
62 vg_loader_start( world_scan_thread, NULL );
63 }
64
65 static void board_processview_thread( void *_args ){
66 addon_cache_load_loop();
67 }
68
69 static void board_scan_thread( void *_args ){
70 addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
71 addon_mount_workshop_items();
72 vg_async_call( async_addon_reg_update, NULL, 0 );
73 vg_async_stall();
74 board_processview_thread(NULL);
75 }
76
77 /* TODO: migrate to addon.c */
78 static void skateshop_op_board_scan(void){
79 vg_loader_start( board_scan_thread, NULL );
80 }
81
82 /* TODO: migrate to addon.c */
83 static void skateshop_autostart_loading(void){
84 if( !vg_loader_availible() ) return;
85
86 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
87 for( u32 type=0; type<k_addon_type_max; type++ ){
88 struct addon_cache *cache = &addon_system.cache[type];
89
90 for( u32 id=1; id<=cache->pool.count; id++ ){
91 addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
92 if( entry->state == k_addon_cache_state_load_request ){
93 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
94 goto launch;
95 }
96 }
97 }
98 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
99 return;
100 launch:
101 vg_loader_start( board_processview_thread, NULL );
102 }
103
104 /*
105 * Regular stuff
106 * -----------------------------------------------------------------------------
107 */
108
109 /*
110 * VG event init
111 */
112 static void skateshop_init(void){
113 }
114
115 static u16 skateshop_selected_cache_id(void){
116 if( addon_count(k_addon_type_board) ){
117 addon_reg *reg = get_addon_from_index(k_addon_type_board,
118 global_skateshop.selected_board_id);
119 return reg->cache_id;
120 }
121 else return 0;
122 }
123
124 /*
125 * VG event preupdate
126 */
127 void temp_update_playermodel(void);
128 static void ent_skateshop_preupdate( ent_skateshop *shop, int active ){
129 if( !active ) return;
130
131 /* input filter */
132 world_instance *world = world_current_instance();
133
134 /* camera positioning */
135 ent_camera *ref = mdl_arritm( &world->ent_camera,
136 mdl_entity_id_id(shop->id_camera) );
137
138 v3f dir = {0.0f,-1.0f,0.0f};
139 mdl_transform_vector( &ref->transform, dir, dir );
140 m3x3_mulv( localplayer.invbasis, dir, dir );
141 player_vector_angles( world_static.focus_cam.angles, dir, 1.0f, 0.0f );
142
143 v3f lookat;
144 if( shop->type == k_skateshop_type_boardshop ||
145 shop->type == k_skateshop_type_worldshop ){
146 ent_marker *display = mdl_arritm( &world->ent_marker,
147 mdl_entity_id_id(shop->boards.id_display) );
148 v3_sub( display->transform.co, localplayer.rb.co, lookat );
149 }
150 else if( shop->type == k_skateshop_type_charshop )
151 v3_sub( ref->transform.co, localplayer.rb.co, lookat );
152 else
153 vg_fatal_error( "Unknown store (%u)\n", shop->type );
154
155 q_axis_angle( localplayer.rb.q, (v3f){0.0f,1.0f,0.0f},
156 atan2f(lookat[0],lookat[2]) );
157
158 v3_copy( ref->transform.co, world_static.focus_cam.pos );
159 world_static.focus_cam.fov = ref->fov;
160
161 /* input */
162 if( shop->type == k_skateshop_type_boardshop ){
163 if( !vg_loader_availible() ) return;
164
165 u16 cache_id = skateshop_selected_cache_id();
166 global_skateshop.helper_pick->greyed = !cache_id;
167
168 /*
169 * Controls
170 * ----------------------
171 */
172 u32 opage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
173
174 if( button_down( k_srbind_mleft ) ){
175 if( global_skateshop.selected_board_id > 0 ){
176 global_skateshop.selected_board_id --;
177 }
178 }
179
180 if( button_down( k_srbind_mright ) ){
181 if( global_skateshop.selected_board_id+1 <
182 addon_count(k_addon_type_board) )
183 {
184 global_skateshop.selected_board_id ++;
185 }
186 }
187
188 u32 npage = global_skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
189
190 if( opage != npage ){
191 skateshop_update_viewpage();
192 //skateshop_op_processview();
193 }
194 else if( cache_id && button_down( k_srbind_maccept )){
195 vg_info( "chose board from skateshop (%u)\n",
196 global_skateshop.selected_board_id );
197
198 addon_cache_unwatch( k_addon_type_board, localplayer.board_view_slot );
199 addon_cache_watch( k_addon_type_board, cache_id );
200 localplayer.board_view_slot = cache_id;
201 network_send_item( k_netmsg_playeritem_board );
202
203 world_entity_unfocus();
204 gui_helper_clear();
205 skaterift_autosave(1);
206 return;
207 }
208 }
209 else if( shop->type == k_skateshop_type_charshop ){
210 if( !vg_loader_availible() ) return;
211
212 int changed = 0;
213
214 if( button_down( k_srbind_mleft ) ){
215 if( global_skateshop.selected_player_id > 0 ){
216 global_skateshop.selected_player_id --;
217 }
218 else{
219 global_skateshop.selected_player_id =
220 addon_count(k_addon_type_player) -1;
221 }
222
223 changed = 1;
224 }
225
226 if( button_down( k_srbind_mright ) ){
227 if( global_skateshop.selected_player_id+1 <
228 addon_count(k_addon_type_player) ){
229 global_skateshop.selected_player_id ++;
230 }
231 else{
232 global_skateshop.selected_player_id = 0;
233 }
234
235 changed = 1;
236 }
237
238 if( changed ){
239 player__use_model( global_skateshop.selected_player_id );
240 //skateshop_op_processview();
241 }
242
243 if( button_down( k_srbind_maccept ) ){
244 network_send_item( k_netmsg_playeritem_player );
245 world_entity_unfocus();
246 gui_helper_clear();
247 }
248 }
249 else if( shop->type == k_skateshop_type_worldshop ){
250 int browseable = 0,
251 loadable = 0;
252
253 if( addon_count(k_addon_type_world) && vg_loader_availible() )
254 browseable = 1;
255
256 if( vg_loader_availible() && global_skateshop.selected_world_id > 0 )
257 loadable = 1;
258
259 global_skateshop.helper_browse->greyed = !browseable;
260 global_skateshop.helper_pick->greyed = !loadable;
261
262 int change = 0;
263
264 if( browseable ){
265 if( button_down( k_srbind_mleft ) ){
266 if( global_skateshop.selected_world_id > 0 ){
267 global_skateshop.selected_world_id --;
268 change = 1;
269 }
270 }
271
272 if( button_down( k_srbind_mright ) ){
273 if( global_skateshop.selected_world_id+1 <
274 addon_count(k_addon_type_world) )
275 {
276 global_skateshop.selected_world_id ++;
277 change = 1;
278 }
279 }
280 }
281
282 #if 0
283 if( change && pointcloud_idle() ){
284 pointcloud_animate( k_pointcloud_anim_hiding );
285 }
286
287 if( vg_loader_availible() ){
288 addon_reg *reg = get_addon_from_index( k_addon_type_world,
289 global_skateshop.selected_world_id );
290
291 /* automatically load in clouds */
292 if( loadable && button_down( k_srbind_maccept ) ){
293 vg_info( "Select rift (%u)\n",
294 global_skateshop.selected_world_id );
295 skaterift_change_world_start( reg );
296 return;
297 }
298 else{
299 if( pointcloud.anim == k_pointcloud_anim_idle_closed ){
300 if( global_skateshop.pointcloud_world_id !=
301 global_skateshop.selected_world_id )
302 {
303 global_skateshop.pointcloud_world_id =
304 global_skateshop.selected_world_id;
305 skateshop_load_world_preview( reg );
306 }
307 else{
308 pointcloud_animate( k_pointcloud_anim_opening );
309 }
310 }
311 else if( pointcloud.anim == k_pointcloud_anim_idle_open ){
312 if( global_skateshop.pointcloud_world_id !=
313 global_skateshop.selected_world_id )
314 {
315 pointcloud_animate( k_pointcloud_anim_hiding );
316 }
317 }
318 }
319 }
320 #endif
321 }
322 else{
323 vg_fatal_error( "Unknown store (%u)\n", shop->type );
324 }
325
326 if( button_down( k_srbind_mback ) ){
327 if( shop->type == k_skateshop_type_charshop )
328 network_send_item( k_netmsg_playeritem_player );
329
330 world_entity_unfocus();
331 gui_helper_clear();
332 return;
333 }
334 }
335
336 static void skateshop_render_boardshop( ent_skateshop *shop ){
337 world_instance *world = world_current_instance();
338 u32 slot_count = vg_list_size(global_skateshop.shop_view_slots);
339
340 ent_marker *mark_rack = mdl_arritm( &world->ent_marker,
341 mdl_entity_id_id(shop->boards.id_rack)),
342 *mark_display = mdl_arritm( &world->ent_marker,
343 mdl_entity_id_id(shop->boards.id_display));
344
345 SDL_AtomicLock( &addon_system.sl_cache_using_resources );
346 struct addon_cache *cache = &addon_system.cache[k_addon_type_board];
347
348 /* Render loaded boards in the view slots */
349 for( u32 i=0; i<slot_count; i++ ){
350 struct shop_view_slot *slot = &global_skateshop.shop_view_slots[i];
351 float selected = 0.0f;
352
353 if( !slot->cache_id )
354 goto fade_out;
355
356 addon_cache_entry *entry = vg_pool_item( &cache->pool, slot->cache_id );
357
358 if( entry->state != k_addon_cache_state_loaded )
359 goto fade_out;
360
361 struct player_board *board =
362 addon_cache_item( k_addon_type_board, slot->cache_id );
363
364 mdl_transform xform;
365 transform_identity( &xform );
366
367 xform.co[0] = -((float)i - ((float)slot_count)*0.5f)*0.45f;
368 mdl_transform_mul( &mark_rack->transform, &xform, &xform );
369
370
371 if( entry->reg_index == global_skateshop.selected_board_id ){
372 selected = 1.0f;
373 }
374
375 float t = slot->view_blend;
376 v3_lerp( xform.co, mark_display->transform.co, t, xform.co );
377 q_nlerp( xform.q, mark_display->transform.q, t, xform.q );
378 v3_lerp( xform.s, mark_display->transform.s, t, xform.s );
379
380 struct player_board_pose pose = {0};
381 m4x3f mmdl;
382 mdl_transform_m4x3( &xform, mmdl );
383 render_board( &skaterift.cam, world, board, mmdl,
384 &pose, k_board_shader_entity );
385
386 fade_out:;
387 float rate = 5.0f*vg.time_delta;
388 slot->view_blend = vg_lerpf( slot->view_blend, selected, rate );
389 }
390
391 ent_marker *mark_info = mdl_arritm( &world->ent_marker,
392 mdl_entity_id_id(shop->boards.id_info));
393 m4x3f mtext, mrack;
394 mdl_transform_m4x3( &mark_info->transform, mtext );
395 mdl_transform_m4x3( &mark_rack->transform, mrack );
396
397 #if 0
398 const char *text_title = "Fish - Title";
399 const char *text_author = "by Shaniqua";
400 #endif
401
402 m4x3f mlocal, mmdl;
403 m4x3_identity( mlocal );
404
405 float scale = 0.2f,
406 thickness = 0.03f;
407
408 font3d_bind( &gui.font, k_font_shader_default, 0, world, &skaterift.cam );
409 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
410
411 /* Selection counter
412 * ------------------------------------------------------------------ */
413 m3x3_zero( mlocal );
414 v3_zero( mlocal[3] );
415 mlocal[0][0] = -scale*2.0f;
416 mlocal[1][2] = -scale*2.0f;
417 mlocal[2][1] = -thickness;
418 mlocal[3][2] = -0.7f;
419 m4x3_mul( mrack, mlocal, mmdl );
420
421 if( addon_count(k_addon_type_board) ){
422 char buf[16];
423 int i=0;
424 i+=highscore_intl( buf+i, global_skateshop.selected_board_id+1, 3 );
425 buf[i++] = '/';
426 i+=highscore_intl( buf+i, addon_count(k_addon_type_board), 3 );
427 buf[i++] = '\0';
428
429 font3d_simple_draw( 0, buf, &skaterift.cam, mmdl );
430 }
431 else{
432 font3d_simple_draw( 0, "Nothing installed", &skaterift.cam, mmdl );
433 }
434
435 u16 cache_id = skateshop_selected_cache_id();
436 struct addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
437 addon_reg *reg = NULL;
438
439 if( entry ) reg = entry->reg_ptr;
440
441 if( !reg ){
442 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
443 global_skateshop.render.item_title = "";
444 global_skateshop.render.item_desc = "";
445 return;
446 }
447
448 if( global_skateshop.render.reg_id != global_skateshop.selected_board_id ){
449 global_skateshop.render.item_title = "";
450 global_skateshop.render.item_desc = "";
451 vg_msg msg;
452 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
453
454 if( vg_msg_seekframe( &msg, "workshop" ) ){
455 const char *title = vg_msg_getkvstr( &msg, "title" );
456 if( title ) global_skateshop.render.item_title = title;
457
458 const char *dsc = vg_msg_getkvstr( &msg, "author" );
459 if( dsc ) global_skateshop.render.item_desc = dsc;
460 vg_msg_skip_frame( &msg );
461 }
462
463 global_skateshop.render.reg_id = global_skateshop.selected_board_id;
464 }
465
466 /* Skin title
467 * ----------------------------------------------------------------- */
468 m3x3_zero( mlocal );
469 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
470 mlocal[3][0] = -font3d_string_width( 0, global_skateshop.render.item_title );
471 mlocal[3][0] *= scale*0.5f;
472 mlocal[3][1] = 0.1f;
473 mlocal[3][2] = 0.0f;
474 m4x3_mul( mtext, mlocal, mmdl );
475 font3d_simple_draw( 0, global_skateshop.render.item_title,
476 &skaterift.cam, mmdl );
477
478 /* Author name
479 * ----------------------------------------------------------------- */
480 scale *= 0.4f;
481 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
482 mlocal[3][0] = -font3d_string_width( 0, global_skateshop.render.item_desc );
483 mlocal[3][0] *= scale*0.5f;
484 mlocal[3][1] = 0.0f;
485 mlocal[3][2] = 0.0f;
486 m4x3_mul( mtext, mlocal, mmdl );
487 font3d_simple_draw( 0, global_skateshop.render.item_desc,
488 &skaterift.cam, mmdl );
489
490 SDL_AtomicUnlock( &addon_system.sl_cache_using_resources );
491 }
492
493 static void skateshop_render_charshop( ent_skateshop *shop ){
494 }
495
496 static void skateshop_render_worldshop( ent_skateshop *shop ){
497 world_instance *world = world_current_instance();
498
499 ent_marker *mark_display = mdl_arritm( &world->ent_marker,
500 mdl_entity_id_id(shop->worlds.id_display)),
501 *mark_info = mdl_arritm( &world->ent_marker,
502 mdl_entity_id_id(shop->boards.id_info));
503
504 if( global_skateshop.render.world_reg != global_skateshop.selected_world_id){
505 global_skateshop.render.world_title = "";
506
507 addon_reg *reg = get_addon_from_index( k_addon_type_world,
508 global_skateshop.selected_world_id );
509 vg_msg msg;
510 vg_msg_init( &msg, reg->metadata, reg->metadata_len );
511 global_skateshop.render.world_loc = vg_msg_getkvstr( &msg, "location" );
512 global_skateshop.render.world_reg = global_skateshop.selected_world_id;
513
514 if( vg_msg_seekframe( &msg, "workshop" ) ){
515 global_skateshop.render.world_title = vg_msg_getkvstr( &msg, "title");
516 vg_msg_skip_frame( &msg );
517 }
518 }
519
520 /* Text */
521 char buftext[128], bufsubtext[128];
522 vg_str info, subtext;
523 vg_strnull( &info, buftext, 128 );
524 vg_strnull( &subtext, bufsubtext, 128 );
525
526 if( addon_count(k_addon_type_world) ){
527 addon_reg *reg = get_addon_from_index( k_addon_type_world,
528 global_skateshop.selected_world_id );
529
530 info.i+=highscore_intl( info.buffer+info.i,
531 global_skateshop.selected_world_id+1, 3 );
532 info.buffer[info.i++] = '/';
533 info.i+=highscore_intl( info.buffer+info.i,
534 addon_count(k_addon_type_world), 3 );
535 info.buffer[info.i++] = ' ';
536 info.buffer[info.i] = '\0';
537
538 vg_strcat( &info, global_skateshop.render.world_title );
539 if( !vg_loader_availible() ){
540 vg_strcat( &subtext, "Loading..." );
541 }
542 else{
543 addon_reg *reg = get_addon_from_index( k_addon_type_world,
544 global_skateshop.selected_world_id );
545
546 if( reg->alias.workshop_id )
547 vg_strcat( &subtext, "(Workshop) " );
548
549 vg_strcat( &subtext, global_skateshop.render.world_loc );
550 }
551 }
552 else{
553 vg_strcat( &info, "No worlds installed" );
554 }
555
556
557 m4x3f mtext,mlocal,mtextmdl;
558 mdl_transform_m4x3( &mark_info->transform, mtext );
559
560 font3d_bind( &gui.font, k_font_shader_default, 0, NULL, &skaterift.cam );
561 shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
562
563 float scale = 0.2f, thickness = 0.015f, scale1 = 0.08f;
564 m3x3_zero( mlocal );
565 m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
566 mlocal[3][0] = -font3d_string_width( 0, buftext );
567 mlocal[3][0] *= scale*0.5f;
568 mlocal[3][1] = 0.1f;
569 mlocal[3][2] = 0.0f;
570 m4x3_mul( mtext, mlocal, mtextmdl );
571 font3d_simple_draw( 0, buftext, &skaterift.cam, mtextmdl );
572
573 m3x3_setdiagonalv3( mlocal, (v3f){ scale1, scale1, thickness } );
574 mlocal[3][0] = -font3d_string_width( 0, bufsubtext );
575 mlocal[3][0] *= scale1*0.5f;
576 mlocal[3][1] = -scale1*0.3f;
577 m4x3_mul( mtext, mlocal, mtextmdl );
578 font3d_simple_draw( 0, bufsubtext, &skaterift.cam, mtextmdl );
579
580 #if 0
581 /* pointcloud */
582 m4x3f mmdl;
583 mdl_transform_m4x3( &mark_display->transform, mmdl );
584 m4x3_rotate_y( mmdl, vg.time * 0.2 );
585
586 glEnable(GL_BLEND);
587 glBlendFunc(GL_ONE, GL_ONE);
588 glDisable(GL_DEPTH_TEST);
589 pointcloud_render( world, &skaterift.cam, mmdl );
590 glDisable(GL_BLEND);
591 glEnable(GL_DEPTH_TEST);
592 #endif
593 }
594
595 /*
596 * World: render event
597 */
598 static void skateshop_render( ent_skateshop *shop ){
599 if( shop->type == k_skateshop_type_boardshop )
600 skateshop_render_boardshop( shop );
601 else if( shop->type == k_skateshop_type_charshop )
602 skateshop_render_charshop( shop );
603 else if( shop->type == k_skateshop_type_worldshop )
604 skateshop_render_worldshop( shop );
605 else
606 vg_fatal_error( "Unknown store (%u)\n", shop->type );
607 }
608
609 static void ent_skateshop_helpers_pickable( const char *acceptance ){
610 vg_str text;
611
612 if( gui_new_helper( input_button_list[k_srbind_mback], &text ))
613 vg_strcat( &text, "exit" );
614
615 if( (global_skateshop.helper_pick = gui_new_helper(
616 input_button_list[k_srbind_maccept], &text))){
617 vg_strcat( &text, acceptance );
618 }
619
620 if( (global_skateshop.helper_browse = gui_new_helper(
621 input_axis_list[k_sraxis_mbrowse_h], &text ))){
622 vg_strcat( &text, "browse" );
623 }
624 }
625
626 /*
627 * Entity logic: entrance event
628 */
629 static void ent_skateshop_call( world_instance *world, ent_call *call ){
630 u32 index = mdl_entity_id_id( call->id );
631 ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, index );
632 vg_info( "skateshop_call\n" );
633
634 if( skaterift.activity != k_skaterift_default ) return;
635 if( !vg_loader_availible() ) return;
636
637 if( call->function == k_ent_function_trigger ){
638 if( localplayer.subsystem != k_player_subsystem_walk ) return;
639
640 vg_info( "Entering skateshop\n" );
641
642 world_entity_focus( call->id );
643 gui_helper_clear();
644
645 if( shop->type == k_skateshop_type_boardshop ){
646 skateshop_update_viewpage();
647 skateshop_op_board_scan();
648 ent_skateshop_helpers_pickable( "pick" );
649 }
650 else if( shop->type == k_skateshop_type_charshop ){
651 ent_skateshop_helpers_pickable( "pick" );
652 }
653 else if( shop->type == k_skateshop_type_worldshop ){
654 ent_skateshop_helpers_pickable( "open rift" );
655 skateshop_op_world_scan();
656 }
657 }
658 }
659
660 #endif /* ENT_SKATESHOP_C */