Compare commits
3 Commits
b2d5f5af61
...
0cd09f6d28
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cd09f6d28 | |||
| 083a57dab5 | |||
| 4244bcaea3 |
34
CLAUDE.md
@@ -86,8 +86,8 @@ The five current objectives are:
|
||||
| `source/core/input/` | New input layer | Free to modify |
|
||||
| `source/utils/` | New utilities | Free to modify |
|
||||
| `source/game/options,defines,defaults` | New config system | Free to modify |
|
||||
| `data/*.gif, *.ogg` | Original assets | **Do not modify** — assets remain untouchable |
|
||||
| `data/fonts/, data/ui/, data/shaders/` | New assets | Free to modify |
|
||||
| `data/gfx/, data/music/` | Original assets | **Do not modify** — assets remain untouchable |
|
||||
| `data/fonts/, data/shaders/, data/locale/` | New assets | Free to modify |
|
||||
|
||||
### Legacy "Jail" Engine (`source/core/jail/`) — modernization target
|
||||
|
||||
@@ -228,7 +228,7 @@ JD8_Flip produces ABGR byte order: `0xFF000000 + R + (G<<8) + (B<<16)`. SDL text
|
||||
| `~/.config/jailgames/aee/postfx.yaml` | PostFX shader presets (6 defaults: CRT, NTSC, CURVED, SCANLINES, SUBTLE, CRT LIVE) |
|
||||
| `~/.config/jailgames/aee/crtpi.yaml` | CRT-Pi shader presets (4 defaults: DEFAULT, CURVED, SHARP, MINIMAL) |
|
||||
|
||||
### Resource Pack (`source/core/resources/`) — **en construcció**
|
||||
### Resource Pack (`source/core/resources/`)
|
||||
|
||||
Sistema d'empaquetat d'assets a l'estil `coffee_crisis_arcade_edition`. Genera un sol fitxer binari opac `resource.pack` que substitueix la carpeta `data/` als releases natius.
|
||||
|
||||
@@ -249,22 +249,13 @@ Checksum: djb2-like amb seed `0x12345678`. Càrrega full-to-RAM (sense mmap).
|
||||
- `make pack` compila l'eina (target `pack_resources` a `EXCLUDE_FROM_ALL` de [CMakeLists.txt](CMakeLists.txt)) i genera `resource.pack` a la rel. 33 entrades ≈ 4 MB.
|
||||
- `./build/pack_resources --list resource.pack` inspecciona el pack.
|
||||
|
||||
**Estat actual (Fase 1 completada, 2026-04-16)**:
|
||||
- Classes + eina compilen i funcionen. El pack es genera correctament i el `--list` mostra les 33 entrades (totes les GIFs, OGGs, font `.fnt`+`.gif`, `locale/ca.yaml`, `shaders/*`).
|
||||
- **Encara no està cablejat al joc**: cap callsite usa `ResourceHelper::loadFile`. Tots segueixen cridant `file_readfile`. El joc funciona exactament igual que abans.
|
||||
- Nou getter `file_getresourcefolder()` afegit a [jfile.hpp](source/core/jail/jfile.hpp) perquè ResourceHelper puga construir el path del fallback.
|
||||
|
||||
**Pendent (Fases 2-6 del pla [.claude/plans/declarative-popping-breeze.md](/home/sergio/.claude/plans/declarative-popping-breeze.md))**:
|
||||
1. **Fase 2** — Afegir `ResourceHelper::initializeResourceSystem(pack_path, enable_fallback=true)` a [main.cpp](source/main.cpp) just després de `file_setresourcefolder`, i `shutdownResourceSystem()` a `SDL_AppQuit`.
|
||||
2. **Fase 3** — Migrar callsites `file_readfile` → `ResourceHelper::loadFile` (tipus canvia `std::vector<char>` → `std::vector<uint8_t>`):
|
||||
- [locale.cpp:30](source/core/locale/locale.cpp#L30)
|
||||
- [text.cpp:65, 129](source/core/rendering/text.cpp) (`.fnt` + bitmap)
|
||||
- [scene_utils.cpp:12](source/scenes/scene_utils.cpp) (música escenes)
|
||||
- [modulegame.cpp:52](source/game/modulegame.cpp) (música gameplay)
|
||||
- [jdraw8.cpp:47, 65](source/core/jail/jdraw8.cpp) (`JD8_LoadSurface`, `JD8_LoadPalette`)
|
||||
3. **Fase 4** — Eliminar scaffold `.jrf` de [jfile.cpp](source/core/jail/jfile.cpp): `file_setresourcefilename`, `file_setsource`, `SOURCE_FILE`/`SOURCE_FOLDER`, `dictionary_loaded()`, `file_getfilepointer()`, `file_readfile()`. Mantenir només config-folder + `file_setresourcefolder` + `file_getresourcefolder`.
|
||||
4. **Fase 5** — Als targets release de [Makefile](Makefile) (`_linux_release`/`_windows_release`/`_macos_release`): afegir dependència `pack` i canviar `cp -r data` → `cp resource.pack`. WASM intacte (segueix usant `--preload-file data@/data`).
|
||||
5. **Fase 6** — A [main.cpp](source/main.cpp): `enable_fallback = false` només per a `NDEBUG && !__EMSCRIPTEN__` (pack obligatori a Release natiu; Debug i WASM mantenen fallback).
|
||||
**Estat actual (Fases 1-6 completades, 2026-04-16)**:
|
||||
- `ResourcePack` + `ResourceHelper` + eina `pack_resources` compilen i funcionen. El pack genera 33 entrades ≈ 4 MB.
|
||||
- Cablejat al joc via `ResourceHelper::initializeResourceSystem` a [main.cpp](source/main.cpp) (amb `return SDL_APP_FAILURE` si falla), i `shutdownResourceSystem` a `SDL_AppQuit`.
|
||||
- Tots els callsites de recursos usen `ResourceHelper::loadFile` (`std::vector<uint8_t>`): [locale.cpp](source/core/locale/locale.cpp), [text.cpp](source/core/rendering/text.cpp), [scene_utils.cpp](source/scenes/scene_utils.cpp), [modulegame.cpp](source/game/modulegame.cpp), [jdraw8.cpp](source/core/jail/jdraw8.cpp).
|
||||
- Scaffold `.jrf` eliminat de [jfile.cpp](source/core/jail/jfile.cpp): `file_setresourcefilename`, `file_setsource`, `SOURCE_FILE`/`SOURCE_FOLDER`, `dictionary_loaded`, `file_getfilepointer`, `file_readfile`. Només queden config-folder i resource-folder getters/setters.
|
||||
- Targets release a [Makefile](Makefile) (`_linux_release`/`_windows_release`/`_macos_release`) depenen de `pack` i copien `resource.pack` en lloc de `data/`. WASM intacte (`--preload-file data@/data`).
|
||||
- `enable_fallback = false` a Release natiu (`NDEBUG && !__EMSCRIPTEN__`): el pack és obligatori. Debug i WASM mantenen el fallback actiu.
|
||||
|
||||
### External Libraries (`source/external/`)
|
||||
|
||||
@@ -274,11 +265,11 @@ Checksum: djb2-like amb seed `0x12345678`. Càrrega full-to-RAM (sense mmap).
|
||||
|
||||
### Data Assets (`data/`)
|
||||
|
||||
- `*.gif`, `*.ogg` — Original game assets (**do not modify**)
|
||||
- `gfx/` — Original game GIFs (**do not modify content**): `frames.gif`/`frames2.gif` (sprite sheet del joc), `logo.gif`/`logo_new.gif` (intros), `menu.gif`/`menu2.gif`, `intro.gif`/`intro2.gif`/`intro3.gif` (slides), `ffase.gif` (banner nivells), `final.gif`/`finals.gif` (crèdits), `gameover.gif`, `tomba1.gif`/`tomba2.gif` (escena secreta)
|
||||
- `music/` — 8 pistes OGG originals (`00000001.ogg`..`00000008.ogg`)
|
||||
- `fonts/8bithud.fnt + .gif` — Bitmap font for overlay (8×8, 124 glyphs, UTF-8 with accents)
|
||||
- `shaders/` — GLSL sources: `postfx.vert`, `postfx.frag`, `upscale.frag`, `downscale.frag`, `crtpi_frag.glsl`
|
||||
- `locale/ca.yaml` — UI strings in Valencian (menu titles/items/values, notifications). Edit freely; reload at restart
|
||||
- `ui/` — Reserved for future UI graphics
|
||||
|
||||
### Known Issues & Technical Debt
|
||||
|
||||
@@ -317,7 +308,6 @@ Checksum: djb2-like amb seed `0x12345678`. Càrrega full-to-RAM (sense mmap).
|
||||
- **FPS counter jitter**: time segment width changes per frame (100 Hz centi updates) causes ~1-2 px horizontal jitter in centered layout. Could lock to max-width or use monospace digits.
|
||||
- **Notification messages partially hardcoded**: overlay/global_inputs/director now use Locale, but the window title (`Texts::WINDOW_TITLE`) and some game-layer strings remain hardcoded.
|
||||
- **jail_audio `JA_Sound_t` RAII**: `JA_Music_t` ja està net (vector + string), però `JA_Sound_t` encara usa `Uint8*` via `SDL_LoadWAV` out-param. Petit polish per a completar la coherència RAII.
|
||||
- **Resource Pack — Fases 2-6**: la classe `ResourcePack`, `ResourceHelper` i l'eina `pack_resources` ja estan fetes (Fase 1). Queda cablejar-ho al joc: init a `main.cpp`, migrar 5 callsites de `file_readfile` a `ResourceHelper::loadFile`, eliminar l'scaffold `.jrf` de `jfile`, integrar `resource.pack` als bundles release, i flip `enable_fallback=false` per a Release natiu. Detall complet a la secció *Resource Pack* i al pla [.claude/plans/declarative-popping-breeze.md](/home/sergio/.claude/plans/declarative-popping-breeze.md).
|
||||
|
||||
### Previously Fixed (kept for reference)
|
||||
|
||||
|
||||
18
Makefile
@@ -99,7 +99,7 @@ endif
|
||||
# ==============================================================================
|
||||
# COMPILACIÓN PARA WINDOWS (RELEASE)
|
||||
# ==============================================================================
|
||||
_windows_release:
|
||||
_windows_release: pack
|
||||
@echo off
|
||||
@echo Creando release para Windows - Version: $(VERSION)
|
||||
|
||||
@@ -112,8 +112,8 @@ _windows_release:
|
||||
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
||||
@powershell -Command "if (-not (Test-Path '$(RELEASE_FOLDER)')) {New-Item '$(RELEASE_FOLDER)' -ItemType Directory}"
|
||||
|
||||
# Copia ficheros
|
||||
@powershell -Command "Copy-Item -Path 'data' -Destination '$(RELEASE_FOLDER)' -Recurse"
|
||||
# Copia ficheros (resource.pack substitueix la carpeta data/)
|
||||
@powershell -Command "Copy-Item 'resource.pack' -Destination '$(RELEASE_FOLDER)'"
|
||||
@powershell -Command "Copy-Item 'LICENSE' -Destination '$(RELEASE_FOLDER)'"
|
||||
@powershell -Command "Copy-Item 'README.md' -Destination '$(RELEASE_FOLDER)'"
|
||||
@powershell -Command "Copy-Item 'gamecontrollerdb.txt' -Destination '$(RELEASE_FOLDER)'"
|
||||
@@ -132,7 +132,7 @@ _windows_release:
|
||||
# ==============================================================================
|
||||
# COMPILACIÓN PARA MACOS (RELEASE)
|
||||
# ==============================================================================
|
||||
_macos_release:
|
||||
_macos_release: pack
|
||||
@echo "Creando release para macOS - Version: $(VERSION)"
|
||||
|
||||
# Verificar e instalar create-dmg si es necesario
|
||||
@@ -154,8 +154,8 @@ _macos_release:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
|
||||
# Copia carpetas y ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
# Copia carpetas y ficheros (resource.pack substitueix la carpeta data/)
|
||||
cp resource.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp gamecontrollerdb.txt "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp -R release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||
cp release/icons/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
@@ -252,7 +252,7 @@ wasm:
|
||||
# ==============================================================================
|
||||
# COMPILACIÓN PARA LINUX (RELEASE)
|
||||
# ==============================================================================
|
||||
_linux_release:
|
||||
_linux_release: pack
|
||||
@echo "Creando release para Linux - Version: $(VERSION)"
|
||||
|
||||
# Compila con cmake
|
||||
@@ -263,8 +263,8 @@ _linux_release:
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia ficheros
|
||||
cp -r data "$(RELEASE_FOLDER)"
|
||||
# Copia ficheros (resource.pack substitueix la carpeta data/)
|
||||
cp resource.pack "$(RELEASE_FOLDER)"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
cp gamecontrollerdb.txt "$(RELEASE_FOLDER)"
|
||||
|
||||
234
data/crtpi.glsl
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
crt-pi - A Raspberry Pi friendly CRT shader.
|
||||
|
||||
Copyright (C) 2015-2016 davej
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA.
|
||||
|
||||
SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely.
|
||||
|
||||
GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA.
|
||||
|
||||
CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot.
|
||||
|
||||
By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER.
|
||||
|
||||
BLOOM_FACTOR controls the increase in width for bright scanlines.
|
||||
|
||||
MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen.
|
||||
|
||||
*/
|
||||
|
||||
#pragma parameter CURVATURE_X "Screen curvature - horizontal" 0.10 0.0 1.0 0.01
|
||||
#pragma parameter CURVATURE_Y "Screen curvature - vertical" 0.15 0.0 1.0 0.01
|
||||
#pragma parameter MASK_BRIGHTNESS "Mask brightness" 0.70 0.0 1.0 0.01
|
||||
#pragma parameter SCANLINE_WEIGHT "Scanline weight" 6.0 0.0 15.0 0.1
|
||||
#pragma parameter SCANLINE_GAP_BRIGHTNESS "Scanline gap brightness" 0.12 0.0 1.0 0.01
|
||||
#pragma parameter BLOOM_FACTOR "Bloom factor" 1.5 0.0 5.0 0.01
|
||||
#pragma parameter INPUT_GAMMA "Input gamma" 2.4 0.0 5.0 0.01
|
||||
#pragma parameter OUTPUT_GAMMA "Output gamma" 2.2 0.0 5.0 0.01
|
||||
|
||||
// Haven't put these as parameters as it would slow the code down.
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
//#define FAKE_GAMMA
|
||||
#define CURVATURE
|
||||
//#define SHARPER
|
||||
// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish)
|
||||
#define MASK_TYPE 1
|
||||
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
precision mediump float;
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
uniform COMPAT_PRECISION float CURVATURE_X;
|
||||
uniform COMPAT_PRECISION float CURVATURE_Y;
|
||||
uniform COMPAT_PRECISION float MASK_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
|
||||
uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float BLOOM_FACTOR;
|
||||
uniform COMPAT_PRECISION float INPUT_GAMMA;
|
||||
uniform COMPAT_PRECISION float OUTPUT_GAMMA;
|
||||
#else
|
||||
#define CURVATURE_X 0.25
|
||||
#define CURVATURE_Y 0.45
|
||||
#define MASK_BRIGHTNESS 0.70
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 1.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
#endif
|
||||
|
||||
/* COMPATIBILITY
|
||||
- GLSL compilers
|
||||
*/
|
||||
|
||||
//uniform vec2 TextureSize;
|
||||
#if defined(CURVATURE)
|
||||
varying vec2 screenScale;
|
||||
#endif
|
||||
varying vec2 TEX0;
|
||||
varying float filterWidth;
|
||||
|
||||
#if defined(VERTEX)
|
||||
//uniform mat4 MVPMatrix;
|
||||
//attribute vec4 VertexCoord;
|
||||
//attribute vec2 TexCoord;
|
||||
//uniform vec2 InputSize;
|
||||
//uniform vec2 OutputSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(CURVATURE)
|
||||
screenScale = vec2(1.0, 1.0); //TextureSize / InputSize;
|
||||
#endif
|
||||
filterWidth = (768.0 / 240.0) / 3.0;
|
||||
TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2D Texture;
|
||||
|
||||
#if defined(CURVATURE)
|
||||
vec2 Distort(vec2 coord)
|
||||
{
|
||||
vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);
|
||||
// Barrel distortion shrinks the display area a bit, this will allow us to counteract that.
|
||||
vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);
|
||||
coord *= screenScale;
|
||||
coord -= vec2(0.5);
|
||||
float rsq = coord.x * coord.x + coord.y * coord.y;
|
||||
coord += coord * (CURVATURE_DISTORTION * rsq);
|
||||
coord *= barrelScale;
|
||||
if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)
|
||||
coord = vec2(-1.0); // If out of bounds, return an invalid value.
|
||||
else
|
||||
{
|
||||
coord += vec2(0.5);
|
||||
coord /= screenScale;
|
||||
}
|
||||
|
||||
return coord;
|
||||
}
|
||||
#endif
|
||||
|
||||
float CalcScanLineWeight(float dist)
|
||||
{
|
||||
return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy)
|
||||
{
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#if defined(MULTISAMPLE)
|
||||
scanLineWeight += CalcScanLineWeight(dy-filterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy+filterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 TextureSize = vec2(320.0, 240.0);
|
||||
#if defined(CURVATURE)
|
||||
vec2 texcoord = Distort(TEX0);
|
||||
if (texcoord.x < 0.0)
|
||||
gl_FragColor = vec4(0.0);
|
||||
else
|
||||
#else
|
||||
vec2 texcoord = TEX0;
|
||||
#endif
|
||||
{
|
||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
||||
#if defined(SHARPER)
|
||||
vec2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
vec2 coord = tempCoord / TextureSize;
|
||||
vec2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y);
|
||||
vec2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
vec2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
vec3 colour = texture2D(Texture, tc).rgb;
|
||||
|
||||
#if defined(SCANLINES)
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, vec3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, vec3(1.0/OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if MASK_TYPE == 0
|
||||
gl_FragColor = vec4(colour, 1.0);
|
||||
#else
|
||||
#if MASK_TYPE == 1
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5);
|
||||
vec3 mask;
|
||||
if (whichMask < 0.5)
|
||||
mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
else
|
||||
mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333);
|
||||
vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333)
|
||||
mask.x = 1.0;
|
||||
else if (whichMask < 0.6666666)
|
||||
mask.y = 1.0;
|
||||
else
|
||||
mask.z = 1.0;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
resource.pack
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "core/jail/jfile.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
||||
@@ -44,10 +44,10 @@ JD8_Surface JD8_NewSurface() {
|
||||
}
|
||||
|
||||
JD8_Surface JD8_LoadSurface(const char* file) {
|
||||
auto buffer = file_readfile(file);
|
||||
auto buffer = ResourceHelper::loadFile(file);
|
||||
|
||||
unsigned short w, h;
|
||||
Uint8* pixels = LoadGif(reinterpret_cast<unsigned char*>(buffer.data()), &w, &h);
|
||||
Uint8* pixels = LoadGif(buffer.data(), &w, &h);
|
||||
|
||||
if (pixels == NULL) {
|
||||
printf("Unable to load bitmap: %s\n", SDL_GetError());
|
||||
@@ -62,8 +62,8 @@ JD8_Surface JD8_LoadSurface(const char* file) {
|
||||
}
|
||||
|
||||
JD8_Palette JD8_LoadPalette(const char* file) {
|
||||
auto buffer = file_readfile(file);
|
||||
return (JD8_Palette)LoadPalette(reinterpret_cast<unsigned char*>(buffer.data()));
|
||||
auto buffer = ResourceHelper::loadFile(file);
|
||||
return (JD8_Palette)LoadPalette(buffer.data());
|
||||
}
|
||||
|
||||
void JD8_SetScreenPalette(JD8_Palette palette) {
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
#include "core/jail/jfile.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -19,58 +14,14 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* DEFAULT_FILENAME = "data.jf2";
|
||||
constexpr const char* DEFAULT_FOLDER = "data/";
|
||||
|
||||
struct file_entry {
|
||||
std::string path;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
struct keyvalue {
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
std::vector<file_entry> toc;
|
||||
std::vector<keyvalue> config;
|
||||
|
||||
std::string resource_filename;
|
||||
std::string resource_folder;
|
||||
std::string config_folder;
|
||||
int file_source = SOURCE_FILE;
|
||||
|
||||
bool dictionary_loaded() {
|
||||
if (resource_filename.empty()) resource_filename = DEFAULT_FILENAME;
|
||||
|
||||
std::ifstream fi(resource_filename, std::ios::binary);
|
||||
if (!fi.is_open()) return false;
|
||||
|
||||
char header[4];
|
||||
fi.read(header, 4);
|
||||
uint32_t num_files, toc_offset;
|
||||
fi.read(reinterpret_cast<char*>(&num_files), 4);
|
||||
fi.read(reinterpret_cast<char*>(&toc_offset), 4);
|
||||
fi.seekg(toc_offset);
|
||||
|
||||
for (uint32_t i = 0; i < num_files; ++i) {
|
||||
uint32_t file_offset, file_size;
|
||||
fi.read(reinterpret_cast<char*>(&file_offset), 4);
|
||||
fi.read(reinterpret_cast<char*>(&file_size), 4);
|
||||
uint8_t path_size;
|
||||
fi.read(reinterpret_cast<char*>(&path_size), 1);
|
||||
char file_name[256];
|
||||
fi.read(file_name, path_size);
|
||||
file_name[path_size] = 0;
|
||||
toc.push_back({std::string(file_name), file_size, file_offset});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string filename_with_folder(const char* filename) {
|
||||
return resource_folder + filename;
|
||||
}
|
||||
|
||||
void load_config_values() {
|
||||
config.clear();
|
||||
@@ -97,10 +48,6 @@ void save_config_values() {
|
||||
|
||||
} // namespace
|
||||
|
||||
void file_setresourcefilename(const char* str) {
|
||||
resource_filename = str;
|
||||
}
|
||||
|
||||
void file_setresourcefolder(const char* str) {
|
||||
resource_folder = str;
|
||||
}
|
||||
@@ -109,58 +56,6 @@ const char* file_getresourcefolder() {
|
||||
return resource_folder.c_str();
|
||||
}
|
||||
|
||||
void file_setsource(const int src) {
|
||||
file_source = src % 2;
|
||||
if (src == SOURCE_FOLDER && resource_folder.empty()) file_setresourcefolder(DEFAULT_FOLDER);
|
||||
}
|
||||
|
||||
FILE* file_getfilepointer(const char* resourcename, int& filesize, const bool binary) {
|
||||
if (file_source == SOURCE_FILE && toc.empty()) {
|
||||
if (!dictionary_loaded()) file_setsource(SOURCE_FOLDER);
|
||||
}
|
||||
|
||||
FILE* f = nullptr;
|
||||
|
||||
if (file_source == SOURCE_FILE) {
|
||||
const std::string name(resourcename);
|
||||
size_t count = 0;
|
||||
for (; count < toc.size(); ++count) {
|
||||
if (toc[count].path == name) break;
|
||||
}
|
||||
if (count == toc.size()) {
|
||||
perror("El recurs no s'ha trobat en l'arxiu de recursos");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
filesize = static_cast<int>(toc[count].size);
|
||||
|
||||
f = fopen(resource_filename.c_str(), binary ? "rb" : "r");
|
||||
if (!f) {
|
||||
perror("No s'ha pogut obrir l'arxiu de recursos");
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, toc[count].offset, SEEK_SET);
|
||||
} else {
|
||||
const std::string full = filename_with_folder(resourcename);
|
||||
f = fopen(full.c_str(), binary ? "rb" : "r");
|
||||
if (!f) return nullptr;
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = static_cast<int>(ftell(f));
|
||||
fseek(f, 0, SEEK_SET);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
std::vector<char> file_readfile(const char* resourcename) {
|
||||
int filesize = 0;
|
||||
FILE* f = file_getfilepointer(resourcename, filesize, true);
|
||||
if (!f) return {};
|
||||
std::vector<char> buffer(filesize);
|
||||
fread(buffer.data(), filesize, 1, f);
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema on guardar les dades.
|
||||
// Accepta rutes amb subdirectoris (ex: "jailgames/aee") i crea tota la jerarquia.
|
||||
void file_setconfigfolder(const char* foldername) {
|
||||
|
||||
@@ -1,26 +1,10 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define SOURCE_FILE 0
|
||||
#define SOURCE_FOLDER 1
|
||||
|
||||
void file_setconfigfolder(const char* foldername);
|
||||
const char* file_getconfigfolder();
|
||||
|
||||
void file_setresourcefilename(const char* str);
|
||||
void file_setresourcefolder(const char* str);
|
||||
const char* file_getresourcefolder();
|
||||
void file_setsource(const int src);
|
||||
|
||||
FILE* file_getfilepointer(const char* resourcename, int& filesize, const bool binary = false);
|
||||
|
||||
// Llig tot el contingut d'un recurs (fitxer solt o entrada del .jrf).
|
||||
// Retorna un vector buit si el recurs no existeix. El vector es destrueix
|
||||
// automàticament en eixir d'àmbit — no fa falta cap free() manual. Mida =
|
||||
// bytes llegits (el buffer no està null-terminated).
|
||||
std::vector<char> file_readfile(const char* resourcename);
|
||||
|
||||
const char* file_getconfigvalue(const char* key);
|
||||
void file_setconfigvalue(const char* key, const char* value);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "core/jail/jfile.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
|
||||
namespace Locale {
|
||||
@@ -27,12 +27,12 @@ namespace Locale {
|
||||
}
|
||||
|
||||
bool load(const char* filename) {
|
||||
auto buffer = file_readfile(filename);
|
||||
auto buffer = ResourceHelper::loadFile(filename);
|
||||
if (buffer.empty()) {
|
||||
std::cerr << "Locale: unable to load " << filename << '\n';
|
||||
return false;
|
||||
}
|
||||
std::string content(buffer.data(), buffer.size());
|
||||
std::string content(reinterpret_cast<const char*>(buffer.data()), buffer.size());
|
||||
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(content);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "core/jail/jfile.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
// Forward declarations de gif.h (inclòs des de jdraw8.cpp, no es pot incloure dos vegades)
|
||||
struct rgb;
|
||||
@@ -62,13 +62,13 @@ auto Text::nextCodepoint(const char*& ptr) -> uint32_t {
|
||||
// --- Càrrega de font ---
|
||||
|
||||
void Text::loadFont(const char* fnt_file) {
|
||||
auto buffer = file_readfile(fnt_file);
|
||||
auto buffer = ResourceHelper::loadFile(fnt_file);
|
||||
if (buffer.empty()) {
|
||||
std::cerr << "Text: unable to load font file: " << fnt_file << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
std::istringstream stream(std::string(buffer.data(), buffer.size()));
|
||||
std::istringstream stream(std::string(reinterpret_cast<const char*>(buffer.data()), buffer.size()));
|
||||
|
||||
std::string line;
|
||||
int glyph_index = 0;
|
||||
@@ -126,14 +126,14 @@ void Text::loadFont(const char* fnt_file) {
|
||||
}
|
||||
|
||||
void Text::loadBitmap(const char* gif_file) {
|
||||
auto buffer = file_readfile(gif_file);
|
||||
auto buffer = ResourceHelper::loadFile(gif_file);
|
||||
if (buffer.empty()) {
|
||||
std::cerr << "Text: unable to load bitmap: " << gif_file << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
// Extrau dimensions del header GIF (bytes 6-7 = width, 8-9 = height, little-endian)
|
||||
auto* raw = reinterpret_cast<unsigned char*>(buffer.data());
|
||||
auto* raw = buffer.data();
|
||||
int w = raw[6] | (raw[7] << 8);
|
||||
int h = raw[8] | (raw[9] << 8);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace ResourceHelper {
|
||||
// Allibera el pack carregat a memòria.
|
||||
void shutdownResourceSystem();
|
||||
|
||||
// Llegeix un recurs per ruta relativa (p.ex. "logo.gif", "fonts/8bithud.fnt").
|
||||
// Llegeix un recurs per ruta relativa (p.ex. "gfx/logo.gif", "fonts/8bithud.fnt").
|
||||
// Retorna un vector buit si no es troba.
|
||||
auto loadFile(const std::string& relative_path) -> std::vector<uint8_t>;
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include "core/jail/jail_audio.hpp"
|
||||
#include "core/jail/jdraw8.hpp"
|
||||
#include "core/jail/jfile.hpp"
|
||||
#include "core/jail/jgame.hpp"
|
||||
#include "core/jail/jinput.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
ModuleGame::ModuleGame() {
|
||||
this->gfx = JD8_LoadSurface(info::ctx.pepe_activat ? "frames2.gif" : "frames.gif");
|
||||
this->gfx = JD8_LoadSurface(info::ctx.pepe_activat ? "gfx/frames2.gif" : "gfx/frames.gif");
|
||||
JG_SetUpdateTicks(10);
|
||||
|
||||
this->sam = new Prota(this->gfx);
|
||||
@@ -42,15 +42,15 @@ void ModuleGame::onEnter() {
|
||||
// fade interpolarien cap a una paleta amb pantalla buida.
|
||||
this->Draw();
|
||||
|
||||
const char* music = info::ctx.num_piramide == 3 ? "00000008.ogg"
|
||||
: info::ctx.num_piramide == 2 ? "00000007.ogg"
|
||||
: info::ctx.num_piramide == 6 ? "00000002.ogg"
|
||||
: "00000006.ogg";
|
||||
const char* music = info::ctx.num_piramide == 3 ? "music/00000008.ogg"
|
||||
: info::ctx.num_piramide == 2 ? "music/00000007.ogg"
|
||||
: info::ctx.num_piramide == 6 ? "music/00000002.ogg"
|
||||
: "music/00000006.ogg";
|
||||
const char* current_music = JA_GetMusicFilename();
|
||||
if ((JA_GetMusicState() != JA_MUSIC_PLAYING) || !current_music ||
|
||||
strcmp(music, current_music) != 0) {
|
||||
auto buffer = file_readfile(music);
|
||||
JA_PlayMusic(JA_LoadMusic(reinterpret_cast<Uint8*>(buffer.data()),
|
||||
auto buffer = ResourceHelper::loadFile(music);
|
||||
JA_PlayMusic(JA_LoadMusic(buffer.data(),
|
||||
static_cast<Uint32>(buffer.size()), music));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "core/rendering/menu.hpp"
|
||||
#include "core/rendering/overlay.hpp"
|
||||
#include "core/rendering/screen.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "core/system/director.hpp"
|
||||
#include "game/options.hpp"
|
||||
|
||||
@@ -32,10 +33,27 @@ SDL_AppResult SDL_AppInit(void** /*appstate*/, int /*argc*/, char* /*argv*/[]) {
|
||||
// SDL_GetBasePath() detecta automàticament si estem dins d'un .app bundle
|
||||
// (retorna Contents/Resources/) o en un executable normal (carpeta del binari).
|
||||
const char* base_path = SDL_GetBasePath();
|
||||
std::string resource_pack_path;
|
||||
if (base_path) {
|
||||
const std::string data_path = std::string(base_path) + "data/";
|
||||
file_setresourcefolder(data_path.c_str());
|
||||
resource_pack_path = std::string(base_path) + "resource.pack";
|
||||
} else {
|
||||
resource_pack_path = "resource.pack";
|
||||
}
|
||||
|
||||
// Sistema de recursos: prova el pack i cau a fitxers solts dins data/.
|
||||
// Release natiu exigix el pack (sense fallback); Debug i WASM mantenen
|
||||
// el fallback actiu per a desenvolupament i per al build amb MEMFS.
|
||||
#if defined(NDEBUG) && !defined(__EMSCRIPTEN__)
|
||||
const bool enable_fallback = false;
|
||||
#else
|
||||
const bool enable_fallback = true;
|
||||
#endif
|
||||
if (!ResourceHelper::initializeResourceSystem(resource_pack_path, enable_fallback)) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
Options::setConfigFile(std::string(file_getconfigfolder()) + "config.yaml");
|
||||
Options::loadFromFile();
|
||||
|
||||
@@ -102,4 +120,5 @@ void SDL_AppQuit(void* /*appstate*/, SDL_AppResult /*result*/) {
|
||||
JD8_Quit();
|
||||
Screen::destroy();
|
||||
JG_Finalize();
|
||||
ResourceHelper::shutdownResourceSystem();
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
namespace scenes {
|
||||
|
||||
void BannerScene::onEnter() {
|
||||
playMusic("00000004.ogg");
|
||||
playMusic("music/00000004.ogg");
|
||||
|
||||
gfx_ = SurfaceHandle("ffase.gif");
|
||||
gfx_ = SurfaceHandle("gfx/ffase.gif");
|
||||
|
||||
JD8_ClearScreen(0);
|
||||
// Títols superior i inferior del banner (compartits per tots els nivells)
|
||||
@@ -30,7 +30,7 @@ void BannerScene::onEnter() {
|
||||
}
|
||||
|
||||
// PaletteFade copia internament amb memcpy; alliberem la paleta temporal.
|
||||
JD8_Palette pal = JD8_LoadPalette("ffase.gif");
|
||||
JD8_Palette pal = JD8_LoadPalette("gfx/ffase.gif");
|
||||
fade_.startFadeTo(pal);
|
||||
std::free(pal);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace scenes {
|
||||
// Banner pre-piràmide ("PIRÀMIDE X"). Reemplaça `ModuleSequence::doBanner()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Arranca música "00000004.ogg" i carrega ffase.gif.
|
||||
// 1. Arranca música "music/00000004.ogg" i carrega gfx/ffase.gif.
|
||||
// 2. Pinta títol, subtítol i número de piràmide segons info::ctx.num_piramide.
|
||||
// 3. Fade-in de paleta.
|
||||
// 4. Mostra ~5s o fins que es polse una tecla.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// Frames del cotxe: 8 posicions dins del sprite sheet final.gif. El
|
||||
// Frames del cotxe: 8 posicions dins del sprite sheet gfx/final.gif. El
|
||||
// vell doCredits tenia aquesta taula inline — la reproduïm idèntica.
|
||||
struct CocheFrame {
|
||||
Uint16 x, y;
|
||||
@@ -35,18 +35,18 @@ CreditsScene::~CreditsScene() {
|
||||
|
||||
void CreditsScene::onEnter() {
|
||||
// El vell doCredits no tocava música — heretava la del doSlides
|
||||
// previ ("00000005.ogg"). Si l'escena s'arrenca directament (test
|
||||
// previ ("music/00000005.ogg"). Si l'escena s'arrenca directament (test
|
||||
// amb piramide_inicial=8) no hi ha res que heretar, així que
|
||||
// arranquem la mateixa pista només si no sona res. Inocu en el
|
||||
// flux normal: JA_MUSIC_PLAYING fa que no la tornem a tocar.
|
||||
if (JA_GetMusicState() != JA_MUSIC_PLAYING) {
|
||||
playMusic("00000005.ogg");
|
||||
playMusic("music/00000005.ogg");
|
||||
}
|
||||
|
||||
vaddr2_ = SurfaceHandle("final.gif");
|
||||
vaddr3_ = SurfaceHandle("finals.gif");
|
||||
vaddr2_ = SurfaceHandle("gfx/final.gif");
|
||||
vaddr3_ = SurfaceHandle("gfx/finals.gif");
|
||||
|
||||
JD8_Palette pal = JD8_LoadPalette("final.gif");
|
||||
JD8_Palette pal = JD8_LoadPalette("gfx/final.gif");
|
||||
JD8_SetScreenPalette(pal);
|
||||
// `pal` passa a ser propietat de main_palette — no l'alliberem.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace scenes {
|
||||
// Crèdits finals del joc. Reemplaça `ModuleSequence::doCredits()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Carrega final.gif (sprites de crèdits) i finals.gif (fons).
|
||||
// 1. Carrega gfx/final.gif (sprites de crèdits) i gfx/finals.gif (fons).
|
||||
// 2. Mostra els crèdits amb scroll vertical de 2 columnes durant
|
||||
// ~62 segons (contador 0..3100 × 20 ms).
|
||||
// 3. Si `info::ctx.diamants == 16`, pinta addicionalment un parallax
|
||||
@@ -39,8 +39,8 @@ class CreditsScene : public Scene {
|
||||
void render();
|
||||
void writeTrickIni();
|
||||
|
||||
SurfaceHandle vaddr2_; // final.gif (sprites i coches)
|
||||
SurfaceHandle vaddr3_; // finals.gif (fons / parallax)
|
||||
SurfaceHandle vaddr2_; // gfx/final.gif (sprites i coches)
|
||||
SurfaceHandle vaddr3_; // gfx/finals.gif (fons / parallax)
|
||||
PaletteFade fade_;
|
||||
FrameAnimator coche_{8, 60, true}; // 8 frames × 60 ms (~3 × 20 ms tick vell)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// Coordenades mesurades del wordmark "Jailgames" dins logo/logo_new.gif.
|
||||
// Coordenades mesurades del wordmark "Jailgames" dins gfx/logo_new.gif.
|
||||
// Idèntiques a les del doIntroNewLogo vell — si canvies el logo, aquí i
|
||||
// al GIF són els únics llocs a tocar.
|
||||
constexpr int LOGO_SRC_X = 60;
|
||||
@@ -44,10 +44,10 @@ IntroNewLogoScene::~IntroNewLogoScene() {
|
||||
}
|
||||
|
||||
void IntroNewLogoScene::onEnter() {
|
||||
playMusic("00000003.ogg");
|
||||
playMusic("music/00000003.ogg");
|
||||
|
||||
gfx_ = SurfaceHandle("logo/logo_new.gif");
|
||||
pal_ = JD8_LoadPalette("logo/logo_new.gif");
|
||||
gfx_ = SurfaceHandle("gfx/logo_new.gif");
|
||||
pal_ = JD8_LoadPalette("gfx/logo_new.gif");
|
||||
JD8_SetScreenPalette(pal_);
|
||||
|
||||
// Surface auxiliar omplida amb el color del cursor — permet pintar
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace scenes {
|
||||
// ciclo de paleta final. Reemplaça `ModuleSequence::doIntroNewLogo()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Carrega logo/logo_new.gif, arranca música "00000003.ogg" i posa
|
||||
// 1. Carrega gfx/logo_new.gif, arranca música "music/00000003.ogg" i posa
|
||||
// la paleta directament (sense fade-in). Mostra pantalla negra 1s.
|
||||
// 2. Revelat: 9 lletres × 2 frames (amb cursor / sense cursor), 150 ms
|
||||
// cada frame.
|
||||
|
||||
@@ -66,10 +66,10 @@ IntroScene::~IntroScene() {
|
||||
}
|
||||
|
||||
void IntroScene::onEnter() {
|
||||
playMusic("00000003.ogg");
|
||||
playMusic("music/00000003.ogg");
|
||||
|
||||
gfx_ = SurfaceHandle("logo.gif");
|
||||
pal_ = JD8_LoadPalette("logo.gif");
|
||||
gfx_ = SurfaceHandle("gfx/logo.gif");
|
||||
pal_ = JD8_LoadPalette("gfx/logo.gif");
|
||||
JD8_SetScreenPalette(pal_);
|
||||
|
||||
JD8_ClearScreen(0);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace scenes {
|
||||
// `IntroNewLogoScene`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Carrega logo.gif, arranca música "00000003.ogg", pantalla negra
|
||||
// 1. Carrega gfx/logo.gif, arranca música "music/00000003.ogg", pantalla negra
|
||||
// 1000 ms.
|
||||
// 2. Revelat: 15 passos (100 o 200 ms) que van acumulant les lletres
|
||||
// "JAILGAMES" d'esquerra a dreta amb un avió escombrant al final
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace {
|
||||
constexpr int TICK_MS = 20;
|
||||
|
||||
// Taules de frames. Ubicacions de cada sprite dins el gfx de la intro
|
||||
// (logo.gif o logo/logo_new.gif — el layout de sprites és el mateix).
|
||||
// (gfx/logo.gif o gfx/logo_new.gif — el layout de sprites és el mateix).
|
||||
// Cada sprite ocupa 15×15 px, disposats horitzontalment per fila.
|
||||
// Els valors són els offsets x (la y la posa l'invocador al src_y).
|
||||
// Derivats dels `fr_ani_N[i] = ...` del vell doIntroSprites.
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
namespace scenes {
|
||||
|
||||
void MenuScene::onEnter() {
|
||||
fondo_ = SurfaceHandle("menu.gif");
|
||||
gfx_ = SurfaceHandle("menu2.gif");
|
||||
fondo_ = SurfaceHandle("gfx/menu.gif");
|
||||
gfx_ = SurfaceHandle("gfx/menu2.gif");
|
||||
|
||||
// Pintat inicial (congelat durant el fade-in de paleta). El loop
|
||||
// d'animació repintarà tot des de zero en el primer tick de Showing.
|
||||
@@ -19,7 +19,7 @@ void MenuScene::onEnter() {
|
||||
JD8_BlitCK(130, 100, gfx_, 0, 0, 80, 74, 255); // camell (frame 0)
|
||||
JD8_BlitCK(0, 150, gfx_, 0, 150, 320, 50, 255); // base "jdes"
|
||||
|
||||
JD8_Palette pal = JD8_LoadPalette("menu2.gif");
|
||||
JD8_Palette pal = JD8_LoadPalette("gfx/menu2.gif");
|
||||
fade_.startFadeTo(pal);
|
||||
std::free(pal);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace scenes {
|
||||
// Menú del títol. Reemplaça `ModuleSequence::doMenu()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Carrega menu.gif (fondo) i menu2.gif (sprites) + paleta.
|
||||
// 1. Carrega gfx/menu.gif (fondo) i gfx/menu2.gif (sprites) + paleta.
|
||||
// 2. Pintat inicial estàtic (fondo, logo, camell frame 0, base "jdes"),
|
||||
// fade-in de paleta.
|
||||
// 3. Loop d'animació: escroll parallax de horitzó (cada 320 ms) i
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
namespace scenes {
|
||||
|
||||
void MortScene::onEnter() {
|
||||
playMusic("00000001.ogg");
|
||||
playMusic("music/00000001.ogg");
|
||||
JI_DisableKeyboard(60);
|
||||
info::ctx.vida = 5;
|
||||
|
||||
gfx_ = SurfaceHandle("gameover.gif");
|
||||
gfx_ = SurfaceHandle("gfx/gameover.gif");
|
||||
JD8_ClearScreen(0);
|
||||
JD8_Blit(gfx_);
|
||||
|
||||
// PaletteFade en fa una còpia interna via memcpy, així que alliberem
|
||||
// la paleta temporal immediatament.
|
||||
JD8_Palette pal = JD8_LoadPalette("gameover.gif");
|
||||
JD8_Palette pal = JD8_LoadPalette("gfx/gameover.gif");
|
||||
fade_.startFadeTo(pal);
|
||||
std::free(pal);
|
||||
|
||||
@@ -44,7 +44,7 @@ void MortScene::tick(int delta_ms) {
|
||||
if (remaining_ms_ <= 0) {
|
||||
// Arrenca música del següent mòdul abans del fade out,
|
||||
// igual que la versió vella feia al final de doMort().
|
||||
playMusic("00000003.ogg");
|
||||
playMusic("music/00000003.ogg");
|
||||
info::ctx.num_piramide = 0;
|
||||
fade_.startFadeOut();
|
||||
phase_ = Phase::FadingOut;
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace scenes {
|
||||
// Pantalla de "game over". Reemplaça `ModuleSequence::doMort()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Carrega gameover.gif, arranca música "00000001.ogg", fade-in de paleta.
|
||||
// 1. Carrega gfx/gameover.gif, arranca música "music/00000001.ogg", fade-in de paleta.
|
||||
// 2. Mostra la pantalla ~10 segons o fins que l'usuari polse una tecla.
|
||||
// 3. Arranca música del menú ("00000003.ogg") i fade-out de paleta.
|
||||
// 3. Arranca música del menú ("music/00000003.ogg") i fade-out de paleta.
|
||||
// 4. Marca num_piramide=0 i retorna nextState=1 perquè el Director
|
||||
// passe a l'escena del menú.
|
||||
class MortScene : public Scene {
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "core/jail/jail_audio.hpp"
|
||||
#include "core/jail/jfile.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
namespace scenes {
|
||||
|
||||
void playMusic(const char* filename, int loop) {
|
||||
if (!filename) return;
|
||||
auto buffer = file_readfile(filename);
|
||||
auto buffer = ResourceHelper::loadFile(filename);
|
||||
if (buffer.empty()) return;
|
||||
// JA_LoadMusic fa una còpia interna del OGG comprimit (via SDL_malloc)
|
||||
// per a stb_vorbis. El `buffer` local es destruirà en sortir d'àmbit.
|
||||
JA_PlayMusic(JA_LoadMusic(reinterpret_cast<Uint8*>(buffer.data()),
|
||||
JA_PlayMusic(JA_LoadMusic(buffer.data(),
|
||||
static_cast<Uint32>(buffer.size()), filename),
|
||||
loop);
|
||||
}
|
||||
|
||||
@@ -42,15 +42,15 @@ SecretaScene::~SecretaScene() {
|
||||
}
|
||||
|
||||
void SecretaScene::onEnter() {
|
||||
playMusic("00000002.ogg");
|
||||
playMusic("music/00000002.ogg");
|
||||
|
||||
// Fade-out de la paleta anterior. Els assets es carreguen ja
|
||||
// però no fem SetScreenPalette fins que acabe el fade — així
|
||||
// el fade opera sobre la paleta del mòdul anterior.
|
||||
fade_.startFadeOut();
|
||||
|
||||
gfx_ = SurfaceHandle("tomba1.gif");
|
||||
pal_aux_ = JD8_LoadPalette("tomba1.gif");
|
||||
gfx_ = SurfaceHandle("gfx/tomba1.gif");
|
||||
pal_aux_ = JD8_LoadPalette("gfx/tomba1.gif");
|
||||
pal_active_ = static_cast<JD8_Palette>(std::malloc(768));
|
||||
std::memcpy(pal_active_, pal_aux_, 768);
|
||||
|
||||
@@ -60,10 +60,10 @@ void SecretaScene::onEnter() {
|
||||
|
||||
void SecretaScene::swapToTomba2() {
|
||||
JD8_ClearScreen(255);
|
||||
gfx_.reset("tomba2.gif");
|
||||
gfx_.reset("gfx/tomba2.gif");
|
||||
|
||||
std::free(pal_aux_);
|
||||
pal_aux_ = JD8_LoadPalette("tomba2.gif");
|
||||
pal_aux_ = JD8_LoadPalette("gfx/tomba2.gif");
|
||||
// pal_active_ continua sent el mateix buffer: només actualitzem
|
||||
// el seu contingut. main_palette ja apunta ací.
|
||||
std::memcpy(pal_active_, pal_aux_, 768);
|
||||
|
||||
@@ -10,11 +10,11 @@ namespace scenes {
|
||||
// Pre-Secreta. Reemplaça `ModuleSequence::doSecreta()`.
|
||||
//
|
||||
// Flux:
|
||||
// 1. Arranca música "00000002.ogg" i fa fade-out de la paleta anterior.
|
||||
// 2. Carrega tomba1.gif + paleta i pinta un scroll vertical doble
|
||||
// 1. Arranca música "music/00000002.ogg" i fa fade-out de la paleta anterior.
|
||||
// 2. Carrega gfx/tomba1.gif + paleta i pinta un scroll vertical doble
|
||||
// (dos blits solapats, un a velocitat meitat que l'altre) durant
|
||||
// ~2.5 s + ~2.5 s de pausa.
|
||||
// 3. Swap a tomba2.gif + reset de paleta, scroll vertical del segon
|
||||
// 3. Swap a gfx/tomba2.gif + reset de paleta, scroll vertical del segon
|
||||
// asset (~1.9 s + ~1.9 s de pausa).
|
||||
// 4. ClearScreen a 0, set colors 253/254 a vermell fosc (12,11,11)
|
||||
// i pinta un revelat horitzontal (~1.6 s + ~1.6 s de pausa).
|
||||
|
||||
@@ -41,10 +41,10 @@ void SlidesScene::onEnter() {
|
||||
const char* arxiu = nullptr;
|
||||
if (num_piramide_at_start_ == 7) {
|
||||
// loop=1 per replicar el vell `play_music("00000005.ogg", 1)`.
|
||||
playMusic("00000005.ogg", 1);
|
||||
arxiu = (info::ctx.diners < 200) ? "intro2.gif" : "intro3.gif";
|
||||
playMusic("music/00000005.ogg", 1);
|
||||
arxiu = (info::ctx.diners < 200) ? "gfx/intro2.gif" : "gfx/intro3.gif";
|
||||
} else {
|
||||
arxiu = "intro.gif";
|
||||
arxiu = "gfx/intro.gif";
|
||||
}
|
||||
|
||||
gfx_ = SurfaceHandle(arxiu);
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace scenes {
|
||||
// fade-out. Reemplaça `ModuleSequence::doSlides()`.
|
||||
//
|
||||
// Tria d'asset segons context:
|
||||
// - num_piramide == 7 i diners < 200: intro2.gif + música "00000005.ogg"
|
||||
// - num_piramide == 7 i diners >= 200: intro3.gif + música "00000005.ogg"
|
||||
// - altre cas (num_piramide == 1): intro.gif, sense música nova
|
||||
// - num_piramide == 7 i diners < 200: gfx/intro2.gif + música "music/00000005.ogg"
|
||||
// - num_piramide == 7 i diners >= 200: gfx/intro3.gif + música "music/00000005.ogg"
|
||||
// - altre cas (num_piramide == 1): gfx/intro.gif, sense música nova
|
||||
//
|
||||
// Flux:
|
||||
// Slide1Enter (1600 ms scroll dreta→centre, easing outCubic)
|
||||
|
||||