- [NEW] jshader (shader fan cosa rara en fullscreen)

- [NEW] jfile convertit
- [NEW] jinput te en compte el ratio per a les coordenades en pantalla (falla en fullscreen, falta afegir offset)
- [NEW] F1 escala avall la finestra
- [NEW] F2 escala amunt la finestra
- [NEW] F3 togglecha la pantalla completa
- [NEW] F4 togglecha el shader
This commit is contained in:
2025-07-01 13:46:58 +02:00
parent 063016cf55
commit bc59b74f15
17 changed files with 759 additions and 230 deletions

38
data/gbc.glsl Normal file
View File

@@ -0,0 +1,38 @@
varying vec2 tex_coord;
varying vec2 pix_coord;
#if defined(VERTEX)
void main()
{
pix_coord = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
tex_coord = vec2((gl_Vertex.x+1.0)*0.5, (-gl_Vertex.y+1.0)*0.5);
vec4 pos = vec4(gl_Vertex.x * 2.0, gl_Vertex.y * 2.0, gl_Vertex.z, gl_Vertex.w);
gl_Position = gl_Vertex; //(gl_Vertex*2)-vec3(1.0, 1.0, 1.0);//gl_ModelViewProjectionMatrix * gl_Vertex;
}
#elif defined(FRAGMENT)
uniform sampler2D Texture;
void main()
{
float x = sign(pix_coord.x)*floor(abs(pix_coord.x)+0.5);
float y = sign(pix_coord.y)*floor(abs(pix_coord.y)+0.5);
float column = mod(x,4.0);
float row = mod(y,4.0);
vec4 color = texture2D(Texture, tex_coord);
vec4 newcolor;
if ((column == 0.0) || (row == 0.0) ) {
newcolor = color * vec4(0.4, 0.4, 0.4, 1.0);
} else if ((column == 1.0) || (row == 1.0) ) {
newcolor = color * vec4(0.6, 0.7, 0.8, 1.0);
} else if ((column == 3.0) || (row == 3.0) ) {
newcolor = color * vec4(0.8, 0.7, 0.6, 1.0);
} else {
newcolor = color;
}
gl_FragColor = newcolor;
}
#endif

41
data/lynx.glsl Normal file
View File

@@ -0,0 +1,41 @@
varying vec2 tex_coord;
varying vec2 pix_coord;
#if defined(VERTEX)
void main()
{
pix_coord = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
tex_coord = vec2((gl_Vertex.x+1.0)*0.5, (-gl_Vertex.y+1.0)*0.5);
vec4 pos = vec4(gl_Vertex.x * 2.0, gl_Vertex.y * 2.0, gl_Vertex.z, gl_Vertex.w);
gl_Position = gl_Vertex; //(gl_Vertex*2)-vec3(1.0, 1.0, 1.0);//gl_ModelViewProjectionMatrix * gl_Vertex;
}
#elif defined(FRAGMENT)
uniform sampler2D Texture;
void main()
{
float x = sign(pix_coord.x)*floor(abs(pix_coord.x)+0.5);
float column = mod(x,4.0);
vec4 color = texture2D(Texture, tex_coord);
float xfade = abs((tex_coord.s * 2.0) - 1.0);
xfade = xfade * xfade * xfade * xfade * xfade;
float yfade = abs((tex_coord.t * 2.0) - 1.0);
yfade = yfade * yfade * yfade * yfade * yfade;
color = color + vec4(0.7, 0.7, 0.7, 0.0) * (1.0-tex_coord.t) * (1.0-xfade) * (1.0-yfade);
vec4 newcolor;
if (column == 0.0) {
newcolor = color * vec4(1.0, 0.4, 0.6, 1.0);
} else if (column == 1.0) {
newcolor = color * vec4(0.4, 1.0, 0.4, 1.0);
} else if (column == 2.0) {
newcolor = color * vec4(0.6, 0.4, 1.0, 1.0);
} else {
newcolor = color * vec4(0.2, 0.2, 0.2, 1.0);
}
gl_FragColor = newcolor;
}
#endif

View File

@@ -22,7 +22,7 @@ namespace textfile
const bool open(std::string filename) const bool open(std::string filename)
{ {
buffer = file_getfilebuffer(filename.c_str(), fsize); buffer = file::getFileBuffer(filename.c_str(), fsize);
p = 0; p = 0;
return true; return true;

View File

@@ -120,7 +120,7 @@ namespace gamestate
{ {
password[10] = 0; password[10] = 0;
int filesize = 0; int filesize = 0;
const char *buffer = file_getfilebuffer("offsets.bal", filesize); const char *buffer = file::getFileBuffer("offsets.bal", filesize);
int punter = 0; int punter = 0;

View File

@@ -104,7 +104,7 @@ namespace gamestate
std::string getPassword() std::string getPassword()
{ {
int size; int size;
char *buffer = file_getfilebuffer("offsets.bal", size); char *buffer = file::getFileBuffer("offsets.bal", size);
int punter = (game::getConfig("fase")-1)*10; int punter = (game::getConfig("fase")-1)*10;
char passFile[11]; char passFile[11];

View File

@@ -34,7 +34,7 @@ namespace gamestate
} }
int size; int size;
sequence_file = file_getfilepointer(filename.c_str(), size); sequence_file = file::getFilePointer(filename.c_str(), size);
game::setState(&gamestate::sequence::loop); game::setState(&gamestate::sequence::loop);
} }

View File

@@ -155,7 +155,7 @@ namespace audio {
audio::music *loadMusic(const char* filename) audio::music *loadMusic(const char* filename)
{ {
int size; int size;
char *buffer = file_getfilebuffer(filename, size); char *buffer = file::getFileBuffer(filename, size);
if (buffer == nullptr) { if (buffer == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "ERROR (audio::loadMusic): No s'ha trobat l'arxiu %s\n", filename); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "ERROR (audio::loadMusic): No s'ha trobat l'arxiu %s\n", filename);
exit(1); exit(1);
@@ -322,7 +322,7 @@ namespace audio {
audio::sound *loadSound(const char* filename) audio::sound *loadSound(const char* filename)
{ {
int size; int size;
uint8_t *buffer = (uint8_t *)file_getfilebuffer(filename, size); uint8_t *buffer = (uint8_t *)file::getFileBuffer(filename, size);
if (buffer == nullptr) { if (buffer == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "ERROR (audio::loadSound): No s'ha trobat l'arxiu %s\n", filename); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "ERROR (audio::loadSound): No s'ha trobat l'arxiu %s\n", filename);

View File

@@ -2,6 +2,7 @@
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
#include "gif.h" #include "gif.h"
#include "jfile.h" #include "jfile.h"
#include "jshader.h"
namespace draw namespace draw
{ {
@@ -13,9 +14,13 @@ namespace draw
SDL_Window *sdl_window {nullptr}; // La finestra de SDL SDL_Window *sdl_window {nullptr}; // La finestra de SDL
SDL_Renderer *sdl_renderer {nullptr}; // El renderer de SDL SDL_Renderer *sdl_renderer {nullptr}; // El renderer de SDL
SDL_Texture *sdl_texture {nullptr}; // La textura de SDL a la que pintarem la nostra superficie "screen" i que despres volcarem a pantalla SDL_Texture *sdl_texture {nullptr}; // La textura de SDL a la que pintarem la nostra superficie "screen" i que despres volcarem a pantalla
SDL_Texture *sdl_shadertex {nullptr}; // La textura de SDL per al shader
static int screen_zoom = 1; static int screen_zoom = 1;
static bool screen_fullscreen = false; static bool screen_fullscreen = false;
static bool screen_cursor = true;
static char* screen_shader = nullptr;
static bool shader_enabled = false;
static float window_ratio = 1; static float window_ratio = 1;
static int canvas_width; static int canvas_width;
static int canvas_height; static int canvas_height;
@@ -51,13 +56,17 @@ namespace draw
// Ajustem el tamany de la finestra, segons el zoom i el ratio // Ajustem el tamany de la finestra, segons el zoom i el ratio
window_width = canvas_width*screen_zoom; window_width = canvas_width*screen_zoom;
window_height = window_ratio != 1 ? canvas_width*window_ratio*screen_zoom : canvas_height*screen_zoom; window_height = window_ratio != 1 ? int(float(canvas_width)*window_ratio*float(screen_zoom)) : canvas_height*screen_zoom;
// Mentres no càpiga en la pantalla, reduïm el zoom // Mentres no càpiga en la pantalla, reduïm el zoom
while (window_width > desktop_width || window_height > desktop_height) { while (window_width > desktop_width || window_height > desktop_height) {
screen_zoom--; screen_zoom--;
window_width = canvas_width*screen_zoom; window_width = canvas_width*screen_zoom;
window_height = window_ratio != 1 ? canvas_width*window_ratio*screen_zoom : canvas_height*screen_zoom; window_height = window_ratio != 1 ? int(float(canvas_width)*window_ratio*float(screen_zoom)) : canvas_height*screen_zoom;
}
if (screen_fullscreen) {
window_width = desktop_width;
window_height = desktop_height;
} }
sdl_window = SDL_CreateWindow(window_title, window_width, window_height, SDL_WINDOW_OPENGL|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:0)); sdl_window = SDL_CreateWindow(window_title, window_width, window_height, SDL_WINDOW_OPENGL|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:0));
@@ -66,6 +75,25 @@ namespace draw
exit(1); exit(1);
} }
sdl_renderer = SDL_CreateRenderer(sdl_window, NULL);
if (!sdl_renderer) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize renderer!\n");
exit(1);
}
if (screen_cursor) SDL_ShowCursor(); else SDL_HideCursor();
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, canvas_width, canvas_height);
SDL_SetTextureScaleMode(sdl_texture, SDL_SCALEMODE_NEAREST);
if (!sdl_texture) {
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize texture!\n");
exit(1);
}
sdl_shadertex = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, window_width, window_height);
SDL_SetTextureScaleMode(sdl_shadertex, SDL_SCALEMODE_NEAREST);
loadShader();
} }
void destroyDisplay() void destroyDisplay()
@@ -93,7 +121,9 @@ namespace draw
desktop_width = dm->w; desktop_width = dm->w;
desktop_height = dm->h; desktop_height = dm->h;
createDisplay();
// Inicialització de les estructures de SDL // Inicialització de les estructures de SDL
/*
sdl_window = SDL_CreateWindow(titol, width * zoom, height * zoom, 0); sdl_window = SDL_CreateWindow(titol, width * zoom, height * zoom, 0);
if (!sdl_window) { if (!sdl_window) {
SDL_LogCritical(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize window!\n"); SDL_LogCritical(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize window!\n");
@@ -110,6 +140,7 @@ namespace draw
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize texture!\n"); SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR (draw::init): Failed to initialize texture!\n");
exit(1); exit(1);
} }
*/
// Creem la superficie "screen" i la establim com a superficie destinació // Creem la superficie "screen" i la establim com a superficie destinació
screen = createSurface(width, height); screen = createSurface(width, height);
@@ -120,7 +151,7 @@ namespace draw
sel_color = transparent = 0; sel_color = transparent = 0;
for (int i=0;i<256;++i) color_indices[i] = i; for (int i=0;i<256;++i) color_indices[i] = i;
SDL_HideCursor(); //SDL_HideCursor();
//textsurf = loadSurface("font.gif"); //textsurf = loadSurface("font.gif");
} }
@@ -136,9 +167,7 @@ namespace draw
} }
// Destruim tot el relacionat amb SDL // Destruim tot el relacionat amb SDL
SDL_DestroyTexture(sdl_texture); destroyDisplay();
SDL_DestroyRenderer(sdl_renderer);
SDL_DestroyWindow(sdl_window);
// Fiquem tots els punters a nullptr, per si de cas no estem eixint del programa // Fiquem tots els punters a nullptr, per si de cas no estem eixint del programa
// i anem a tornar a inicialitzar el sistema // i anem a tornar a inicialitzar el sistema
@@ -148,11 +177,81 @@ namespace draw
screen = destination = source = nullptr; screen = destination = source = nullptr;
} }
void setZoom(const int value) {
screen_zoom = value;
destroyDisplay();
createDisplay();
char strzoom[3];
file::setConfigValue("zoom", SDL_itoa(screen_zoom, strzoom, 10));
}
const int getZoom() const int getZoom()
{ {
return screen_zoom; return screen_zoom;
} }
const float getScaleX()
{
return float(window_width) / float(canvas_width);
}
const float getScaleY()
{
return float(window_height) / float(canvas_height);
}
bool getFullscreen() {
return screen_fullscreen;
}
void setFullscreen(const bool value) {
screen_fullscreen=value;
destroyDisplay();
createDisplay();
file::setConfigValue("fullscreen", screen_fullscreen?"true":"false");
}
void loadShader()
{
char *buffer = nullptr;
if (screen_shader) {
int size;
buffer = file::getFileBuffer(screen_shader, size, true);
}
shader::setAspectRatio(3.0f/4.0f);
shader::init(sdl_window, sdl_shadertex, buffer);
if (buffer) free(buffer);
}
void setShader(const char* shader_file)
{
if (screen_shader) free(screen_shader);
screen_shader = (char*)malloc(strlen(shader_file)+1);
strcpy(screen_shader, shader_file);
loadShader();
}
void enableShader()
{
shader_enabled = true;
shader::enable();
//destroyDisplay();
//createDisplay();
}
void disableShader()
{
shader_enabled = false;
shader::disable();
//destroyDisplay();
//createDisplay();
}
void toggleShader()
{
shader_enabled ? disableShader() : enableShader();
}
// Crea una superficie i torna un punter a ella // Crea una superficie i torna un punter a ella
surface *createSurface(const uint16_t w, const uint16_t h) surface *createSurface(const uint16_t w, const uint16_t h)
{ {
@@ -176,7 +275,7 @@ namespace draw
// Agafem un buffer de bytes de l'arxiu especificat // Agafem un buffer de bytes de l'arxiu especificat
// getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char // getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char
int size; int size;
uint8_t *buffer = (uint8_t *)file_getfilebuffer(filename, size); uint8_t *buffer = (uint8_t *)file::getFileBuffer(filename, size);
// Si ens ha tornat nullptr, es que no l'ha trobat, tornem nosaltres també nullptr ja que no s'ha pogut crear la superficie // Si ens ha tornat nullptr, es que no l'ha trobat, tornem nosaltres també nullptr ja que no s'ha pogut crear la superficie
if (buffer == nullptr) if (buffer == nullptr)
@@ -292,7 +391,7 @@ namespace draw
// Agafem un buffer de bytes de l'arxiu especificat // Agafem un buffer de bytes de l'arxiu especificat
// getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char // getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char
int size; int size;
uint8_t *buffer = (uint8_t *)file_getfilebuffer(filename, size); uint8_t *buffer = (uint8_t *)file::getFileBuffer(filename, size);
// Li passem el array del arxiu a LoadPalette. Ell ens torna un array de uint32_t amb la paleta // Li passem el array del arxiu a LoadPalette. Ell ens torna un array de uint32_t amb la paleta
// Van a ser 256 entrades de 32 bits, cada entrada es un color, amb el format 0xAARRGGBB // Van a ser 256 entrades de 32 bits, cada entrada es un color, amb el format 0xAARRGGBB
@@ -565,11 +664,13 @@ namespace draw
// Desbloquejem la textura // Desbloquejem la textura
SDL_UnlockTexture(sdl_texture); SDL_UnlockTexture(sdl_texture);
SDL_SetRenderTarget(sdl_renderer, sdl_shadertex);
// Pintem la textura a pantalla // Pintem la textura a pantalla
SDL_RenderTexture(sdl_renderer, sdl_texture, NULL, NULL); SDL_RenderTexture(sdl_renderer, sdl_texture, NULL, NULL);
// I ho presentem // I ho presentem
SDL_RenderPresent(sdl_renderer); shader::render();
//SDL_RenderPresent(sdl_renderer);
} }
} }

View File

@@ -25,12 +25,24 @@ namespace draw
/// @param width es el ample de la finestra "virtual" /// @param width es el ample de la finestra "virtual"
/// @param height es el alt de la finestra "virtual" /// @param height es el alt de la finestra "virtual"
/// @param zoom es com de grans son els pixels. /// @param zoom es com de grans son els pixels.
void init(const char *titol, const uint16_t width, const uint16_t height, const int zoom, const float ratio=1.0); void init(const char *titol, const uint16_t width, const uint16_t height, const int zoom, const bool fullscreen=false, const float ratio=1.0);
/// @brief Finalització del sistema (tancar coses de SDL, superficies fixes, etc...) /// @brief Finalització del sistema (tancar coses de SDL, superficies fixes, etc...)
void quit(); void quit();
void setZoom(const int value);
const int getZoom(); const int getZoom();
const float getScaleX();
const float getScaleY();
bool getFullscreen();
void setFullscreen(const bool value);
void loadShader();
void setShader(const char* shader_file);
void enableShader();
void disableShader();
void toggleShader();
/// @brief Crea una superficie i torna un punter a ella /// @brief Crea una superficie i torna un punter a ella
/// @param w ample de la superficie /// @param w ample de la superficie

View File

@@ -19,213 +19,216 @@
#define DEFAULT_FOLDER "data/" #define DEFAULT_FOLDER "data/"
#define CONFIG_FILENAME "config.txt" #define CONFIG_FILENAME "config.txt"
struct file_t namespace file
{ {
std::string path; struct file_t
uint32_t size;
uint32_t offset;
};
std::vector<file_t> toc;
/* El std::map me fa coses rares, vaig a usar un good old std::vector amb una estructura key,value propia i au, que sempre funciona */
struct keyvalue_t {
std::string key, value;
};
char *resource_filename = NULL;
char *resource_folder = NULL;
int file_source = SOURCE_FILE;
char scratch[255];
static std::string config_folder;
std::vector<keyvalue_t> config;
void file_setresourcefilename(const char *str) {
if (resource_filename != NULL) free(resource_filename);
resource_filename = (char*)malloc(strlen(str)+1);
strcpy(resource_filename, str);
}
void file_setresourcefolder(const char *str) {
if (resource_folder != NULL) free(resource_folder);
resource_folder = (char*)malloc(strlen(str)+1);
strcpy(resource_folder, str);
}
void file_setsource(const int src) {
file_source = src%2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder)
if (src==SOURCE_FOLDER && resource_folder==NULL) file_setresourcefolder(DEFAULT_FOLDER);
}
bool file_getdictionary() {
if (resource_filename == NULL) file_setresourcefilename(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((char*)&num_files, 4);
fi.read((char*)&toc_offset, 4);
fi.seekg(toc_offset);
for (uint i=0; i<num_files; ++i)
{
uint32_t file_offset, file_size;
fi.read( (char*)&file_offset, 4 );
fi.read( (char*)&file_size, 4 );
uint8_t path_size;
fi.read( (char*)&path_size, 1 );
char file_name[path_size+1];
fi.read( file_name, path_size );
file_name[path_size] = 0;
std::string filename = file_name;
toc.push_back({filename, file_size, file_offset});
}
fi.close();
return true;
}
char *file_getfilenamewithfolder(const char* filename) {
strcpy(scratch, resource_folder);
strcat(scratch, filename);
return scratch;
}
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary) {
if (file_source==SOURCE_FILE and toc.size()==0) {
if (not file_getdictionary()) file_setsource(SOURCE_FOLDER);
}
FILE *f;
if (file_source==SOURCE_FILE) {
bool found = false;
uint32_t count = 0;
while( !found && count < toc.size() ) {
found = ( std::string(resourcename) == toc[count].path );
if( !found ) count++;
}
if( !found ) {
perror("El recurs no s'ha trobat en l'arxiu de recursos");
exit(1);
}
filesize = toc[count].size;
f = fopen(resource_filename, binary?"rb":"r");
if (not f) {
perror("No s'ha pogut obrir l'arxiu de recursos");
exit(1);
}
fseek(f, toc[count].offset, SEEK_SET);
} else {
f = fopen(file_getfilenamewithfolder(resourcename), binary?"rb":"r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
}
return f;
}
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
FILE *f = file_getfilepointer(resourcename, filesize, true);
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
// Crea la carpeta del sistema donde guardar datos
void file_setconfigfolder(const char *foldername)
{
#ifdef _WIN32
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
#elif __APPLE__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/Library/Application Support/" + foldername;
#elif __linux__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/." + foldername;
#endif
struct stat st = {0};
if (stat(config_folder.c_str(), &st) == -1)
{ {
#ifdef _WIN32 std::string path;
int ret = mkdir(config_folder.c_str()); uint32_t size;
#else uint32_t offset;
int ret = mkdir(config_folder.c_str(), S_IRWXU); };
#endif
if (ret == -1) std::vector<file_t> toc;
/* El std::map me fa coses rares, vaig a usar un good old std::vector amb una estructura key,value propia i au, que sempre funciona */
struct keyvalue_t {
std::string key, value;
};
char *resource_filename = NULL;
char *resource_folder = NULL;
int file_source = SOURCE_FILE;
char scratch[255];
static std::string config_folder;
std::vector<keyvalue_t> config;
void setResourceFilename(const char *str) {
if (resource_filename != NULL) free(resource_filename);
resource_filename = (char*)malloc(strlen(str)+1);
strcpy(resource_filename, str);
}
void setResourceFolder(const char *str) {
if (resource_folder != NULL) free(resource_folder);
resource_folder = (char*)malloc(strlen(str)+1);
strcpy(resource_folder, str);
}
void setSource(const int src) {
file_source = src%2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder)
if (src==SOURCE_FOLDER && resource_folder==NULL) setResourceFolder(DEFAULT_FOLDER);
}
bool getDictionary() {
if (resource_filename == NULL) setResourceFilename(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((char*)&num_files, 4);
fi.read((char*)&toc_offset, 4);
fi.seekg(toc_offset);
for (uint i=0; i<num_files; ++i)
{ {
printf("ERROR CREATING CONFIG FOLDER."); uint32_t file_offset, file_size;
exit(EXIT_FAILURE); fi.read( (char*)&file_offset, 4 );
fi.read( (char*)&file_size, 4 );
uint8_t path_size;
fi.read( (char*)&path_size, 1 );
char file_name[path_size+1];
fi.read( file_name, path_size );
file_name[path_size] = 0;
std::string filename = file_name;
toc.push_back({filename, file_size, file_offset});
}
fi.close();
return true;
}
char *getFilenameWithFolder(const char* filename) {
strcpy(scratch, resource_folder);
strcat(scratch, filename);
return scratch;
}
FILE *getFilePointer(const char *resourcename, int& filesize, const bool binary) {
if (file_source==SOURCE_FILE and toc.size()==0) {
if (not getDictionary()) setSource(SOURCE_FOLDER);
}
FILE *f;
if (file_source==SOURCE_FILE) {
bool found = false;
uint32_t count = 0;
while( !found && count < toc.size() ) {
found = ( std::string(resourcename) == toc[count].path );
if( !found ) count++;
}
if( !found ) {
perror("El recurs no s'ha trobat en l'arxiu de recursos");
exit(1);
}
filesize = toc[count].size;
f = fopen(resource_filename, binary?"rb":"r");
if (not f) {
perror("No s'ha pogut obrir l'arxiu de recursos");
exit(1);
}
fseek(f, toc[count].offset, SEEK_SET);
} else {
f = fopen(getFilenameWithFolder(resourcename), binary?"rb":"r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
}
return f;
}
char *getFileBuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
FILE *f = getFilePointer(resourcename, filesize, true);
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
// Crea la carpeta del sistema donde guardar datos
void setConfigFolder(const char *foldername)
{
#ifdef _WIN32
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
#elif __APPLE__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/Library/Application Support/" + foldername;
#elif __linux__
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/." + foldername;
#endif
struct stat st = {0};
if (stat(config_folder.c_str(), &st) == -1)
{
#ifdef _WIN32
int ret = mkdir(config_folder.c_str());
#else
int ret = mkdir(config_folder.c_str(), S_IRWXU);
#endif
if (ret == -1)
{
printf("ERROR CREATING CONFIG FOLDER.");
exit(EXIT_FAILURE);
}
} }
} }
}
const char *file_getconfigfolder() { const char *getConfigFolder() {
std::string folder = config_folder + "/"; std::string folder = config_folder + "/";
return folder.c_str(); return folder.c_str();
} }
void file_loadconfigvalues() { void loadConfigValues() {
config.clear(); config.clear();
std::string config_file = config_folder + "/config.txt"; std::string config_file = config_folder + "/config.txt";
FILE *f = fopen(config_file.c_str(), "r"); FILE *f = fopen(config_file.c_str(), "r");
if (!f) return; if (!f) return;
char line[1024]; char line[1024];
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
char *value = strchr(line, '='); char *value = strchr(line, '=');
if (value) { if (value) {
*value='\0'; value++; *value='\0'; value++;
value[strlen(value)-1] = '\0'; value[strlen(value)-1] = '\0';
config.push_back({line, value}); config.push_back({line, value});
} }
}
fclose(f);
}
void file_saveconfigvalues() {
std::string config_file = config_folder + "/config.txt";
FILE *f = fopen(config_file.c_str(), "w");
if (f) {
for (auto pair : config) {
fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
} }
fclose(f); fclose(f);
} }
}
const char* file_getconfigvalue(const char *key) { void saveConfigValues() {
if (config.empty()) file_loadconfigvalues(); std::string config_file = config_folder + "/config.txt";
for (auto pair : config) { FILE *f = fopen(config_file.c_str(), "w");
if (pair.key == std::string(key)) { if (f) {
strcpy(scratch, pair.value.c_str()); for (auto pair : config) {
return scratch; fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
}
fclose(f);
} }
} }
return NULL;
}
void file_setconfigvalue(const char* key, const char* value) { const char* getConfigValue(const char *key) {
if (config.empty()) file_loadconfigvalues(); if (config.empty()) loadConfigValues();
for (auto &pair : config) { for (auto pair : config) {
if (pair.key == std::string(key)) { if (pair.key == std::string(key)) {
pair.value = value; strcpy(scratch, pair.value.c_str());
file_saveconfigvalues(); return scratch;
return; }
} }
return NULL;
}
void setConfigValue(const char* key, const char* value) {
if (config.empty()) loadConfigValues();
for (auto &pair : config) {
if (pair.key == std::string(key)) {
pair.value = value;
saveConfigValues();
return;
}
}
config.push_back({key, value});
saveConfigValues();
return;
} }
config.push_back({key, value});
file_saveconfigvalues();
return;
} }

View File

@@ -4,15 +4,18 @@
#define SOURCE_FILE 0 #define SOURCE_FILE 0
#define SOURCE_FOLDER 1 #define SOURCE_FOLDER 1
void file_setconfigfolder(const char *foldername); namespace file
const char *file_getconfigfolder(); {
void setConfigFolder(const char *foldername);
const char *getConfigFolder();
void file_setresourcefilename(const char *str); void setResourceFilename(const char *str);
void file_setresourcefolder(const char *str); void setResourceFolder(const char *str);
void file_setsource(const int src); void setSource(const int src);
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false); FILE *getFilePointer(const char *resourcename, int& filesize, const bool binary=false);
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate=false); char *getFileBuffer(const char *resourcename, int& filesize, const bool zero_terminate=false);
const char* file_getconfigvalue(const char *key); const char* getConfigValue(const char *key);
void file_setconfigvalue(const char* key, const char* value); void setConfigValue(const char* key, const char* value);
}

View File

@@ -63,7 +63,7 @@ int main(int argc, char *argv[])
game::windowHasFocus = true; game::windowHasFocus = true;
game::init(); game::init();
input::init(draw::getZoom()); input::init();
static unsigned int current_ticks = SDL_GetTicks(); static unsigned int current_ticks = SDL_GetTicks();
@@ -84,7 +84,22 @@ int main(int argc, char *argv[])
} }
if (e.type==SDL_EVENT_KEY_UP) if (e.type==SDL_EVENT_KEY_UP)
{ {
input::updateKeypressed(e.key.scancode); switch (e.key.scancode) {
case SDL_SCANCODE_F1:
draw::setZoom(draw::getZoom()-1);
break;
case SDL_SCANCODE_F2:
draw::setZoom(draw::getZoom()+1);
break;
case SDL_SCANCODE_F3:
draw::setFullscreen(!draw::getFullscreen());
break;
case SDL_SCANCODE_F4:
draw::toggleShader();
break;
default:
input::updateKeypressed(e.key.scancode);
}
} }
if (e.type==SDL_EVENT_MOUSE_BUTTON_UP) if (e.type==SDL_EVENT_MOUSE_BUTTON_UP)
{ {

View File

@@ -9,12 +9,10 @@ namespace input
static uint8_t keydown = 0; static uint8_t keydown = 0;
static uint8_t btnClicked = 0; static uint8_t btnClicked = 0;
static int wheel = 0; static int wheel = 0;
static int screen_zoom = 1;
void init(const int zoom) void init()
{ {
keys = SDL_GetKeyboardState(NULL); keys = SDL_GetKeyboardState(NULL);
screen_zoom = zoom;
} }
// Determina si la tecla especificada està sent polsada ara mateix // Determina si la tecla especificada està sent polsada ara mateix
@@ -81,7 +79,7 @@ namespace input
{ {
float x; float x;
SDL_GetMouseState(&x, NULL); SDL_GetMouseState(&x, NULL);
return x/screen_zoom; return x/draw::getScaleX();
} }
// Torna la posició Y actual del ratolí // Torna la posició Y actual del ratolí
@@ -89,7 +87,7 @@ namespace input
{ {
float y; float y;
SDL_GetMouseState(NULL, &y); SDL_GetMouseState(NULL, &y);
return y/screen_zoom; return y/draw::getScaleY();
} }
// Determina si el botó del ratolí especificat està sent polsada ara mateix // Determina si el botó del ratolí especificat està sent polsada ara mateix

View File

@@ -14,7 +14,7 @@ namespace input
} }
/// @brief Inicialitza els sistemes de teclat, ratolí i gamepad /// @brief Inicialitza els sistemes de teclat, ratolí i gamepad
void init(const int zoom); void init();
/// @brief Determina si la tecla especificada està sent polsada ara mateix /// @brief Determina si la tecla especificada està sent polsada ara mateix
/// @param key tecla a consultar /// @param key tecla a consultar

270
source/jshader.cpp Normal file
View File

@@ -0,0 +1,270 @@
#include "jshader.h"
#include <iostream>
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#include <OpenGL/OpenGL.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_FRect window = {0, 0, 640, 480};
SDL_FPoint tex_size = {320, 240};
float aspect_ratio = 1;
bool can_use_opengl = false;
bool using_opengl = false;
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;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
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");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
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");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
glDeleteProgram && glLinkProgram && glValidateProgram && glGetProgramiv &&
glGetProgramInfoLog && glUseProgram && glGetUniformLocation;
}
#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;
//std::cout << source << std::endl;
free(log);
}
glDeleteShader(result);
result = 0;
}
return result;
}
GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
{
GLuint programId = 0;
GLuint vtxShaderId, fragShaderId;
if (programId != 0) glDeleteProgram(programId);
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;
int w, h;
SDL_GetWindowSize(win, &w, &h);
if (w * aspect_ratio > h) {
window.y = 0;
window.h = h;
window.w = h/aspect_ratio;
window.x = (w - window.w)/2;
} else {
window.x = 0;
window.w = w;
window.h = w*aspect_ratio;
window.y = (h - window.h)/2;
}
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__
static bool gl_extensions_initialized = false;
if (!gl_extensions_initialized) {
if (!initGLExtensions()) {
std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl;
can_use_opengl = false;
return false;
}
gl_extensions_initialized = true;
}
#endif
// Compilar el shader y dejarlo listo para usar.
if (!vertexShader) {
can_use_opengl = false;
return false;
}
programId = compileProgram(vertexShader, fragmentShader);
} else {
std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl;
can_use_opengl = false;
return false;
}
can_use_opengl = true;
return true;
}
unsigned char pixels[512*240*4];
void enable() { if (can_use_opengl) using_opengl = true; }
void disable() { using_opengl = false; }
void setAspectRatio(const float ratio)
{
aspect_ratio = ratio;
}
void render()
{
SDL_FlushRenderer(renderer);
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_FlushRenderer(renderer);
if (using_opengl)
{
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, &param);
//printf("tex width: %i\n", param);
glViewport(window.x, window.y, window.w, window.h);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(tex_size.x, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(0.0f, tex_size.y);
glVertex2f(-1.0f, 1.0f);
glTexCoord2f(tex_size.x, tex_size.y);
glVertex2f(1.0f, 1.0f);
glEnd();
SDL_GL_SwapWindow(win);
if (programId != 0) glUseProgram(oldProgramId);
} else {
SDL_RenderTexture(renderer, backBuffer, NULL, &window);
SDL_RenderPresent(renderer);
}
if (glGetError()) { printf("GLERROR!\n"); exit(1); }
}
}

48
source/jshader.h Normal file
View File

@@ -0,0 +1,48 @@
#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 setAspectRatio(const float ratio);
void enable();
void disable();
void render();
}

View File

@@ -4,12 +4,12 @@
void game::init() void game::init()
{ {
draw::init("Arounders", 320, 200, 3); draw::init("Arounders", 320, 200, 3, false, 3.0f/4.0f);
draw::setShader("lynx.glsl");
draw::setTrans(0); draw::setTrans(0);
input::init(3);
audio::init(48000, SDL_AUDIO_S16, 2); audio::init(48000, SDL_AUDIO_S16, 2);
file::setConfigFolder("arounders");
font::init(); font::init();
game::setUpdateTicks(16); game::setUpdateTicks(16);