Let's get this up to date, i'll update the readme later on

This commit is contained in:
2026-05-27 14:30:33 +02:00
parent f1c1035c74
commit 570d7f8bc4
53 changed files with 938 additions and 897 deletions
+258 -57
View File
@@ -1,9 +1,17 @@
#include "storage.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sprite_data.h"
#include "defs/screen_defs.h"
#include "TFT_eSPI.h"
const char* TAG_S = "[STORAGE]";
// All sprites are upscaled by this factor at load time so draw_drawSprite
// can skip the scaling loop entirely at runtime.
#define SPRITE_SCALE 6
void storage_init() {
if (!SPIFFS.begin(true)) {
printf("%s Failed to mount file system\n", TAG_S);
@@ -20,56 +28,93 @@ void storage_readFile(const char* path, struct SpriteData* spriteData) {
return;
}
size_t bytesRead = 0;
size_t fileSize = file.size();
uint8_t width, height, spriteNumber;
bytesRead += file.read(&width, 1);
bytesRead += file.read(&height, 1);
bytesRead += file.read(&spriteNumber, 1);
file.read(&width, 1);
file.read(&height, 1);
file.read(&spriteNumber, 1);
if (spriteData->spriteData != NULL) {
memory_free(spriteData);
}
spriteData->spriteWidth = width;
spriteData->spriteHeight = height;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = memory_allocate(spriteData->spriteNumber, spriteData->spriteWidth, spriteData->spriteHeight);
}
const uint8_t scaledW = width * SPRITE_SCALE;
const uint8_t scaledH = height * SPRITE_SCALE;
// Allocate scaled buffers in PSRAM (ps_malloc falls back to regular heap
// automatically if PSRAM is not available for a given allocation).
uint16_t** scaled = (uint16_t**) ps_malloc(spriteNumber * sizeof(uint16_t*));
if (!scaled) {
printf("%s PSRAM alloc failed for pointer table\n", TAG_S);
file.close();
return;
}
for (uint8_t i = 0; i < spriteNumber; i++) {
scaled[i] = (uint16_t*) ps_malloc(scaledW * scaledH * sizeof(uint16_t));
if (!scaled[i]) {
printf("%s PSRAM alloc failed for sprite %d\n", TAG_S, i);
for (uint8_t j = 0; j < i; j++) free(scaled[j]);
free(scaled);
file.close();
return;
}
}
// Temporary single-row scratch buffer in internal RAM for reading from file
uint16_t* rowBuf = (uint16_t*) malloc(width * sizeof(uint16_t));
if (!rowBuf) {
printf("%s scratch alloc failed\n", TAG_S);
for (uint8_t i = 0; i < spriteNumber; i++) free(scaled[i]);
free(scaled);
file.close();
return;
}
printf(
"%s Read header: width=%d, height=%d, numSprites=%d\n",
TAG_S, spriteData->spriteWidth, spriteData->spriteHeight, spriteData->spriteNumber
"%s Read header: width=%d, height=%d, numSprites=%d -> scaled to %dx%d\n",
TAG_S, width, height, spriteNumber, scaledW, scaledH
);
fileSize = (fileSize - 3) / sizeof(uint16_t);
for (int sprN = 0; sprN < spriteNumber; sprN++) {
uint16_t* dst = scaled[sprN];
size_t bufferSize = spriteData->spriteNumber * spriteData->spriteWidth * spriteData->spriteHeight;
for (int srcY = 0; srcY < height; srcY++) {
// --- Read one source row, byte-swapping as we go ---
for (int srcX = 0; srcX < width; srcX++) {
uint8_t hi, lo;
file.read(&hi, 1);
file.read(&lo, 1);
// File is big-endian RGB565; TFT_eSPI expects little-endian
rowBuf[srcX] = (lo << 8) | hi;
}
uint8_t highByte;
uint8_t lowByte;
// --- Scale row vertically (repeat SPRITE_SCALE times) ---
for (int dy = 0; dy < SPRITE_SCALE; dy++) {
uint16_t* dstRow = dst + (srcY * SPRITE_SCALE + dy) * scaledW;
for (int sprN = 0; sprN < spriteData->spriteNumber; sprN++) {
for (int i = 0; i < spriteData->spriteWidth * spriteData->spriteHeight; i++) {
bytesRead += file.read(&highByte, 1);
bytesRead += file.read(&lowByte, 1);
uint16_t pixel = (highByte << 8) | lowByte;
if (i < bufferSize) {
(spriteData->spriteData)[sprN][i] = pixel;
} else {
printf("%s Buffer overflow, skipping pixel\n", TAG_S);
break;
// --- Scale each pixel horizontally ---
for (int srcX = 0; srcX < width; srcX++) {
uint16_t color = rowBuf[srcX];
uint16_t* dstPixel = dstRow + srcX * SPRITE_SCALE;
for (int dx = 0; dx < SPRITE_SCALE; dx++) {
dstPixel[dx] = color;
}
}
}
}
}
printf("%s Read %zu bytes from file %s\n", TAG_S, bytesRead, path);
free(rowBuf);
file.close();
// Store scaled dimensions so the rest of the code sees the final size
spriteData->spriteWidth = scaledW;
spriteData->spriteHeight = scaledH;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = scaled;
printf("%s Loaded & upscaled %s (%d sprites, each %dx%d px)\n",
TAG_S, path, spriteNumber, scaledW, scaledH);
}
void storage_initBackground(const char* path, TFT_eSprite& bg) {
@@ -79,40 +124,196 @@ void storage_initBackground(const char* path, TFT_eSprite& bg) {
return;
}
size_t bytesRead = 0;
uint8_t width, height;
file.read(&width, 1);
file.read(&height, 1);
size_t fileSize = file.size();
size_t pixelCount = width * height;
uint8_t width;
uint8_t height;
bytesRead += file.read(&width, 1);
bytesRead += file.read(&height, 1);
printf("%s Read header: width=%d, height=%d\n", TAG_S, width, height);
fileSize = (fileSize - 2) / sizeof(uint16_t);
printf("%s width=%d height=%d pixels=%zu\n", TAG_S, width, height, pixelCount);
bg.createSprite(width, height);
for(int i = 0; i < width * height; i++) {
uint8_t highByte;
uint8_t lowByte;
uint16_t* bgBuf = (uint16_t*) bg.getPointer();
bytesRead += file.read(&highByte, 1);
bytesRead += file.read(&lowByte, 1);
for (size_t i = 0; i < pixelCount; i++) {
uint8_t hi, lo;
file.read(&lo, 1);
file.read(&hi, 1);
// Store directly into sprite buffer – no byte swap needed here since
// background pixels are not going through the draw_drawSprite path.
bgBuf[i] = (hi << 8) | lo;
}
uint16_t pixel = (highByte << 8) | lowByte;
file.close();
}
if (i < fileSize) {
bg.drawPixel(i % width, i / width, pixel);
} else {
printf("%s Buffer overflow, skipping pixel\n", TAG_S);
break;
void storage_saveState() {
File file;
file = SPIFFS.open("/save.bin", "w");
if (!file) {
printf("%s Cannot save: cannot open save file.\n", TAG_S);
return;
}
file.write(
(uint8_t*) charaData,
sizeof(struct CharacterData) * CHARA_COUNT_IN_DEVICE
);
printf("%s Saved current character data.\n", TAG_S);
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
printf("%s Saving line data %i\n", TAG_S, i);
uint8_t lineUsed = (currentLine[i] != NULL);
file.write(lineUsed);
if (lineUsed) {
file.write(currentLine[i]->id);
file.write((uint8_t*) &(currentLine[i]->hatchTime), sizeof(uint16_t));
file.write((uint8_t*) currentLine[i]->name, 16);
file.write(currentLine[i]->charaNumber);
printf("%s Done saving static line %i\n", TAG_S, i);
uint8_t hasCharacters = (currentLine[i]->characters != NULL);
file.write(hasCharacters);
printf("%s hasCharacters=%i, characters=%i, charaNumber=%i\n",
TAG_S, hasCharacters, currentLine[i]->characters, currentLine[i]->charaNumber);
if (hasCharacters) {
file.write(
(uint8_t*) currentLine[i]->characters,
sizeof(LineChara_t) * currentLine[i]->charaNumber
);
}
printf("%s Done saving line data for %i\n", TAG_S, i);
}
}
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
printf("%s Saving care data %i\n", TAG_S, i);
uint8_t careDataUsed = currentLineCareInstr[i] != NULL;
file.write(careDataUsed);
if (careDataUsed) {
file.write(currentLineCareInstr[i]->lineId);
file.write(currentLineCareInstr[i]->numCareMistakesData);
printf("%s Done saving static care data %i\n", TAG_S, i);
uint8_t hasCareData = (currentLineCareInstr[i]->careMistakeData != NULL);
file.write(hasCareData);
printf("%s hasCharacters=%i, characters=%i, charaNumber=%i\n",
TAG_S, hasCareData, currentLineCareInstr[i]->careMistakeData, currentLineCareInstr[i]->numCareMistakesData);
if (hasCareData) {
file.write(
(uint8_t*) currentLineCareInstr[i]->careMistakeData,
sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData
);
}
printf("%s Done saving care data for %i\n", TAG_S, i);
}
}
file.write(currentCharacter);
file.close();
printf("%s Save completed!\n", TAG_S);
}
void storage_loadState() {
File file;
if (!SPIFFS.exists("/save.bin")) {
printf("%s Cannot load: File does not exist.\n", TAG_S);
return;
}
file = SPIFFS.open("/save.bin", "r");
if (!file) {
printf("%s Cannot save: cannot open save file.\n", TAG_S);
return;
}
file.read((uint8_t*) charaData, sizeof(struct CharacterData) * CHARA_COUNT_IN_DEVICE);
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
uint8_t currentLineUsed = file.read();
if (currentLineUsed) {
currentLine[i] = (Line_t*) calloc(1, sizeof(Line_t));
currentLine[i]->id = file.read();
file.read((uint8_t*) &(currentLine[i]->hatchTime), sizeof(uint16_t));
file.read((uint8_t*) currentLine[i]->name, 16);
currentLine[i]->charaNumber = file.read();
uint8_t hasCharacters = file.read();
if (hasCharacters) {
if (currentLine[i]->characters != NULL) {
free(currentLine[i]->characters);
}
currentLine[i]->characters = (LineChara_t*) malloc(sizeof(LineChara_t) * currentLine[i]->charaNumber);
file.read(
(uint8_t*) currentLine[i]->characters,
sizeof(LineChara_t) * currentLine[i]->charaNumber
);
} else {
currentLine[i]->characters = NULL;
}
}
}
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
uint8_t currentLineUsed = file.read();
if (currentLineUsed) {
currentLineCareInstr[i] = (LineCare_t*) calloc(1, sizeof(LineCare_t));
currentLineCareInstr[i]->lineId = file.read();
currentLineCareInstr[i]->numCareMistakesData = file.read();
uint8_t hasCareData = file.read();
if (hasCareData) {
if (currentLineCareInstr[i]->careMistakeData != NULL) {
free(currentLineCareInstr[i]->careMistakeData);
}
currentLineCareInstr[i]->careMistakeData = (CareMistakes_t*) malloc(sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData);
file.read(
(uint8_t*) currentLineCareInstr[i]->careMistakeData,
sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData
);
} else {
currentLineCareInstr[i]->careMistakeData = NULL;
}
}
}
printf("%s Read %zu bytes from file %s\n", TAG_S, bytesRead, path);
currentCharacter = file.read();
file.close();
char spriteFileName[30];
snprintf(spriteFileName, 30, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(spriteFileName, &mainCharacterSprites);
printf("%s Load completed!\n", TAG_S);
}
+4 -1
View File
@@ -9,6 +9,9 @@
void storage_init();
void storage_readFile(const char* path, struct SpriteData* spriteData);
void storage_initBackground(const char* path, TFT_eSprite& bg);
void storage_initBackground(const char* path, TFT_eSprite &bg);
void storage_saveState();
void storage_loadState();
#endif