#include "grafix.h" #include #include "gif.c" #include "crt.h" namespace draw { SDL_Window *sdl_window = nullptr; // La finestra 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 surface *screen = nullptr; // La superficie screen, que representa la pantalla. Se crea i destrueix internament uint32_t palette[256]; // La paleta de colors void init(const char* titol, const uint16_t width, const uint16_t height, const uint8_t zoom) { // Inicialització de les estructures de SDL sdl_window = SDL_CreateWindow(titol, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width * zoom, height * zoom, SDL_WINDOW_SHOWN); sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0); sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); // Establim el tamany "logic", indepndent del tamany de finestra SDL_RenderSetLogicalSize(sdl_renderer, width, height); // Creem la superficie "screen" i la establim com a superficie destinació screen = createSurface(width, height); } // Finalització del sistema void quit() { // Si la superficie "screen" existia, alliberem la seua memòria if (screen != nullptr) { freeSurface(screen); } // Destruim tot el relacionat amb SDL SDL_DestroyTexture(sdl_texture); SDL_DestroyRenderer(sdl_renderer); SDL_DestroyWindow(sdl_window); // Fiquem tots els punters a nullptr, per si de cas no estem eixint del programa // i anem a tornar a inicialitzar el sistema sdl_window = nullptr; sdl_renderer = nullptr; sdl_texture = nullptr; screen = nullptr; } surface *createSurface(const int width, const int height) { // Primer reservem memòria per a la estructura "surface" surface *surf = (surface *)malloc(sizeof(surface)); // Després reservem memòria per als pixels surf->pixels = (uint8_t *)malloc(width * height); // I apuntem el ample i alt de la superficie surf->w = width; surf->h = height; // ...i tornem la superficie creada, clar return surf; } surface *loadSurface(const char *filename) { // Agafem un buffer de bytes de l'arxiu especificat FILE *f = fopen(filename, "r"); if (f==nullptr) return nullptr; fseek(f, 0, SEEK_END); const int size = ftell(f); fseek(f, 0, SEEK_SET); uint8_t *buffer = (uint8_t*)malloc(size); fread(buffer, size, 1, f); fclose(f); // Primer reservem memòria per a la estructura "surface" surface *surf = (surface *)malloc(sizeof(surface)); // Després li passem el buffer de bytes a la funció de carregar un GIF. // El resultat es un array de bytes, els pixels en sí. Ja havem reservat // la memòria necessaria en "LoadGif", així que no tenim que fer-ho ara, // però, ojo, sí que tindrem que alliberar-la. surf->pixels = LoadGif(buffer, &surf->w, &surf->h); // Com ja no ens fa falta, alliberem la memòria del buffer del arxiu free(buffer); // I finalment tornem la superficie return surf; } void freeSurface(surface *surface) { // Si la superficie existeix... if (surface != nullptr) { // Si el array de pixels existeix, l'alliberem if (surface->pixels != nullptr) { free(surface->pixels); } // ... alliberem la superficie free(surface); } } void draw(surface *src, surface *dst, uint16_t src_offset, uint16_t w, uint16_t h, uint16_t dst_x, uint16_t dst_y) { if (!src) src = screen; if (!dst) dst = screen; const int src_x = src_offset % src->w; const int src_y = src_offset / src->w; for (int y=0; yww ? src->w : dst->w; const int h = src->hh ? src->h : dst->h; for (int y=0;ypixels[x+y*dst->w] = src->pixels[x+y*src->w]; if (dst==screen) render(); } void cls(const uint8_t color, surface *dst) { if (!dst) dst = screen; // El tamany es width x height bytes const int size = dst->w * dst->h; // Omplim la memòria dels pixels de la superficie de destinació amb "color" memset(dst->pixels, color, size); if (dst==screen) render(); } // Estableix la paleta del sistema carregant-la d'un GIF void loadPalette(const char *filename) { // Agafem un buffer de bytes de l'arxiu especificat FILE *f = fopen(filename, "r"); if (f==nullptr) return; fseek(f, 0, SEEK_END); const int size = ftell(f); fseek(f, 0, SEEK_SET); uint8_t *buffer = (uint8_t*)malloc(size); fread(buffer, size, 1, f); fclose(f); // 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 uint32_t *pal = LoadPalette(buffer); // Copiem eixe array al nostre array de la paleta de sistema. Ara ja tenim la paleta carregada. memcpy(palette, pal, 1024); // 32 bits per entrada == 4 bytes x 256 entrades == 1024 // Alliberem el array que ens habia tornat LoadPalette() free(pal); // I també el buffer del arxiu free(buffer); } void setPalette(uint8_t *paleta) { uint8_t *p = paleta; for (int i=0; i<256; ++i) { uint32_t color = (*p++)<<16; color += (*p++)<<8; color += (*p++); palette[i] = color; } } uint8_t *getPalette() { uint8_t *paleta = (uint8_t*)malloc(768); uint8_t *p = paleta; for (int i=0; i<256; ++i) { const uint32_t color = palette[i]; *p = (color >> 16) & 0xff; p++; *p = (color >> 8) & 0xff; p++; *p = color & 0xff; p++; } return paleta; } void setColor(const uint8_t index, const uint8_t r, const uint8_t g, const uint8_t b) { palette[index] = (uint32_t(r)<<16) + (uint32_t(g)<<8) + (uint32_t(b)); } void getColor(const uint8_t index, uint8_t *r, uint8_t *g, uint8_t *b) { const uint32_t color = palette[index]; *r = (color >> 16) & 0xff; *g = (color >> 8) & 0xff; *b = color & 0xff; } void blackout() { for (int i=0; i<256; ++i) palette[i] = 0; } void fadeDown(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t espera) // espera son el nombre de waitVsync a executar en cada iteració del bucle { for (int i=0; i<256; ++i) { bool done = true; for (int j=0; jr+4) { rr-=4; done = false; } if (gg>g+4) { gg-=4; done = false; } if (bb>b+4) { bb-=4; done = false; } setColor(j, rr, gg, bb); } render(); if (done) return; } } void fadeUp(const uint8_t *paleta, const uint8_t espera) { for (int i=0; i<256; ++i) { bool done = true; for (int j=0; jr+4) { r+=4; done = false; } else { r=paleta[j*3]; } if (paleta[j*3+1]>g+4) { g+=4; done = false; } else { g=paleta[j*3+1]; } if (paleta[j*3+2]>b+4) { b+=4; done = false; } else { b=paleta[j*3+2]; } setColor(j, r, g, b); } render(); if (done) return; } } void putPixel(const int x, const int y, const uint8_t color, surface *dst) { if (!dst) dst = screen; if (x<0 || y<0 || x>=dst->w || y>=dst->h) return; dst->pixels[x+y*dst->w] = color; } uint8_t getPixel(const int x, const int y, surface *src) { if (!src) src = screen; if (x<0 || y<0 || x>=src->w || y>=src->h) return 0; return src->pixels[x+y*src->w]; } void vline(const int x, const int y1, const int y2, const uint8_t color, surface *dst) { if (!dst) dst = screen; for (int y=y1; y<=y2; ++y) dst->pixels[x+(y*dst->w)] = color; } void waitVsync() { const uint32_t next_vsync = SDL_GetTicks() + (17 - SDL_GetTicks()%17); while (SDL_GetTicks() < next_vsync) { update(); } } void render() { Uint32 *sdl_pixels; // Punter al array de pixels que enstornarà SDL_LockTexture int sdl_pitch; // Ací estarà guardat el pitch de la textura, com es de 32 bits, no m'afecta const uint32_t size = screen->w * screen->h; // tamany de la superficie // Bloquejem la textura SDL i agafem els seus pixels (son enters de 32 bits amb format 0xAARRGGBB) SDL_LockTexture(sdl_texture, NULL, (void **)&sdl_pixels, &sdl_pitch); // Cada pixel de la superficie "screen" es un enter de 8 bits que representa un index en la paleta de colors // Per tant, per a pintar en la textura SDL, pillem el color de la paleta que correspon al index en "screen" // i el enviem a la textura SDL for (uint32_t i = 0; i < size; ++i) { sdl_pixels[i] = palette[screen->pixels[i]]; } // Desbloquejem la textura SDL_UnlockTexture(sdl_texture); // Pintem la textura a pantalla SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL); // I ho presentem SDL_RenderPresent(sdl_renderer); } }