Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL metadata strings and save data #429

Merged
merged 12 commits into from
Dec 7, 2020
20 changes: 11 additions & 9 deletions 32blit-sdl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_library(BlitHalSDL STATIC
DefaultMetadata.cpp
File.cpp
Input.cpp
JPEG.cpp
Expand Down Expand Up @@ -90,15 +91,6 @@ if(SDL2_IMAGE_DLL)
install(FILES ${SDL2_IMAGE_DLL} DESTINATION bin)
endif()

if(NOT 32BLIT_SDL_TITLE)
set(32BLIT_SDL_TITLE CMake!)
endif()

target_compile_definitions(BlitHalSDL
PRIVATE
-DWINDOW_TITLE=\"${32BLIT_SDL_TITLE}\"
)

if(DEFINED VIDEO_CAPTURE AND VIDEO_CAPTURE)
find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY avcodec)
Expand Down Expand Up @@ -188,4 +180,14 @@ function(blit_metadata TARGET FILE)
target_sources(${TARGET} PRIVATE ${ICON})
set_source_files_properties(${ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endif()

file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/metadata.cpp
CONTENT "
const char *metadata_title = \"${METADATA_TITLE}\";
const char *metadata_author = \"${METADATA_AUTHOR}\";
const char *metadata_description = \"${METADATA_DESCRIPTION}\";
const char *metadata_version = \"${METADATA_VERSION}\";
"
)
target_sources(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/metadata.cpp)
endfunction()
12 changes: 12 additions & 0 deletions 32blit-sdl/DefaultMetadata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Default metadata if there is non compiled into the game
// There should be nothing else in this file so that the VS linker drops it when not needed
#ifdef _MSC_VER
#define WEAK
#else
#define WEAK [[gnu::weak]]
#endif

WEAK const char *metadata_title = "32Blit Game";
WEAK const char *metadata_author = "Unknown";
WEAK const char *metadata_description = "";
WEAK const char *metadata_version = "v0.0.0";
18 changes: 18 additions & 0 deletions 32blit-sdl/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "SDL.h"

#include "File.hpp"
#include "UserCode.hpp"

static std::string basePath;

Expand All @@ -36,6 +37,14 @@ void *open_file(const std::string &name, int mode) {
return nullptr;

auto file = SDL_RWFromFile((basePath + name).c_str(), str_mode);

if(!file) {
// check if the path is under the save path
auto save_path = get_save_path();
if(name.compare(0, save_path.length(), save_path) == 0)
file = SDL_RWFromFile(name.c_str(), str_mode);
}

return file;
}

Expand Down Expand Up @@ -178,4 +187,13 @@ bool rename_file(const std::string &old_name, const std::string &new_name) {

bool remove_file(const std::string &path) {
return remove((basePath + path).c_str()) == 0;
}

std::string get_save_path() {
auto tmp = SDL_GetPrefPath(metadata_author, metadata_title);
std::string ret(tmp);

SDL_free(tmp);

return ret;
}
3 changes: 2 additions & 1 deletion 32blit-sdl/File.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ bool file_exists(const std::string &path);
bool directory_exists(const std::string &path);
bool create_directory(const std::string &path);
bool rename_file(const std::string &old_name, const std::string &new_name);
bool remove_file(const std::string &path);
bool remove_file(const std::string &path);
std::string get_save_path();
13 changes: 5 additions & 8 deletions 32blit-sdl/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@
#include "System.hpp"
#include "Renderer.hpp"
#include "Audio.hpp"
#include "UserCode.hpp"

#ifdef VIDEO_CAPTURE
#include "VideoCapture.hpp"
#endif

#ifndef WINDOW_TITLE
#define WINDOW_TITLE "32blit development (SDL)"
#endif

static bool running = true;

SDL_Window* window = nullptr;
Expand Down Expand Up @@ -112,13 +109,13 @@ void handle_event(SDL_Event &event) {
} else if (event.type == System::timer_event) {
switch(event.user.code) {
case 0:
SDL_SetWindowTitle(window, WINDOW_TITLE);
SDL_SetWindowTitle(window, metadata_title);
break;
case 1:
SDL_SetWindowTitle(window, WINDOW_TITLE " [SLOW]");
SDL_SetWindowTitle(window, (std::string(metadata_title) + " [SLOW]").c_str());
break;
case 2:
SDL_SetWindowTitle(window, WINDOW_TITLE " [FROZEN]");
SDL_SetWindowTitle(window, (std::string(metadata_title) + " [FROZEN]").c_str());
break;
}
}
Expand Down Expand Up @@ -149,7 +146,7 @@ int main(int argc, char *argv[]) {
}

window = SDL_CreateWindow(
WINDOW_TITLE,
metadata_title,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
System::width*2, System::height*2,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
Expand Down
1 change: 1 addition & 0 deletions 32blit-sdl/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ void System::run() {
blit::api.create_directory = ::create_directory;
blit::api.rename_file = ::rename_file;
blit::api.remove_file = ::remove_file;
blit::api.get_save_path = ::get_save_path;

blit::api.enable_us_timer = ::enable_us_timer;
blit::api.get_us_timer = ::get_us_timer;
Expand Down
11 changes: 8 additions & 3 deletions 32blit-sdl/UserCode.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#pragma once
#include <string>

void init();
void update(uint32_t time);
void render(uint32_t time);
void init();
void update(uint32_t time);
void render(uint32_t time);

extern const char *metadata_title;
extern const char *metadata_author;
extern const char *metadata_description;
extern const char *metadata_version;
10 changes: 10 additions & 0 deletions 32blit-stm32/Inc/executable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@ struct BlitGameHeader {

uint32_t end;
uint32_t start;
};

// missing the "BLITMETA" header and size
struct RawMetadata {
uint32_t crc32;
char datetime[16];
char title[25];
char description[129];
char version[17];
char author[17];
};
3 changes: 2 additions & 1 deletion 32blit-stm32/Inc/file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ bool file_exists(const std::string &path);
bool directory_exists(const std::string &path);
bool create_directory(const std::string &path);
bool rename_file(const std::string &old_name, const std::string &new_name);
bool remove_file(const std::string &path);
bool remove_file(const std::string &path);
std::string get_save_path();
12 changes: 10 additions & 2 deletions 32blit-stm32/Src/32blit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ void blit_init() {
blit::api.create_directory = ::create_directory;
blit::api.rename_file = ::rename_file;
blit::api.remove_file = ::remove_file;
blit::api.get_save_path = ::get_save_path;

blit::api.enable_us_timer = ::enable_us_timer;
blit::api.get_us_timer = ::get_us_timer;
Expand Down Expand Up @@ -963,7 +964,14 @@ void blit_switch_execution(uint32_t address)
if(game_header->magic == blit_game_magic) {
// load function pointers
auto init = (BlitInitFunction)((uint8_t *)game_header->init + address);

// set these up early so that blit_user_code_running works in code called from init
user_render = (BlitRenderFunction) ((uint8_t *)game_header->render + address);
user_tick = (BlitTickFunction) ((uint8_t *)game_header->tick + address);

if(!init(address)) {
user_render = nullptr;
user_tick = nullptr;
// this would just be a return, but qspi is already mapped by this point
persist.reset_target = prtFirmware;
SCB_CleanDCache();
Expand All @@ -973,8 +981,8 @@ void blit_switch_execution(uint32_t address)

persist.last_game_offset = address;

blit::render = user_render = (BlitRenderFunction) ((uint8_t *)game_header->render + address);
do_tick = user_tick = (BlitTickFunction) ((uint8_t *)game_header->tick + address);
blit::render = user_render;
do_tick = user_tick;
return;
}
// anything flashed at a non-zero offset should have a valid header
Expand Down
38 changes: 38 additions & 0 deletions 32blit-stm32/Src/file.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include <cstdint>
#include <cstring>
#include <map>

#include "fatfs.h"

#include "file.hpp"
#include "32blit.h"
#include "executable.hpp"

void *open_file(const std::string &file, int mode) {
FIL *f = new FIL();
Expand Down Expand Up @@ -134,4 +137,39 @@ bool rename_file(const std::string &old_name, const std::string &new_name) {

bool remove_file(const std::string &path) {
return f_unlink(path.c_str()) == FR_OK;
}

std::string get_save_path() {
std::string app_name;

if(!directory_exists(".blit"))
create_directory(".blit");

if(!blit_user_code_running())
app_name = "_firmware";
else {
// TODO: this probably can be used for other things
auto game_ptr = reinterpret_cast<uint8_t *>(0x90000000 + persist.last_game_offset);

auto header = reinterpret_cast<BlitGameHeader *>(game_ptr);

if(header->magic == blit_game_magic) {
auto end_ptr = game_ptr + (header->end - 0x90000000);
if(memcmp(end_ptr, "BLITMETA", 8) == 0) {
auto meta = reinterpret_cast<RawMetadata *>(end_ptr + 10);
app_name = meta->title;
}
}

if(app_name.empty()) {
// fallback to offset
app_name = std::to_string(persist.last_game_offset);
}
}

// make sure it exists
if(!directory_exists(".blit/" + app_name))
create_directory(".blit/" + app_name);

return ".blit/" + app_name + "/";
}
1 change: 1 addition & 0 deletions 32blit/32blit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "engine/output.hpp"
#include "engine/input.hpp"
#include "audio/audio.hpp"
#include "engine/save.hpp"
#include "engine/timer.hpp"
#include "engine/tweening.hpp"
#include "graphics/blend.hpp"
Expand Down
3 changes: 2 additions & 1 deletion 32blit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ set(SOURCES
engine/output.cpp
engine/particle.cpp
engine/profiler.cpp
engine/running_average.cpp
engine/running_average.cpp
engine/save.cpp
engine/timer.cpp
engine/tweening.cpp
engine/version.cpp
Expand Down
1 change: 1 addition & 0 deletions 32blit/engine/api_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace blit {
bool (*create_directory) (const std::string &path);
bool (*rename_file) (const std::string &old_name, const std::string &new_name);
bool (*remove_file) (const std::string &path);
std::string (*get_save_path)();

// profiler
void (*enable_us_timer)();
Expand Down
31 changes: 31 additions & 0 deletions 32blit/engine/save.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "save.hpp"
#include "api_private.hpp"
#include "file.hpp"

namespace blit {
/**
* Read a block of save data from a save slot.
*
* \param data Pointer to store data into, should be at least `length` bytes
* \param length Expected length of save data
* \param slot Save slot to load, can be any number
*
* \return `true` if a save exists and contains enough data
*/
bool read_save(char *data, uint32_t length, int slot) {
File file(api.get_save_path() + "save" + std::to_string(slot));

return file.is_open() && uint32_t(file.read(0, length, data)) == length;
}

/**
* Write a block of save data to a save slot.
*
* \param data Pointer to data to write, should be `length` bytes
* \param length Length of data to write
* \param slot Save slot to write to, can be any number
*/
void write_save(const char *data, uint32_t length, int slot) {
File(api.get_save_path() + "save" + std::to_string(slot), OpenMode::write).write(0, length, data);
}
}
22 changes: 22 additions & 0 deletions 32blit/engine/save.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <cstdint>

namespace blit {
bool read_save(char *data, uint32_t length, int slot = 0);
void write_save(const char *data, uint32_t length, int slot = 0);

/**
* \overload
*/
template<class T>
bool read_save(T &data, int slot = 0) {
return read_save(reinterpret_cast<char *>(&data), sizeof(T), slot);
}

/**
* \overload
*/
template<class T>
void write_save(const T &data, int slot = 0) {
write_save(reinterpret_cast<const char *>(&data), sizeof(T), slot);
}
}
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_subdirectory(profiler-test)
#add_subdirectory(racer)
add_subdirectory(raycaster)
add_subdirectory(rotozoom)
add_subdirectory(saves)
add_subdirectory(scrolly-tile)
add_subdirectory(serial-debug)
add_subdirectory(shmup)
Expand Down
8 changes: 8 additions & 0 deletions examples/saves/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

cmake_minimum_required(VERSION 3.8)
project (saves)
set(32BLIT_PATH "../../" CACHE PATH "Path to 32blit.cmake")
include (${32BLIT_PATH}/32blit.cmake)

blit_executable (saves saves.cpp)
blit_metadata (saves metadata.yml)
8 changes: 8 additions & 0 deletions examples/saves/metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title: Saves
description: Save data example.
author: daft_freak
splash:
file: ../no-image.png
icon:
file: ../no-icon.png
version: v1.0.0
Loading