From: hgn Date: Tue, 21 Dec 2021 07:30:02 +0000 (+0000) Subject: basic world text X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=commitdiff_plain;h=7238ed7ceebb781ebd757990832f55933a768b2c basic world text --- diff --git a/fishladder.c b/fishladder.c index fcdd58d..9a567df 100644 --- a/fishladder.c +++ b/fishladder.c @@ -132,6 +132,34 @@ struct mesh u32 elements; }; +struct +{ + GLuint vao; + GLuint vbo; + GLuint ebo; + + u32 + title_start, title_count, + desc_start, desc_count, + score_start, score_count, + time_start, time_count + ; + + #pragma pack(push,1) + struct vector_glyph_vert + { + v2f co; + v2f uv; + + u32 colour; + } + *buffer; + #pragma pack(pop) + + u16 *indices; +} +text_buffers; + struct world { #pragma pack(push,1) @@ -145,7 +173,6 @@ struct world *data; #pragma pack(pop) - int initialzed; int sim_run, max_runs; @@ -479,6 +506,94 @@ static void map_reclassify( v2i start, v2i end, int update_texbuffer ) } } +static u32 gen_text_buffer( const char *str, struct sdf_font *font, v2f origin, float size, u32 start ) +{ + u32 count = 0; + + v2f cursor; + v2f invUv; + v2_copy( origin, cursor ); + + float invScale = (size / (float)font->size); + invUv[0] = 1.0f / (float)font->width; + invUv[1] = 1.0f / (float)font->height; + + const char *_c = str; + char c; + while( (c = *(_c ++)) ) + { + if( c == '\n' ) + { + cursor[1] += size * 1.25f; + cursor[0] = origin[0]; + } + else if( c >= 32 && c <= 126 ) + { + struct sdf_char *pch = &font->characters[ c - ' ' ]; + struct vector_glyph_vert *vt = &text_buffers.buffer[ count * 4 ]; + u16 *ind = &text_buffers.indices[ count * 6 ]; + + // Emit quad + v2f p0; v2f uv0; + v2f p1; v2f uv1; + + v2_muladds( cursor, (v2f){ pch->originX, -pch->originY }, -invScale, p0 ); + v2_muladds( p0, (v2f){ pch->w, -pch->h }, invScale, p1 ); + + v2_mul( (v2f){ pch->uvx, pch->uvy }, invUv, uv0 ); + v2_muladd( uv0, (v2f){ pch->w, pch->h }, invUv, uv1 ); + + v2_copy( p0, vt[0].co ); + v2_copy( uv0, vt[0].uv ); + vt[0].colour = 0xffffffff; + + v2_copy( (v2f){ p0[0], p1[1] }, vt[1].co ); + v2_copy( (v2f){ uv0[0], uv1[1] }, vt[1].uv ); + vt[1].colour = 0xffffffff; + + v2_copy( p1, vt[2].co ); + v2_copy( uv1, vt[2].uv ); + vt[2].colour = 0xffffffff; + + v2_copy( (v2f){ p1[0], p0[1] }, vt[3].co ); + v2_copy( (v2f){ uv1[0], uv0[1] }, vt[3].uv ); + vt[3].colour = 0xffffffff; + + // Emit indices + ind[0] = count*4; + ind[1] = count*4+1; + ind[2] = count*4+2; + ind[3] = count*4; + ind[4] = count*4+2; + ind[5] = count*4+3; + + cursor[0] += (float)pch->advance * invScale; + count ++; + } + } + + glBindVertexArray( text_buffers.vao ); + + glBindBuffer( GL_ARRAY_BUFFER, text_buffers.vbo ); + glBufferSubData( GL_ARRAY_BUFFER, + start*4*sizeof( struct vector_glyph_vert ), + count*4*sizeof( struct vector_glyph_vert ), + text_buffers.buffer + ); + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, text_buffers.ebo ); + glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, start*6*sizeof(u16), count*6*sizeof( u16 ), text_buffers.indices ); + + return count; +} + +static void gen_level_text( struct cmp_level *pLevel ) +{ + text_buffers.title_count = gen_text_buffer( pLevel->title, &font_Ubuntu, (v2f){ 0.0f, 0.0f }, 1.0f, text_buffers.title_start ); + text_buffers.desc_count = gen_text_buffer( pLevel->description, &font_Ubuntu, (v2f){ 0.0f, 0.0f }, 0.5f, text_buffers.desc_start ); + text_buffers.desc_count = 0; +} + static int map_load( const char *str, const char *name ) { //TODO: It may be worthwhile, at this point, to switch to binary encoding for save data @@ -1044,7 +1159,10 @@ static void career_load(void) if( lvl->serial_id == encoded.in_map ) { if( console_changelevel( 1, &lvl->map_name ) ) + { world.pCmpLevel = lvl; + gen_level_text( world.pCmpLevel ); + } } } } @@ -1768,6 +1886,10 @@ void vg_update(void) { career_pass_level( world.pCmpLevel, world.score, 1 ); } + + sfx_set_play( &audio_tones, &audio_system_balls_extra, 9 ); + failure_this_frame = 0; + success_this_frame = 0; } } else @@ -2187,6 +2309,7 @@ static void level_selection_buttons(void) if( console_changelevel( 1, &switch_level_to->map_name ) ) { world.pCmpLevel = switch_level_to; + gen_level_text( world.pCmpLevel ); } } } @@ -2397,6 +2520,18 @@ void vg_render(void) level_selection_buttons(); + // TEXT ELEMENTS + // ======================================================================================================== + SHADER_USE( shader_sdf ); + glBindVertexArray( text_buffers.vao ); + glUniformMatrix3fv( SHADER_UNIFORM( shader_sdf, "uPv" ), 1, GL_FALSE, (float *)vg_pv ); + + vg_tex2d_bind( &tex_ubuntu, 0 ); + glUniform1i( SHADER_UNIFORM( shader_sdf, "uTexGlyphs" ), 0 ); + + glDrawElements( GL_TRIANGLES, text_buffers.title_count*6, GL_UNSIGNED_SHORT, (void*)( text_buffers.title_start*6*sizeof(u16) ) ); + glDrawElements( GL_TRIANGLES, text_buffers.desc_count*6, GL_UNSIGNED_SHORT, (void*)( text_buffers.desc_start*6*sizeof(u16) ) ); + // WIRES // ======================================================================================================== //glDisable(GL_BLEND); @@ -3393,6 +3528,88 @@ void vg_start(void) resource_load_main(); + // Create text buffers + { + // Work out the counts for each 'segment' + u32 desc_max_size = 0, title_max_size = 0, + score_max_size = 10, + time_max_size = 10 + ; + + for( int i = 0; i < vg_list_size( career_serializable ); i ++ ) + { + struct serializable_set *set = &career_serializable[i]; + for( int j = 0; j < set->count; j ++ ) + { + struct cmp_level *lvl = &set->pack[j]; + + desc_max_size = VG_MAX( desc_max_size, strlen( lvl->description ) ); + title_max_size = VG_MAX( title_max_size, strlen( lvl->title ) ); + } + } + + // Full buffer + u32 total_characters = + title_max_size + + desc_max_size + + score_max_size + + time_max_size; + + u32 total_faces = total_characters * 2, + total_vertices = total_characters * 4, + total_indices = total_faces * 3; + + // Working buffer + u32 work_buffer_total_chars = + VG_MAX( VG_MAX( desc_max_size, title_max_size ), VG_MAX( score_max_size, time_max_size ) ); + u32 total_work_faces = work_buffer_total_chars * 2, + total_work_vertices = work_buffer_total_chars * 4, + total_work_indices = total_work_faces * 3; + + text_buffers.title_count = 0; + text_buffers.desc_count = 0; + text_buffers.score_count = 0; + text_buffers.time_count = 0; + + // Calculate offsets + text_buffers.title_start = 0; + text_buffers.desc_start = title_max_size; + text_buffers.score_start = text_buffers.desc_start + desc_max_size; + text_buffers.time_start = text_buffers.score_start + score_max_size; + + // Opengl + glGenVertexArrays(1, &text_buffers.vao); + glGenBuffers( 1, &text_buffers.vbo ); + glGenBuffers( 1, &text_buffers.ebo ); + glBindVertexArray( text_buffers.vao ); + + glBindBuffer( GL_ARRAY_BUFFER, text_buffers.vbo ); + glBufferData( GL_ARRAY_BUFFER, total_vertices * sizeof( struct vector_glyph_vert ), NULL, GL_DYNAMIC_DRAW ); + + glBindVertexArray( text_buffers.vao ); + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, text_buffers.ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, total_indices * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW ); + + u32 const stride = sizeof( struct vector_glyph_vert ); + + // XY + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)offsetof( struct vector_glyph_vert, co ) ); + glEnableVertexAttribArray( 0 ); + + // UV + glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, stride, (void *)offsetof( struct vector_glyph_vert, uv ) ); + glEnableVertexAttribArray( 1 ); + + // COLOUR + glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof( struct vector_glyph_vert, colour ) ); + glEnableVertexAttribArray( 2 ); + + // Offline memory + text_buffers.buffer = (struct vector_glyph_vert *)malloc( total_work_vertices * sizeof(struct vector_glyph_vert) ); + text_buffers.indices = (u16*)malloc( total_work_indices * sizeof(u16) ); + } + // Restore gamestate career_local_data_init(); career_load(); @@ -3404,6 +3621,13 @@ void vg_free(void) console_save_map( 0, NULL ); career_serialize(); + glDeleteVertexArrays( 1, &text_buffers.vao ); + glDeleteBuffers( 1, &text_buffers.vbo ); + glDeleteBuffers( 1, &text_buffers.ebo ); + + free( text_buffers.buffer ); + free( text_buffers.indices ); + resource_free_main(); glDeleteTextures( 1, &world.background_data ); diff --git a/fishladder_resources.h b/fishladder_resources.h index 4cdd894..431c8d8 100644 --- a/fishladder_resources.h +++ b/fishladder_resources.h @@ -198,7 +198,8 @@ sound/y4.ogg\0\ sound/y5.ogg\0\ sound/y6.ogg\0\ sound/y7.ogg\0\ -sound/y8.ogg\0" +sound/y8.ogg\0\ +sound/win.ogg\0" }; // One two or three layers of rolling noise @@ -572,6 +573,40 @@ SHADER_DEFINE( shader_buttons, UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" }) ) +SHADER_DEFINE( shader_sdf, + + // VERTEX + "layout (location=0) in vec2 a_co;" + "layout (location=1) in vec2 a_uv;" + "layout (location=2) in vec4 a_colour;" + "uniform mat3 uPv;" + "" + "out vec2 aTexCoords;" + "out vec4 aColour;" + "" + "void main()" + "{" + "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );" + "aTexCoords = a_uv;" + "aColour = a_colour;" + "}", + + // FRAGMENT + "uniform sampler2D uTexGlyphs;" + "out vec4 FragColor;" + "" + "in vec2 aTexCoords;" + "in vec4 aColour;" + "" + "void main()" + "{" + "vec4 glyph = texture( uTexGlyphs, aTexCoords );" + "FragColor = vec4( aColour.rgb, smoothstep( 0.48, 0.52, glyph.r ) * aColour.a );" + //"FragColor = glyph;" + "}" + , + UNIFORMS({ "uPv", "uTexGlyphs" }) +) void vg_register(void) { @@ -581,6 +616,7 @@ void vg_register(void) SHADER_INIT( shader_background ); SHADER_INIT( shader_wire ); SHADER_INIT( shader_buttons ); + SHADER_INIT( shader_sdf ); } /* diff --git a/sound/win.ogg b/sound/win.ogg new file mode 100644 index 0000000..b1b4a01 Binary files /dev/null and b/sound/win.ogg differ diff --git a/sound/y0.ogg b/sound/y0.ogg index f4735af..bc03524 100644 Binary files a/sound/y0.ogg and b/sound/y0.ogg differ diff --git a/sound/y1.ogg b/sound/y1.ogg index bed449b..6955a02 100644 Binary files a/sound/y1.ogg and b/sound/y1.ogg differ diff --git a/sound/y2.ogg b/sound/y2.ogg index 2994944..2c3bfdb 100644 Binary files a/sound/y2.ogg and b/sound/y2.ogg differ diff --git a/sound/y3.ogg b/sound/y3.ogg index 740ca0a..62b3f86 100644 Binary files a/sound/y3.ogg and b/sound/y3.ogg differ diff --git a/sound/y4.ogg b/sound/y4.ogg index 0156c5a..cd2d7ac 100644 Binary files a/sound/y4.ogg and b/sound/y4.ogg differ diff --git a/sound/y5.ogg b/sound/y5.ogg index 8af3fc6..a12fed5 100644 Binary files a/sound/y5.ogg and b/sound/y5.ogg differ diff --git a/sound/y6.ogg b/sound/y6.ogg index f51a778..f5da329 100644 Binary files a/sound/y6.ogg and b/sound/y6.ogg differ diff --git a/sound/y7.ogg b/sound/y7.ogg index f7f1cb8..694da67 100644 Binary files a/sound/y7.ogg and b/sound/y7.ogg differ diff --git a/sound/y8.ogg b/sound/y8.ogg index 935503e..d4d438b 100644 Binary files a/sound/y8.ogg and b/sound/y8.ogg differ diff --git a/textures/ubuntu.png b/textures/ubuntu.png index 0834322..bf15bff 100644 Binary files a/textures/ubuntu.png and b/textures/ubuntu.png differ diff --git a/vg/vg_audio.h b/vg/vg_audio.h index 35d7756..e62d584 100644 --- a/vg/vg_audio.h +++ b/vg/vg_audio.h @@ -26,6 +26,7 @@ struct sfx_vol_control struct sfx_system { sfx_system *persisitent_source; + int in_queue; // Source buffer start float *source, *replacement; @@ -54,7 +55,7 @@ struct sfx_set float *main; char *sources; - u32 segments[20]; //from->to,from->to ... + u32 segments[32]; //from->to,from->to ... u32 numsegments; u32 ch; u32 flags; @@ -228,7 +229,7 @@ static int sfx_begin_edit( sfx_system *sys ) { MUTEX_LOCK( sfx_mux_t01 ); - if( sfx_q_len >= SFX_MAX_SYSTEMS ) + if( sfx_q_len >= SFX_MAX_SYSTEMS && !sys->in_queue ) { MUTEX_UNLOCK( sfx_mux_t01 ); vg_warn( "Warning: No free space in sound queue\n" ); @@ -246,8 +247,12 @@ static void sfx_end_edit( sfx_system *sys ) // Mark change to be uploaded to queue system static int sfx_push( sfx_system *sys ) { - // Mark change in queue - sfx_q[ sfx_q_len ++ ] = sys; + if( !sys->in_queue ) + { + // Mark change in queue + sfx_q[ sfx_q_len ++ ] = sys; + sys->in_queue = 1; + } MUTEX_UNLOCK( sfx_mux_t01 ); @@ -379,6 +384,8 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput sfx_system *src = sfx_q[sfx_q_len]; sfx_system *clone; + src->in_queue = 0; + // Copy clone = sfx_alloc(); *clone = *src; @@ -522,8 +529,6 @@ void audio_mixer_callback( ma_device *pDevice, void *pOutBuf, const void *pInput // String layout: "sounda.ogg\0soundb.ogg\0soundc.ogg\0\0" static void sfx_set_strings( sfx_set *dest, char *strSources, u32 flags, int bAsync ) { - printf( "Init sfx set\n| start | end | length | name \n" ); - dest->ch = (flags & SFX_FLAG_STEREO)? 2: 1; dest->main = NULL; @@ -556,8 +561,6 @@ static void sfx_set_strings( sfx_set *dest, char *strSources, u32 flags, int bAs dest->segments[ dest->numsegments*2+0 ] = total-samples; dest->segments[ dest->numsegments*2+1 ] = total; - - printf( "| %09u | %09u | %09u | %s\n", total-samples, total, samples, source ); } else { @@ -569,8 +572,6 @@ static void sfx_set_strings( sfx_set *dest, char *strSources, u32 flags, int bAs source += len +1; dest->numsegments ++; } - - vg_info( "finished, numsegments: %u\n", dest->numsegments ); } static void sfx_set_init( sfx_set *dest, char *sources ) diff --git a/vg/vg_m.h b/vg/vg_m.h index a567092..577138f 100644 --- a/vg/vg_m.h +++ b/vg/vg_m.h @@ -110,7 +110,8 @@ static inline void v2_divs( v2f a, float s, v2f d ) static inline void v2_mul( v2f a, v2f b, v2f d ) { - d[0] = a[0]*b[0]; d[1] = a[1]*b[1]; + d[0] = a[0]*b[0]; + d[1] = a[1]*b[1]; } static inline void v2_div( v2f a, v2f b, v2f d ) @@ -118,9 +119,16 @@ static inline void v2_div( v2f a, v2f b, v2f d ) d[0] = a[0]/b[0]; d[1] = a[1]/b[1]; } +static inline void v2_muladd( v2f a, v2f b, v2f s, v2f d ) +{ + d[0] = a[0]+b[0]*s[0]; + d[1] = a[1]+b[1]*s[1]; +} + static inline void v2_muladds( v2f a, v2f b, float s, v2f d ) { - d[0] = a[0]+b[0]*s; d[1] = a[1]+b[1]*s; + d[0] = a[0]+b[0]*s; + d[1] = a[1]+b[1]*s; } static inline float v2_length2( v2f a )