git repos / sago_multi_scrambler_puzzle2

commit 48ed64d1

Poul Sander · 2026-03-31 18:13
48ed64d135c6df95ce33f0ddd3ddb3b5eb6fbfc9 patch · browse files
parent b53e42789ae075585ce5cc33b4ee180a39a4965f

Use PhysFS for the collections

Changed files

M src/CollectionPlayState.cpp before
M src/CollectionPlayState.hpp before
M src/ImageHolder.cpp before
M src/ImageHolder.hpp before
M src/PuzzleSingleImageState.cpp before
M src/PuzzleSingleImageState.hpp before
diff --git a/src/CollectionPlayState.cpp b/src/CollectionPlayState.cpp index 06e34b6..8bbbf4f 100644 --- a/src/CollectionPlayState.cpp +++ b/src/CollectionPlayState.cpp
@@ -30,7 +30,6 @@ https://github.com/sago007/saland
#include "SagoImGui.hpp"
#include "nlohmann/json.hpp"
#include <iostream>
-#include <physfs.h>
CollectionPlayState::CollectionPlayState(const std::string& collectionDir)
: collectionDir(collectionDir) {
@@ -204,13 +203,13 @@ void CollectionPlayState::Update() {
if (currentPuzzleIndex >= 0 && currentPuzzleIndex < static_cast<int>(puzzles.size())) {
const CollectionPuzzleInfo& puzzle = puzzles[currentPuzzleIndex];
- std::string imagePath = GetImageFilesystemPath(puzzle.image);
+ std::string imagePath = GetImagePhysFSPath(puzzle.image);
if (!imagePath.empty()) {
PuzzleSingleImageState psi;
psi.flipMode = puzzle.flip_mode;
psi.rectangularMode = puzzle.rectangular_mode;
- psi.LoadPictureFromFile(imagePath, globalData.screen);
+ psi.LoadPictureFromPhysFS(imagePath, globalData.screen);
RunGameState(psi);
globalData.mouseUp = true;
@@ -280,22 +279,17 @@ void CollectionPlayState::LoadCollection() {
void CollectionPlayState::LoadCurrentImage() {
if (currentPuzzleIndex >= 0 && currentPuzzleIndex < static_cast<int>(puzzles.size())) {
- std::string imagePath = GetImageFilesystemPath(puzzles[currentPuzzleIndex].image);
+ std::string imagePath = GetImagePhysFSPath(puzzles[currentPuzzleIndex].image);
ImageHolder newHolder;
if (!imagePath.empty()) {
- newHolder.LoadPictureFromFileLazy(imagePath);
+ newHolder.LoadPictureFromPhysFSLazy(imagePath);
}
currentImageHolder = std::move(newHolder);
}
}
-std::string CollectionPlayState::GetImageFilesystemPath(const std::string& imageFilename) const {
- std::string physfsPath = "collections/" + collectionDir + "/" + imageFilename;
- const char* realDir = PHYSFS_getRealDir(physfsPath.c_str());
- if (realDir) {
- return std::string(realDir) + "/" + physfsPath;
- }
- return "";
+std::string CollectionPlayState::GetImagePhysFSPath(const std::string& imageFilename) const {
+ return "collections/" + collectionDir + "/" + imageFilename;
}
int CollectionPlayState::FindFirstUnsolved() const {
diff --git a/src/CollectionPlayState.hpp b/src/CollectionPlayState.hpp index 311793e..163a791 100644 --- a/src/CollectionPlayState.hpp +++ b/src/CollectionPlayState.hpp
@@ -52,7 +52,7 @@ public:
private:
void LoadCollection();
void LoadCurrentImage();
- std::string GetImageFilesystemPath(const std::string& imageFilename) const;
+ std::string GetImagePhysFSPath(const std::string& imageFilename) const;
int FindFirstUnsolved() const;
bool isActive = true;
diff --git a/src/ImageHolder.cpp b/src/ImageHolder.cpp index 5bf955c..8b101ee 100644 --- a/src/ImageHolder.cpp +++ b/src/ImageHolder.cpp
@@ -23,6 +23,8 @@ https://github.com/sago007/saland
#include "ImageHolder.hpp"
#include <SDL_image.h>
+#include "sago/SagoMisc.hpp"
+#include <memory>
ImageHolder::ImageHolder() : pictureTex(nullptr), source_image_width(1), source_image_height(1) {}
@@ -32,6 +34,7 @@ ImageHolder::ImageHolder(ImageHolder&& other) {
source_image_height = other.source_image_height;
source_filename = other.source_filename;
do_lazy_load = other.do_lazy_load;
+ physfs_lazy_load = other.physfs_lazy_load;
other.pictureTex = nullptr;
}
@@ -45,6 +48,7 @@ ImageHolder& ImageHolder::operator=(ImageHolder&& other) {
source_image_height = other.source_image_height;
source_filename = other.source_filename;
do_lazy_load = other.do_lazy_load;
+ physfs_lazy_load = other.physfs_lazy_load;
other.pictureTex = nullptr;
}
return *this;
@@ -80,11 +84,42 @@ void ImageHolder::LoadPictureFromFile(const std::string& filename, SDL_Renderer*
SDL_FreeSurface(pictureSurface);
}
+void ImageHolder::LoadPictureFromPhysFS(const std::string& physfsPath, SDL_Renderer* renderer) {
+ source_filename = physfsPath;
+ std::unique_ptr<char[]> data;
+ unsigned int bytes = 0;
+ sago::ReadBytesFromFile(physfsPath.c_str(), data, bytes);
+ if (!data || bytes == 0) {
+ printf("ImageHolder::LoadPictureFromPhysFS() failed to read file: %s\n", physfsPath.c_str());
+ return;
+ }
+ SDL_RWops* rw = SDL_RWFromMem(data.get(), bytes);
+ SDL_Surface* pictureSurface = IMG_Load_RW(rw, 0);
+ SDL_RWclose(rw);
+ if (pictureSurface == nullptr) {
+ printf("ImageHolder::LoadPictureFromPhysFS() failed to load image: %s\n", physfsPath.c_str());
+ return;
+ }
+ if (pictureTex != nullptr) {
+ SDL_DestroyTexture(pictureTex);
+ }
+ pictureTex = SDL_CreateTextureFromSurface(renderer, pictureSurface);
+ source_image_width = pictureSurface->w;
+ source_image_height = pictureSurface->h;
+ SDL_FreeSurface(pictureSurface);
+}
+
void ImageHolder::LoadPictureFromFileLazy(const std::string& filename) {
source_filename = filename;
do_lazy_load = true;
}
+void ImageHolder::LoadPictureFromPhysFSLazy(const std::string& physfsPath) {
+ source_filename = physfsPath;
+ do_lazy_load = true;
+ physfs_lazy_load = true;
+}
+
int ImageHolder::GetWidth() const {
return source_image_width;
@@ -102,8 +137,13 @@ void ImageHolder::Draw(SDL_Renderer* target, int x, int y, int max_w, int max_h)
if (do_lazy_load) {
printf("Lazy loading image: %s\n", source_filename.c_str());
std::string filename = source_filename;
- LoadPictureFromFile(filename, target);
+ if (physfs_lazy_load) {
+ LoadPictureFromPhysFS(filename, target);
+ } else {
+ LoadPictureFromFile(filename, target);
+ }
do_lazy_load = false;
+ physfs_lazy_load = false;
}
if (pictureTex == nullptr) {
//printf("ImageHolder::Draw() called with no image loaded. Filename: %s\n", source_filename.c_str());
diff --git a/src/ImageHolder.hpp b/src/ImageHolder.hpp index 28a15fd..d15f990 100644 --- a/src/ImageHolder.hpp +++ b/src/ImageHolder.hpp
@@ -49,7 +49,9 @@ public:
// Other member functions and variables
void LoadPictureFromFile(const std::string& filename, SDL_Renderer* renderer);
+ void LoadPictureFromPhysFS(const std::string& physfsPath, SDL_Renderer* renderer);
void LoadPictureFromFileLazy(const std::string& filename);
+ void LoadPictureFromPhysFSLazy(const std::string& physfsPath);
int GetWidth() const;
int GetHeight() const;
SDL_Texture* GetTexture() const;
@@ -70,6 +72,7 @@ private:
// Private member variables
SDL_Texture* pictureTex = NULL;
bool do_lazy_load = false;
+ bool physfs_lazy_load = false;
int source_image_height = 1;
int source_image_width = 1;
std::string source_filename;
diff --git a/src/PuzzleSingleImageState.cpp b/src/PuzzleSingleImageState.cpp index c4ac61f..1a4abd9 100644 --- a/src/PuzzleSingleImageState.cpp +++ b/src/PuzzleSingleImageState.cpp
@@ -28,8 +28,10 @@ https://github.com/sago007/saland
#include "globals.hpp"
#include <SDL2/SDL2_gfxPrimitives.h>
#include <time.h>
+#include <memory>
#include <filesystem>
#include "SagoImGui.hpp"
+#include "sago/SagoMisc.hpp"
#include "rhash.hpp"
#include "config.hpp"
#include "sago_common.hpp"
@@ -357,6 +359,60 @@ void PuzzleSingleImageState::LoadPictureFromFile(const std::string& filename, SD
Shuffle();
}
+void PuzzleSingleImageState::LoadPictureFromPhysFS(const std::string& physfsPath, SDL_Renderer* renderer) {
+ ClearPicture();
+ imageFilePath = physfsPath;
+ IMG_Init(IMG_INIT_JPG|IMG_INIT_PNG);
+ std::unique_ptr<char[]> data;
+ unsigned int bytes = 0;
+ sago::ReadBytesFromFile(physfsPath.c_str(), data, bytes);
+ if (!data || bytes == 0) {
+ std::cerr << "Failed to read " << physfsPath << " from PhysFS" << std::endl;
+ return;
+ }
+ SDL_RWops* rw = SDL_RWFromMem(data.get(), bytes);
+ SDL_Surface* bitmapSurface = IMG_Load_RW(rw, 0);
+ SDL_RWclose(rw);
+ if (!bitmapSurface) {
+ std::cerr << "Failed to load " << physfsPath << std::endl;
+ return;
+ }
+ RHash h(RHASH_SHA256);
+ h.update(physfsPath);
+ picture_id = h.hex(RHASH_SHA256);
+ source_image_height = bitmapSurface->h;
+ source_image_width = bitmapSurface->w;
+ ResizeImage();
+ this->pictureTex = SDL_CreateTextureFromSurface(renderer, bitmapSurface);
+ std::cerr << resized_image_logical_width << ", " << resized_image_logical_height << ", id: " << picture_id << ", file: " << physfsPath << "\n";
+ SDL_FreeSurface(bitmapSurface);
+ SDL_SetTextureBlendMode(this->pictureTex, SDL_BLENDMODE_BLEND);
+ pieces_logical.clear();
+
+ if (rectangularMode) {
+ if (!LoadCustomPieceLayout(picture_id, pieces_logical)) {
+ CreateRectangularPieces(4, 4);
+ }
+ else {
+ std::cerr << "Loaded custom piece layout with " << pieces_logical.size() << " pieces\n";
+ }
+ }
+ else {
+ SDL_Rect piece;
+ piece.x = 0;
+ piece.y = 0;
+ piece.h = resized_image_logical_height;
+ piece.w = resized_image_logical_width;
+ pieces_logical.push_back(piece);
+ for (int i = 0; i<10; ++i) {
+ SplitPiece();
+ }
+ }
+
+ ResizeImagePhysical();
+ Shuffle();
+}
+
void PuzzleSingleImageState::SplitPiece(size_t piece_number) {
srand(time(NULL));
if (rand()%2==1) {
diff --git a/src/PuzzleSingleImageState.hpp b/src/PuzzleSingleImageState.hpp index b55663c..6e3f9e6 100644 --- a/src/PuzzleSingleImageState.hpp +++ b/src/PuzzleSingleImageState.hpp
@@ -40,6 +40,7 @@ public:
void Update() override;
void LoadPictureFromFile(const std::string& filename, SDL_Renderer* renderer);
+ void LoadPictureFromPhysFS(const std::string& physfsPath, SDL_Renderer* renderer);
bool IsSolved() const { return puzzleSolved; }