int num_fishes;
char map_name[64];
- struct career_level *ptr_career_level;
+ //struct career_level *ptr_career_level;
+ struct cmp_level *pCmpLevel;
u32 score;
u32 completed;
u32 time;
} world = {};
+void leaderboard_set_score( struct cmp_level *cmp_level, u32 score );
+
static void map_free(void)
{
arrfree( world.data );
if( text_source )
{
vg_info( "Loading map: '%s'\n", map_path );
- world.ptr_career_level = NULL;
+ world.pCmpLevel = NULL;
if( !map_load( text_source, argv[0] ) )
{
return 0;
}
- free( text_source );
-
- for( int i = 0; i < vg_list_size( level_pack_1 ); i ++ )
- {
- if( !strcmp( level_pack_1[i], argv[0] ) )
- {
- world.ptr_career_level = career.levels + i;
- break;
- }
- }
-
+ free( text_source );
return 1;
}
else
}
void leaderboard_found( LeaderboardFindResult_t *pCallback );
+void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback );
+
void vg_start(void)
{
// Steamworks callbacks
sw_leaderboard_found = &leaderboard_found;
+ sw_leaderboard_downloaded = &leaderboard_downloaded;
vg_function_push( (struct vg_cmd){
.name = "_map_write",
void vg_free(void)
{
+ sw_free_opengl();
console_save_map( 0, NULL );
career_serialize();
}
// Copy into career data
- if( world.ptr_career_level )
+ if( world.pCmpLevel )
{
- world.ptr_career_level->score = world.score;
- world.ptr_career_level->time = world.time;
- world.ptr_career_level->completed = world.completed;
+ if( world.score > world.pCmpLevel->completed_score )
+ leaderboard_set_score( world.pCmpLevel, world.score );
+
+ world.pCmpLevel->completed_score = world.score;
}
simulation_stop(); // TODO: Async?
static struct
{
SteamLeaderboard_t steam_leaderboard;
- int leaderboard_matches;
+ int leaderboard_show;
+
+ struct leaderboard_player
+ {
+ // Internal
+ u64_steamid id;
+ i32 score;
+
+ // To be displayed
+ char score_text[ 16 ];
+ char player_name[ 48 ];
+ GLuint texture; // Not dynamic
+ }
+ leaderboard_players[10];
+ int leaderboard_count;
+
+ struct
+ {
+ struct cmp_level *level;
+
+ i32 score;
+ int is_waiting;
+ }
+ upload_request;
struct cmp_level *level_selected;
}
if( gui_button( 2 + i ) == k_button_click )
{
ui_data.level_selected = &levels[i];
- ui_data.leaderboard_matches = 0;
+ ui_data.leaderboard_show = 0;
sw_find_leaderboard( ui_data.level_selected->map_name );
}
if( gui_button( 3002 ) == k_button_click )
{
console_changelevel( 1, &ui_data.level_selected->map_name );
+ world.pCmpLevel = ui_data.level_selected;
+
ui_data.level_selected = NULL;
- ui_data.leaderboard_matches = 0;
+ ui_data.leaderboard_show = 0;
}
gui_text( "Play", 6, 0 );
gui_end();
}
gui_end_right();
- if( ui_data.leaderboard_matches )
+ if( ui_data.leaderboard_show )
{
ui_global_ctx.cursor[0] += 16;
ui_global_ctx.cursor[3] = 250;
gui_new_node();
{
gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
+
+ ui_rect_pad( ui_global_ctx.cursor, 8 );
+
+ gui_new_node();
+ {
+ ui_global_ctx.cursor[3] = 32+8;
+
+ for( int i = 0; i < ui_data.leaderboard_count; i ++ )
+ {
+ gui_new_node();
+ {
+ struct leaderboard_player *player = &ui_data.leaderboard_players[i];
+
+ ui_global_ctx.cursor[0] += 4;
+ ui_global_ctx.cursor[1] += 4;
+ ui_global_ctx.cursor[2] = 32;
+ ui_global_ctx.cursor[3] = 32;
+
+ gui_new_node();
+ {
+ gui_push_image( ui_global_ctx.cursor, player->texture );
+ }
+ gui_end_right();
+
+ gui_text( player->player_name, 6, 0 );
+
+ ui_global_ctx.cursor[2] = 50;
+ gui_align_right();
+
+ gui_text( player->score_text, 6, 0 );
+ }
+ gui_end_down();
+
+ ui_global_ctx.cursor[1] += 2;
+
+ }
+ }
+ gui_end();
}
gui_end();
}
}
}
+void leaderboard_dispatch_score(void)
+{
+ sw_upload_leaderboard_score(
+ ui_data.upload_request.level->steam_leaderboard,
+ k_ELeaderboardUploadScoreMethodKeepBest,
+ ui_data.upload_request.score,
+ NULL,
+ 0
+ );
+
+ ui_data.upload_request.is_waiting = 0;
+
+ vg_success( "Dispatched leaderboard score\n" );
+}
+
void leaderboard_found( LeaderboardFindResult_t *pCallback )
{
if( !pCallback->m_bLeaderboardFound )
+ {
vg_error( "Leaderboard could not be found\n" );
+ ui_data.steam_leaderboard = 0;
+ }
+ else
+ {
+ const char *recieved_name = sw_get_leaderboard_name( pCallback->m_hSteamLeaderboard );
+
+ // Update UI state and request entries if this callback found the current UI level
+ if( ui_data.level_selected )
+ {
+ if( !strcmp( recieved_name, ui_data.level_selected->map_name ) )
+ {
+ sw_download_leaderboard_entries( pCallback->m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, 0, 10 );
+ ui_data.level_selected->steam_leaderboard = pCallback->m_hSteamLeaderboard;
+ }
+ }
+
+ // Dispatch the waiting request if there was one
+ if( ui_data.upload_request.is_waiting )
+ {
+ if( !strcmp( recieved_name, ui_data.upload_request.level->map_name ) )
+ {
+ ui_data.upload_request.level->steam_leaderboard = pCallback->m_hSteamLeaderboard;
+ leaderboard_dispatch_score();
+ }
+ }
+ }
+}
+
+void leaderboard_downloaded( LeaderboardScoresDownloaded_t *pCallback )
+{
+ // Update UI if this leaderboard matches what we currently have in view
+ if( ui_data.level_selected->steam_leaderboard == pCallback->m_hSteamLeaderboard )
+ {
+ vg_info( "Recieved %d entries\n", pCallback->m_cEntryCount );
+ ui_data.leaderboard_count = VG_MIN( pCallback->m_cEntryCount, 10 );
+
+ for( int i = 0; i < ui_data.leaderboard_count; i ++ )
+ {
+ LeaderboardEntry_t entry;
+ sw_get_downloaded_entry( pCallback->m_hSteamLeaderboardEntries, i, &entry, NULL, 0 );
+
+ struct leaderboard_player *player = &ui_data.leaderboard_players[i];
+
+ player->id = entry.m_steamIDUser.m_unAll64Bits;
+ strncpy( player->player_name, sw_get_friend_persona_name( player->id ), vg_list_size( player->player_name )-1 );
+ player->score = entry.m_nScore;
+
+ snprintf( player->score_text, vg_list_size(player->score_text), "%d", player->score );
+ player->texture = sw_get_player_image( player->id );
+
+ if( player->texture == 0 )
+ player->texture = tex_unkown.name;
+ }
+
+ if( ui_data.leaderboard_count )
+ ui_data.leaderboard_show = 1;
+ else
+ ui_data.leaderboard_show = 0;
+ }
+ else vg_warn( "Downloaded leaderboard does not match requested!\n" );
+}
+
+void leaderboard_set_score( struct cmp_level *cmp_level, u32 score )
+{
+ if( ui_data.upload_request.is_waiting )
+ vg_warn( "You are uploading leaderboard entries too quickly!\n" );
+
+ ui_data.upload_request.level = cmp_level;
+ ui_data.upload_request.score = score;
+ ui_data.upload_request.is_waiting = 1;
- ui_data.steam_leaderboard = pCallback->m_hSteamLeaderboard;
- ui_data.leaderboard_matches = 0;
-
- if( ui_data.level_selected )
- if( !strcmp( sw_get_leaderboard_name( ui_data.steam_leaderboard ), ui_data.level_selected->map_name ) )
- ui_data.leaderboard_matches = 1;
+ // If leaderboard ID has been downloaded already then just immediately dispatch this
+ if( cmp_level->steam_leaderboard )
+ leaderboard_dispatch_score();
+ else
+ sw_find_leaderboard( cmp_level->map_name );
}
vg_tex2d tex_background = { .path = "textures/background.qoi" };
vg_tex2d tex_ball_noise = { .path = "textures/bnoise.qoi" };
vg_tex2d tex_monofur = { .path = "textures/ascii.qoi", .flags = VG_TEXTURE_NO_MIP };
+vg_tex2d tex_unkown = { .path = "textures/unkown.qoi" };
-vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_background, &tex_ball_noise, &tex_monofur };
+vg_tex2d *texture_list[] = { &tex_tile_detail, &tex_tile_data, &tex_wood, &tex_background, &tex_ball_noise, &tex_monofur, &tex_unkown };
// AUDIO
// ===========================================================================================================
int linked_unlocks; // When unlocked, unlock this many levels additionally
int serial_id;
+
+ SteamLeaderboard_t steam_leaderboard;
};
struct cmp_level cmp_levels_tutorials[] =
for( int i = 0; i < vg_console.len; i ++ )
{
- ui_text( &ui_global_ctx, vg_console.lines[ptr], vg_console.scale, 0 );
+ ui_text( &ui_global_ctx, vg_console.lines[ptr], vg_console.scale*2, 0 );
ui_global_ctx.cursor[1] -= 8*vg_console.scale;
ptr --;
{
ui_fill_rect( &ui_global_ctx, ui_global_ctx.cursor, 0x77333333 );
- ui_text( &ui_global_ctx, vg_console.input, vg_console.scale, 0 );
+ ui_text( &ui_global_ctx, vg_console.input, vg_console.scale*2, 0 );
int start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ),
end = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user );
ESteamAPICallFailure SteamAPI_ISteamUtils_GetAPICallFailureReason( ISteamUtils* self, SteamAPICall_t hSteamAPICall );
+// Friends
+char *SteamAPI_ISteamFriends_GetPersonaName( ISteamFriends *self );
+const char *SteamAPI_ISteamFriends_GetFriendPersonaName( ISteamFriends *self, u64_steamid steamIDFriend );
+u64_steamid SteamAPI_ISteamUser_GetSteamID( ISteamUser *self );
+int SteamAPI_ISteamFriends_GetSmallFriendAvatar( ISteamFriends *self, u64_steamid steamIDFriend ); // 32x32
+int SteamAPI_ISteamUtils_GetImageSize( ISteamUtils *self, int iImage, u32 *pnWidth, u32 *pnHeight );
+int SteamAPI_ISteamUtils_GetImageRGBA( ISteamUtils *self, int iImage, u8 *pubDest, int nDestBufferSize );
+
// Leaderboards
SteamAPICall_t SteamAPI_ISteamUserStats_FindOrCreateLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType );
SteamAPICall_t SteamAPI_ISteamUserStats_FindLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName );
SteamAPICall_t SteamAPI_ISteamUserStats_UploadLeaderboardScore( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, i32 nScore, const i32 * pScoreDetails, int cScoreDetailsCount );
SteamAPICall_t SteamAPI_ISteamUserStats_AttachLeaderboardUGC( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC );
+#define sw_get_image_size(...) SteamAPI_ISteamUtils_GetImageSize( steam_api_classes.utils, __VA_ARGS__ )
+#define sw_get_image_rgba(...) SteamAPI_ISteamUtils_GetImageRGBA( steam_api_classes.utils, __VA_ARGS__ )
+#define sw_get_small_friend_avatar(...) SteamAPI_ISteamFriends_GetSmallFriendAvatar( steam_api_classes.friends, __VA_ARGS__ )
+#define sw_get_steamid() SteamAPI_ISteamUser_GetSteamID( steam_api_classes.friends )
+#define sw_get_friend_persona_name(...) SteamAPI_ISteamFriends_GetFriendPersonaName( steam_api_classes.friends, __VA_ARGS__ )
+#define sw_get_persona_name() SteamAPI_ISteamFriends_GetPersonaName( steam_api_classes.friends )
+#define sw_find_leaderboard(...) SteamAPI_ISteamUserStats_FindLeaderboard( steam_api_classes.stats, __VA_ARGS__ );
+#define sw_get_leaderboard_name(...) SteamAPI_ISteamUserStats_GetLeaderboardName( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_download_leaderboard_entries(...) SteamAPI_ISteamUserStats_DownloadLeaderboardEntries( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_get_downloaded_entry(...) SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry( steam_api_classes.stats, __VA_ARGS__ )
+#define sw_upload_leaderboard_score(...) SteamAPI_ISteamUserStats_UploadLeaderboardScore( steam_api_classes.stats, __VA_ARGS__ )
+
HSteamPipe SteamAPI_GetHSteamPipe();
HSteamUser SteamAPI_GetHSteamUser();
HSteamPipe pipe;
+ struct cached_player
+ {
+ u64_steamid id;
+ GLuint avatar_texture; // tex_unkown.name
+
+ struct cached_player *l, *r;
+ }
+ cached_players[20];
+
+ struct cached_player *cache_head, *cache_tail;
+
+ u32 cache_count;
+
} steam_api_classes;
+static void _sw_cache_push( struct cached_player *player )
+{
+ player->l = NULL;
+ player->r = steam_api_classes.cache_head;
+ if( steam_api_classes.cache_head ) steam_api_classes.cache_head->l = player;
+ if( !steam_api_classes.cache_tail ) steam_api_classes.cache_tail = player;
+ steam_api_classes.cache_head = player;
+ steam_api_classes.cache_count ++;
+}
+
+static void _sw_cache_evict( struct cached_player *player )
+{
+ if( player == steam_api_classes.cache_tail ) steam_api_classes.cache_tail = player->l;
+ if( player == steam_api_classes.cache_head ) steam_api_classes.cache_head = player->r;
+ if( player->l ) player->l->r = player->r;
+ if( player->r ) player->r->l = player->l;
+ steam_api_classes.cache_count --;
+}
+
+static void _sw_access_cache( struct cached_player *player )
+{
+ _sw_cache_evict( player );
+ _sw_cache_push( player );
+}
+
+static GLuint sw_get_player_image( u64_steamid usr )
+{
+ // Look for player in cache
+ for( int i = 0; i < steam_api_classes.cache_count; i ++ )
+ {
+ struct cached_player *player = &steam_api_classes.cached_players[i];
+
+ if( player->id == usr )
+ {
+ _sw_access_cache( player );
+ return player->avatar_texture;
+ }
+ }
+
+ struct cached_player *dest;
+
+ if( steam_api_classes.cache_count == vg_list_size( steam_api_classes.cached_players ) )
+ {
+ dest = steam_api_classes.cache_tail;
+ _sw_access_cache( dest );
+
+ // Delete previous before creating a new one
+ glDeleteTextures( 1, &dest->avatar_texture );
+ }
+ else
+ {
+ dest = &steam_api_classes.cached_players[ steam_api_classes.cache_count ];
+ _sw_cache_push( dest );
+ }
+
+ dest->id = usr;
+ dest->avatar_texture = 0;
+
+ // Upload new image
+ u32 x = 32, y = 32;
+ int steam_image;
+
+ steam_image = sw_get_small_friend_avatar( usr );
+ if( !steam_image )
+ return 0;
+
+ if( !sw_get_image_size( steam_image, &x, &y ) )
+ return 0;
+
+ u8 * img_buf = (u8 *)malloc( x * y * 4 );
+
+ if( !sw_get_image_rgba(steam_image, img_buf, x * y * 4) )
+ {
+ free( img_buf );
+ return 0;
+ }
+
+ glGenTextures( 1, &dest->avatar_texture );
+ glBindTexture( GL_TEXTURE_2D, dest->avatar_texture );
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_buf );
+ glGenerateMipmap( GL_TEXTURE_2D );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ free( img_buf );
+
+ return dest->avatar_texture;
+}
+
ISteamFriends *SteamAPI_SteamFriends_v017();
ISteamUser *SteamAPI_SteamUser_v021();
ISteamUserStats *SteamAPI_SteamUserStats_v012();
SteamAPI_Shutdown();
}
+// Needs to be manually called by client unfortunately
+static void sw_free_opengl(void)
+{
+ for( int i = 0; i < steam_api_classes.cache_count; i ++ )
+ if( steam_api_classes.cached_players[i].avatar_texture )
+ glDeleteTextures( 1, &steam_api_classes.cached_players[i].avatar_texture );
+}
+
static int sw_init(void)
{
#if defined(VALVE_CALLBACK_PACK_SMALL)
void (*sw_leaderboard_found)( LeaderboardFindResult_t *pCallback );
+void (*sw_leaderboard_downloaded)( LeaderboardScoresDownloaded_t *pCallback );
static void sw_event_loop(void)
{
case SW_CBID_LeaderboardFindResult:
if( sw_leaderboard_found ) sw_leaderboard_found( (LeaderboardFindResult_t*)pTmpCallResult );
break;
+ case SW_CBID_LeaderboardScoresDownloaded:
+ if( sw_leaderboard_downloaded ) sw_leaderboard_downloaded( (LeaderboardScoresDownloaded_t*)pTmpCallResult );
+ break;
default:break;
}
}
vg_success( "Achievement set: '%s'\n", vg_ach_name );
}
}
-
-static void sw_find_leaderboard( const char *name )
-{
- SteamAPI_ISteamUserStats_FindLeaderboard( steam_api_classes.stats, name );
-}
-
-static const char *sw_get_leaderboard_name( SteamLeaderboard_t hSteamLeaderboard )
-{
- return SteamAPI_ISteamUserStats_GetLeaderboardName( steam_api_classes.stats, hSteamLeaderboard );
-}
"float clip_blend = step( aWsp.x, aClip.z ) * step( aWsp.y, aClip.w ) * step( aClip.x, aWsp.x ) * step( aClip.y, aWsp.y );"
"vec4 glyph = texture( uTexGlyphs, aTexCoords );"
- "FragColor = aColour * vec4( 1.0, 1.0, 1.0, glyph.r * clip_blend );"
+ "FragColor = vec4( aColour.rgb * glyph.rgb, aColour.a*glyph.a*clip_blend );"
"}"
,
UNIFORMS({ "uPv", "uTexGlyphs" })
ui_colourset *colours_main;
ui_colourset *colours_current;
+
+ GLuint vao;
+ GLuint vbo;
+ GLuint ebo;
+
+ struct ui_image
+ {
+ ui_rect rc;
+ GLuint image;
+ }
+ images[16];
+ int image_count;
};
-// Shortnames
-#define gui_draw(...) ui_draw( &ui_global_ctx, __VA_ARGS__)
-#define gui_current(...) ui_current( &ui_global_ctx, __VA_ARGS__)
-#define gui_new_node() ui_new_node( &ui_global_ctx )
-#define gui_hasmouse(...) ui_hasmouse( &ui_global_ctx, __VA_ARGS__)
-#define gui_end() ui_end( &ui_global_ctx )
-#define gui_end_down() ui_end_down( &ui_global_ctx )
-#define gui_end_right() ui_end_right( &ui_global_ctx )
-#define gui_fill_y() ui_fill_y( &ui_global_ctx)
-#define gui_fill_x() ui_fill_x( &ui_global_ctx)
-#define gui_align_bottom() ui_align_bottom( &ui_global_ctx )
-#define gui_align_right() ui_align_right( &ui_global_ctx )
-#define gui_align_top() ui_align_top( &ui_global_ctx )
-#define gui_align_left() ui_align_left( &ui_global_ctx )
-#define gui_clamp_rect(...) ui_clamp_rect( &ui_global_ctx, __VA_ARGS__)
-#define gui_group_id(...) ui_group_id( &ui_global_ctx, __VA_ARGS__)
-#define gui_capture_mouse(...) ui_capture_mouse( &ui_global_ctx, __VA_ARGS__)
-#define gui_set_clip(...) ui_set_clip( &ui_global_ctx, __VA_ARGS__)
-#define gui_release_clip() ui_release_clip( &ui_global_ctx )
-#define gui_fill_rect_uv(...) ui_fill_rect_uv( &ui_global_ctx, __VA_ARGS__)
-#define gui_fill_rect(...) ui_fill_rect( &ui_global_ctx, __VA_ARGS__)
-#define gui_text(...) ui_text( &ui_global_ctx, __VA_ARGS__)
-#define gui_begin(...) ui_begin( &ui_global_ctx, __VA_ARGS__)
-#define gui_resolve(...) ui_resolve( &ui_global_ctx, __VA_ARGS__)
-#define gui_set_mouse(...) ui_set_mouse( &ui_global_ctx, __VA_ARGS__)
-#define gui_button(...) ui_button( &ui_global_ctx, __VA_ARGS__)
-#define gui_window(...) ui_window( &ui_global_ctx, __VA_ARGS__)
-#define gui_want_mouse() ui_want_mouse( &ui_global_ctx )
-
-#define gui_scrollbar(...) ui_scrollbar( &ui_global_ctx, __VA_ARGS__)
-#define gui_override_colours(...) ui_override_colours( &ui_global_ctx, __VA_ARGS__)
-#define gui_reset_colours(...) ui_reset_colours( &ui_global_ctx )
-
// Globals
// ===========================================================================================================
int ui_glyph_override = 0;
ui_px ui_glyph_spacing_x = 6;
GLuint ui_glyph_texture = 0;
-GLuint ui_vao;
-GLuint ui_vbo;
-GLuint ui_ebo;
-
-#define UI_BUFFER_SIZE 30000
-#define UI_INDEX_SIZE 20000
ui_colourset ui_default_colours = {
.main = 0xff00ff00,
};
ui_ctx ui_global_ctx = {
.padding = 8,
- .colours_current = &ui_default_colours,
.colours_main = &ui_default_colours
};
// Initialization
// ===========================================================================================================
+static void ui_reset_colours( ui_ctx *ctx );
+static void ui_init_context( ui_ctx *ctx, int index_buffer_size )
+{
+ ui_reset_colours( ctx );
+
+ u32 vertex_buffer_size = (index_buffer_size+(index_buffer_size/2));
+
+ // Generate the buffer we are gonna be drawing to
+ {
+ glGenVertexArrays(1, &ctx->vao);
+ glGenBuffers( 1, &ctx->vbo );
+ glGenBuffers( 1, &ctx->ebo );
+ glBindVertexArray( ctx->vao );
+
+ glBindBuffer( GL_ARRAY_BUFFER, ctx->vbo );
+
+ glBufferData( GL_ARRAY_BUFFER, vertex_buffer_size * sizeof( struct ui_vert ), NULL, GL_DYNAMIC_DRAW );
+ glBindVertexArray( ctx->vao );
+
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ctx->ebo );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, index_buffer_size * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW );
+
+ u32 const stride = sizeof( struct ui_vert );
+
+ // XY
+ glVertexAttribPointer( 0, 2, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, co ) );
+ glEnableVertexAttribArray( 0 );
+
+ // UV
+ glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE, GL_FALSE, stride, (void *)offsetof( struct ui_vert, uv ) );
+ glEnableVertexAttribArray( 1 );
+
+ // COLOUR
+ glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof( struct ui_vert, colour ) );
+ glEnableVertexAttribArray( 2 );
+
+ // CLIPPING
+ glVertexAttribPointer( 3, 4, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, clip ) );
+ glEnableVertexAttribArray( 3 );
+ }
+
+ // Initialize default context
+ {
+ ctx->verts = (struct ui_vert *)malloc( vertex_buffer_size * sizeof(struct ui_vert) );
+ ctx->indices = (u16*)malloc( index_buffer_size * sizeof(u16) );
+ }
+}
+
+static void ui_context_free( ui_ctx *ctx )
+{
+ glDeleteVertexArrays( 1, &ctx->vao );
+ glDeleteBuffers( 1, &ctx->vbo );
+ glDeleteBuffers( 1, &ctx->ebo );
+
+ free( ctx->verts );
+ free( ctx->indices );
+}
+
static void ui_override_font( GLuint new_tex, ui_px space_x )
{
if( ui_glyph_texture )
}
// Setup OpenGL memory
- {
- SHADER_INIT( shader_ui );
-
- // Generate the buffer we are gonna be drawing to
- glGenVertexArrays(1, &ui_vao);
- glGenBuffers( 1, &ui_vbo );
- glGenBuffers( 1, &ui_ebo );
- glBindVertexArray( ui_vao );
-
- glBindBuffer( GL_ARRAY_BUFFER, ui_vbo );
-
- glBufferData( GL_ARRAY_BUFFER, UI_BUFFER_SIZE * sizeof( struct ui_vert ), NULL, GL_DYNAMIC_DRAW );
- glBindVertexArray( ui_vao );
-
- glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ui_ebo );
- glBufferData( GL_ELEMENT_ARRAY_BUFFER, UI_INDEX_SIZE * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW );
-
- u32 const stride = sizeof( struct ui_vert );
-
- // XY
- glVertexAttribPointer( 0, 2, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, co ) );
- glEnableVertexAttribArray( 0 );
-
- // UV
- glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE, GL_FALSE, stride, (void *)offsetof( struct ui_vert, uv ) );
- glEnableVertexAttribArray( 1 );
-
- // COLOUR
- glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof( struct ui_vert, colour ) );
- glEnableVertexAttribArray( 2 );
-
- // CLIPPING
- glVertexAttribPointer( 3, 4, GL_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, clip ) );
- glEnableVertexAttribArray( 3 );
- }
-
- // Initialize default context
- {
- ui_global_ctx.verts = (struct ui_vert *)malloc( UI_BUFFER_SIZE * sizeof(struct ui_vert) );
- ui_global_ctx.indices = (u16*)malloc( UI_INDEX_SIZE * sizeof(u16) );
- }
+ SHADER_INIT( shader_ui );
+ ui_init_context( &ui_global_ctx, 20000 );
}
static void ui_default_free(void)
if( !ui_glyph_override )
glDeleteTextures( 1, &ui_glyph_texture );
- glDeleteVertexArrays( 1, &ui_vao );
- glDeleteBuffers( 1, &ui_vbo );
- glDeleteBuffers( 1, &ui_ebo );
-
- free( ui_global_ctx.verts );
- free( ui_global_ctx.indices );
+ ui_context_free( &ui_global_ctx );
}
+static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, u32 colour, ui_px uv[4] );
static void ui_draw( ui_ctx *ctx, m3x3f view_override )
{
- glBindVertexArray( ui_vao );
+ u32 num_indices_normal = ctx->num_indices;
- glBindBuffer( GL_ARRAY_BUFFER, ui_vbo );
+ // Append images to back of buffer
+ for( int i = 0; i < ctx->image_count; i ++ )
+ ui_fill_rect_uv( ctx, ctx->images[i].rc, 0xffffffff, (ui_px[4]){0,0,128,128} );
+
+ glBindVertexArray( ctx->vao );
+
+ glBindBuffer( GL_ARRAY_BUFFER, ctx->vbo );
glBufferSubData( GL_ARRAY_BUFFER, 0, ctx->num_verts * sizeof( struct ui_vert ), ctx->verts );
- glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ui_ebo );
+ glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ctx->ebo );
glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, ctx->num_indices * sizeof( u16 ), ctx->indices );
glEnable(GL_BLEND);
glBindTexture( GL_TEXTURE_2D, ui_glyph_texture );
glUniform1i( SHADER_UNIFORM( shader_ui, "uTexGlyphs" ), 0 );
- glDrawElements( GL_TRIANGLES, ctx->num_indices, GL_UNSIGNED_SHORT, (void*)(0) );
+ glDrawElements( GL_TRIANGLES, num_indices_normal, GL_UNSIGNED_SHORT, (void*)(0) );
- //vg_info( "Verts: %u, Indices: %u\n", ctx->num_verts, ctx->num_indices );
+ // Draw image elements
+ for( int i = 0; i < ctx->image_count; i ++ )
+ {
+ struct ui_image *img = &ctx->images[i];
+
+ glBindTexture( GL_TEXTURE_2D, img->image );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)( (num_indices_normal + 6*i)*sizeof(u16) ) );
+ }
glDisable(GL_BLEND);
}
if( ctx->click_state == 0 )
ctx->capture_mouse_id = 0;
+
+ ctx->image_count = 0;
}
static void ui_resolve( ui_ctx *ctx )
ctx->colours_current = ctx->colours_main;
ctx->override_colour = 0xffffffff;
}
+
+static void ui_push_image( ui_ctx *ctx, ui_rect rc, GLuint image )
+{
+ struct ui_image *img = &ctx->images[ ctx->image_count ++ ];
+ ui_rect_copy( rc, img->rc );
+ img->image = image;
+}
+
+// Shortnames
+#define gui_draw(...) ui_draw( &ui_global_ctx, __VA_ARGS__)
+#define gui_current(...) ui_current( &ui_global_ctx, __VA_ARGS__)
+#define gui_new_node() ui_new_node( &ui_global_ctx )
+#define gui_hasmouse(...) ui_hasmouse( &ui_global_ctx, __VA_ARGS__)
+#define gui_end() ui_end( &ui_global_ctx )
+#define gui_end_down() ui_end_down( &ui_global_ctx )
+#define gui_end_right() ui_end_right( &ui_global_ctx )
+#define gui_fill_y() ui_fill_y( &ui_global_ctx)
+#define gui_fill_x() ui_fill_x( &ui_global_ctx)
+#define gui_align_bottom() ui_align_bottom( &ui_global_ctx )
+#define gui_align_right() ui_align_right( &ui_global_ctx )
+#define gui_align_top() ui_align_top( &ui_global_ctx )
+#define gui_align_left() ui_align_left( &ui_global_ctx )
+#define gui_clamp_rect(...) ui_clamp_rect( &ui_global_ctx, __VA_ARGS__)
+#define gui_group_id(...) ui_group_id( &ui_global_ctx, __VA_ARGS__)
+#define gui_capture_mouse(...) ui_capture_mouse( &ui_global_ctx, __VA_ARGS__)
+#define gui_set_clip(...) ui_set_clip( &ui_global_ctx, __VA_ARGS__)
+#define gui_release_clip() ui_release_clip( &ui_global_ctx )
+#define gui_fill_rect_uv(...) ui_fill_rect_uv( &ui_global_ctx, __VA_ARGS__)
+#define gui_fill_rect(...) ui_fill_rect( &ui_global_ctx, __VA_ARGS__)
+#define gui_text(...) ui_text( &ui_global_ctx, __VA_ARGS__)
+#define gui_begin(...) ui_begin( &ui_global_ctx, __VA_ARGS__)
+#define gui_resolve(...) ui_resolve( &ui_global_ctx, __VA_ARGS__)
+#define gui_set_mouse(...) ui_set_mouse( &ui_global_ctx, __VA_ARGS__)
+#define gui_button(...) ui_button( &ui_global_ctx, __VA_ARGS__)
+#define gui_window(...) ui_window( &ui_global_ctx, __VA_ARGS__)
+#define gui_want_mouse() ui_want_mouse( &ui_global_ctx )
+#define gui_push_image(...) ui_push_image( &ui_global_ctx, __VA_ARGS__ )
+#define gui_scrollbar(...) ui_scrollbar( &ui_global_ctx, __VA_ARGS__)
+#define gui_override_colours(...) ui_override_colours( &ui_global_ctx, __VA_ARGS__)
+#define gui_reset_colours(...) ui_reset_colours( &ui_global_ctx )