Skip to content

Commit

Permalink
Temp2
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Mar 15, 2024
1 parent f9b8c2f commit fe67e2b
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 83 deletions.
80 changes: 27 additions & 53 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,26 +519,22 @@ typedef struct se_ra_tracker_node{
}se_ra_tracker_node_t;
typedef struct se_ra_challenge_indicator_node{
uint32_t id;
sg_image image;
atlas_tile_t image;
struct se_ra_challenge_indicator_node* next;
} se_ra_challenge_indicator_node_t;
typedef struct{
int x, y;
}se_ra_atlas_offset_t;
typedef struct{
rc_client_t* client;
char username[256];
char password[256];
sg_image image;
se_ra_atlas_offset_t** achievement_images;
atlas_tile_t image;
atlas_tile_t** achievement_images;
// TODO: make widgets that use these lists and progress indicator
rc_client_achievement_list_t* achievement_list;
se_ra_tracker_node_t* tracker_list;
se_ra_challenge_indicator_node_t* challenge_indicator_list;
sg_image progress_indicator_image;
atlas_tile_t progress_indicator_image;
bool progress_indicator_shown;
char measured_progress[24];
sg_image atlas; // for achievement images
bool pending_login;
}se_ra_info_t;
#endif
Expand Down Expand Up @@ -1741,10 +1737,7 @@ static uint32_t se_ra_read_memory_callback(uint32_t address, uint8_t* buffer, ui
return 0;
}
static void se_ra_game_cleanup(){
if(ra_info.image.id != SG_INVALID_ID){
sg_destroy_image((sg_image){ra_info.image.id});
ra_info.image.id = SG_INVALID_ID;
}
ra_reset();
rc_client_achievement_list_t* list = ra_info.achievement_list;
if (list){
for (int i = 0; i < list->num_buckets; i++)
Expand Down Expand Up @@ -1789,7 +1782,6 @@ static void se_ra_load_game_callback(int result, const char* error_message, rc_c
ra_get_image(url, &ra_info.image);
}

mutex_lock(ra_get_mutex());
if(ra_info.achievement_list) // TODO: deduplicate this code
{
rc_client_destroy_achievement_list(ra_info.achievement_list);
Expand All @@ -1798,12 +1790,12 @@ static void se_ra_load_game_callback(int result, const char* error_message, rc_c
RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS);
rc_client_achievement_list_t* list = ra_info.achievement_list;
ra_info.achievement_images = (se_ra_atlas_offset_t**)malloc(sizeof(se_ra_atlas_offset_t*)*list->num_buckets);
ra_info.achievement_images = (atlas_tile_t**)malloc(sizeof(atlas_tile_t*)*list->num_buckets);
for (int i = 0; i < list->num_buckets; i++)
{
uint32_t num_achievements=list->buckets[i].num_achievements;
ra_info.achievement_images[i] = (se_ra_atlas_offset_t*)malloc(sizeof(se_ra_atlas_offset_t)*num_achievements);
memset(ra_info.achievement_images[i], 0, sizeof(se_ra_atlas_offset_t)*num_achievements);
ra_info.achievement_images[i] = (atlas_tile_t*)malloc(sizeof(atlas_tile_t)*num_achievements);
memset(ra_info.achievement_images[i], 0, sizeof(atlas_tile_t)*num_achievements);
for (int j = 0; j < num_achievements; j++)
{
char url[512];
Expand All @@ -1822,7 +1814,6 @@ static void se_ra_load_game_callback(int result, const char* error_message, rc_c
printf("locked\n");
}
}
mutex_unlock(ra_get_mutex());
}
static void se_ra_load_game(){
if(!emu_state.rom_loaded)return;
Expand Down Expand Up @@ -1947,7 +1938,7 @@ static void se_ra_challenge_indicator_show(const rc_client_achievement_t* achiev
char url[128];
if (rc_client_achievement_get_image_url(achievement, RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED, url, sizeof(url)) == RC_OK)
{
ra_get_image(url, &new_indicator->image);
// ra_get_image(url, &new_indicator->image);
}
}
static void se_ra_challenge_indicator_hide(const rc_client_achievement_t* achievement)
Expand Down Expand Up @@ -1979,7 +1970,7 @@ static void se_ra_progress_indicator_update(const rc_client_achievement_t* achie

if (rc_client_achievement_get_image_url(achievement, RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE, url, sizeof(url)) == RC_OK)
{
ra_get_image(url, &ra_info.progress_indicator_image);
// ra_get_image(url, &ra_info.progress_indicator_image);
}

strncpy(ra_info.measured_progress, achievement->measured_progress, sizeof(ra_info.measured_progress));
Expand Down Expand Up @@ -2101,30 +2092,6 @@ static void se_ra_initialize() {
free(text);
}
}

// Create the texture
sg_image_desc desc={
.type= SG_IMAGETYPE_2D,
.render_target= false,
.width= atlas_pixel_stride,
.height= atlas_pixel_stride,
.num_slices= 1,
.num_mipmaps= 1,
.usage= SG_USAGE_STREAM,
.pixel_format= SG_PIXELFORMAT_RGBA8,
.sample_count= 1,
.min_filter= SG_FILTER_LINEAR,
.mag_filter= SG_FILTER_LINEAR,
.wrap_u= SG_WRAP_CLAMP_TO_EDGE,
.wrap_v= SG_WRAP_CLAMP_TO_EDGE,
.wrap_w= SG_WRAP_CLAMP_TO_EDGE,
.border_color= SG_BORDERCOLOR_TRANSPARENT_BLACK,
.max_anisotropy= 1,
.min_lod= 0.0f,
.max_lod= 1e9f,
};

ra_info.atlas = sg_make_image(&desc);
}
#endif

Expand Down Expand Up @@ -6374,13 +6341,13 @@ void se_draw_menu_panel(){
se_text("Username");
igSameLine(win_w-150,0);
if(pending_login)se_push_disabled();
igInputText("##Username",ra_info.username,sizeof(ra_info.username),ImGuiInputTextFlags_None,NULL,NULL);
bool enter = igInputText("##Username",ra_info.username,sizeof(ra_info.username),ImGuiInputTextFlags_EnterReturnsTrue,NULL,NULL);
if(pending_login)se_pop_disabled();
se_text("Password");
igSameLine(win_w-150,0);
if(pending_login)se_push_disabled();
igInputText("##Password",ra_info.password,sizeof(ra_info.password),ImGuiInputTextFlags_Password,NULL,NULL);
if(se_button(ICON_FK_SIGN_IN " Login", (ImVec2){0,0})){
enter |= igInputText("##Password",ra_info.password,sizeof(ra_info.password),ImGuiInputTextFlags_Password|ImGuiInputTextFlags_EnterReturnsTrue,NULL,NULL);
if(se_button(ICON_FK_SIGN_IN " Login", (ImVec2){0,0}) || enter){
ra_info.pending_login = true;
rc_client_begin_login_with_password(ra_info.client, ra_info.username, ra_info.password, se_ra_login_callback, NULL);
}
Expand All @@ -6389,22 +6356,27 @@ void se_draw_menu_panel(){
}else {
const rc_client_game_t* game = rc_client_get_game_info(ra_info.client);
ImVec2 pos;
sg_image image;
sg_image image = {0};
const char* play_string = "No Game Loaded";
char line1[256];
char line2[256];
snprintf(line1,256,se_localize_and_cache("Logged in as %s"),user->display_name);
if(game){
image.id=ra_info.image.id;
image.id=ra_info.image.atlas_id;
snprintf(line2,256,se_localize_and_cache("Playing: %s"),game->title);
}else snprintf(line2,256,"%s",se_localize_and_cache("No Game Loaded"));
se_boxed_image_dual_label(line1,line2, ICON_FK_TROPHY, image, 0, (ImVec2){0,0}, (ImVec2){1,1});
se_boxed_image_dual_label(line1,line2, ICON_FK_TROPHY, image, 0, (ImVec2){ra_info.image.x1,ra_info.image.y1}, (ImVec2){ra_info.image.x2,ra_info.image.y2});
if(se_button(ICON_FK_SIGN_OUT " Logout", (ImVec2){0,0})){
char login_info_path[SB_FILE_PATH_SIZE];
snprintf(login_info_path,SB_FILE_PATH_SIZE,"%sra_token.txt",se_get_pref_path());
remove(login_info_path);
rc_client_logout(ra_info.client);
}
#ifndef NDEBUG
if (se_button("Dump atlases", (ImVec2){0,0})){
ra_dump_atlases();
}
#endif
mutex_lock(ra_get_mutex());
rc_client_achievement_list_t* list = ra_info.achievement_list;
if (list){
Expand All @@ -6414,10 +6386,10 @@ void se_draw_menu_panel(){
sg_image image;
ImVec2 uv0, uv1;
if(ra_info.achievement_images && ra_info.achievement_images[i]){
image = ra_info.atlas;
se_ra_atlas_offset_t* tile = &ra_info.achievement_images[i][j];
uv0 = (ImVec2){ tile->x / atlas_pixel_stride, tile->y / atlas_pixel_stride };
uv1 = (ImVec2){ (tile->x + atlas_tile_size) / atlas_pixel_stride, (tile->y + atlas_tile_size) / atlas_pixel_stride };
atlas_tile_t* tile = &ra_info.achievement_images[i][j];
uv0 = (ImVec2){ tile->x1, tile->y1 };
uv1 = (ImVec2){ tile->x2, tile->y2 };
image.id = tile->atlas_id;
}
se_boxed_image_dual_label(list->buckets[i].achievements[j]->title,
list->buckets[i].achievements[j]->description, ICON_FK_SPINNER, image, 0, uv0, uv1);
Expand Down Expand Up @@ -7401,6 +7373,7 @@ static void frame(void) {
screen_x = left_padding;
screen_width-=(left_padding+right_padding)*se_dpi_scale();
#ifdef ENABLE_RETRO_ACHIEVEMENTS
ra_update_atlases();
ra_run_pending_callbacks();
#endif
if(gui_state.sidebar_open){
Expand Down Expand Up @@ -8240,6 +8213,7 @@ static void cleanup(void) {
SDL_Quit();
#endif
https_shutdown();
ra_cleanup();
}
#ifdef EMSCRIPTEN
static void emsc_load_callback(const sapp_html5_fetch_response* response) {
Expand Down
76 changes: 51 additions & 25 deletions src/retro_achievements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ extern "C" {
#define STBI_ONLY_PNG
#include "stb_image.h"

#include <fstream>

// Access to some parts such as the atlas and the pending callbacks can happen from multiple threads
// so we need to synchronize access to them
std::mutex* synchronization_mutex = new std::mutex();
Expand All @@ -37,7 +35,7 @@ struct atlas_t {

sg_image image = {};
std::vector<uint8_t> data; // we construct the atlas here before uploading it to the GPU
int pixel_stride;
int pixel_stride = 0;
int offset_x = 0, offset_y = 0; // to keep track of where next tile needs to be placed, in pixels
int tile_width, tile_height;
bool resized = false;
Expand Down Expand Up @@ -94,7 +92,7 @@ std::thread thread([type, url, post_data, callback, callback_data](){ // TODO: r

// Heavy work (http request) is done, do rest of the work in the ui thread to avoid
// potential synchronization issues
std::lock_guard<std::mutex> lock(*synchronization_mutex);
std::unique_lock<std::mutex> lock(*synchronization_mutex);
pending_callbacks.push_back([result, callback, callback_data]() { // TODO: std::move?
rc_api_server_response_t response;
response.body = (const char*)result.data();
Expand All @@ -116,8 +114,7 @@ extern "C" void ra_log_callback(const char* message, const rc_client_t* client)

// We got some data (either by downloading it, or from the cache), let's handle it
void handle_downloaded_image(downloaded_image_t* image, atlas_tile_t* out_image) {
std::lock_guard<std::mutex> lock(*synchronization_mutex); // no access to the atlases or the image cache without locking

printf("[rcheevos]: handling downloaded image\n");
atlas_t* atlas = nullptr;

// Check if we already have an atlas for this exact tile size
Expand All @@ -142,7 +139,7 @@ void handle_downloaded_image(downloaded_image_t* image, atlas_tile_t* out_image)
atlas->resized = true;

// Find a sufficient power of two
uint32_t power = 256;
uint32_t power = 2048; // TODO: reduce to 256x256
uint32_t max = std::max(minimum_width, minimum_height);
while (power < max) {
power *= 2;
Expand Down Expand Up @@ -185,33 +182,40 @@ void handle_downloaded_image(downloaded_image_t* image, atlas_tile_t* out_image)
}

atlas->data.swap(new_data);
// TODO: maybe we can use TLS to immediately create the atlas if this is the UI thread
}

// At this point we should have an atlas that has enough room for our incoming tile

int offset_x = atlas->offset_x;
int offset_y = atlas->offset_y;

// Prepare offsets for next tile
atlas->offset_x += atlas->tile_width + atlas_spacing;
if (atlas->offset_x + atlas->tile_width > atlas->pixel_stride) {
atlas->offset_x = 0;
atlas->offset_y += atlas->tile_width + atlas_spacing;
}

printf("atlas size: %dx%d\n", atlas->pixel_stride, atlas->pixel_stride);

// Copy tile to atlas
for (int y = 0; y < atlas->tile_height; y++) {
for (int x = 0; x < atlas->tile_width; x++) {
uint32_t atlas_offset = ((atlas->offset_x + x) * 4) + (((atlas->offset_y + y) * atlas->pixel_stride) * 4);
uint32_t atlas_offset = ((offset_x + x) * 4) + (((offset_y + y) * atlas->pixel_stride) * 4);
atlas->data[atlas_offset + 0] = image->data[x * 4 + (y * 4 * atlas->tile_width) + 0];
atlas->data[atlas_offset + 1] = image->data[x * 4 + (y * 4 * atlas->tile_width) + 1];
atlas->data[atlas_offset + 2] = image->data[x * 4 + (y * 4 * atlas->tile_width) + 2];
atlas->data[atlas_offset + 3] = image->data[x * 4 + (y * 4 * atlas->tile_width) + 3];
}
}

out_image->offset_x = atlas->offset_x;
out_image->offset_y = atlas->offset_y;
out_image->width = image->width;
out_image->height = image->height;
out_image->x1 = (float)offset_x/ atlas->pixel_stride;
out_image->y1 = (float)offset_y / atlas->pixel_stride;
out_image->x2 = (float)(offset_x + image->width) / atlas->pixel_stride;
out_image->y2 = (float)(offset_y + image->height) / atlas->pixel_stride;

printf("%d %d %d %d\n", atlas->offset_x, atlas->offset_y, image->width, image->height);
printf("atlas tile: %f %f %f %f\n", out_image->x1, out_image->y1, out_image->x2, out_image->y2);

// Note: at this point atlas->dirty might be true and we can't be certain we are on the UI thread
// (this might be called from the UI thread if the image is cached,
Expand All @@ -227,9 +231,8 @@ void handle_downloaded_image(downloaded_image_t* image, atlas_tile_t* out_image)
// or from the retro achievements event handler
void ra_get_image(const char* url, atlas_tile_t* out_image)
{
// Images might be getting downloaded and added to the cache asynchronously
// so let's lock it here
std::unique_lock<std::mutex> lock(*synchronization_mutex);

if (image_cache.find(url) != image_cache.end())
{
// Great, image was already downloaded in the past and is in the cache
Expand All @@ -240,10 +243,9 @@ void ra_get_image(const char* url, atlas_tile_t* out_image)

// When this function returns, the const char* will be invalid, so we need to copy the contents
std::string url_str = url;
#ifndef EMSCRIPTEN
std::thread thread([url_str, out_image](){ // TODO: again is this really needed?
#endif
https_request(http_request_e::GET, url_str, {}, {}, [out_image, url_str](const std::vector<uint8_t>& result) {
printf("downloaded: %s\n", url_str.c_str());
std::unique_lock<std::mutex> lock(*synchronization_mutex);
rc_api_server_response_t response;
response.body = (const char*)result.data();
response.body_length = result.size();
Expand All @@ -261,29 +263,39 @@ void ra_get_image(const char* url, atlas_tile_t* out_image)
handle_downloaded_image(image, out_image);
});
});
#ifndef EMSCRIPTEN
});
thread.detach();
#endif
}

void ra_run_pending_callbacks()
{
// Pending callbacks is always added to from non-UI threads, so before we run them
// we need to lock the mutex
std::lock_guard<std::mutex> lock(*synchronization_mutex);
std::unique_lock<std::mutex> lock(*synchronization_mutex);
if(pending_callbacks.empty())
return;
std::vector<std::function<void()>> callbacks;
callbacks.swap(pending_callbacks);
lock.unlock();

for (auto& callback : pending_callbacks)
for (auto& callback : callbacks)
{
callback();
}
}

void ra_reset() {
std::unique_lock<std::mutex> lock(*synchronization_mutex);
for (auto& atlas : atlases) {
if (atlas->image.id != SG_INVALID_ID) {
sg_destroy_image(atlas->image);
}
delete atlas;
}
atlases.clear();
pending_callbacks.clear();
}

void ra_update_atlases() {
std::lock_guard<std::mutex> lock(*synchronization_mutex);
std::unique_lock<std::mutex> lock(*synchronization_mutex);
for (atlas_t* atlas : atlases) {
if (atlas->resized) {
if (atlas->image.id != SG_INVALID_ID) {
Expand Down Expand Up @@ -334,4 +346,18 @@ void ra_update_atlases() {

mutex_t ra_get_mutex() {
return synchronization_mutex;
}

void ra_cleanup() {
ra_reset();
delete synchronization_mutex;
for (auto& image : image_cache) {
stbi_image_free(image.second->data);
delete image.second;
}
image_cache.clear();
}

void ra_dump_atlases() {
printf("todo\n");
}
Loading

0 comments on commit fe67e2b

Please sign in to comment.