#include "mini.h" #include "jfile.h" #include #include "lua.h" #include "gif.h" #include "gifenc.h" #include "jail_audio.h" #include "jshader.h" #include "log.h" #include "default_font_gif.h" #include "default_font_fnt.h" #define MAX_SURFACES 100 #define MAX_FONTS 5 #define SURF_NOTHING 0 #define SURF_EXTERNAL 1 #define SURF_GENERATED 2 #define DRAWMODE_NORMAL 0 #define DRAWMODE_PATTERN 1 #define DRAWMODE_AND 2 #define DRAWMODE_OR 3 #define DRAWMODE_XOR 4 #define DRAWMODE_NOT 5 #define UPDATE_ALWAYS 0 #define UPDATE_WAIT 1 #define UPDATE_TIMEOUT 2 #ifdef MACOS_BUNDLE #include #endif struct surface_t { char *name {nullptr}; uint8_t *p {nullptr}; uint16_t w, h; uint32_t size; uint8_t flags {SURF_NOTHING}; }; struct char_t { uint8_t x,y,w,h,base; }; struct font_t { char *name {nullptr}; uint8_t surface {0}; uint8_t spacing {1}; char_t chars[256]; }; int fps=0; char window_title[256]; char config_folder[256]; uint16_t screen_width = 160; uint16_t screen_height = 120; uint8_t screen_zoom = 4; bool screen_fullscreen = false; bool screen_cursor = true; surface_t surfaces[MAX_SURFACES]; surface_t *screen_surface = &surfaces[0]; surface_t *dest_surface = screen_surface; surface_t *source_surface = NULL; surface_t *map_surface = NULL; uint8_t tile_width = 8; uint8_t tile_height = 8; font_t fonts[MAX_FONTS]; font_t *current_font; char main_lua_file[200] = "main.lua"; bool override_ini = false; //char lua_files[1024]; #define DEST(x, y) dest_surface->p[x+y*dest_surface->w] #define SOURCE(x, y) source_surface->p[x+y*source_surface->w] #define TILES(x, y) map_surface->p[x+y*map_surface->w] #define CURRENT(x, y) surfaces[i].p[(x)+(y)*surfaces[i].w] namespace ds { int origin[2] = {0, 0}; int clip[4] = {0, 0, screen_width-1, screen_height-1}; uint8_t trans = 0; uint16_t fill_pattern = 0b1111111111111111; uint8_t draw_palette[256]; uint8_t mode = DRAWMODE_NORMAL; } int update_mode = UPDATE_ALWAYS; int timeout = 0; uint32_t last_update = 0; float delta_time = 0.0f; bool should_exit = false; bool should_quit = false; SDL_Window *mini_win; SDL_Renderer *mini_ren; SDL_Texture *mini_bak; SDL_Texture *mini_shadertex; Uint32 windowID; Uint32 *pixels; int pitch; uint32_t palette[256] = { 0xFF1a1c2c, 0xFF5d275d, 0xFFb13e53, 0xFFef7d57, 0xFFffcd75, 0xFFa7f070, 0xFF38b764, 0xFF257179, 0xFF29366f, 0xFF3b5dc9, 0xFF41a6f6, 0xFF73eff7, 0xFFf4f4f4, 0xFF94b0c2, 0xFF566c86, 0xFF333c57 }; const bool *keys; Uint8 key_just_pressed = 0; static char text_input_buffer[10]; static bool has_text_input = false; int mouse_x, mouse_y, mouse_wheel; Uint32 mouse_buttons; uint8_t mouse_just_pressed = 0; bool double_click = false; bool mouse_discard = false; SDL_Gamepad *gamepad = NULL; int8_t pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID; #define MAX_SOUNDS 50 JA_Sound_t *sounds[MAX_SOUNDS]; int16_t beats, num_beats = 0; void createNewProject(); void createDisplay(); void destroyDisplay(); void raisewindow() { SDL_RaiseWindow(mini_win); } char* get_value_from_line(char* line) { char* equal_character = strchr(line, '='); if (equal_character == NULL) return NULL; *equal_character = '\0'; return ++equal_character; } void read_ini() { int size; FILE *f = file_getfilepointer("game.ini", size); // fopen("game.ini", "r"); char line[1024]; if (f == NULL) { log_msg(LOG_FAIL, "No s'ha pogut obrir 'game.ini'\n"); exit(-1); } log_msg(LOG_OK, "'game.ini' carregat\n"); while (fgets(line, sizeof(line), f)) { char *value = get_value_from_line(line); if (value != NULL) { value[strlen(value)-1] = '\0'; if (strcmp(line, "title") == 0) { strcpy(window_title, value); log_msg(LOG_VERBOSE, "title = %s\n", window_title); } else if (strcmp(line, "config") == 0) { strcpy(config_folder, value); log_msg(LOG_VERBOSE, "config = %s\n", config_folder); } else if (strcmp(line, "width") == 0) { screen_width = atoi(value); log_msg(LOG_VERBOSE, "screen width = %i\n", screen_width); } else if (strcmp(line, "height") == 0) { screen_height = atoi(value); log_msg(LOG_VERBOSE, "screen height = %i\n", screen_height); } else if (strcmp(line, "zoom") == 0) { screen_zoom = atoi(value); log_msg(LOG_VERBOSE, "screen zoom = %i\n", screen_zoom); } else if (strcmp(line, "fullscreen") == 0) { screen_fullscreen = atoi(value); log_msg(LOG_VERBOSE, "screen sullscreen = %i\n", screen_fullscreen); } //else if (strcmp(line, "files") == 0) { //lua_files = (char*)malloc(strlen(value)); // strcpy(lua_files, value); //} } } fclose(f); //SDL_Log("'game.ini' carregat!\n"); } namespace mini { namespace surf { uint8_t create(int w, int h) { unsigned int i = 0; while (ip, col, dest_surface->size); } namespace target { void recalculate_clip() { if (ds::clip[0]<0) ds::clip[0]=0; if (ds::clip[1]<0) ds::clip[1]=0; if (ds::clip[2]>=dest_surface->w) ds::clip[2]=dest_surface->w-1; if (ds::clip[3]>=dest_surface->h) ds::clip[3]=dest_surface->h-1; } void set(uint8_t surface) { dest_surface = &surfaces[surface]; recalculate_clip(); } uint8_t get() { for (unsigned int i=0; i ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; switch (ds::mode) { case DRAWMODE_NORMAL: pset_fast(x,y,color); break; case DRAWMODE_PATTERN: pset_pattern(x,y,color); break; default: pset_bool(x,y,color); break; } } // Per a les funcions que van canviant de color (surf.pixel i draw.surf, bàsicament) static inline void subst_pset(int x, int y, uint8_t color) { direct_pset(x,y,ds::draw_palette[color]); } void set(int x, int y, uint8_t color) { subst_pset(x,y,color); } uint8_t get(int x, int y) { if (!source_surface) return 0; if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0; return SOURCE(x, y); } } } namespace map { namespace surf { void set(uint8_t surface) { map_surface = &surfaces[surface]; } uint8_t get() { for (unsigned int i=0; iw / tw; // Coordenadas del tile dentro del spritesheet int tx = (n % tiles_per_row) * tw; int ty = (n / tiles_per_row) * th; int src_y = ty; for (int yi = 0; yi < th; ++yi) { int src_x = tx; for (int xi = 0; xi < tw; ++xi) { uint8_t c = mini::surf::pixel::get(src_x, src_y); mini::surf::pixel::subst_pset(x + xi, y + yi, c); src_x++; } src_y++; } } void draw() { if (!map_surface || !source_surface) return; const int tw = tile_width; const int th = tile_height; int celw = map_surface->w; int celh = map_surface->h; int celx = 0; int cely = 0; int ox = ds::origin[0]; int oy = ds::origin[1]; int sx = ox; int sy = oy; // Clipping global rápido if (sx + celw * tw < ds::clip[0] || sy + celh * th < ds::clip[1] || sx > ds::clip[2] || sy > ds::clip[3]) return; // Recorte por izquierda if (sx < ds::clip[0]) { int diff = (ds::clip[0] - sx) / tw; celx += diff; celw -= diff; sx += diff * tw; } // Recorte por arriba if (sy < ds::clip[1]) { int diff = (ds::clip[1] - sy) / th; cely += diff; celh -= diff; sy += diff * th; } // Recorte por derecha int max_x = ds::clip[2] - sx; if (max_x < celw * tw) celw = max_x / tw + 1; // Recorte por abajo int max_y = ds::clip[3] - sy; if (max_y < celh * th) celh = max_y / th + 1; // Ahora sx, sy son relativos al origen y ya están recortados for (int y = 0; y < celh; ++y) { int ty = sy + y * th; for (int x = 0; x < celw; ++x) { uint8_t tile = tile::get(celx + x, cely + y); if (!tile) continue; int tx = sx + x * tw; tileblit(tile, tx - ox, ty - oy); } } } namespace tile { uint8_t get(int celx, int cely) { if (!map_surface) return 0; if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0; return TILES(celx, cely); } void set(int celx, int cely, uint8_t snum) { if (!map_surface) return; if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return; TILES(celx, cely) = snum; } } namespace cell { uint8_t getw() { return tile_width; } uint8_t geth() { return tile_height; } void set(int w, int h) { tile_width = w; tile_height = h; } } } namespace pal { uint32_t *load(const char* filename, uint16_t *palsize) { int size; uint8_t *buffer = (uint8_t*)file_getfilebuffer(filename, size); uint32_t *pal = LoadPalette(buffer, palsize); free(buffer); return pal; } void set(uint32_t *pal) { for (int i=0; i<256; ++i) palette[i] = pal[i] | 0xff000000; } namespace color { void set(uint8_t index, uint32_t color) { palette[index] = color | 0xff000000; } uint32_t get(uint8_t index) { return palette[index]; } } namespace trans { void set(uint8_t index) { ds::trans = index; } uint8_t get() { return ds::trans; } } namespace subpal { uint8_t set(uint8_t index, uint8_t color) { const uint8_t old = ds::draw_palette[SDL_clamp(index,0,255)]; ds::draw_palette[SDL_clamp(index,0,255)] = SDL_clamp(color,0,255); return old; } void reset() { for (int i=0;i<256;++i) ds::draw_palette[i]=i; } } } namespace view { namespace clip { void set(int x, int y, int w, int h) { ds::clip[0] = x; ds::clip[1] = y; ds::clip[2] = w-x-1; ds::clip[3] = h-y-1; surf::target::recalculate_clip(); } void reset() { ds::clip[0] = ds::clip[1] = 0; ds::clip[2] = dest_surface->w-1; ds::clip[3] = dest_surface->h-1; surf::target::recalculate_clip(); } } namespace origin { void set(int x, int y) { ds::origin[0] = x; ds::origin[1] = y; } int getx() { return ds::origin[0]; } int gety() { return ds::origin[1]; } } } namespace draw { // Bresenham Line Algorithm void line(int x0, int y0, int x1, int y1, uint8_t color) { int x, y; int dx, dy; int incx, incy; int balance; color = ds::draw_palette[color]; if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; } if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; } x = x0; y = y0; if (dx >= dy) { dy <<= 1; balance = dy - dx; dx <<= 1; while (x != x1) { surf::pixel::direct_pset(x, y, color); if (balance >= 0) { y += incy; balance -= dx; } balance += dy; x += incx; } surf::pixel::direct_pset(x, y, color); } else { dx <<= 1; balance = dx - dy; dy <<= 1; while (y != y1) { surf::pixel::direct_pset(x, y, color); if (balance >= 0) { x += incx; balance -= dy; } balance += dx; y += incy; } surf::pixel::direct_pset(x, y, color); } } void hline(int x0, int y, int x1, uint8_t color) { color = ds::draw_palette[color]; if (x0>x1) { const int tmp=x0;x0=x1;x1=tmp; } for (int x=x0; x<=x1; ++x) surf::pixel::direct_pset(x, y, color); } void vline(int x, int y0, int y1, uint8_t color) { color = ds::draw_palette[color]; if (y0>y1) { const int tmp=y0;y0=y1;y1=tmp; } for (int y=y0; y<=y1; ++y) surf::pixel::direct_pset(x, y, color); } void rect(int x, int y, int w, int h, uint8_t color) { int x1 = w+x-1; int y1 = h+y-1; hline(x, y, x1, color); hline(x, y1, x1, color); vline(x, y, y1, color); vline(x1, y, y1, color); } void rectf(int x, int y, int w, int h, uint8_t color) { int x1 = w+x-1; int y1 = h+y-1; for (int i=y; i<=y1; ++i) hline(x, i, x1, color); } static inline void circ_scanline(int xc, int yc, int x, int y, uint8_t color) { surf::pixel::direct_pset(xc+x, yc+y, color); surf::pixel::direct_pset(xc-x, yc+y, color); surf::pixel::direct_pset(xc+x, yc-y, color); surf::pixel::direct_pset(xc-x, yc-y, color); surf::pixel::direct_pset(xc+y, yc+x, color); surf::pixel::direct_pset(xc-y, yc+x, color); surf::pixel::direct_pset(xc+y, yc-x, color); surf::pixel::direct_pset(xc-y, yc-x, color); } void circ(int x, int y, uint8_t r, uint8_t color) { color = ds::draw_palette[color]; int xi=0, yi=r; int d=3-2*r; circ_scanline(x, y, xi, yi, color); while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; circ_scanline(x, y, xi, yi, color); } } static inline void circf_scanline(int xc, int yc, int x, int y, uint8_t color) { hline(xc-x, yc+y, xc+x, color); hline(xc-x, yc-y, xc+x, color); hline(xc-y, yc+x, xc+y, color); hline(xc-y, yc-x, xc+y, color); } void circf(int x, int y, uint8_t r, uint8_t color) { int xi=0, yi=r; int d=3-2*r; circf_scanline(x, y, xi, yi, color); while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; circf_scanline(x, y, xi, yi, color); } } void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) { int xi=0, yi=r; int d=3-2*r; int xf = w+x-1; int yf = h+y-1; int x1 = x+r, y1 = y+r; int x2 = xf-r, y2 = yf-r; hline(x1, y, x2, color); hline(x1, yf, x2, color); vline(x, y1, y2, color); vline(xf, y1, y2, color); color = ds::draw_palette[color]; while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; surf::pixel::direct_pset(x2+xi, y2+yi, color); surf::pixel::direct_pset(x1-xi, y2+yi, color); surf::pixel::direct_pset(x2+xi, y1-yi, color); surf::pixel::direct_pset(x1-xi, y1-yi, color); surf::pixel::direct_pset(x2+yi, y2+xi, color); surf::pixel::direct_pset(x1-yi, y2+xi, color); surf::pixel::direct_pset(x2+yi, y1-xi, color); surf::pixel::direct_pset(x1-yi, y1-xi, color); } } void roundrectf(int x, int y, int w, int h, uint8_t r, uint8_t color) { int xi=0, yi=r; int d=3-2*r; int xf = w+x-1; int yf = h+y-1; int x1 = x+r, y1 = y+r; int x2 = xf-r, y2 = yf-r; for (int i=y1; i<=y2; ++i) hline(x, i, xf, color); while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; hline(x1-xi, y2+yi, x2+xi, color); hline(x1-xi, y1-yi, x2+xi, color); hline(x1-yi, y2+xi, x2+yi, color); hline(x1-yi, y1-xi, x2+yi, color); } } void oval_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { surf::pixel::direct_pset((xc+x)*xf, (yc+y)*yf, color); surf::pixel::direct_pset((xc-x)*xf, (yc+y)*yf, color); surf::pixel::direct_pset((xc+x)*xf, (yc-y)*yf, color); surf::pixel::direct_pset((xc-x)*xf, (yc-y)*yf, color); surf::pixel::direct_pset((xc+y)*xf, (yc+x)*yf, color); surf::pixel::direct_pset((xc-y)*xf, (yc+x)*yf, color); surf::pixel::direct_pset((xc+y)*xf, (yc-x)*yf, color); surf::pixel::direct_pset((xc-y)*xf, (yc-x)*yf, color); } void oval(int x0, int y0, int x1, int y1, uint8_t color) { color = ds::draw_palette[color]; int rx = (x1-x0)/2; int ry = (y1-y0)/2; int r = rx; int x = x0 + rx; int y = y0 + ry; float xf = 1.0f, yf = 1.0f; if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} int xi=0, yi=r; int d=3-2*r; oval_scanline(x, y, xi, yi, xf, yf, color); while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; oval_scanline(x, y, xi, yi, xf, yf, color); } } static inline void ovalf_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) { hline((xc-x)*xf, (yc+y)*yf, (xc+x)*xf, color); hline((xc-x)*xf, (yc-y)*yf, (xc+x)*xf, color); hline((xc-y)*xf, (yc+x)*yf, (xc+y)*xf, color); hline((xc-y)*xf, (yc-x)*yf, (xc+y)*xf, color); } void ovalf(int x0, int y0, int x1, int y1, uint8_t color) { int rx = (x1-x0)/2; int ry = (y1-y0)/2; int r = rx; int x = x0 + rx; int y = y0 + ry; float xf = 1.0f, yf = 1.0f; if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);} int xi=0, yi=r; int d=3-2*r; ovalf_scanline(x, y, xi, yi, xf, yf, color); while (yi>=xi++) { d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6; ovalf_scanline(x, y, xi, yi, xf, yf, color); } } namespace pattern { void set(uint16_t pat, bool transparent) { ds::fill_pattern = pat; } } void surf(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, bool invert) { if (dw == 0) dw = sw; if (dh == 0) dh = sh; // 16.16 fixed point int sdx = (sw << 16) / dw; int sdy = (sh << 16) / dh; if (flip_x) sdx = -sdx; if (flip_y) sdy = -sdy; int ssx = flip_x ? ((sx + sw - 1) << 16) : (sx << 16); int ssy = flip_y ? ((sy + sh - 1) << 16) : (sy << 16); int csy = ssy; if (!invert) { for (int y = dy; y < dy + dh; ++y) { int csx = ssx; for (int x = dx; x < dx + dw; ++x) { uint8_t color = surf::pixel::get(csx >> 16, csy >> 16); surf::pixel::subst_pset(x, y, color); csx += sdx; } csy += sdy; } } else { for (int y = dy; y < dy + dh; ++y) { int csx = ssx; for (int x = dx; x < dx + dw; ++x) { uint8_t color = surf::pixel::get(csy >> 16, csx >> 16); surf::pixel::subst_pset(x, y, color); csx += sdx; } csy += sdy; } } } void surfrot(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg) { if (dw == 0) dw = sw; if (dh == 0) dh = sh; // Centro del destino (rectángulo sin rotar) float dcx = dx + dw * 0.5f; float dcy = dy + dh * 0.5f; // Centro del subrectángulo origen float scx = sx + sw * 0.5f; float scy = sy + sh * 0.5f; // Escalado destino -> origen float inv_scale_x = float(sw) / float(dw); float inv_scale_y = float(sh) / float(dh); // Flips integrados en la escala if (flip_x) inv_scale_x = -inv_scale_x; if (flip_y) inv_scale_y = -inv_scale_y; // Ángulo en radianes float a = angle_deg * 3.14159265f / 180.0f; float ca = SDL_cosf(a); float sa = SDL_sinf(a); // --- 1. Bounding box rotado del rectángulo destino --- float hx = dw * 0.5f; float hy = dh * 0.5f; float vx[4] = { -hx, hx, -hx, hx }; float vy[4] = { -hy, -hy, hy, hy }; float min_x = 1e9f, max_x = -1e9f; float min_y = 1e9f, max_y = -1e9f; for (int i = 0; i < 4; ++i) { float rr_x = vx[i] * ca - vy[i] * sa; float rr_y = vx[i] * sa + vy[i] * ca; float dxp = dcx + rr_x; float dyp = dcy + rr_y; if (dxp < min_x) min_x = dxp; if (dxp > max_x) max_x = dxp; if (dyp < min_y) min_y = dyp; if (dyp > max_y) max_y = dyp; } int bb_x0 = (int)SDL_floorf(min_x); int bb_x1 = (int)SDL_ceilf (max_x); int bb_y0 = (int)SDL_floorf(min_y); int bb_y1 = (int)SDL_ceilf (max_y); // --- 2. Rotación inversa + escalado + clipping estricto --- for (int y = bb_y0; y <= bb_y1; ++y) { for (int x = bb_x0; x <= bb_x1; ++x) { // Coordenadas relativas al centro destino float rx = x - dcx; float ry = y - dcy; // Rotación inversa float ux = rx * ca + ry * sa; float uy = -rx * sa + ry * ca; // Escalado destino -> origen (con flips) float sxp = scx + ux * inv_scale_x; float syp = scy + uy * inv_scale_y; // Clipping estricto al subrectángulo origen if (sxp < sx || sxp >= sx + sw || syp < sy || syp >= sy + sh) continue; // no pintamos nada uint8_t color = surf::pixel::get((int)sxp, (int)syp); surf::pixel::subst_pset(x, y, color); } } } const uint8_t printchar(uint8_t c, int x, int y) { char_t &chr = current_font->chars[c]; draw::surf(chr.x, chr.y, chr.w, chr.h, x, y-chr.base); return chr.w; } void text(const char* str, int x, int y, uint8_t color) { const unsigned char* p = (const unsigned char*)str; uint8_t cp; uint8_t xpos = x; uint8_t old_source = surf::source::get(); surf::source::set(current_font->surface); uint8_t old_color = ds::draw_palette[1]; ds::draw_palette[1] = color; uint8_t old_trans = ds::trans; ds::trans = 0; while (p[0]!=0) { if (p[0] < 0x80) { cp = p[0]; p+=1; } else if ((p[0] & 0xE0) == 0xC0) { cp = (p[0] << 6) | (p[1] & 0x3F); p+=2; } xpos += printchar(cp, xpos, y) + current_font->spacing; } ds::trans = old_trans; ds::draw_palette[1] = old_color; surf::source::set(old_source); } namespace mode { void set(uint8_t mode) { ds::mode = mode; } } } namespace shader { void init(const char* vshader, const char* fshader) { int filesize; char *vshaderfile = file_getfilebuffer(vshader, filesize, true); char *fshaderfile = nullptr; if (fshader) { fshaderfile = file_getfilebuffer(fshader, filesize, true); } init(mini_win, mini_shadertex, vshaderfile, fshaderfile); } //void enable() { shader::enable(); } //void disable() { shader::disable(); } } namespace audio { JA_Music_t *current_music = NULL; void init() { JA_Init(48000, SDL_AUDIO_S16, 1); for (int i=0;i 0 && line[len - 1] == '\r') line[len - 1] = '\0'; if (strncmp(line, "bitmap=", 7) != 0) return false; // Parse first line fonts[index].surface = surf::load(line + 7); fonts[index].name = (char*)malloc(strlen(name)+1); strcpy(fonts[index].name, name); } // --- Read character lines --- while (*ptr) { // Extract next line int len = 0; while (ptr[len] && ptr[len] != '\n' && len < 255) len++; memcpy(line, ptr, len); line[len] = '\0'; ptr += (ptr[len] == '\n') ? len + 1 : len; // Advance pointer if (len > 0 && line[len - 1] == '\r') line[len - 1] = '\0'; // Remove comments char* hash = strchr(line, '#'); if (hash) *hash = '\0'; // Parse int code, x, y, w, h, base; if (sscanf(line, "%d: %d %d %d %d %d", &code, &x, &y, &w, &h, &base) == 6) { if (code >= 0 && code < 256) { fonts[index].chars[code] = { (uint8_t)x, (uint8_t)y, (uint8_t)w, (uint8_t)h, (uint8_t)base }; } } } return index; } uint8_t load(const char *filename) { // Si la font ja s'ha carregat, tornem eixa font for (unsigned int i=0; ispacing = spacing; } uint8_t get() { return current_font->spacing; } } } namespace mouse { int posx() { return mouse_x-ds::origin[0]; } int posy() { return mouse_y-ds::origin[1]; } int wheel() { return mouse_wheel; } bool down(uint8_t i) { if (mouse_discard) return false; return mouse_buttons & SDL_BUTTON_MASK(i); } bool press(uint8_t i) { return mouse_just_pressed == i; } bool dblclick() { return double_click; } void discard() { mouse_discard = true; } bool inside(int x, int y, int w, int h) { const int mx = mouse_x-ds::origin[0]; const int my = mouse_y-ds::origin[1]; return (mx>=x) && (my>=y) && (mx dm->w || screen_height*screen_zoom > dm->h) screen_zoom--; mini_win = SDL_CreateWindow(window_title, screen_width*screen_zoom, screen_height*screen_zoom, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:0)); windowID = SDL_GetWindowID(mini_win); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); mini_ren = SDL_CreateRenderer(mini_win, NULL); if (screen_cursor) SDL_ShowCursor(); else SDL_HideCursor(); mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height); SDL_SetTextureScaleMode(mini_bak, SDL_SCALEMODE_NEAREST); SDL_PropertiesID props = SDL_GetTextureProperties(mini_bak); int real_pixelformat = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_FORMAT_NUMBER, -1); if (real_pixelformat != SDL_PIXELFORMAT_ARGB8888) { log_msg(LOG_FAIL, "Pixelformat incorrecte: %i\n", real_pixelformat); exit(1); } mini_shadertex = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, screen_width*screen_zoom, screen_height*screen_zoom); SDL_SetTextureScaleMode(mini_shadertex, SDL_SCALEMODE_NEAREST); mini::shader::init(mini_win, mini_shadertex, nullptr); log_msg(LOG_OK, "Graphics subsystem initialized\n"); } void destroyDisplay() { SDL_DestroyTexture(mini_shadertex); SDL_DestroyTexture(mini_bak); SDL_DestroyRenderer(mini_ren); SDL_DestroyWindow(mini_win); } void reinit() { log_msg(LOG_INFO, "STARTING A SYSTEM REINITIALIZATION\n"); ds::mode = DRAWMODE_NORMAL; ds::origin[0] = ds::origin[1] = 0; ds::clip[0] = ds::clip[1] = 0; ds::clip[2] = screen_width-1; ds::clip[3] = screen_height-1; ds::trans=0; ds::fill_pattern = 0b1111111111111111; for (unsigned int i=0; i1) { if (argv[1][0]=='-' && argv[1][1]=='-') { const char *command = &argv[1][2]; if (strcmp(command, "new")==0) { createNewProject(); exit(0); } else if (strcmp(command, "version")==0) { exit(0); } } else if (strstr(argv[1], ".lua")!=nullptr) { file_setresourcefolder("./"); file_setsource(SOURCE_FOLDER); strcpy(main_lua_file, argv[1]); strcpy(window_title, argv[1]); override_ini = true; } else if (strstr(argv[1], ".jf2")!=nullptr) { file_setresourcefilename(argv[1]); file_setsource(SOURCE_FILE); } else { char path[256] = "./"; strcat(path, argv[1]); file_setresourcefolder(path); } } #ifdef MACOS_BUNDLE char res_file[255] = ""; strcpy(res_file, dirname(argv[0])); strcat(res_file, "/../Resources/data.jrf"); file_setresourcefilename(res_file); #endif while (!should_quit) { should_exit=false; // READ INI if (!override_ini) { read_ini(); file_setconfigfolder(config_folder); const char *zoom = file_getconfigvalue("zoom"); if (zoom) screen_zoom=atoi(zoom); const char *fullscreen = file_getconfigvalue("fullscreen"); if (fullscreen) screen_fullscreen=strcmp(fullscreen, "true")==0?true:false; const char *cursor = file_getconfigvalue("cursor"); if (cursor) screen_cursor=strcmp(cursor, "true")?true:false; const char *music_enabled = file_getconfigvalue("music"); if (music_enabled) JA_EnableMusic(strcmp(music_enabled, "true")==0?true:false); const char *sound_enabled = file_getconfigvalue("sound"); if (sound_enabled) JA_EnableSound(strcmp(sound_enabled, "true")==0?true:false); } SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD); createDisplay(); mini::pad::init(); reinit(); mini::audio::init(); uint8_t font_surf = mini::surf::load(default_font_gif, "default_font"); surfaces[font_surf].flags |= SURF_GENERATED; mini::font::load_from_buffer((const char*)default_font_fnt, 0, "default_font"); current_font = &fonts[0]; mini::lua::init(main_lua_file); mini::lua::callbacks::init(); Uint32 dt=SDL_GetTicks(); key_just_pressed = 0; pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID; mouse_just_pressed = 0; mouse_wheel = 0; double_click = false; has_text_input = false; int fps_counter=0; uint32_t fps_timer=0; while(!should_exit) { if (update_mode==UPDATE_WAIT) SDL_WaitEvent(NULL); else if (update_mode==UPDATE_TIMEOUT) SDL_WaitEventTimeout(NULL, timeout); SDL_Event mini_eve; while(SDL_PollEvent(&mini_eve)) { if (mini_eve.type == SDL_EVENT_QUIT) { should_exit=true; should_quit=true; break; } if (mini_eve.type == SDL_EVENT_TEXT_INPUT) { SDL_strlcpy(text_input_buffer, mini_eve.text.text, sizeof(text_input_buffer)); has_text_input = true; } if (mini_eve.type == SDL_EVENT_KEY_DOWN) { #ifdef DEBUG if (mini_eve.key.scancode == SDL_SCANCODE_F12) { mini::surf::reloadsurfs(); //} else if (mini_eve.key.scancode == SDL_SCANCODE_F11) { // mini::lua::debug::toggle(); } else if (mini_eve.key.scancode == SDL_SCANCODE_F5) { should_exit=true; } else { key_just_pressed = mini_eve.key.scancode; } #else key_just_pressed = mini_eve.key.scancode; #endif } if (mini_eve.type == SDL_EVENT_MOUSE_BUTTON_UP) { if (mouse_discard) mouse_discard = false; else if (mini_eve.button.clicks==2 && mini_eve.button.button==SDL_BUTTON_LEFT) { double_click = true; } else { mouse_just_pressed = mini_eve.button.button; } } if (mini_eve.type == SDL_EVENT_MOUSE_WHEEL) { mouse_wheel = mini_eve.wheel.y; } if (mini_eve.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { pad_just_pressed = mini_eve.gbutton.button; } /*if ( (mini_eve.type == SDL_WINDOWEVENT) && (mini_eve.window.windowID == windowID) && (mini_eve.window.event == SDL_WINDOWEVENT_MOVED) ) { windowpos_x = mini_eve.window.data1-4; windowpos_y = mini_eve.window.data2-36; //SDL_GetWindowPosition(mini_win, &windowpos_x, &windowpos_y); }*/ } keys = SDL_GetKeyboardState(NULL); float real_mouse_x, real_mouse_y; mouse_buttons = SDL_GetMouseState(&real_mouse_x, &real_mouse_y); float mx, my; SDL_RenderCoordinatesFromWindow(mini_ren, real_mouse_x, real_mouse_y, &mx, &my); mouse_x = int(mx/screen_zoom); mouse_y = int(my/screen_zoom); //mouse_x /= screen_zoom; mouse_y /= screen_zoom; if (SDL_GetTicks()-dt>13) { dt = SDL_GetTicks(); if (mini::lua::running()) { delta_time = float(SDL_GetTicks() - last_update)/1000.0f; last_update = SDL_GetTicks(); mini::lua::callbacks::update(); } else { exception_loop(); } if (beats==0)beats=num_beats; if (beats>0)beats--; key_just_pressed = 0; mouse_just_pressed = 0; has_text_input = false; text_input_buffer[0] = '\0'; double_click = false; mouse_wheel = 0; pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID; } SDL_SetRenderTarget(mini_ren, mini_shadertex); SDL_SetRenderDrawColor(mini_ren, 0, 0, 0, 255); SDL_RenderClear(mini_ren); SDL_LockTexture(mini_bak, NULL, (void**)&pixels, &pitch); for (uint32_t i=0;isize;++i) pixels[i] = palette[screen_surface->p[i]]; SDL_UnlockTexture(mini_bak); SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); //NEW mini::shader::render(); //SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); //SDL_RenderPresent(mini_ren); fps_counter++; if (SDL_GetTicks()>=(fps_timer+1000)) { fps = fps_counter; fps_counter=0; fps_timer = SDL_GetTicks(); } } mini::lua::quit(); mini::audio::quit(); //Mix_Quit(); for (unsigned int i=0;i