/* Ejemplo de uso de las unidades incluídas en jail_engine Código fuente creado por JailDesigner */ #include #include #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 "units/on_screen_keyboard.h" #include "quickcg.h" using namespace QuickCG; using namespace std; // 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; OnScreenKeyboard *osk = nullptr; // 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 int fx = 0; // Efecto seleccionado para el fondo // 0 - Degradado // 1 - Fuego 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 fireDesp = 3; // Desplazamiento inferior del efecto de fuego para eliminar las primeras filas const int fireWidth = 320; // Ancho del efecto de fuego const int fireHeight = 240 + fireDesp; // Alto del efecto de fuego Uint8 fire[fireHeight][fireWidth]; // Buffer con el fuego Uint32 palette[256]; // Paleta de color para el fuego int fireModifier = 28; // Valor para modificar el efecto de fuego (0-30) SDL_Texture *fireTexture; // Textura donde pintar los pixels del fuego Uint32 *fireBuffer; // Ubiación donde se guardan los pixeles del fuego int pitch; // No se utiliza pero se necesita para dibujar los pixeles en la textura SDL_Rect fireSource = {0, 0, fireWidth, fireHeight - fireDesp}; // Parte de la textura donde está el efecto de fuego que se copiará a la pantalla // 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 teclado en pantalla void initOnScreenKeyboard(); // 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/nokia.txt", t_font); asset->add("/data/nokia.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 teclado en pantalla void initOnScreenKeyboard() { osk = new OnScreenKeyboard(renderer, input, asset->get("nokia.png"), asset->get("nokia.txt"), options, options->screen.nativeWidth - 30, options->screen.nativeHeight - 80, "JailDesigner"); osk->setBgColor({123, 99, 63}); osk->setCaption("JAILER_ID"); osk->setChars(USE_UPPER | USE_LOWER | USE_NUMBER); } // Elimina el teclado en pantalla void deleteOnScreenKeyboard() { if (osk != nullptr) { delete osk; osk = nullptr; } } // Dibuja el teclado en pantalla void renderOnScreenKeyboard() { if (osk != nullptr) osk->render(); } // Actualiza el teclado en pantalla void updateOnScreenKeyboard() { if (osk != nullptr) osk->update(); } // 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 generador de numeros aleatorios srand((unsigned)SDL_GetTicks()); // Inicializa el buffer de fuego for (int y = 0; y < fireHeight; ++y) for (int x = 0; x < fireWidth; ++x) fire[y][x] = 0; fireTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, fireWidth, fireHeight); // 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, min(255, x * 2))); // Pon en la paleta el color calculado palette[x] = (Uint32)16777216 * 255 + 65536 * color.r + 256 * color.g + color.b; } // Coloca algo de fuego en la textura for (int x = 0; x < 100; ++x) updateFire(); } // 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 teclado en pantalla // initOnScreenKeyboard(); // 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_F3: --fireModifier; fireModifier = max(0, fireModifier); break; case SDL_SCANCODE_F4: ++fireModifier; fireModifier = min(30, fireModifier); break; case SDL_SCANCODE_SPACE: ++fx %= fxTotal; break; case SDL_SCANCODE_N: screen->showNotification("Ejemplo de notificacion", "con 2 lineas de texto", 0); break; case SDL_SCANCODE_T: if (osk == nullptr) initOnScreenKeyboard(); else deleteOnScreenKeyboard(); 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() { const int w = fireWidth; const int h = fireHeight; const int mod = 157 - fireModifier; // Bloquea la textura para poder escribir en los pixeles SDL_LockTexture(fireTexture, NULL, (void **)&fireBuffer, &pitch); // Crea la fila inferior del fuego con pixels aleatorios for (int x = 0; x < w; ++x) { fire[h - 1][x] = rand() % 256; fireBuffer[x + (h - 1) * 320] = palette[fire[h - 1][x]]; } // Calcula los pixeles del efecto de fuego, desde la fila superior hasta la inferior 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) / mod; fireBuffer[x + y * 320] = palette[fire[y][x]]; } // Desbloquea la textura SDL_UnlockTexture(fireTexture); } // Actualiza el efecto de fondo void updateFX() { switch (fx) { case 0: // Degradado updateGradient(); break; case 1: // Fuego updateFire(); 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 los objetos updateOnScreenKeyboard(); // Actualiza el teclado en pantalla screen->update(); // Actualiza la pantalla updateSprite(); // Actualiza el sprite // 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() { SDL_RenderCopy(renderer, fireTexture, &fireSource, NULL); } // Dibuja el efecto de fondo void renderFX() { switch (fx) { case 0: // Degradado renderGradient(); break; case 1: // Fuego renderFire(); break; default: break; } } // Dibuja el texto void renderText() { const string fxName = fx == 0 ? "Degradado" : "Fuego"; 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 'ESPACIO' para cambiar el efecto de fondo: " + fxName, 1, {240, 240, 240}, 1, {0, 0, 192}); if (fxName == "Fuego") debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 11, "Pulsa 'F3' o 'F4' para modificar el fuego: " + to_string(fireModifier), 1, {240, 240, 240}, 1, {0, 0, 192}); debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 13, "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() * 15, controllerName, 1, {240, 240, 240}, 1, {0, 0, 192}); debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 17, 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(); // Dibuja el teclado en pantalla renderOnScreenKeyboard(); // 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 teclado en pantalla if (osk != nullptr) delete osk; // 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; }