Files
jail_engine/main.cpp

646 lines
15 KiB
C++

/*
Ejemplo de uso de las unidades incluídas en jail_engine
Código fuente creado por JailDesigner
*/
#include <SDL2/SDL.h>
#include <iostream>
#include "units/jail_audio.h"
#include "units/text.h"
#include "units/utils.h"
#include "units/asset.h"
#include "units/movingsprite.h"
#include "units/texture.h"
#include "units/screen.h"
#include "units/input.h"
#include "quickcg.h"
using namespace QuickCG;
// Punteros
SDL_Event *event;
SDL_Window *window;
SDL_Renderer *renderer;
Asset *asset;
JA_Music_t *music;
JA_Sound_t *sound;
Input *input;
struct options_t *options;
Screen *screen;
Text *text;
Text *debugText;
Texture *texture;
MovingSprite *sprite;
// Listas
enum e_fx // Tipos de efectos disponibles para el fondo
{
fx_fire,
fx_gradient
};
// Variables de uso general
Uint32 ticks = 0; // Variable para la frecuencia de actualización de la lógica del programa
const Uint32 ticksSpeed = 15; // Variable para la frecuencia de actualización de la lógica del programa
bool should_exit = false; // Variable para saber si ha terminado el progra,a
int counter = 0; // Contador para lo que se necesite
string controllerName; // Nombre del primer mando detectado
string inputPressed; // Texto con el último input que se ha pulsado
e_fx fx = fx_fire; // Efecto seleccionado para el fondo
int fxTotal = 2; // Cantidad total de efectos disponibles para el fondo
// Variables para el efecto del degradado
int gradColorMin = 64; // Minimo color más alto del degradado
int gradColorMax = 192; // Minimo color más alto del degradado
int gradCurrentColor = 192; // Color actual más alto del degradado
int gradBreathDirection = 0; // Indica si gradCurrentColor crece o decrece
// Variables para el efecto de fuego
const int fireScreenWidth = 320; // Ancho del efecto de fuego
const int fireScreenHeight = 180; // Alto del efecto de fuego
Uint32 fire[fireScreenHeight][fireScreenWidth]; // Buffer con el fuego
Uint32 buffer[fireScreenHeight][fireScreenWidth]; // Buffer para dibujar en pantalla
ColorRGB palette[256]; // Paleta de color para el fuego
const int fireDesp = 240 - fireScreenHeight + 3; // Fila donde comienza a dibujarse el efecto de fuego
// Inicializa las opciones
void initOptions();
// Inicializa la lista de recursos
void initAsset(char *argv[]);
// Inicializa SDL
void initSDL();
// Inicializa la ventana
void initWindow();
// Inicializa el gestor de eventos
void initEvent();
// Inicializa jail_audio
void initJailAudio();
// Inicializa el objeto screen
void initScreen();
// Inicializa el objeto input
void initInput();
// Inicializa el texto
void initText();
// Inicializa el sprite
void initSprite();
// Inicializa el efecto de fuego
void initFire();
// Inicializa todo
void initAll(char *argv[]);
// Comprueba el teclado y los eventos
void checkEvents();
// Comprueba el objeto input
void checkInput();
// Actualiza el sprite
void updateSprite();
// Actualiza el efecto de degradado
void updateGradient();
// Actualiza el efecto de fuego
void updateFire();
// Actualiza el efecto de fondo
void updateFX();
// Actualiza la lógica del programa
void update();
// Dibuja un degradado de fondo
void renderGradient();
// Dibuja el efecto de fuego
void renderFire();
// Dibuja el efecto de fondo
void renderFX();
// Dibuja el texto
void renderText();
// Dibuja los elementos del programa en pantalla
void render();
// Libera la memoria reservada
void freeAll();
// Inicializa las opciones
void initOptions()
{
options = new options_t;
initOptions(options);
options->screen.nativeWidth = 320;
options->screen.nativeHeight = 240;
options->screen.nativeZoom = 2;
options->screen.windowZoom = 1;
options->console = true;
}
// Inicializa la lista de recursos
void initAsset(char *argv[])
{
asset = new Asset(argv[0]);
asset->add("/data/music.ogg", t_music);
asset->add("/data/sound.wav", t_sound);
asset->add("/data/smb2.txt", t_font);
asset->add("/data/smb2.png", t_bitmap);
asset->add("/data/debug.txt", t_font);
asset->add("/data/debug.png", t_bitmap);
asset->add("/data/z80.png", t_bitmap);
asset->add("/data/notify.png", t_bitmap);
asset->add("/data/notify.wav", t_sound);
asset->add("/data/gamecontrollerdb.txt", t_data);
asset->setVerbose(options->console);
if (!asset->check())
{
exit(EXIT_FAILURE);
}
}
// Inicializa SDL
void initSDL()
{
SDL_Init(SDL_INIT_EVERYTHING);
}
// Inicializa la ventana
void initWindow()
{
window = SDL_CreateWindow("Jail Engine DEMO", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, options->screen.nativeWidth * options->screen.nativeZoom * options->screen.windowZoom, options->screen.nativeHeight * options->screen.nativeZoom * options->screen.windowZoom, SDL_WINDOW_SHOWN);
if (window != nullptr)
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer != nullptr)
{
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
}
else
{
exit(EXIT_FAILURE);
}
}
else
{
exit(EXIT_FAILURE);
}
}
// Inicializa el gestor de eventos
void initEvent()
{
event = new SDL_Event();
}
// Inicializa jail_audio
void initJailAudio()
{
JA_Init(48000, AUDIO_S16, 2);
music = JA_LoadMusic(asset->get("music.ogg").c_str());
sound = JA_LoadSound(asset->get("sound.wav").c_str());
// JA_PlayMusic(music, true);
}
// Inicializa el objeto screen
void initScreen()
{
screen = new Screen(window, renderer, options);
screen->addNotifier(asset->get("notify.png"), asset->get("smb2.png"), asset->get("smb2.txt"), asset->get("notify.wav"));
}
// Inicializa el objeto input
void initInput()
{
input = new Input(asset->get("gamecontrollerdb.txt"), options->console);
controllerName = input->getNumControllers() > 0 ? input->getControllerName(0) : "No se ha encontrado ningun mando";
}
// Inicializa el texto
void initText()
{
text = new Text(asset->get("smb2.txt"), asset->get("smb2.png"), renderer);
debugText = new Text(asset->get("debug.txt"), asset->get("debug.png"), renderer);
}
// Inicializa el sprite
void initSprite()
{
texture = new Texture(renderer, asset->get("z80.png"));
sprite = new MovingSprite();
sprite->setRenderer(renderer);
sprite->setTexture(texture);
sprite->setPosX(140);
sprite->setPosY(100);
sprite->setWidth(16);
sprite->setHeight(32);
sprite->setSpriteClip({0, 0, 16, 32});
sprite->setVelX(1);
sprite->setVelY(2);
}
// Inicializa el efecto de fuego
void initFire()
{
// Inicializa el buffer de fuego
for (int y = 0; y < fireScreenHeight; ++y)
for (int x = 0; x < fireScreenWidth; ++x)
fire[y][x] = 0;
// Inicializa la paleta
for (int x = 0; x < 256; ++x)
{
// HSLtoRGB is used to generate colors:
// Hue goes from 0 to 85: red to yellow
// Saturation is always the maximum: 255
// Lightness is 0..255 for x=0..128, and 255 for x=128..255
ColorRGB color = HSLtoRGB(ColorHSL(x / 3, 255, std::min(255, x * 2)));
// set the palette to the calculated RGB value
// palette[x] = RGBtoINT(color);
palette[x] = color;
}
}
// Inicializa todo
void initAll(char *argv[])
{
// Inicializa las opciones
initOptions();
// Inicializa la lista de recursos
initAsset(argv);
// Inicializa SDL
initSDL();
// Inicializa la ventana
initWindow();
// Inicializa el gestor de eventos
initEvent();
// Inicializa jail_audio
initJailAudio();
// Inicializa el objeto screen
initScreen();
// Inicializa el objeto input
initInput();
// Inicializa el texto
initText();
// Inicializa el sprite
initSprite();
// Inicializa el efecto de fuego
initFire();
}
// Comprueba el teclado y los eventos
void checkEvents()
{
while (SDL_PollEvent(event))
{
if (event->type == SDL_QUIT)
{
should_exit = true;
break;
}
if (event->type == SDL_KEYDOWN)
{
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_ESCAPE:
should_exit = true;
break;
case SDL_SCANCODE_F1:
screen->decWindowSize();
break;
case SDL_SCANCODE_F2:
screen->incWindowSize();
break;
case SDL_SCANCODE_N:
screen->showNotification("Ejemplo de notificacion", "con 2 lineas de texto", 0);
break;
default:
break;
}
}
}
}
// Comprueba el objeto input
void checkInput()
{
inputPressed = "";
if (input->checkInput(INPUT_LEFT))
{
inputPressed = "Izquierda";
}
if (input->checkInput(INPUT_RIGHT))
{
inputPressed = "Derecha";
}
if (input->checkInput(INPUT_UP))
{
inputPressed = "Arriba";
}
if (input->checkInput(INPUT_DOWN))
{
inputPressed = "Abajo";
}
}
// Actualiza el sprite
void updateSprite()
{
if (sprite->getPosX() + sprite->getWidth() > options->screen.nativeWidth or sprite->getPosX() < 0)
{
sprite->undoMoveX();
int spr_direction = 1;
int spr_force = 1;
if (sprite->getVelX() > 0)
{
spr_direction = -1;
}
if (SDL_GetTicks() % 2 == 0)
{
spr_force = 2;
}
sprite->setVelX(spr_force * spr_direction);
JA_PlaySound(sound);
}
if (sprite->getPosY() + sprite->getHeight() > options->screen.nativeHeight or sprite->getPosY() < 0)
{
sprite->undoMoveY();
int spr_direction = 1;
int spr_force = 1;
if (sprite->getVelY() > 0)
{
spr_direction = -1;
}
if (SDL_GetTicks() % 2 == 0)
{
spr_force = 2;
}
sprite->setVelY(spr_force * spr_direction);
JA_PlaySound(sound);
}
sprite->update();
}
// Actualiza el degradado
void updateGradient()
{
if (counter % 1 == 0)
{
gradBreathDirection == 0 ? gradCurrentColor-- : gradCurrentColor++;
if (gradCurrentColor == gradColorMin)
{
gradBreathDirection = 1;
}
if (gradCurrentColor == gradColorMax)
{
gradBreathDirection = 0;
}
}
}
// Actualiza el efecto de fuego
void updateFire()
{
// randomize the bottom row of the fire buffer
const int w = fireScreenWidth;
const int h = fireScreenHeight;
for (int x = 0; x < w; ++x)
fire[h - 1][x] = abs(32768 + rand()) % 256;
// do the fire calculations for every pixel, from top to bottom
for (int y = 0; y < h - 1; ++y)
for (int x = 0; x < w; ++x)
{
fire[y][x] =
((fire[(y + 1) % h][(x - 1 + w) % w] + fire[(y + 1) % h][(x) % w] + fire[(y + 1) % h][(x + 1) % w] + fire[(y + 2) % h][(x) % w]) * 32) / 129;
}
}
// Actualiza el efecto de fondo
void updateFX()
{
switch (fx)
{
case fx_fire:
updateFire();
break;
case fx_gradient:
updateGradient();
break;
default:
break;
}
}
// Actualiza la lógica del programa
void update()
{
// Comprueba el teclado y los eventos
checkEvents();
// Comprueba el objeto input
checkInput();
// Actualiza la lógica del programa
if (SDL_GetTicks() - ticks > ticksSpeed)
{
// Actualiza la variable
ticks = SDL_GetTicks();
// Incrementa el contador
counter++;
// Actualiza el objeto screen
screen->update();
// Actualiza el sprite
updateSprite();
// Actualiza el efecto de fondo
updateFX();
}
}
// Dibuja un degradado de fondo
void renderGradient()
{
const int gradFirstLine = options->screen.nativeHeight / 3;
const int gradLastLine = options->screen.nativeHeight;
const int gradNumLines = gradLastLine - gradFirstLine;
const int gradColorFrom = 0;
for (int i = gradFirstLine; i < gradLastLine; ++i)
{
float step = ((float)(i - gradFirstLine) / gradNumLines);
int color = gradColorFrom + ((gradCurrentColor - gradColorFrom) * step);
SDL_SetRenderDrawColor(renderer, color, 0x00, 0x00, 0xFF);
SDL_RenderDrawLine(renderer, 0, i, options->screen.nativeWidth, i);
}
for (int i = gradLastLine; i > gradFirstLine; --i)
{
float step = ((float)(i - gradFirstLine) / gradNumLines);
int alpha = 0 + ((255 - 0) * step);
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0xFF, alpha);
SDL_RenderDrawLine(renderer, 0, gradLastLine - i, options->screen.nativeWidth, gradLastLine - i);
}
}
// Dibuja el efecto de fuego
void renderFire()
{
for (int y = 0; y < fireScreenHeight; ++y)
for (int x = 0; x < fireScreenWidth; ++x)
{
const ColorRGB c = palette[fire[y][x]];
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, 255);
SDL_RenderDrawPoint(renderer, x, y + fireDesp);
}
}
// Dibuja el efecto de fondo
void renderFX()
{
switch (fx)
{
case fx_fire:
renderFire();
break;
case fx_gradient:
renderGradient();
break;
default:
break;
}
}
// Dibuja el texto
void renderText()
{
text->setZoom(2);
text->writeDX(TXT_CENTER | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize(), "Jail Engine DEMO", 1, {255, 255, 255}, 1, {0, 0, 192});
text->disableZoom();
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 4, "2023 JailDesigner", 1, {240, 240, 240}, 1, {0, 0, 192});
debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 7, "Pulsa 'F1' o 'F2' para disminuir o aumentar la ventana", 1, {240, 240, 240}, 1, {0, 0, 192});
debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 9, "Pulsa 'N' para mostrar una notificacion", 1, {240, 240, 240}, 1, {0, 0, 192});
debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 11, controllerName, 1, {240, 240, 240}, 1, {0, 0, 192});
debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 13, inputPressed, 1, {240, 240, 240}, 1, {0, 0, 192});
debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, options->screen.nativeHeight - (text->getCharacterSize() * 2), "Pulsa 'ESCAPE' para terminar el programa", 1, {240, 240, 240}, 1, {0, 0, 192});
}
// Dibuja los elementos del programa en pantalla
void render()
{
// Prepara el objeto screen para dibujar
screen->start();
screen->clean();
// Dibuja el efecto de fondo
renderFX();
// Dibuja el sprite
sprite->render();
// Dinuja el texto
renderText();
// Vuelca el buffer en pantalla
screen->blit();
}
// Libera la memoria reservada
void freeAll()
{
// Finaliza el sprite
if (sprite != nullptr)
delete sprite;
if (texture != nullptr)
delete texture;
// Finaliza el texto
if (text != nullptr)
delete text;
if (debugText != nullptr)
delete debugText;
// Finaliza el objeto input
if (input != nullptr)
delete input;
// Finaliza el objeto screen
if (screen != nullptr)
delete screen;
// Finaliza jail_audio
JA_DeleteSound(sound);
JA_DeleteMusic(music);
// Finaliza el objeto con la lista de recuros
if (asset != nullptr)
delete asset;
// Finaliza las opciones
if (options != nullptr)
delete options;
// Finaliza SDL y la ventana
if (event != nullptr)
delete event;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
int main(int argc, char *argv[])
{
// Inicializa todo
initAll(argv);
// Bucle principal
while (!should_exit)
{
// Actualiza la lógica del programa
update();
// Dibuja los elementos del programa en pantalla
render();
}
// Libera la memoria reservada
freeAll();
return 0;
}