ja tenim el control de la finestra i de la imatge
treballant en les tecles de funcio
This commit is contained in:
@@ -65,6 +65,10 @@ Follows the pattern from `jaildoctors_dilemma`:
|
|||||||
|
|
||||||
A state machine alternates between `ModuleSequence` (state 1) and `ModuleGame` (state 0). Each module's `Go()` returns the next state (-1 to quit). Modules are allocated/freed each transition.
|
A state machine alternates between `ModuleSequence` (state 1) and `ModuleGame` (state 0). Each module's `Go()` returns the next state (-1 to quit). Modules are allocated/freed each transition.
|
||||||
|
|
||||||
|
### Golden Rule: Do Not Touch Gameplay
|
||||||
|
|
||||||
|
The original game logic (gameplay, entities, map, scoring, collisions, animations) must remain untouched. All modernization work targets the presentation layer and infrastructure only: window management, configuration/persistence, rendering pipeline (overlay/UI), and build system. Any new feature (save states, options menu, etc.) must be implemented as an overlay on top of the existing game, never by modifying the original gameplay code.
|
||||||
|
|
||||||
### Key Conventions
|
### Key Conventions
|
||||||
|
|
||||||
- All surfaces are 320x200 = 64000 bytes. Pixel coordinates assume this fixed resolution
|
- All surfaces are 320x200 = 64000 bytes. Pixel coordinates assume this fixed resolution
|
||||||
|
|||||||
@@ -13,12 +13,13 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||||||
# --- LISTA EXPLÍCITA DE FUENTES ---
|
# --- LISTA EXPLÍCITA DE FUENTES ---
|
||||||
set(APP_SOURCES
|
set(APP_SOURCES
|
||||||
# Core - Motor "Jail"
|
# Core - Motor "Jail"
|
||||||
|
source/core/global_inputs.cpp
|
||||||
source/core/jail_audio.cpp
|
source/core/jail_audio.cpp
|
||||||
source/core/jdraw8.cpp
|
source/core/jdraw8.cpp
|
||||||
source/core/jfile.cpp
|
source/core/jfile.cpp
|
||||||
source/core/jgame.cpp
|
source/core/jgame.cpp
|
||||||
source/core/jinput.cpp
|
source/core/jinput.cpp
|
||||||
source/core/jshader.cpp
|
source/core/screen.cpp
|
||||||
|
|
||||||
# Game
|
# Game
|
||||||
source/game/options.cpp
|
source/game/options.cpp
|
||||||
@@ -58,10 +59,7 @@ target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-Os -ffunctio
|
|||||||
|
|
||||||
# --- CONFIGURACIÓN POR PLATAFORMA ---
|
# --- CONFIGURACIÓN POR PLATAFORMA ---
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE mingw32 opengl32)
|
target_link_libraries(${PROJECT_NAME} PRIVATE mingw32)
|
||||||
elseif(UNIX AND NOT APPLE)
|
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Ejecutable en la raíz del proyecto
|
# Ejecutable en la raíz del proyecto
|
||||||
|
|||||||
37
source/core/global_inputs.cpp
Normal file
37
source/core/global_inputs.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include "core/global_inputs.hpp"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "core/jinput.hpp"
|
||||||
|
#include "core/screen.hpp"
|
||||||
|
|
||||||
|
namespace GlobalInputs {
|
||||||
|
|
||||||
|
static bool f1_was_pressed = false;
|
||||||
|
static bool f2_was_pressed = false;
|
||||||
|
static bool f3_was_pressed = false;
|
||||||
|
|
||||||
|
void handle() {
|
||||||
|
// F1 — decrement zoom
|
||||||
|
bool f1 = JI_KeyPressed(SDL_SCANCODE_F1);
|
||||||
|
if (f1 && !f1_was_pressed) {
|
||||||
|
Screen::get()->decZoom();
|
||||||
|
}
|
||||||
|
f1_was_pressed = f1;
|
||||||
|
|
||||||
|
// F2 — increment zoom
|
||||||
|
bool f2 = JI_KeyPressed(SDL_SCANCODE_F2);
|
||||||
|
if (f2 && !f2_was_pressed) {
|
||||||
|
Screen::get()->incZoom();
|
||||||
|
}
|
||||||
|
f2_was_pressed = f2;
|
||||||
|
|
||||||
|
// F3 — toggle fullscreen
|
||||||
|
bool f3 = JI_KeyPressed(SDL_SCANCODE_F3);
|
||||||
|
if (f3 && !f3_was_pressed) {
|
||||||
|
Screen::get()->toggleFullscreen();
|
||||||
|
}
|
||||||
|
f3_was_pressed = f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GlobalInputs
|
||||||
6
source/core/global_inputs.hpp
Normal file
6
source/core/global_inputs.hpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace GlobalInputs {
|
||||||
|
// Comprovar una vegada per frame, després de JI_Update()
|
||||||
|
void handle();
|
||||||
|
} // namespace GlobalInputs
|
||||||
@@ -3,54 +3,23 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "core/jfile.hpp"
|
#include "core/jfile.hpp"
|
||||||
#include "core/jshader.hpp"
|
#include "core/screen.hpp"
|
||||||
#include "external/gif.h"
|
#include "external/gif.h"
|
||||||
|
|
||||||
#define SCREEN_WIDTH 960
|
|
||||||
#define SCREEN_HEIGHT 720
|
|
||||||
|
|
||||||
JD8_Surface screen = NULL;
|
JD8_Surface screen = NULL;
|
||||||
JD8_Palette main_palette = NULL;
|
JD8_Palette main_palette = NULL;
|
||||||
Uint32 *pixel_data = NULL;
|
Uint32 *pixel_data = NULL;
|
||||||
|
|
||||||
int screenWidth = 320;
|
void JD8_Init() {
|
||||||
int screenHeight = 200;
|
|
||||||
|
|
||||||
Uint32 contadorFPS = 0;
|
|
||||||
Uint32 tempsFPS = SDL_GetTicks();
|
|
||||||
char *fps = (char *)malloc(10);
|
|
||||||
|
|
||||||
SDL_Window *sdlWindow = NULL;
|
|
||||||
SDL_Renderer *sdlRenderer = NULL;
|
|
||||||
SDL_Texture *sdlTexture = NULL;
|
|
||||||
SDL_Texture *backBuffer = NULL;
|
|
||||||
|
|
||||||
void JD8_Init(const char *title) {
|
|
||||||
screen = (JD8_Surface)calloc(1, 64000);
|
screen = (JD8_Surface)calloc(1, 64000);
|
||||||
main_palette = (JD8_Palette)calloc(1, 768);
|
main_palette = (JD8_Palette)calloc(1, 768);
|
||||||
pixel_data = (Uint32 *)calloc(1, 320 * 200 * 4); // 1048576 );
|
pixel_data = (Uint32 *)calloc(1, 320 * 200 * 4);
|
||||||
|
|
||||||
sdlWindow = SDL_CreateWindow(title, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
|
|
||||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
|
||||||
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
|
|
||||||
sdlRenderer = SDL_CreateRenderer(sdlWindow, NULL);
|
|
||||||
|
|
||||||
sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, 320, 200);
|
|
||||||
backBuffer = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 320, 200);
|
|
||||||
|
|
||||||
int filesize = 0;
|
|
||||||
char *buffer = file_getfilebuffer("crtpi.glsl", filesize, true);
|
|
||||||
|
|
||||||
shader::init(sdlWindow, backBuffer, buffer);
|
|
||||||
free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JD8_Quit() {
|
void JD8_Quit() {
|
||||||
if (screen != NULL) free(screen);
|
if (screen != NULL) free(screen);
|
||||||
if (main_palette != NULL) free(main_palette);
|
if (main_palette != NULL) free(main_palette);
|
||||||
if (pixel_data != NULL) free(pixel_data);
|
if (pixel_data != NULL) free(pixel_data);
|
||||||
SDL_DestroyRenderer(sdlRenderer);
|
|
||||||
SDL_DestroyWindow(sdlWindow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JD8_ClearScreen(Uint8 color) {
|
void JD8_ClearScreen(Uint8 color) {
|
||||||
@@ -177,8 +146,6 @@ void JD8_BlitCKToSurface(int x, int y, JD8_Surface surface, int sx, int sy, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect rect{0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
|
||||||
|
|
||||||
void JD8_Flip() {
|
void JD8_Flip() {
|
||||||
for (int x = 0; x < 320; x++) {
|
for (int x = 0; x < 320; x++) {
|
||||||
for (int y = 0; y < 200; y++) {
|
for (int y = 0; y < 200; y++) {
|
||||||
@@ -186,11 +153,7 @@ void JD8_Flip() {
|
|||||||
pixel_data[x + (y * 320)] = color;
|
pixel_data[x + (y * 320)] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_UpdateTexture(sdlTexture, NULL, pixel_data, 320 * sizeof(Uint32));
|
Screen::get()->present(pixel_data);
|
||||||
SDL_SetRenderTarget(sdlRenderer, backBuffer);
|
|
||||||
SDL_RenderTexture(sdlRenderer, sdlTexture, NULL, NULL);
|
|
||||||
shader::render();
|
|
||||||
// SDL_RenderPresent(sdlRenderer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JD8_FreeSurface(JD8_Surface surface) {
|
void JD8_FreeSurface(JD8_Surface surface) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ struct Color {
|
|||||||
typedef Uint8 *JD8_Surface;
|
typedef Uint8 *JD8_Surface;
|
||||||
typedef Color *JD8_Palette;
|
typedef Color *JD8_Palette;
|
||||||
|
|
||||||
void JD8_Init(const char *title);
|
void JD8_Init();
|
||||||
|
|
||||||
void JD8_Quit();
|
void JD8_Quit();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "core/global_inputs.hpp"
|
||||||
#include "core/jgame.hpp"
|
#include "core/jgame.hpp"
|
||||||
|
|
||||||
const bool* keystates; // = SDL_GetKeyboardState( NULL );
|
const bool* keystates; // = SDL_GetKeyboardState( NULL );
|
||||||
@@ -35,6 +36,8 @@ void JI_Update() {
|
|||||||
JI_moveCheats(event.key.scancode);
|
JI_moveCheats(event.key.scancode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalInputs::handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JI_KeyPressed(int key) {
|
bool JI_KeyPressed(int key) {
|
||||||
|
|||||||
@@ -1,225 +0,0 @@
|
|||||||
#include "core/jshader.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenGL/OpenGL.h>
|
|
||||||
|
|
||||||
#include "CoreFoundation/CoreFoundation.h"
|
|
||||||
|
|
||||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
|
||||||
#include <OpenGL/gl3.h>
|
|
||||||
#else
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#endif //! ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
|
||||||
#else
|
|
||||||
#include <SDL3/SDL_opengl.h>
|
|
||||||
#include <SDL3/SDL_opengl_glext.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace shader {
|
|
||||||
SDL_Window* win = nullptr;
|
|
||||||
SDL_Renderer* renderer = nullptr;
|
|
||||||
GLuint programId = 0;
|
|
||||||
SDL_Texture* backBuffer = nullptr;
|
|
||||||
SDL_Point win_size = {640, 480};
|
|
||||||
SDL_FPoint tex_size = {320, 240};
|
|
||||||
bool usingOpenGL;
|
|
||||||
GLuint texture_number;
|
|
||||||
GLuint nose;
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
|
||||||
|
|
||||||
// I'm avoiding the use of GLEW or some extensions handler, but that
|
|
||||||
// doesn't mean you should...
|
|
||||||
PFNGLCREATESHADERPROC glCreateShader;
|
|
||||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
|
||||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
|
||||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
|
||||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
|
||||||
PFNGLDELETESHADERPROC glDeleteShader;
|
|
||||||
PFNGLATTACHSHADERPROC glAttachShader;
|
|
||||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
|
||||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
|
||||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
|
|
||||||
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
|
||||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
|
||||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
|
||||||
|
|
||||||
bool initGLExtensions() {
|
|
||||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
|
||||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
|
||||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
|
||||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
|
||||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
|
||||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
|
||||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
|
||||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
|
||||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
|
||||||
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
|
|
||||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
|
||||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
|
||||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
|
||||||
|
|
||||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
|
||||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
|
||||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
|
||||||
glUseProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLuint compileShader(const char* source, GLuint shaderType) {
|
|
||||||
// Create ID for shader
|
|
||||||
GLuint result = glCreateShader(shaderType);
|
|
||||||
// Add define depending on shader type
|
|
||||||
const char* sources[2] = {shaderType == GL_VERTEX_SHADER ? "#define VERTEX\n" : "#define FRAGMENT\n", source};
|
|
||||||
// Define shader text
|
|
||||||
glShaderSource(result, 2, sources, NULL);
|
|
||||||
// Compile shader
|
|
||||||
glCompileShader(result);
|
|
||||||
|
|
||||||
// Check vertex shader for errors
|
|
||||||
GLint shaderCompiled = GL_FALSE;
|
|
||||||
glGetShaderiv(result, GL_COMPILE_STATUS, &shaderCompiled);
|
|
||||||
if (shaderCompiled != GL_TRUE) {
|
|
||||||
std::cout << "Error en la compilación: " << result << "!" << std::endl;
|
|
||||||
GLint logLength;
|
|
||||||
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength);
|
|
||||||
if (logLength > 0) {
|
|
||||||
GLchar* log = (GLchar*)malloc(logLength);
|
|
||||||
glGetShaderInfoLog(result, logLength, &logLength, log);
|
|
||||||
std::cout << "Shader compile log:" << log << std::endl;
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
glDeleteShader(result);
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource) {
|
|
||||||
GLuint programId = 0;
|
|
||||||
GLuint vtxShaderId, fragShaderId;
|
|
||||||
|
|
||||||
programId = glCreateProgram();
|
|
||||||
|
|
||||||
vtxShaderId = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
|
|
||||||
fragShaderId = compileShader(fragmentShaderSource ? fragmentShaderSource : vertexShaderSource, GL_FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
if (vtxShaderId && fragShaderId) {
|
|
||||||
// Associate shader with program
|
|
||||||
glAttachShader(programId, vtxShaderId);
|
|
||||||
glAttachShader(programId, fragShaderId);
|
|
||||||
glLinkProgram(programId);
|
|
||||||
glValidateProgram(programId);
|
|
||||||
|
|
||||||
// Check the status of the compile/link
|
|
||||||
GLint logLen;
|
|
||||||
glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logLen);
|
|
||||||
if (logLen > 0) {
|
|
||||||
char* log = (char*)malloc(logLen * sizeof(char));
|
|
||||||
// Show any errors as appropriate
|
|
||||||
glGetProgramInfoLog(programId, logLen, &logLen, log);
|
|
||||||
std::cout << "Prog Info Log: " << std::endl
|
|
||||||
<< log << std::endl;
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vtxShaderId) glDeleteShader(vtxShaderId);
|
|
||||||
if (fragShaderId) glDeleteShader(fragShaderId);
|
|
||||||
return programId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader) {
|
|
||||||
shader::win = win;
|
|
||||||
shader::renderer = SDL_GetRenderer(win);
|
|
||||||
shader::backBuffer = backBuffer;
|
|
||||||
SDL_GetWindowSize(win, &win_size.x, &win_size.y);
|
|
||||||
SDL_GetTextureSize(backBuffer, &tex_size.x, &tex_size.y);
|
|
||||||
printf("tex size: %fx%f\n", tex_size.x, tex_size.y);
|
|
||||||
SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer);
|
|
||||||
texture_number = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER, -1);
|
|
||||||
printf("texture number: %i\n", texture_number);
|
|
||||||
int access = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_ACCESS_NUMBER, -1);
|
|
||||||
nose = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER, -1);
|
|
||||||
printf("texture target number: %i\n", nose);
|
|
||||||
|
|
||||||
if (access != SDL_TEXTUREACCESS_TARGET) {
|
|
||||||
std::cout << "ERROR FATAL: La textura per al render ha de tindre SDL_TEXTUREACCESS_TARGET definit." << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* renderer_name = SDL_GetRendererName(renderer);
|
|
||||||
printf("rendererInfo.name: %s\n", renderer_name);
|
|
||||||
|
|
||||||
if (!strncmp(renderer_name, "opengl", 6)) {
|
|
||||||
#ifndef __APPLE__
|
|
||||||
if (!initGLExtensions()) {
|
|
||||||
std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl;
|
|
||||||
usingOpenGL = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Compilar el shader y dejarlo listo para usar.
|
|
||||||
programId = compileProgram(vertexShader, fragmentShader);
|
|
||||||
} else {
|
|
||||||
std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl;
|
|
||||||
usingOpenGL = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
usingOpenGL = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char pixels[512 * 240 * 4];
|
|
||||||
|
|
||||||
void render() {
|
|
||||||
SDL_FlushRenderer(renderer);
|
|
||||||
SDL_SetRenderTarget(renderer, NULL);
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
SDL_FlushRenderer(renderer);
|
|
||||||
|
|
||||||
if (usingOpenGL) {
|
|
||||||
GLint oldProgramId;
|
|
||||||
if (programId != 0) {
|
|
||||||
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
|
||||||
glUseProgram(programId);
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 1);
|
|
||||||
// glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
|
|
||||||
// if (glGetError()) { printf("GLGETERROR!\n"); exit(1);}
|
|
||||||
// GLint param;
|
|
||||||
// glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, ¶m);
|
|
||||||
// printf("tex width: %i\n", param);
|
|
||||||
glViewport(0, 0, win_size.x, win_size.y);
|
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
|
||||||
glTexCoord2f(0.0f, 0.0f);
|
|
||||||
glVertex2f(0.0f, 0.0f);
|
|
||||||
glTexCoord2f(1.0f, 0.0f);
|
|
||||||
glVertex2f(tex_size.x, 0.0f);
|
|
||||||
glTexCoord2f(0.0f, 1.0f);
|
|
||||||
glVertex2f(0.0f, tex_size.y);
|
|
||||||
glTexCoord2f(1.0f, 1.0f);
|
|
||||||
glVertex2f(tex_size.x, tex_size.y);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
SDL_GL_SwapWindow(win);
|
|
||||||
|
|
||||||
if (programId != 0) glUseProgram(oldProgramId);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SDL_RenderTexture(renderer, backBuffer, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
|
||||||
if (glGetError()) {
|
|
||||||
printf("GLERROR!\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace shader
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
// TIPS:
|
|
||||||
// =======================================================================
|
|
||||||
// Abans de crear el renderer, cridar a la següent funció:
|
|
||||||
//
|
|
||||||
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
|
||||||
//
|
|
||||||
// Aixó li diu que volem un renderer que use especificament opengl. A més,
|
|
||||||
// al crear el renderer li tenim que dir que el volem que use acceeració
|
|
||||||
// per hardware, i que soporte render a textura. Per exemple:
|
|
||||||
//
|
|
||||||
// SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED |
|
|
||||||
// SDL_RENDERER_TARGETTEXTURE);
|
|
||||||
//
|
|
||||||
// Per altra part, al crear la textura tenim que definir que puga ser target
|
|
||||||
// de renderitzat (SDL_TEXTUREACCESS_TARGET), per exemple:
|
|
||||||
//
|
|
||||||
// SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
|
|
||||||
// SDL_TEXTUREACCESS_TARGET, 320, 240);
|
|
||||||
//
|
|
||||||
// Els shaders li'ls passem com una cadena, som nosaltres els que s'encarreguem
|
|
||||||
// de carregarlos de disc, amb fopen, ifstream, jfile o el que vullgues.
|
|
||||||
// Si els tens en un std::string, passa-li-la com "cadena.c_str()".
|
|
||||||
//
|
|
||||||
// Poden ser els dos el mateix arxiu, com fa libRetro, jo desde dins ja fique
|
|
||||||
// els defines necessaris. Si es el mateix arxiu, pots no ficar el quart paràmetre.
|
|
||||||
//
|
|
||||||
// Els shaders de libRetro no funcionen directament, hi ha que fer algunes modificacions.
|
|
||||||
//
|
|
||||||
// El pintat final de la teua escena l'has de fer com si "backBuffer" fora la pantalla.
|
|
||||||
//
|
|
||||||
// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32".
|
|
||||||
// En Mac ni idea
|
|
||||||
|
|
||||||
namespace shader {
|
|
||||||
const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader = nullptr);
|
|
||||||
|
|
||||||
void render();
|
|
||||||
} // namespace shader
|
|
||||||
106
source/core/screen.cpp
Normal file
106
source/core/screen.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "core/screen.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "game/defines.hpp"
|
||||||
|
#include "game/options.hpp"
|
||||||
|
|
||||||
|
Screen* Screen::instance_ = nullptr;
|
||||||
|
|
||||||
|
void Screen::init() {
|
||||||
|
instance_ = new Screen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::destroy() {
|
||||||
|
delete instance_;
|
||||||
|
instance_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Screen::get() -> Screen* {
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::Screen() {
|
||||||
|
// Carrega opcions guardades
|
||||||
|
zoom_ = Options::window.zoom;
|
||||||
|
fullscreen_ = Options::window.fullscreen;
|
||||||
|
|
||||||
|
calculateMaxZoom();
|
||||||
|
|
||||||
|
if (zoom_ < 1) zoom_ = 1;
|
||||||
|
if (zoom_ > max_zoom_) zoom_ = max_zoom_;
|
||||||
|
|
||||||
|
int w = GAME_WIDTH * zoom_;
|
||||||
|
int h = GAME_HEIGHT * zoom_;
|
||||||
|
|
||||||
|
window_ = SDL_CreateWindow(Texts::WINDOW_TITLE, w, h, fullscreen_ ? SDL_WINDOW_FULLSCREEN : 0);
|
||||||
|
renderer_ = SDL_CreateRenderer(window_, nullptr);
|
||||||
|
SDL_SetRenderLogicalPresentation(renderer_, GAME_WIDTH, GAME_HEIGHT, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||||
|
|
||||||
|
texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, GAME_WIDTH, GAME_HEIGHT);
|
||||||
|
SDL_SetTextureScaleMode(texture_, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
|
std::cout << "Screen initialized: " << w << "x" << h << " (zoom " << zoom_ << ", max " << max_zoom_ << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::~Screen() {
|
||||||
|
// Guarda opcions abans de destruir
|
||||||
|
Options::window.zoom = zoom_;
|
||||||
|
Options::window.fullscreen = fullscreen_;
|
||||||
|
|
||||||
|
if (texture_) SDL_DestroyTexture(texture_);
|
||||||
|
if (renderer_) SDL_DestroyRenderer(renderer_);
|
||||||
|
if (window_) SDL_DestroyWindow(window_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::present(const Uint32* pixel_data) {
|
||||||
|
SDL_UpdateTexture(texture_, nullptr, pixel_data, GAME_WIDTH * sizeof(Uint32));
|
||||||
|
SDL_RenderClear(renderer_);
|
||||||
|
SDL_RenderTexture(renderer_, texture_, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::toggleFullscreen() {
|
||||||
|
fullscreen_ = !fullscreen_;
|
||||||
|
SDL_SetWindowFullscreen(window_, fullscreen_);
|
||||||
|
if (!fullscreen_) {
|
||||||
|
adjustWindowSize();
|
||||||
|
}
|
||||||
|
std::cout << (fullscreen_ ? "Fullscreen ON\n" : "Fullscreen OFF\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::incZoom() {
|
||||||
|
if (fullscreen_ || zoom_ >= max_zoom_) return;
|
||||||
|
zoom_++;
|
||||||
|
adjustWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::decZoom() {
|
||||||
|
if (fullscreen_ || zoom_ <= 1) return;
|
||||||
|
zoom_--;
|
||||||
|
adjustWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::setZoom(int zoom) {
|
||||||
|
if (zoom < 1 || zoom > max_zoom_ || fullscreen_) return;
|
||||||
|
zoom_ = zoom;
|
||||||
|
adjustWindowSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::adjustWindowSize() {
|
||||||
|
int w = GAME_WIDTH * zoom_;
|
||||||
|
int h = GAME_HEIGHT * zoom_;
|
||||||
|
SDL_SetWindowSize(window_, w, h);
|
||||||
|
SDL_SetWindowPosition(window_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::calculateMaxZoom() {
|
||||||
|
SDL_DisplayID display = SDL_GetPrimaryDisplay();
|
||||||
|
const SDL_DisplayMode* mode = SDL_GetCurrentDisplayMode(display);
|
||||||
|
if (mode) {
|
||||||
|
int max_w = mode->w / GAME_WIDTH;
|
||||||
|
int max_h = mode->h / GAME_HEIGHT;
|
||||||
|
max_zoom_ = (max_w < max_h) ? max_w : max_h;
|
||||||
|
if (max_zoom_ < 1) max_zoom_ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
source/core/screen.hpp
Normal file
47
source/core/screen.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static void destroy();
|
||||||
|
static auto get() -> Screen*;
|
||||||
|
|
||||||
|
// Presentació — rep el buffer ARGB de 320x200 de JD8
|
||||||
|
void present(const Uint32* pixel_data);
|
||||||
|
|
||||||
|
// Gestió de finestra
|
||||||
|
void toggleFullscreen();
|
||||||
|
void incZoom();
|
||||||
|
void decZoom();
|
||||||
|
void setZoom(int zoom);
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
[[nodiscard]] auto isFullscreen() const -> bool { return fullscreen_; }
|
||||||
|
[[nodiscard]] auto getZoom() const -> int { return zoom_; }
|
||||||
|
[[nodiscard]] auto getWindow() -> SDL_Window* { return window_; }
|
||||||
|
[[nodiscard]] auto getRenderer() -> SDL_Renderer* { return renderer_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Screen();
|
||||||
|
~Screen();
|
||||||
|
|
||||||
|
void adjustWindowSize();
|
||||||
|
void calculateMaxZoom();
|
||||||
|
|
||||||
|
static Screen* instance_;
|
||||||
|
|
||||||
|
SDL_Window* window_{nullptr};
|
||||||
|
SDL_Renderer* renderer_{nullptr};
|
||||||
|
SDL_Texture* texture_{nullptr}; // 320x200 streaming, ARGB8888
|
||||||
|
|
||||||
|
int zoom_{3};
|
||||||
|
int max_zoom_{6};
|
||||||
|
bool fullscreen_{false};
|
||||||
|
|
||||||
|
static constexpr int GAME_WIDTH = 320;
|
||||||
|
static constexpr int GAME_HEIGHT = 200;
|
||||||
|
};
|
||||||
@@ -8,6 +8,11 @@ namespace Defaults::Audio {
|
|||||||
constexpr float SOUND_VOLUME = 1.0F;
|
constexpr float SOUND_VOLUME = 1.0F;
|
||||||
} // namespace Defaults::Audio
|
} // namespace Defaults::Audio
|
||||||
|
|
||||||
|
namespace Defaults::Window {
|
||||||
|
constexpr int ZOOM = 3;
|
||||||
|
constexpr bool FULLSCREEN = false;
|
||||||
|
} // namespace Defaults::Window
|
||||||
|
|
||||||
namespace Defaults::Game {
|
namespace Defaults::Game {
|
||||||
constexpr int HABITACIO_INICIAL = 1;
|
constexpr int HABITACIO_INICIAL = 1;
|
||||||
constexpr int PIRAMIDE_INICIAL = 255;
|
constexpr int PIRAMIDE_INICIAL = 255;
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
// Textos
|
// Textos
|
||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_TITLE = "Aventures En Egipte";
|
constexpr const char* WINDOW_TITLE = "© 2000 Aventures en Egipte — JailDesigner";
|
||||||
constexpr const char* VERSION = "1.00";
|
constexpr const char* VERSION = "1.00";
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
// Resolución del juego
|
// Resolución del juego
|
||||||
namespace Screen {
|
namespace GameScreen {
|
||||||
constexpr int WIDTH = 320;
|
constexpr int WIDTH = 320;
|
||||||
constexpr int HEIGHT = 200;
|
constexpr int HEIGHT = 200;
|
||||||
constexpr int BUFFER_SIZE = WIDTH * HEIGHT; // 64000
|
constexpr int BUFFER_SIZE = WIDTH * HEIGHT; // 64000
|
||||||
} // namespace Screen
|
} // namespace GameScreen
|
||||||
|
|||||||
@@ -41,6 +41,16 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
|
||||||
|
if (!yaml.contains("window")) return;
|
||||||
|
const auto& node = yaml["window"];
|
||||||
|
|
||||||
|
if (node.contains("zoom"))
|
||||||
|
window.zoom = node["zoom"].get_value<int>();
|
||||||
|
if (node.contains("fullscreen"))
|
||||||
|
window.fullscreen = node["fullscreen"].get_value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
static void loadGameConfigFromYaml(const fkyaml::node& yaml) {
|
static void loadGameConfigFromYaml(const fkyaml::node& yaml) {
|
||||||
if (!yaml.contains("game")) return;
|
if (!yaml.contains("game")) return;
|
||||||
const auto& node = yaml["game"];
|
const auto& node = yaml["game"];
|
||||||
@@ -84,6 +94,7 @@ namespace Options {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadWindowConfigFromYaml(yaml);
|
||||||
loadAudioConfigFromYaml(yaml);
|
loadAudioConfigFromYaml(yaml);
|
||||||
loadGameConfigFromYaml(yaml);
|
loadGameConfigFromYaml(yaml);
|
||||||
|
|
||||||
@@ -118,6 +129,13 @@ namespace Options {
|
|||||||
file << "version: \"" << Texts::VERSION << "\"\n";
|
file << "version: \"" << Texts::VERSION << "\"\n";
|
||||||
file << "\n";
|
file << "\n";
|
||||||
|
|
||||||
|
// WINDOW
|
||||||
|
file << "# WINDOW\n";
|
||||||
|
file << "window:\n";
|
||||||
|
file << " zoom: " << window.zoom << "\n";
|
||||||
|
file << " fullscreen: " << (window.fullscreen ? "true" : "false") << "\n";
|
||||||
|
file << "\n";
|
||||||
|
|
||||||
// AUDIO
|
// AUDIO
|
||||||
file << "# AUDIO\n";
|
file << "# AUDIO\n";
|
||||||
file << "audio:\n";
|
file << "audio:\n";
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ namespace Options {
|
|||||||
float volume{Defaults::Audio::VOLUME};
|
float volume{Defaults::Audio::VOLUME};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Opcions de finestra
|
||||||
|
struct Window {
|
||||||
|
int zoom{Defaults::Window::ZOOM};
|
||||||
|
bool fullscreen{Defaults::Window::FULLSCREEN};
|
||||||
|
};
|
||||||
|
|
||||||
// Opcions de joc
|
// Opcions de joc
|
||||||
struct Game {
|
struct Game {
|
||||||
int habitacio_inicial{Defaults::Game::HABITACIO_INICIAL};
|
int habitacio_inicial{Defaults::Game::HABITACIO_INICIAL};
|
||||||
@@ -26,6 +32,7 @@ namespace Options {
|
|||||||
// --- Variables globals ---
|
// --- Variables globals ---
|
||||||
inline std::string version{};
|
inline std::string version{};
|
||||||
inline Audio audio{};
|
inline Audio audio{};
|
||||||
|
inline Window window{};
|
||||||
inline Game game{};
|
inline Game game{};
|
||||||
inline std::string config_file_path{};
|
inline std::string config_file_path{};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "core/global_inputs.hpp"
|
||||||
#include "core/jail_audio.hpp"
|
#include "core/jail_audio.hpp"
|
||||||
#include "core/jdraw8.hpp"
|
#include "core/jdraw8.hpp"
|
||||||
#include "core/jfile.hpp"
|
#include "core/jfile.hpp"
|
||||||
#include "core/jgame.hpp"
|
#include "core/jgame.hpp"
|
||||||
|
#include "core/screen.hpp"
|
||||||
#include "game/defines.hpp"
|
#include "game/defines.hpp"
|
||||||
#include "game/info.hpp"
|
#include "game/info.hpp"
|
||||||
#include "game/modulegame.hpp"
|
#include "game/modulegame.hpp"
|
||||||
@@ -20,7 +22,8 @@ int main(int argc, char* args[]) {
|
|||||||
Options::loadFromFile();
|
Options::loadFromFile();
|
||||||
|
|
||||||
JG_Init();
|
JG_Init();
|
||||||
JD8_Init(Texts::WINDOW_TITLE);
|
Screen::init();
|
||||||
|
JD8_Init();
|
||||||
JA_Init(48000, SDL_AUDIO_S16, 2);
|
JA_Init(48000, SDL_AUDIO_S16, 2);
|
||||||
|
|
||||||
info::num_habitacio = Options::game.habitacio_inicial;
|
info::num_habitacio = Options::game.habitacio_inicial;
|
||||||
@@ -61,6 +64,7 @@ int main(int argc, char* args[]) {
|
|||||||
|
|
||||||
JA_Quit();
|
JA_Quit();
|
||||||
JD8_Quit();
|
JD8_Quit();
|
||||||
|
Screen::destroy();
|
||||||
JG_Finalize();
|
JG_Finalize();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user