minor changes
[carveJwlIkooP6JGAAIwe30JlM.git] / world_sfd.c
1 #ifndef SFD_C
2 #define SFD_C
3
4 #include "world_sfd.h"
5 #include "shaders/scene_scoretext.h"
6 #include "shaders/scene_vertex_blend.h"
7 #include "network.h"
8 #include "entity.h"
9 #include "network_common.h"
10 #include "world_routes.h"
11
12 static f32 sfd_encode_glyph( char c ){
13 int value = 0;
14 if( c >= 'a' && c <= 'z' )
15 value = c-'a'+11;
16 else if( c >= '0' && c <= '9' )
17 value = c-'0'+1;
18 else if( c >= 'A' && c <= 'Z' )
19 value = c-'A'+11;
20 else if( c >= '\x01' && c <= '\x01'+10 )
21 value = 63-c;
22 else{
23 int base = 11+26;
24
25 switch( c ){
26 case '!': value=base+0; break;
27 case '?': value=base+1; break;
28 case ',': value=base+2; break;
29 case '.': value=base+3; break;
30 case '#': value=base+4; break;
31 case '$': value=base+5; break;
32 case '%': value=base+6; break;
33 case '*': value=base+7; break;
34 case '+': value=base+8; break;
35 case '-': value=base+9; break;
36 case '/': value=base+10; break;
37 case ':': value=base+11; break;
38 default: value=0; break;
39 }
40 }
41
42 return (float)value;
43 }
44
45 static void sfd_encode( u32 row, const char *str ){
46 int end=0;
47 u32 row_h = world_sfd.h -1 -row;
48
49 for( int i=0; i<world_sfd.w; i++ ){
50 u32 idx = (world_sfd.w*row_h + i) * 2;
51
52 if( end ){
53 world_sfd.buffer[idx] = 0.0f;
54 }
55 else{
56 if( !str[i] )
57 end = 1;
58
59 world_sfd.buffer[idx] = sfd_encode_glyph( str[i] );
60 }
61 }
62 }
63
64 static void world_sfd_compile_scores( struct leaderboard_cache *board ){
65 for( u32 i=0; i<13; i++ )
66 sfd_encode( i, "" );
67
68 if( !board ){
69 sfd_encode( 4, "Error out of range" );
70 return;
71 }
72
73 if( !network_client.remote ){
74 sfd_encode( 4, "Offline" );
75 return;
76 }
77
78 if( board->status == k_request_status_not_found ){
79 sfd_encode( 4, "No records" );
80 return;
81 }
82
83 if( board->status != k_request_status_ok ){
84 char buf[32];
85 vg_str s;
86 vg_strnull( &s, buf, 32 );
87 vg_strcat( &s, "Error: " );
88 vg_strcati32( &s, board->status );
89 sfd_encode( 4, buf );
90 return;
91 }
92
93 vg_msg body;
94 vg_msg_init( &body, board->data, board->data_len );
95
96 const char *alias = "rows";
97
98 if( world_sfd.view_weekly ){
99 alias = "rows_weekly";
100 sfd_encode( 0, "Weekly" );
101 }
102 else {
103 sfd_encode( 0, "All-Time" );
104 }
105
106 u32 l = 1;
107 if( vg_msg_seekframe( &body, alias ) ){
108 while( vg_msg_seekframe( &body, NULL ) ){
109 const char *username = vg_msg_getkvstr( &body, "username" );
110
111 if( username )
112 sfd_encode( l ++, username );
113 else
114 sfd_encode( l ++, "UNKNOWN USER" );
115
116 vg_msg_skip_frame( &body );
117 }
118 }
119 else {
120 sfd_encode( 4, "No records" );
121 }
122 }
123
124 static void world_sfd_compile_active_scores(void){
125 world_instance *world = world_current_instance();
126
127 struct leaderboard_cache *board = NULL;
128
129 if( world_sfd.active_route_board < mdl_arrcount( &world->ent_route ) )
130 board = &world->leaderboard_cache[ world_sfd.active_route_board ];
131
132 world_sfd_compile_scores( board );
133 }
134
135 static void world_sfd_update( world_instance *world, v3f pos ){
136 if( mdl_arrcount( &world->ent_route ) ){
137 u32 closest = 0;
138 float min_dist = INFINITY;
139
140 for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
141 ent_route *route = mdl_arritm( &world->ent_route, i );
142 float dist = v3_dist2( route->board_transform[3], pos );
143
144 if( dist < min_dist ){
145 min_dist = dist;
146 closest = i;
147 }
148 }
149
150 struct leaderboard_cache *board = &world->leaderboard_cache[ closest ];
151
152 /* request new board if cache expires */
153 if( network_client.remote ){
154 f64 delta = vg.time_real - board->cache_time;
155 if( (delta > 45.0) || (board->cache_time == 0.0) ){
156 board->cache_time = vg.time_real;
157 ent_route *route = mdl_arritm( &world->ent_route, closest );
158 addon_reg *world_reg =
159 world_static.instance_addons[ world - world_static.instances ];
160
161 char mod_uid[ ADDON_UID_MAX ];
162 addon_alias_uid( &world_reg->alias, mod_uid );
163
164 network_request_scoreboard(
165 mod_uid,
166 mdl_pstr( &world->meta, route->pstr_name ),
167 NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, closest );
168 }
169 }
170
171 /* compile board text if we changed. */
172 if( world_sfd.active_route_board != closest ){
173 world_sfd_compile_active_scores();
174 }
175
176 world_sfd.active_route_board = closest;
177 }
178
179 for( int i=0; i<world_sfd.w*world_sfd.h; i++ ){
180 float *target = &world_sfd.buffer[i*2+0],
181 *cur = &world_sfd.buffer[i*2+1];
182
183 float const rate = vg.time_delta * 25.2313131414f;
184 float d1 = *target-*cur;
185
186 if( fabsf(d1) > rate ){
187 *cur += rate;
188 if( *cur > 60.0f )
189 *cur -= 60.0f;
190 }
191 else
192 *cur = *target;
193 }
194 }
195
196 static void bind_terrain_noise(void);
197 static void sfd_render( world_instance *world, camera *cam, m4x3f transform ){
198 mesh_bind( &world_sfd.mesh_display );
199 shader_scene_scoretext_use();
200 shader_scene_scoretext_uTexMain(1);
201 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_scoretext );
202
203 bind_terrain_noise();
204
205 glActiveTexture( GL_TEXTURE1 );
206 glBindTexture( GL_TEXTURE_2D, world_sfd.tex_scoretex );
207
208 m4x4f pvm_prev;
209 m4x3_expand( transform, pvm_prev );
210 m4x4_mul( cam->mtx_prev.pv, pvm_prev, pvm_prev );
211
212 shader_scene_scoretext_uPv( cam->mtx.pv );
213 shader_scene_scoretext_uPvmPrev( pvm_prev );
214 shader_scene_scoretext_uMdl( transform );
215 shader_scene_scoretext_uCamera( cam->transform[3] );
216
217 for( int y=0;y<world_sfd.h; y++ ){
218 for( int x=0; x<world_sfd.w; x++ ){
219 float value = world_sfd.buffer[(y*world_sfd.w+x)*2+1];
220 shader_scene_scoretext_uInfo( (v3f){ x,y, value } );
221 mesh_draw( &world_sfd.mesh_display );
222 }
223 }
224
225 shader_scene_vertex_blend_use();
226 shader_scene_vertex_blend_uTexGarbage(0);
227 shader_scene_vertex_blend_uTexGradients(1);
228 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_vertex_blend );
229
230 bind_terrain_noise();
231 glActiveTexture( GL_TEXTURE1 );
232 glBindTexture( GL_TEXTURE_2D, world_sfd.tex_scoretex );
233
234 shader_scene_vertex_blend_uPv( cam->mtx.pv );
235 shader_scene_vertex_blend_uPvmPrev( pvm_prev );
236 shader_scene_vertex_blend_uMdl( transform );
237 shader_scene_vertex_blend_uCamera( cam->transform[3] );
238
239 mesh_bind( &world_sfd.mesh_base );
240 mdl_draw_submesh( &world_sfd.sm_base );
241 }
242
243 static int world_sfd_test( int argc, const char *argv[] ){
244 if( argc == 2 ){
245 int row = vg_min( vg_max(atoi(argv[0]),0), world_sfd.h);
246 sfd_encode( row, argv[1] );
247 }
248
249 return 0;
250 }
251
252 static void world_sfd_init(void){
253 vg_info( "world_sfd_init\n" );
254 shader_scene_scoretext_register();
255 vg_console_reg_cmd( "sfd", world_sfd_test, NULL );
256
257 vg_linear_clear( vg_mem.scratch );
258
259 mdl_context mscoreboard;
260 mdl_open( &mscoreboard, "models/rs_scoretext.mdl", vg_mem.scratch );
261 mdl_load_metadata_block( &mscoreboard, vg_mem.scratch );
262 mdl_async_load_glmesh( &mscoreboard, &world_sfd.mesh_base );
263
264 mdl_load_mesh_block( &mscoreboard, vg_mem.scratch );
265
266 scene_context *scene = &world_sfd.scene;
267 vg_async_item *call = scene_alloc_async( scene, &world_sfd.mesh_display,
268 3000, 8000 );
269
270
271 mdl_mesh *m_backer = mdl_find_mesh( &mscoreboard, "backer" ),
272 *m_card = mdl_find_mesh( &mscoreboard, "score_card" );
273
274 mdl_submesh
275 *sm_backer = mdl_arritm( &mscoreboard.submeshs, m_backer->submesh_start ),
276 *sm_card = mdl_arritm( &mscoreboard.submeshs, m_card->submesh_start );
277 world_sfd.sm_base = *sm_backer;
278
279 m4x3f identity;
280 m4x3_identity( identity );
281
282 for( int i=0;i<4;i++ ){
283 u32 vert_start = scene->vertex_count;
284 scene_add_mdl_submesh( scene, &mscoreboard, sm_card, identity );
285
286 for( int j=0; j<sm_card->vertex_count; j++ ){
287 scene_vert *vert = &scene->arrvertices[ vert_start+j ];
288
289 float const k_glyph_uvw = 1.0f/64.0f;
290 vert->uv[0] -= k_glyph_uvw * (float)(i-1);
291 vert->norm[3] = i*42;
292 }
293 }
294
295 vg_async_dispatch( call, async_scene_upload );
296 vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi",
297 VG_TEX2D_CLAMP|VG_TEX2D_NEAREST,
298 &world_sfd.tex_scoretex );
299
300 mdl_close( &mscoreboard );
301
302 int w = 27,
303 h = 13;
304
305 world_sfd.w = w;
306 world_sfd.h = h;
307 world_sfd.buffer = vg_linear_alloc( vg_mem.rtmemory, 2*w*h*sizeof(float) );
308
309 for( int i=0; i<w*h*2; i++ )
310 world_sfd.buffer[i] = 0.0f;
311 }
312
313 #endif /* WORLD_SFD_C */