5 #include "shaders/scene_scoretext.h"
6 #include "shaders/scene_vertex_blend.h"
9 #include "network_common.h"
10 #include "world_routes.h"
12 struct world_sfd world_sfd
;
14 static f32
sfd_encode_glyph( char c
){
16 if( c
>= 'a' && c
<= 'z' )
18 else if( c
>= '0' && c
<= '9' )
20 else if( c
>= 'A' && c
<= 'Z' )
22 else if( c
>= '\x01' && c
<= '\x01'+10 )
28 case '!': value
=base
+0; break;
29 case '?': value
=base
+1; break;
30 case ',': value
=base
+2; break;
31 case '.': value
=base
+3; break;
32 case '#': value
=base
+4; break;
33 case '$': value
=base
+5; break;
34 case '%': value
=base
+6; break;
35 case '*': value
=base
+7; break;
36 case '+': value
=base
+8; break;
37 case '-': value
=base
+9; break;
38 case '/': value
=base
+10; break;
39 case ':': value
=base
+11; break;
40 default: value
=0; break;
47 static void sfd_clear( u32 row
){
48 u32 row_h
= world_sfd
.h
-1 -row
;
49 for( int i
=0; i
<world_sfd
.w
; i
++ ){
50 u32 idx
= (world_sfd
.w
*row_h
+ i
) * 2;
51 world_sfd
.buffer
[idx
] = 0.0f
;
55 void sfd_encode( v2i co
, const char *str
, enum world_sfd_align align
)
57 i32 row_h
= world_sfd
.h
-1 -co
[1];
60 i32 w
= VG_MIN( strlen(str
), world_sfd
.w
);
61 if( align
== k_world_sfd_center
)
62 offset_x
= (world_sfd
.w
- w
) / 2;
63 else if( align
== k_world_sfd_right
)
64 offset_x
= world_sfd
.w
- w
;
68 for( i32 i
=0; i
<world_sfd
.w
; i
++ ){
70 idx
= (world_sfd
.w
*row_h
+ u
) * 2;
72 if( (u
>= world_sfd
.w
) || (u
< 0) )
78 world_sfd
.buffer
[idx
] = sfd_encode_glyph( str
[i
] );
82 void world_sfd_compile_scores( struct leaderboard_cache
*board
,
85 for( u32 i
=0; i
<13; i
++ )
88 sfd_encode( (v2i
){0,0}, title
, k_world_sfd_left
);
91 sfd_encode( (v2i
){-1,4}, "Error out of range", k_world_sfd_center
);
95 if( !network_connected() ){
96 sfd_encode( (v2i
){-1,0}, "Offline", k_world_sfd_right
);
100 if( board
->status
== k_request_status_not_found
){
101 sfd_encode( (v2i
){-1,4}, "No records", k_world_sfd_center
);
105 if( board
->status
!= k_request_status_ok
){
108 vg_strnull( &s
, buf
, 32 );
109 vg_strcat( &s
, "Error: " );
110 vg_strcati32( &s
, board
->status
);
111 sfd_encode( (v2i
){-1,4}, buf
, k_world_sfd_center
);
116 vg_msg_init( &body
, board
->data
, board
->data_len
);
118 const char *alias
= "rows";
120 if( world_sfd
.view_weekly
){
121 alias
= "rows_weekly";
122 sfd_encode( (v2i
){-1,0}, "Weekly", k_world_sfd_right
);
125 sfd_encode( (v2i
){-1,0}, "All-Time", k_world_sfd_right
);
129 if( vg_msg_seekframe( &body
, alias
) ){
130 while( vg_msg_seekframe( &body
, NULL
) ){
132 const char *username
= vg_msg_getkvstr( &body
, "username" );
136 vg_strnull( &str
, buf
, 100 );
137 vg_strcati32( &str
, l
);
138 vg_strcat( &str
, " " );
141 vg_strcat( &str
, username
);
143 vg_strcat( &str
, "??????" );
145 sfd_encode( (v2i
){0,l
}, str
.buffer
, k_world_sfd_left
);
148 vg_strnull( &str
, buf
, 100 );
151 vg_msg_getkvintg( &body
, "time", k_vg_msg_i32
, ¢iseconds
);
153 i32 seconds
= centiseconds
/ 100,
154 minutes
= seconds
/ 60;
159 if( minutes
> 9 ) vg_strcat( &str
, "?" );
160 else vg_strcati32( &str
, minutes
);
161 vg_strcat( &str
, ":" );
162 vg_strcati32r( &str
, seconds
, 2, '0' );
163 vg_strcat( &str
, "." );
164 vg_strcati32r( &str
, centiseconds
, 2, '0' );
165 sfd_encode( (v2i
){-1,l
}, str
.buffer
, k_world_sfd_right
);
168 vg_msg_skip_frame( &body
);
172 sfd_encode( (v2i
){-1,4}, "No records", k_world_sfd_center
);
176 void world_sfd_compile_active_scores(void)
178 world_instance
*world
= world_current_instance();
180 struct leaderboard_cache
*board
= NULL
;
181 const char *name
= "Out of range";
183 if( world_sfd
.active_route_board
< mdl_arrcount( &world
->ent_route
) ){
184 board
= &world
->leaderboard_cache
[ world_sfd
.active_route_board
];
185 ent_route
*route
= mdl_arritm( &world
->ent_route
,
186 world_sfd
.active_route_board
);
187 name
= mdl_pstr( &world
->meta
, route
->pstr_name
);
190 world_sfd_compile_scores( board
, name
);
193 void world_sfd_update( world_instance
*world
, v3f pos
)
195 if( mdl_arrcount( &world
->ent_route
) ){
197 float min_dist
= INFINITY
;
199 for( u32 i
=0; i
<mdl_arrcount( &world
->ent_route
); i
++ ){
200 ent_route
*route
= mdl_arritm( &world
->ent_route
, i
);
201 float dist
= v3_dist2( route
->board_transform
[3], pos
);
203 if( dist
< min_dist
){
209 struct leaderboard_cache
*board
= &world
->leaderboard_cache
[ closest
];
211 /* request new board if cache expires */
212 if( network_connected() ){
213 f64 delta
= vg
.time_real
- board
->cache_time
;
214 if( (delta
> 45.0) || (board
->cache_time
== 0.0) ){
215 board
->cache_time
= vg
.time_real
;
216 ent_route
*route
= mdl_arritm( &world
->ent_route
, closest
);
217 addon_reg
*world_reg
=
218 world_static
.instance_addons
[ world
- world_static
.instances
];
220 char mod_uid
[ ADDON_UID_MAX
];
221 addon_alias_uid( &world_reg
->alias
, mod_uid
);
223 network_request_scoreboard(
225 mdl_pstr( &world
->meta
, route
->pstr_name
),
226 NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK
, closest
);
230 /* compile board text if we changed. */
231 if( world_sfd
.active_route_board
!= closest
){
232 world_sfd_compile_active_scores();
235 world_sfd
.active_route_board
= closest
;
238 for( int i
=0; i
<world_sfd
.w
*world_sfd
.h
; i
++ ){
239 float *target
= &world_sfd
.buffer
[i
*2+0],
240 *cur
= &world_sfd
.buffer
[i
*2+1];
242 float const rate
= vg
.time_delta
* 25.2313131414f
;
243 float d1
= *target
-*cur
;
245 if( fabsf(d1
) > rate
){
255 void bind_terrain_noise(void);
256 void sfd_render( world_instance
*world
, vg_camera
*cam
, m4x3f transform
)
258 mesh_bind( &world_sfd
.mesh_display
);
259 shader_scene_scoretext_use();
260 shader_scene_scoretext_uTexMain(1);
261 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world
, scene_scoretext
);
263 bind_terrain_noise();
265 glActiveTexture( GL_TEXTURE1
);
266 glBindTexture( GL_TEXTURE_2D
, world_sfd
.tex_scoretex
);
269 m4x3_expand( transform
, pvm_prev
);
270 m4x4_mul( cam
->mtx_prev
.pv
, pvm_prev
, pvm_prev
);
272 shader_scene_scoretext_uPv( cam
->mtx
.pv
);
273 shader_scene_scoretext_uPvmPrev( pvm_prev
);
274 shader_scene_scoretext_uMdl( transform
);
275 shader_scene_scoretext_uCamera( cam
->transform
[3] );
277 for( int y
=0;y
<world_sfd
.h
; y
++ ){
278 for( int x
=0; x
<world_sfd
.w
; x
++ ){
279 float value
= world_sfd
.buffer
[(y
*world_sfd
.w
+x
)*2+1];
280 shader_scene_scoretext_uInfo( (v3f
){ x
,y
, value
} );
281 mesh_draw( &world_sfd
.mesh_display
);
285 shader_scene_vertex_blend_use();
286 shader_scene_vertex_blend_uTexGarbage(0);
287 shader_scene_vertex_blend_uTexGradients(1);
288 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world
, scene_vertex_blend
);
290 bind_terrain_noise();
291 glActiveTexture( GL_TEXTURE1
);
292 glBindTexture( GL_TEXTURE_2D
, world_sfd
.tex_scoretex
);
294 shader_scene_vertex_blend_uPv( cam
->mtx
.pv
);
295 shader_scene_vertex_blend_uPvmPrev( pvm_prev
);
296 shader_scene_vertex_blend_uMdl( transform
);
297 shader_scene_vertex_blend_uCamera( cam
->transform
[3] );
299 mesh_bind( &world_sfd
.mesh_base
);
300 mdl_draw_submesh( &world_sfd
.sm_base
);
303 void world_sfd_init(void)
305 vg_info( "world_sfd_init\n" );
306 vg_linear_clear( vg_mem
.scratch
);
308 mdl_context mscoreboard
;
309 mdl_open( &mscoreboard
, "models/rs_scoretext.mdl", vg_mem
.scratch
);
310 mdl_load_metadata_block( &mscoreboard
, vg_mem
.scratch
);
311 mdl_async_load_glmesh( &mscoreboard
, &world_sfd
.mesh_base
, NULL
);
313 mdl_load_mesh_block( &mscoreboard
, vg_mem
.scratch
);
315 scene_context
*scene
= &world_sfd
.scene
;
316 vg_async_item
*call
= scene_alloc_async( scene
, &world_sfd
.mesh_display
,
320 mdl_mesh
*m_backer
= mdl_find_mesh( &mscoreboard
, "backer" ),
321 *m_card
= mdl_find_mesh( &mscoreboard
, "score_card" );
324 *sm_backer
= mdl_arritm( &mscoreboard
.submeshs
, m_backer
->submesh_start
),
325 *sm_card
= mdl_arritm( &mscoreboard
.submeshs
, m_card
->submesh_start
);
326 world_sfd
.sm_base
= *sm_backer
;
329 m4x3_identity( identity
);
331 for( int i
=0;i
<4;i
++ ){
332 u32 vert_start
= scene
->vertex_count
;
333 scene_add_mdl_submesh( scene
, &mscoreboard
, sm_card
, identity
);
335 for( int j
=0; j
<sm_card
->vertex_count
; j
++ ){
336 scene_vert
*vert
= &scene
->arrvertices
[ vert_start
+j
];
338 float const k_glyph_uvw
= 1.0f
/64.0f
;
339 vert
->uv
[0] -= k_glyph_uvw
* (float)(i
-1);
340 vert
->norm
[3] = i
*42;
344 vg_async_dispatch( call
, async_scene_upload
);
345 vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi",
346 VG_TEX2D_CLAMP
|VG_TEX2D_NEAREST
,
347 &world_sfd
.tex_scoretex
);
349 mdl_close( &mscoreboard
);
356 world_sfd
.buffer
= vg_linear_alloc( vg_mem
.rtmemory
, 2*w
*h
*sizeof(float) );
358 for( int i
=0; i
<w
*h
*2; i
++ )
359 world_sfd
.buffer
[i
] = 0.0f
;
362 #endif /* WORLD_SFD_C */