Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM ghcr.io/wiiu-env/devkitppc:20240704
FROM ghcr.io/wiiu-env/devkitppc:20241128

WORKDIR project
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ INCLUDES := source include
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -g -Wall -O2 -ffunction-sections -fno-exceptions \
CFLAGS := -g -Wall -Os -ffunction-sections \
$(MACHDEP)

CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__

CXXFLAGS := $(CFLAGS) -std=c++20 -fno-rtti
CXXFLAGS := $(CFLAGS) -std=c++23 -fno-rtti

ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
Expand Down
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ This module is supposed to be loaded with the [EnvironmentLoader](https://github
other modules of the environment are loading.

## Usage
Place the `01_splashscreen.rpx` in the `[ENVIRONMENT]/modules/setup` folder and run the EnvironmentLoader.
- Requires a `splash.png` (recommended) or `splash.tga` in the `[ENVIRONMENT]` directory.
- When using a `tga` make sure its 24 bit and uncompressed
- In theory any (reasonable) resolution is supported, something like 1280x720 is recommended
Place the `01_splashscreen.rpx` in the `[ENVIRONMENT]/modules/setup` folder and run the
EnvironmentLoader. The module will attempt to load the splash image, in this order:
1. `[ENVIRONMENT]/splash.png`
2. `[ENVIRONMENT]/splash.tga`
3. A random image from the directory `[ENVIRONMENT]/splashes/`.

If no splash screen is found on the sd card, this module will effectively do nothing.

**Note:** `[ENVIRONMENT]` is the directory of the environment, for Aroma with would be `sd:/wiiu/enviroments/aroma/splash.png`
**Notes:**
- `[ENVIRONMENT]` is the directory of the environment, for Aroma with would be `sd:/wiiu/enviroments/aroma/splash.png`
- When using a `tga` make sure its 24 bit and uncompressed
- In theory any (reasonable) resolution is supported, something like 1280x720 is recommended

## Buildflags

Expand Down Expand Up @@ -48,4 +52,4 @@ docker run -it --rm -v ${PWD}:/project splashscreenmodule-builder make clean

## Credits
- Maschell
- Crementif
- Crementif
18 changes: 18 additions & 0 deletions source/gfx/PNGTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <gx2/mem.h>
#include <malloc.h>
#include <png.h>
#include <utils/logger.h>

static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
void **data = (void **) png_get_io_ptr(png_ptr);
Expand All @@ -11,6 +12,15 @@ static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t by
*((uint8_t **) data) += byteCountToRead;
}

void my_png_error_fn(png_structp png_ptr, png_const_charp error_msg) {
DEBUG_FUNCTION_LINE_ERR("libpng error: %s\n", error_msg);
longjmp(png_jmpbuf(png_ptr), 1);
}

void my_png_warning_fn(png_structp png_ptr, png_const_charp warning_msg) {
DEBUG_FUNCTION_LINE_ERR("libpng warning: %s\n", warning_msg);
}

GX2Texture *PNG_LoadTexture(std::span<uint8_t> data) {
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png_ptr == nullptr) {
Expand All @@ -23,6 +33,14 @@ GX2Texture *PNG_LoadTexture(std::span<uint8_t> data) {
return nullptr;
}

png_set_error_fn(png_ptr, nullptr, my_png_error_fn, my_png_warning_fn);
// Error handling using setjmp/longjmp
if (setjmp(png_jmpbuf(png_ptr))) {
DEBUG_FUNCTION_LINE_ERR("An error occurred while processing the PNG file\n");
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return nullptr;
}

png_set_read_fn(png_ptr, (void *) &data, png_read_data);

png_read_info(png_ptr, info_ptr);
Expand Down
65 changes: 51 additions & 14 deletions source/gfx/SplashScreenDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
#include "gfx.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include <fstream>
#include <cctype>
#include <coreinit/time.h>
#include <gx2/draw.h>
#include <gx2/mem.h>
#include <gx2r/draw.h>
#include <random>
#include <whb/log.h>

/*
Expand Down Expand Up @@ -115,24 +117,59 @@ uint8_t empty_png[119] = {
0x0C, 0x0C, 0x00, 0x00, 0x0E, 0x00, 0x01, 0x7A, 0xB1, 0xB9, 0x30, 0x00,
0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82};

static GX2Texture *LoadImageAsTexture(std::string_view path) {
static std::filesystem::path ToLower(const std::filesystem::path &p) {
std::string result;
for (auto c : p.string()) {
result.push_back(std::tolower(static_cast<unsigned char>(c)));
}
return result;
}

static GX2Texture *LoadImageAsTexture(const std::filesystem::path &filename) {
std::vector<uint8_t> buffer;
if (LoadFileIntoBuffer(std::string(path).append("splash.png"), buffer)) {
auto *texture = PNG_LoadTexture(buffer);
if (texture) {
return texture;
}
} else if (LoadFileIntoBuffer(std::string(path).append("splash.tga"), buffer)) {
auto *texture = TGA_LoadTexture(buffer);
if (texture) {
return texture;
if (LoadFileIntoBuffer(filename, buffer)) {
auto ext = ToLower(filename.extension());
if (ext == ".png") {
return PNG_LoadTexture(buffer);
} else if (ext == ".tga") {
return TGA_LoadTexture(buffer);
}
}
return PNG_LoadTexture(empty_png);
return nullptr;
}

SplashScreenDrawer::SplashScreenDrawer(std::string_view splash_base_path) {
mTexture = LoadImageAsTexture(splash_base_path);
SplashScreenDrawer::SplashScreenDrawer(const std::filesystem::path &splash_base_path) {
mTexture = LoadImageAsTexture(splash_base_path / "splash.png");
if (!mTexture) {
mTexture = LoadImageAsTexture(splash_base_path / "splash.tga");
}
if (!mTexture) {
// try to load a random one from "splashes/*"
try {
std::vector<std::filesystem::path> candidates;
for (const auto &entry : std::filesystem::directory_iterator{splash_base_path / "splashes"}) {
if (!entry.is_regular_file()) {
continue;
}
auto ext = ToLower(entry.path().extension());
if (ext == ".png" || ext == ".tga") {
candidates.push_back(entry.path());
}
}
if (!candidates.empty()) {
auto t = static_cast<std::uint64_t>(OSGetTime());
std::seed_seq seed{static_cast<std::uint32_t>(t),
static_cast<std::uint32_t>(t >> 32)};
std::minstd_rand eng{seed};
std::uniform_int_distribution<std::size_t> dist{0, candidates.size() - 1};
auto selected = dist(eng);
mTexture = LoadImageAsTexture(candidates[selected]);
}
} catch (std::exception &) {}
}
if (!mTexture) {
mTexture = PNG_LoadTexture(empty_png);
}
if (!mTexture) {
return;
}
Expand Down
3 changes: 2 additions & 1 deletion source/gfx/SplashScreenDrawer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "ShaderSerializer.h"
#include "gfx.h"
#include <filesystem>
#include <gx2/sampler.h>
#include <gx2/shaders.h>
#include <gx2/texture.h>
Expand All @@ -10,7 +11,7 @@

class SplashScreenDrawer {
public:
explicit SplashScreenDrawer(std::string_view meta_dir);
explicit SplashScreenDrawer(const std::filesystem::path &meta_dir);

void Draw();

Expand Down
4 changes: 2 additions & 2 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ int32_t main(int32_t argc, char **argv) {
initLogging();
DEBUG_FUNCTION_LINE_INFO("Running SplashScreen Module " MODULE_VERSION_FULL "");

std::string basePath = "fs:/vol/external01/wiiu";
std::filesystem::path basePath = "fs:/vol/external01/wiiu";
if (argc >= 1) {
basePath = argv[0];
}

GfxInit();
{
SplashScreenDrawer splashScreenDrawer(basePath + "/");
SplashScreenDrawer splashScreenDrawer(basePath);
splashScreenDrawer.Draw();
}
GfxShutdown();
Expand Down
23 changes: 14 additions & 9 deletions source/utils/utils.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
#include "utils.h"
#include "logger.h"
#include <cstdint>
#include <cstdio>
#include <string_view>
#include <stdexcept>
#include <sys/stat.h>
#include <vector>

bool LoadFileIntoBuffer(std::string_view path, std::vector<uint8_t> &buffer) {
bool LoadFileIntoBuffer(const std::filesystem::path &filename, std::vector<uint8_t> &buffer) {
struct stat st {};
if (stat(path.data(), &st) < 0 || !S_ISREG(st.st_mode)) {
DEBUG_FUNCTION_LINE_INFO("\"%s\" doesn't exists", path.data());
if (stat(filename.c_str(), &st) < 0 || !S_ISREG(st.st_mode)) {
DEBUG_FUNCTION_LINE_INFO("\"%s\" doesn't exists", filename.c_str());
return false;
}

FILE *f = fopen(path.data(), "rb");
FILE *f = fopen(filename.c_str(), "rb");
if (!f) {
return false;
}
buffer.resize(st.st_size);
try {
buffer.resize(st.st_size);
} catch (std::bad_alloc &e) {
DEBUG_FUNCTION_LINE_WARN("Failed allocate memory for %s: %s", filename.c_str(), e.what());
}

if (fread(buffer.data(), 1, st.st_size, f) != st.st_size) {
DEBUG_FUNCTION_LINE_WARN("Failed load %s", path.data());
DEBUG_FUNCTION_LINE_WARN("Failed load %s", filename.c_str());
fclose(f);
return false;
}
fclose(f);
return true;
}
}
5 changes: 2 additions & 3 deletions source/utils/utils.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#pragma once

#include <cstdint>
#include <string_view>
#include <sys/stat.h>
#include <filesystem>
#include <vector>

bool LoadFileIntoBuffer(std::string_view path, std::vector<uint8_t> &buffer);
bool LoadFileIntoBuffer(const std::filesystem::path &filename, std::vector<uint8_t> &buffer);