103 Commits

Author SHA1 Message Date
536987f89b VERSIÓ 1.4.1
- [NEW] Ara require soporta rutes relatives (he tingut que fer un parxe al codi de Lua)
2026-03-12 16:23:48 +01:00
4084cb64f2 VERSIÓ 1.4
- [NEW] jfile_listdir()
- [NEW] ara els moduls es deuen carregar amb 'require "directori.modul" '
- [NEW] Ara es poden carregar directoris sencers amb 'require "directori.*" '
2026-03-12 14:58:39 +01:00
33bbf940ea - [FIX] JA_StopChannel() petava al parar tots els sons. 2026-03-04 10:19:16 +01:00
f12e46db1b - [NEW] sys.debug() returns true if we are on a debug version of mini. false otherwise. 2026-03-04 10:12:53 +01:00
681cbc2207 - [FIX] Updatat el makefile per a incloure opengl (per lo dels shaders, un dia he de tirar-los a la basura) 2026-03-03 13:40:59 +01:00
5db06a0645 - [FIX] sys.subpal() now clamps values for safety 2026-02-25 11:53:15 +01:00
a17a1bb517 - [CHG] surf.target() i surf.source() sense paràmetres ara el que fan es tornar les surfaces actuals de target i de source 2026-02-24 22:18:54 +01:00
fc962b4e18 - [NEW] draw.mode(), amb modes NORMAL, PATTERN, AND, OR, XOR i NOT
- [NEW] Ara per a pintar en pattern hi ha que dir-ho en draw.mode(), no es automatic al ficar un pattern.
- [NEW] Nous modes de pintat booleans. AND, OR i XOR fan l'operació pixel_actual = pixel_actual OP color_especificat. NOT no usa el color especificat, nomes fa un NOT del pixel actual.
2026-02-24 18:53:53 +01:00
9581ce67fd - [NEW] sys.chrono() 2026-02-18 10:53:31 +01:00
7c3b58c5f0 - [WIP] Font Editor 2025-12-10 14:03:11 +01:00
6e15fe7231 - [NEW] mouse.inside(x,y,w,h)
- [WIP] fonted tool
2025-12-09 14:05:12 +01:00
eac20bbbe0 VERSIÓ 1.3.15
- [NEW] mouse.dblclick()
- [FIX] de vegades no pillava be la rodeta del ratolí
- [NEW] sys.dir() torna el contingut del directori primer les carpetes, i tot ordenat alfabèticament
- [WIP] Treballant en ferramentes
2025-12-04 17:46:22 +01:00
7fac42c9fe - [NEW] sys.dir() ara torna un array de entrades amb nom i si es directori 2025-12-04 14:47:25 +01:00
4858d94378 VERSIÓ 1.3.14
- [NEW] draw.pattern() sense paràmetres restableix el patró de relleno
- [FIX] Llevat el std::vector que estava donant pel cul. No, si ja sabia jo...
- [NEW] Gestió del cas en que es supere el nombre màxim de textures (en compte d'explotar, tira un error bonico)
2025-12-04 11:35:34 +01:00
3e524fd32d VERSIÓ 1.3.13
- [NEW]  Executant la versió de debug amb el paràmeter "--new" crea un projecte nou en eixe directori.
- [NEW] Nou sistema de log
- [FIX] Amb el tema de usar std::vector no s'estava inicialitzant la surface de pantalla correctament.
- [FIX] Proteccions per a que no pete quan s'intenta usar funcions que els fa falta una surface de oritge, pero no hi ha ninguna seleccionada.
- [NEW] file_createFolder() (ATENCIÓ: No funcionarà en Windows encara)
2025-12-03 14:05:52 +01:00
ace4a0f9f0 - [NEW] Ara les textures usen un std::vector i ja no hi ha limit. Espere no arrepentir-me
- [WIP] Treballant en les custom fonts
2025-11-27 22:18:46 +01:00
839c1e82eb VERSIÓ 1.3.12
- [FIX] La paleta per defecte era tota transparent
- [NEW] draw.rrect() i draw.rrectf()
2025-11-27 17:18:07 +01:00
33d7cc3b6d VERSIÓ 1.3.11
- [NEW] surf.loadex()
2025-11-27 11:22:52 +01:00
a7cbdea4c5 - [FIX] uncompress() cleanup 2025-11-24 14:30:11 +01:00
3383b415cd - [FIX] Arreglat el guardat de GIFs 2025-11-14 17:31:09 +01:00
02dc0a4953 - Treballant en que els GIFs no donen pel cul 2025-11-13 17:45:30 +01:00
091c2617a4 VERSIÓ 1.3.10
- [NEW] sys.delta()
2025-11-10 09:06:13 +01:00
c7559f0d29 VERSIÓ 1.3.9
- [FIX] el mapa sempre pintava TOTS els tiles, es veren o no. Ara te en compte el oritge i la regió de clipping.
2025-11-05 13:08:56 +01:00
327453b02c VERSIÓ 1.3.8
- [FIX] Al pintar el mapa usava uint8_t i per tant els mapes de mes de 255 tiles en alguna dimensió no funcionaven be
2025-11-05 09:55:38 +01:00
62ac5ae92d VERSIÓ 1.3.7
- [NEW] music.enable() i sound.enable()
2025-10-30 16:27:40 +01:00
4172c6af3d - Ajustat el nombre de versió
- Retocades dos funcions de la llibreria de vscode
2025-10-30 12:35:13 +01:00
7bff57c6fa - [NEW] mouse.discard() 2025-06-20 13:49:59 +02:00
f154e1a36b - [NEW] Ara mouse.pos() torna les coordenades relatives al origen, no a la finestra. 2025-06-20 12:07:30 +02:00
0471bcbdda - [FIX] No guardava be els GIFs sense paleta 2025-06-19 17:48:56 +02:00
76e2925791 - [ONGOING] A meitat de arreglar el bug del guardat de GIFs 2025-06-19 13:56:44 +02:00
34a56fedcf - [FIX] mouse.pos() donava coordenades reals de finestra, en compte de tindre en compte el zoom. 2025-06-19 12:44:51 +02:00
9cd991cb44 - [FIX] draw.text() també soporta que li pases un numero pa escriure-lo 2025-06-18 19:52:24 +02:00
e1d5eb051c VERSIÓ 1.3
- [NEW] shader.init(), shader.enable i shader.disable
- [NEW] Deixe els shaders de Lynx i GBC de exemple.
- [NEW] file_getfilebuffer() ara soporta un tercer paràmetre opcional, per a 'zeroterminar' el buffer per si es un arxiu de text.
2025-06-18 19:29:17 +02:00
79781bbed1 VERSIÓ 1.2.5
- [NEW] Soport bàsic per a shaders.
2025-06-18 13:49:35 +02:00
0cb1296ad3 VERSIÓ 1.2
- [NEW] Convertit a SDL3
2025-06-18 12:47:24 +02:00
16be589a72 - VERSIÓ 1.1
- [NEW] map.surf() per a obtindre i fixar la surface que usa el tilemap
- [NEW] Llevats map.new, map.load i map.save. Es fa des de les surfaces.
2025-06-17 13:53:45 +02:00
2a4195c839 VERSIÓ 1.0.1
- [FIX] view.clip() calculaba mal el ample i el alt de la zona clipada.
- [FIX] view.origin() funcionava al reves.
2025-06-17 11:34:38 +02:00
5e24117266 - [CHG] Renombrat "stb_vorbis.c" a "stb_vorbis.h"
- [NEW] Afegit lagueirtofile
2025-06-16 13:45:54 +02:00
88609465cb - [CHG] Renombrat "gif.c" a "gif.h"
- [FIX] El codi de exemple petava
2025-06-16 13:39:50 +02:00
8f8009e8af - [FIX] Updated 'library.lua' with sys.fps() and sys.clipboard(). 2025-06-04 13:14:59 +02:00
150cb9f4ff VERSIÓ 1.0 RC4
- [NEW] sys.clipboard() per a llegir i escriure al portapapers.
2025-06-04 11:56:51 +02:00
4bda9cbd39 VERSIÓ 1.0 RC3
- [FIX] Funció "view.local()" canviada a "view.tolocal()", per a evitar problemes.
- [FIX] Si una surface no s'ha creat, no hi ha res que alliberar.
- [NEW] Afegit log de creació i destrucció de surfaces.
2025-06-03 13:26:11 +02:00
adcc44ddab - [NEW] Augmentat el màxim de textures a 100.
- [NEW] Camp "name" per a les textures.
- [NEW] Si s'intenta carregar un gif que ja està en memòria, se torna el que està en memòria.
2025-06-02 12:30:58 +02:00
8e855fa2c1 - [FIX] No permetia carregar GIFs de mes de 256 pixels de ample o alt
- [FIX] No tornava be la ruta al arxiu de configuració
- [NEW] Ara guarda en "~/.config/jailgames/loquesiga/"
- [FIX] El mapa de tiles ha de pillar els tiles de la surface source
- [NEW] Actualitzada la llibreria de autocompletar per a vscode
2025-05-31 14:28:20 +02:00
8f98d52385 VERSIÓ 1.0 RC2
- Nova i, espere, definitiva API
2025-05-30 20:16:02 +02:00
b6e5dca277 - [NEW] system.fps() 2025-05-30 17:45:12 +02:00
3d14c33971 - [NEW] Proposta de API inclosa al repositori 2025-05-30 13:53:30 +02:00
61b02fdeef - [FIX] bug en draw.rect i draw.rectFill 2025-02-19 13:44:25 +01:00
7abc8648a1 - [FIX] cls() no pillava el color de la subpaleta
- [FIX] cosa rara al modificar noms de variables
2025-02-19 13:38:19 +01:00
2f0817d20c - [CHG] draw.rect i draw.rectFill ara pillen (x,y,w,h), com les persones normals, no (x1,y1,x2,y2) com el subnormal de pico-8 2025-02-19 13:34:55 +01:00
ecb493f9c8 - [CHG] surface.cls(color) ompli del color especificat tota la surface 2025-02-19 12:45:13 +01:00
9c3baebc1e - [FIX] Les surfaces creades ara s'inicialitzen a tot ceros 2025-02-19 12:01:49 +01:00
173654e0bd - [FIX] map.draw no agafava be el tamany de la surface 2025-02-19 11:26:07 +01:00
ba1daf810d - [FIX] Hi ha que proveïr de una surface amb tiles al tilemap 2025-02-19 11:19:34 +01:00
45d31579d2 - [NEW] tilemap.new(x,y)
- [CHG] tilemap.new i tilemap.load alliberen la surface anterior (si hi havia) del mapa
2025-02-19 10:40:14 +01:00
5306e82897 - Adaptat exemple a la nova API
- [NEW] viewport.resetClipping()
2025-02-19 06:49:56 +01:00
6c9221cd20 - WIP 2025-02-18 14:00:42 +01:00
99a29cf2e0 - Saving progress... 2025-02-18 06:50:37 +01:00
88e406dae0 - Seguim treballant en polir bugs i deixar guapeta la API 2025-02-17 14:01:34 +01:00
29a90f4b46 - Esta tot fet una marranà, en mig de la conversió 2025-02-16 21:48:07 +01:00
40e98737ce - Tota la API canviada. Fent la documentació.
- v1.0 RC1
2025-02-14 14:14:26 +01:00
b56a0c0f71 - [NEW] surfsize(surface) torna el tamany de la surface que se li pasa 2024-11-29 14:33:45 +01:00
e36caf566c - [DEPRECATED] camera()
- [DEPRECATED] view()
- [FIX] la regió de clip ara es calcula sempre ajustada a la surface de destí, siga la que siga encara que es canvie
2024-11-28 17:04:35 +01:00
c07e09cebd - [FIX] Aplicat un fix de JailAudio 2024-11-27 13:33:52 +01:00
802f32f1b8 v0.9.97d
- Ara mini usa Respak2
2024-11-26 16:15:31 +01:00
377f0a238b v0.9.96d
- [NEW] Ara mini ja no requereix SDL_mixer, usa JailAudio
2024-11-26 14:40:49 +01:00
916a24230e - Treballant en el canvi a JailAudio 2024-11-25 14:20:51 +01:00
cddd79f05e - [NEW] res() without arguments returns width and height of window.
- [NEW] camera() without arguments returns 'x' and 'y' of camera.
- [NEW] palcolor() to set or get a color from the palette (replaces setcolor() & getcolor() ).
- [NEW] paltrans() to set or get which color index is transparent (replaces settrans() & gettrans() ).
- [RENAME] sspr() to blit(), spr_r() to blit_r()
- [NEW] mouse() returns both x and y mouse coordinates.
- [DEPRECATED] setcolor(), getcolor(), settrans(), gettrans(), spr(), sspr(), spr_r(), mousex(), mousey(), abs(), ceil(), flr(), sgn(), sin(), cos(), atan2(), sqrt(), max(), mid(), min(), tostr(), ascii(), strlen(), fopen(), fopenres(), fclose(), feof(), fwritei(), fwrited(), fwrites(), fwritew(), fwriteb(), fwriteln(), freadi(), freadd(), freads(), freadw(), freadb()
- [FIX] Now the background on resizable windows  is filled with black instead of garbage.
- [FIX] Compiling on Linux uses POSIX functions.
2024-02-15 13:54:17 +01:00
4b6a9d8188 - [NEW] stopmusic() accepta com a paràmetre els milisegons que tardarà en fadechar out (per defecte 1000ms).
- [NEW] musicpos() per a obtindre o especificar la posició de la música.
2024-02-14 14:11:45 +01:00
9e08a693c7 - [FIX] Ara les coordinades del ratolí son lo que toca respecte al joc, no al tamany real de la finestra 2024-02-13 13:20:07 +01:00
8618e922c8 - [NEW] spr_r per a rotar sprites (retalla cantos)
- [NEW] sspr admet un nou paràmetre "invert", per a invertir la x i la y.
2024-02-07 14:20:12 +01:00
63eaaa857e - Es pot canviar la resolució des del programa abm res(w,h)
- La finestra es resizable
- Es permet arrancar des d'un arxiu .lua passat com a paràmetre.
2023-11-28 19:03:13 +01:00
7569c24d04 Updatat nombre versió 2023-10-09 11:48:14 +02:00
b29c6c873d - La tecla de parar passa a ser F12 (en compte de F1).
- [FIX] Ja no intentem recuperar la posició de la finestra. Ara reapareix centrada.
- [NEW] Si s'intenta ficar un zoom menor de 1, es corregeix a 1.
- [NEW] Si s'intenta ficar un zoom major que el tamany de la pantalla, redueix el zoom fins a un correcte.
2023-10-09 11:45:42 +02:00
1fe151ee1e - La tecla de parar passa a ser F12 (en compte de F1).
- [FIX] Ja no intentem recuperar la posició de la finestra. Ara reapareix centrada.
- [NEW] Si s'intenta ficar un zoom menor de 1, es corregeix a 1.
- [NEW] Si s'intenta ficar un zoom major que el tamany de la pantalla, redueix el zoom fins a un correcte.
2023-10-09 11:29:17 +02:00
0b6e30c01b - [NEW] funció dir() per a obtindre els arxius del directori "data" 2023-09-11 15:06:05 +02:00
663a4af6cb - [NEW] tolocal(x,y) converteix coordenades de pantalla en coordenades de camera 2023-09-11 11:39:14 +02:00
d1f13a0036 - [NEW] Afegit missatge descriptiu si no es troba un require 2023-08-31 23:41:07 +02:00
135db2c5e0 -[FIX] Arreglat el bug que feia petar el Cacaus 2023-08-31 23:31:36 +02:00
d16f0fef07 - Reactivat relleno de patró (fillp)
- [New] bcolor() per a especificar el color de fons del patró, si no es transparent.
- [New] subpal() per a fer intercanvis de color de la paleta
2023-08-04 16:26:57 +02:00
040697fcbd -Secció "files" del game.ini obsoleta. Ara sempre obri "main.lua". Els demes arxius s'inclouen amb "require()" 2023-08-04 14:06:10 +02:00
4fd9a443f2 - require() implementat 2023-08-04 13:52:11 +02:00
88237804f7 - [FIX] Non-turbo mode was buggy 2023-07-28 09:47:11 +02:00
9b99aa23cf MINI v.0.9.64d:
- [NEW] origin(x,y) sets the origin of the coordinate system.
- [FIX] false extern declaration removed.
- MINI_VERSION has its own header file.
2023-07-05 07:58:31 +02:00
dab7a96ec2 Merge branch 'master' of https://gitea.sustancia.synology.me/JailDoctor/mini 2023-07-04 23:12:00 +02:00
584b65041c - [NEW] view(x,y,w,h) Creates a clipped viewport that also translates origin.
-[NEW] view() Resets the viewport to all the window.
2023-07-04 23:03:19 +02:00
0a92e29aa3 -[NEW] Window refreshes at the position it was
-[FIX] Window slightly moved after refresh. Probably only fixed on MY Linux.
2023-07-04 22:53:34 +02:00
58f4845746 - [FIX] clip(x,y,w,h) works as expected.
- [NEW] clip() with no arguments resets clipping region.
- [FIX] cls() respects clipping region (but now it's slower)
- [FIX] pset's and pget now respect clipping region correctly
2023-07-04 19:50:13 +02:00
724592ec67 - Added turbo option, to allow waiting for events and use less CPU 2023-06-23 11:22:12 +02:00
38e209fa76 - [NEW] Function "configfolder()" 2023-02-01 19:15:18 +01:00
f457075c49 - btnp() i padp() consumeixen la tecla polsada si es la que arriba com a paràmetre
- anykey() tambe mira si s'ha pulsat algun botó del pad
- anykey() consumeix qualsevol tecla o botó del pad pulsats.
2023-01-31 19:47:52 +01:00
0e1e74a000 - [NEW] beat() function 2023-01-30 15:51:45 +01:00
c335edee57 - [NEW] mbtnp() added 2023-01-27 19:50:49 +01:00
5e4f0559c4 - [FIX] Crash if map() used without map surface assigned
- [FIX] Crash on restart, system surfaces not finalized properly (Cacaus crash maybe solved?)
2023-01-27 17:15:03 +01:00
3675f887a6 - Fixed problem with SDL constants on linux (outdated SDL version, anyways) 2023-01-21 14:45:06 +01:00
a03053b717 - Minor changes for macos build 2023-01-21 14:08:24 +01:00
3565c02636 - c++11 mode for macos compilation 2023-01-21 14:07:47 +01:00
ff1ca6279d - Icon added to Windows compilation 2023-01-20 19:13:55 +01:00
3ac16958b9 - [FIX] Removed unused variable, minor readjustment of code to avoid errors. 2023-01-19 18:24:01 +01:00
618cc83c8e - Removed stray 'stb_vorbis.c'. 2023-01-18 18:46:29 +01:00
b96e80ab1d - [NEW] Gamepad support (not tested)
- [NEW] pad(), padp(), gamepad constants
2023-01-18 18:43:27 +01:00
e53befb700 - [NEW] configuration file working.
- [NEW] zoom(), fullscreen(), cursor(), getconf(), setconf().
- [CHG] now zoom and fullscreen are controlled by the game, not by mini.
- [FIX] quit() now actually quits.
- [NEW] btnp() without parameters returns key pressed.
- [NEW] zoom, fullscreen and cursor are saved to config automatically.
2023-01-18 17:41:57 +01:00
4c0cf979d3 - [WIP] Config files 2023-01-17 20:04:01 +01:00
35 changed files with 5034 additions and 1598 deletions

2
.gitignore vendored
View File

@@ -4,3 +4,5 @@ mini_debug.exe
mini_debug
.vscode/*
info.plist
*.dll
build/*

View File

@@ -3,25 +3,25 @@ source = *.cpp ./lua/*.c
windows:
@echo off
g++ $(source) -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lmingw32 -lSDL2main -lSDL2 -lSDL2_mixer -mwindows -o "$(executable).exe"
g++ $(source) icon.res -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lmingw32 -lSDL3 -lopengl32 -mwindows -o "$(executable).exe"
strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable).exe"
windows_debug:
@echo off
g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL2main -lSDL2 -lSDL2_mixer -o "$(executable)_debug.exe"
g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL3 -lopengl32 -o "$(executable)_debug.exe"
macos:
clang++ $(source) -Wall -Os -ffunction-sections -fdata-sections -lSDL2 -lSDL2_mixer -o "$(executable)"
clang++ $(source) -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)"
macos_debug:
clang++ $(source) -D DEBUG -g -Wall -Os -ffunction-sections -fdata-sections -lSDL2 -lSDL2_mixer -o "$(executable)_debug"
clang++ $(source) -D DEBUG -g -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)_debug"
macos_bundle:
clang++ $(source) -D MACOS_BUNDLE -Wall -Os -framework SDL2 -framework SDL2_mixer -F /Library/Frameworks -ffunction-sections -fdata-sections -o mini_bundle -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
clang++ $(source) -D MACOS_BUNDLE -Wall -Os -std=c++11 -framework SDL3 -F /Library/Frameworks -ffunction-sections -fdata-sections -o mini_bundle -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
linux:
g++ $(source) -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL2 -lSDL2_mixer -o "$(executable)"
g++ $(source) -D LUA_USE_LINUX -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL3 -lGL -o "$(executable)"
strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable)"
linux_debug:
g++ $(source) -D DEBUG -g -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL2 -lSDL2_mixer -o "$(executable)_debug"
g++ $(source) -D LUA_USE_LINUX -D DEBUG -g -Wall -lSDL3 -lGL -o "$(executable)_debug"

View File

@@ -1,5 +1,5 @@
title=HOLA MINI
width=160
height=120
zoom=3
files=game.lua
title=TESTS
config=minitests
width=400
height=300
zoom=2

View File

@@ -1,12 +0,0 @@
x=0
function _init()
text="HOLA MINI"
end
function _update()
cls(20)
prnt(text,x,60)
x=x+1
if x>160 then x=-strlen(text)*4 end
end

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

BIN
data/gfx/logo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

9
data/ia/other.lua Normal file
View File

@@ -0,0 +1,9 @@
require "ia.test"
other = {
peiv = function()
pal.color(1, 1, 1, 1)
test2()
return "HOLA OTHER UNIT"
end
}

3
data/ia/test.lua Normal file
View File

@@ -0,0 +1,3 @@
function test2()
draw.text("THIS WORKS!",1,140,4)
end

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

45
data/main.lua Normal file
View File

@@ -0,0 +1,45 @@
require "ia.other"
x=0
function mini.init()
s = surf.load("gfx/logo.gif")
surf.source(s)
p = pal.load("gfx/logo.gif")
pal.set(p)
pal.trans(255)
--surf.save(s, "prova.gif", p)
print("=== PACKAGES LOADED ===")
for name, value in pairs(package.loaded) do
print(name, value)
end
print("========================")
end
function mini.update()
surf.cls(0)
draw.surf(0, 0, 160, 144, 0, 0)
draw.text("PRESS START", 60, 110, 28)
if key.press(key.ESCAPE) then sys.quit() end
draw.text(sys.fps(), 1, 1, 28)
if key.press(key.N1) then
shader.init("lynx.glsl")
shader.enable()
end
if key.press(key.N2) then
shader.init("gbc.glsl")
shader.enable()
end
if key.press(key.N3) then
shader.disable()
end
local mx, my = mouse.pos()
draw.rectf(mx, my, 4, 4, 8)
draw.text(mx .. " " .. my, 1, 8, 8)
draw.text(other.peiv(),1,100,4)
end

BIN
data/tiles01.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

478
gif.c
View File

@@ -1,478 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define EXTENSION_INTRODUCER 0x21
#define IMAGE_DESCRIPTOR 0x2C
#define TRAILER 0x3B
#define GRAPHIC_CONTROL 0xF9
#define APPLICATION_EXTENSION 0xFF
#define COMMENT_EXTENSION 0xFE
#define PLAINTEXT_EXTENSION 0x01
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
typedef struct
{
unsigned short width;
unsigned short height;
unsigned char fields;
unsigned char background_color_index;
unsigned char pixel_aspect_ratio;
}
screen_descriptor_t;
typedef struct
{
unsigned char r;
unsigned char g;
unsigned char b;
}
rgb;
typedef struct
{
unsigned short image_left_position;
unsigned short image_top_position;
unsigned short image_width;
unsigned short image_height;
unsigned char fields;
}
image_descriptor_t;
typedef struct
{
unsigned char byte;
int prev;
int len;
}
dictionary_entry_t;
typedef struct
{
unsigned char extension_code;
unsigned char block_size;
}
extension_t;
typedef struct
{
unsigned char fields;
unsigned short delay_time;
unsigned char transparent_color_index;
}
graphic_control_extension_t;
typedef struct
{
unsigned char application_id[ 8 ];
unsigned char version[ 3 ];
}
application_extension_t;
typedef struct
{
unsigned short left;
unsigned short top;
unsigned short width;
unsigned short height;
unsigned char cell_width;
unsigned char cell_height;
unsigned char foreground_color;
unsigned char background_color;
}
plaintext_extension_t;
//static unsigned short width = 0;
//static unsigned short height = 0;
//static unsigned char* uncompressed_data = NULL;
void uncompress( int code_length,
const unsigned char *input,
int input_length,
unsigned char *out )
{
//int maxbits;
int i, bit;
int code, prev = -1;
dictionary_entry_t *dictionary;
int dictionary_ind;
unsigned int mask = 0x01;
int reset_code_length;
int clear_code; // This varies depending on code_length
int stop_code; // one more than clear code
int match_len;
clear_code = 1 << ( code_length );
stop_code = clear_code + 1;
// To handle clear codes
reset_code_length = code_length;
// Create a dictionary large enough to hold "code_length" entries.
// Once the dictionary overflows, code_length increases
dictionary = ( dictionary_entry_t * )
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
// Initialize the first 2^code_len entries of the dictionary with their
// indices. The rest of the entries will be built up dynamically.
// Technically, it shouldn't be necessary to initialize the
// dictionary. The spec says that the encoder "should output a
// clear code as the first code in the image data stream". It doesn't
// say must, though...
for ( dictionary_ind = 0;
dictionary_ind < ( 1 << code_length );
dictionary_ind++ )
{
dictionary[ dictionary_ind ].byte = dictionary_ind;
// XXX this only works because prev is a 32-bit int (> 12 bits)
dictionary[ dictionary_ind ].prev = -1;
dictionary[ dictionary_ind ].len = 1;
}
// 2^code_len + 1 is the special "end" code; don't give it an entry here
dictionary_ind++;
dictionary_ind++;
// TODO verify that the very last byte is clear_code + 1
while ( input_length )
{
code = 0x0;
// Always read one more bit than the code length
for ( i = 0; i < ( code_length + 1 ); i++ )
{
// This is different than in the file read example; that
// was a call to "next_bit"
bit = ( *input & mask ) ? 1 : 0;
mask <<= 1;
if ( mask == 0x100 )
{
mask = 0x01;
input++;
input_length--;
}
code = code | ( bit << i );
}
if ( code == clear_code )
{
code_length = reset_code_length;
dictionary = ( dictionary_entry_t * ) realloc( dictionary,
sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
for ( dictionary_ind = 0;
dictionary_ind < ( 1 << code_length );
dictionary_ind++ )
{
dictionary[ dictionary_ind ].byte = dictionary_ind;
// XXX this only works because prev is a 32-bit int (> 12 bits)
dictionary[ dictionary_ind ].prev = -1;
dictionary[ dictionary_ind ].len = 1;
}
dictionary_ind++;
dictionary_ind++;
prev = -1;
continue;
}
else if ( code == stop_code )
{
/*if ( input_length > 1 )
{
fprintf( stderr, "Malformed GIF (early stop code)\n" );
exit( 0 );
}*/
break;
}
// Update the dictionary with this character plus the _entry_
// (character or string) that came before it
if ( ( prev > -1 ) && ( code_length < 12 ) )
{
if ( code > dictionary_ind )
{
fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n",
code, dictionary_ind );
exit( 0 );
}
// Special handling for KwKwK
if ( code == dictionary_ind )
{
int ptr = prev;
while ( dictionary[ ptr ].prev != -1 )
{
ptr = dictionary[ ptr ].prev;
}
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
}
else
{
int ptr = code;
while ( dictionary[ ptr ].prev != -1 )
{
ptr = dictionary[ ptr ].prev;
}
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
}
dictionary[ dictionary_ind ].prev = prev;
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
dictionary_ind++;
// GIF89a mandates that this stops at 12 bits
if ( ( dictionary_ind == ( 1 << ( code_length + 1 ) ) ) &&
( code_length < 11 ) )
{
code_length++;
dictionary = ( dictionary_entry_t * ) realloc( dictionary,
sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
}
}
prev = code;
// Now copy the dictionary entry backwards into "out"
match_len = dictionary[ code ].len;
while ( code != -1 )
{
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
if ( dictionary[ code ].prev == code )
{
fprintf( stderr, "Internal error; self-reference." );
exit( 0 );
}
code = dictionary[ code ].prev;
}
out += match_len;
}
}
static int read_sub_blocks( unsigned char* buffer, unsigned char **data )
{
int data_length;
int index;
unsigned char block_size;
// Everything following are data sub-blocks, until a 0-sized block is
// encountered.
data_length = 0;
*data = NULL;
index = 0;
while ( 1 )
{
READ(&block_size, 1);
if ( block_size == 0 ) // end of sub-blocks
{
break;
}
data_length += block_size;
*data = (unsigned char*)realloc( *data, data_length );
// TODO this could be split across block size boundaries
READ(*data + index, block_size);
index += block_size;
}
return data_length;
}
unsigned char* process_image_descriptor( unsigned char* buffer,
rgb *gct,
int gct_size,
int resolution_bits )
{
image_descriptor_t image_descriptor;
int compressed_data_length;
unsigned char *compressed_data = NULL;
unsigned char lzw_code_size;
int uncompressed_data_length = 0;
unsigned char *uncompressed_data = NULL;
// TODO there could actually be lots of these
READ(&image_descriptor, 9);
// TODO if LCT = true, read the LCT
READ(&lzw_code_size, 1);
compressed_data_length = read_sub_blocks( buffer, &compressed_data );
// width = image_descriptor.image_width;
// height = image_descriptor.image_height;
uncompressed_data_length = image_descriptor.image_width *
image_descriptor.image_height;
uncompressed_data = (unsigned char*)malloc( uncompressed_data_length );
uncompress( lzw_code_size, compressed_data, compressed_data_length,
uncompressed_data );
if ( compressed_data ) free( compressed_data );
//if ( uncompressed_data )
// free( uncompressed_data );
return uncompressed_data;
}
/**
* @param gif_file the file descriptor of a file containing a
* GIF-encoded file. This should point to the first byte in
* the file when invoked.
*/
#define rb (*(buffer++))
uint32_t* LoadPalette(unsigned char *buffer) {
unsigned char header[7];
screen_descriptor_t screen_descriptor;
//int color_resolution_bits;
int global_color_table_size = 0; // number of entries in global_color_table
uint32_t *global_color_table = NULL;
READ(header, 6);
READ(&screen_descriptor, 7);
//color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
global_color_table = (uint32_t *)calloc(1, 1024);
if (screen_descriptor.fields & 0x80) {
global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
//global_color_table = (rgb *)malloc(3 * global_color_table_size);
//READ(global_color_table, 3 * global_color_table_size);
for (int i=0; i<global_color_table_size;++i) {
global_color_table[i] = (buffer[0]<<16) + (buffer[1]<<8) + buffer[2];
buffer+=3;
}
}
return global_color_table;
}
static unsigned char* process_gif_stream(unsigned char *buffer, unsigned short* w, unsigned short* h)
{
unsigned char header[ 7 ];
screen_descriptor_t screen_descriptor;
int color_resolution_bits;
int global_color_table_size =0; // number of entries in global_color_table
rgb *global_color_table = NULL;
unsigned char block_type = 0x0;
// A GIF file starts with a Header (section 17)
READ(header, 6);
header[ 6 ] = 0x0;
// XXX there's another format, GIF87a, that you may still find
// floating around.
/*if ( strcmp( "GIF89a", (char*)header ) )
{
fprintf( stderr,
"Invalid GIF file (header is '%s', should be 'GIF89a')\n",
header );
return NULL;
}*/
// Followed by a logical screen descriptor
// Note that this works because GIFs specify little-endian order; on a
// big-endian machine, the height & width would need to be reversed.
// Can't use sizeof here since GCC does byte alignment;
// sizeof( screen_descriptor_t ) = 8!
READ(&screen_descriptor, 7);
*w = screen_descriptor.width;
*h = screen_descriptor.height;
color_resolution_bits = ( ( screen_descriptor.fields & 0x70 ) >> 4 ) + 1;
if ( screen_descriptor.fields & 0x80 )
{
//int i;
// If bit 7 is set, the next block is a global color table; read it
global_color_table_size = 1 <<
( ( ( screen_descriptor.fields & 0x07 ) + 1 ) );
global_color_table = ( rgb * ) malloc( 3 * global_color_table_size );
// XXX this could conceivably return a short count...
READ(global_color_table, 3 * global_color_table_size);
}
while ( block_type != TRAILER )
{
READ(&block_type, 1);
unsigned char size;
switch ( block_type )
{
case IMAGE_DESCRIPTOR:
return process_image_descriptor(buffer,
global_color_table,
global_color_table_size,
color_resolution_bits);
break;
case EXTENSION_INTRODUCER:
buffer++;
size = *(buffer++);
buffer += size;
do {
size = *(buffer++);
buffer += size;
} while (size != 0);
/*if ( !process_extension( buffer ) )
{
return NULL;
}*/
break;
case TRAILER:
break;
default:
fprintf( stderr, "Bailing on unrecognized block type %.02x\n",
block_type );
return NULL;
}
}
return NULL;
}
unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
return process_gif_stream(buffer, w, h);
}
/*int main( int argc, char *argv[] )
{
FILE* gif_file;
if ( argc < 2 )
{
fprintf( stderr, "Usage: %s <path-to-gif-file>\n", argv[ 0 ] );
exit( 0 );
}
gif_file = fopen( argv[ 1 ], "rb" );
if ( gif_file == NULL )
{
fprintf( stderr, "Unable to open file '%s'", argv[ 1 ] );
perror( ": " );
}
process_gif_stream( gif_file );
fclose( gif_file );
}*/

227
gif.h Normal file
View File

@@ -0,0 +1,227 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
struct rgb { uint8_t r, g, b; };
struct image_descriptor_t
{
uint16_t left, top, width, height;
uint8_t fields;
};
struct dictionary_entry_t
{
unsigned char byte;
int prev, len;
};
void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out )
{
dictionary_entry_t *dictionary;
int dictionary_ind;
const int clear_code = 1 << ( code_length );
const int stop_code = clear_code + 1;
const int reset_code_length = code_length;
dictionary = ( dictionary_entry_t * )
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
{
dictionary[ dictionary_ind ].byte = dictionary_ind;
dictionary[ dictionary_ind ].prev = -1;
dictionary[ dictionary_ind ].len = 1;
}
dictionary_ind+=2;
int prev = -1;
uint32_t mask = 0x01;
while ( input_length )
{
int code = 0x0;
for (int i=0; i<(code_length + 1); i++)
{
const int bit = ( *input & mask ) ? 1 : 0;
mask <<= 1;
if ( mask == 0x100 )
{
mask = 0x01;
input++;
input_length--;
}
code = code | ( bit << i );
}
if ( code == clear_code )
{
code_length = reset_code_length;
dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
{
dictionary[ dictionary_ind ].byte = dictionary_ind;
dictionary[ dictionary_ind ].prev = -1;
dictionary[ dictionary_ind ].len = 1;
}
dictionary_ind+=2;
prev = -1;
continue;
}
else if ( code == stop_code ) break;
if ( (prev > -1) && (code_length < 12) )
{
if (code > dictionary_ind)
{
fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind );
exit( 0 );
}
int ptr = (code == dictionary_ind) ? prev : code;
while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
dictionary[ dictionary_ind ].prev = prev;
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
dictionary_ind++;
if ( (dictionary_ind == (1 << (code_length + 1))) && (code_length < 11) )
{
code_length++;
dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
}
}
prev = code;
const int match_len = dictionary[ code ].len;
while ( code != -1 )
{
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
if ( dictionary[ code ].prev == code )
{
fprintf( stderr, "Internal error; self-reference." );
exit( 0 );
}
code = dictionary[ code ].prev;
}
out += match_len;
}
}
static int read_sub_blocks( uint8_t* buffer, uint8_t **data )
{
int data_length = 0;
*data = NULL;
int index = 0;
while (1) {
uint8_t block_size = *(buffer++);
if ( block_size == 0 ) break;
data_length += block_size;
*data = (uint8_t*)realloc( *data, data_length );
READ(*data + index, block_size);
index += block_size;
}
return data_length;
}
uint8_t* process_image_descriptor( uint8_t* buffer, rgb *gct, int gct_size, int resolution_bits )
{
image_descriptor_t image_descriptor;
READ(&image_descriptor, 9);
uint8_t lzw_code_size;
READ(&lzw_code_size, 1);
uint8_t *compressed_data = NULL;
const int compressed_data_length = read_sub_blocks( buffer, &compressed_data );
const int uncompressed_data_length = image_descriptor.width * image_descriptor.height;
uint8_t *uncompressed_data = (uint8_t*)malloc( uncompressed_data_length );
uncompress( lzw_code_size, compressed_data, compressed_data_length, uncompressed_data );
if ( compressed_data ) free( compressed_data );
return uncompressed_data;
}
uint32_t* LoadPalette(uint8_t *buffer, uint16_t *size = NULL )
{
buffer += 10;
const uint8_t fields = *buffer;
uint32_t *global_color_table = (uint32_t *)calloc(1, 1024);;
if (size) *size = 0;
if (fields & 0x80) {
int global_color_table_size = 1 << (((fields & 0x07) + 1));
if (size) *size = global_color_table_size;
for (int i=0; i<global_color_table_size;++i) {
buffer+=3;
global_color_table[i] = (buffer[0]<<16) + (buffer[1]<<8) + buffer[2];
}
}
return global_color_table;
}
static uint8_t* LoadGif(uint8_t *buffer, uint16_t* w, uint16_t* h)
{
int global_color_table_size = 0; // number of entries in global_color_table
rgb *global_color_table = NULL;
buffer += 6; // Ignore header
*w = *((uint16_t*)buffer); buffer+=2;
*h = *((uint16_t*)buffer); buffer+=2;
const uint8_t fields = *buffer; buffer+=3;
const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1;
if ( fields & 0x80 )
{
global_color_table_size = 1 << ( ( ( fields & 0x07 ) + 1 ) );
global_color_table = (rgb*)malloc( 3 * global_color_table_size );
READ(global_color_table, 3 * global_color_table_size);
}
uint8_t block_type = 0x0;
while ( block_type != 0x3B )
{
READ(&block_type, 1);
uint8_t size;
switch ( block_type )
{
case 0x2C:
return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits);
case 0x21:
buffer++; //size = *(buffer++); buffer += size;
do { size = *(buffer++); buffer += size; } while (size != 0);
break;
case 0x3B:
break;
default:
fprintf( stderr, "Bailing on unrecognized block type %.02x\n", block_type );
return NULL;
}
}
return NULL;
}
/*unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
return process_gif_stream(buffer, w, h);
}*/

174
gifenc.h Normal file
View File

@@ -0,0 +1,174 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define MAX_DICT_SIZE 4096
namespace gif
{
typedef struct {
int prefix;
uint8_t character;
} DictEntry;
typedef struct {
uint8_t *data;
size_t size;
size_t capacity;
int bit_pos;
uint32_t bit_buffer;
} BitStream;
void bitstream_init(BitStream *bs) {
bs->capacity = 256;
bs->size = 0;
bs->data = (uint8_t*)malloc(bs->capacity);
bs->bit_pos = 0;
bs->bit_buffer = 0;
}
void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
bs->bit_pos += code_size;
while (bs->bit_pos >= 8) {
if (bs->size >= bs->capacity) {
bs->capacity *= 2;
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
}
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
bs->bit_buffer >>= 8;
bs->bit_pos -= 8;
}
}
void bitstream_flush(BitStream *bs) {
if (bs->bit_pos > 0) {
if (bs->size >= bs->capacity) {
bs->capacity *= 2;
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
}
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
}
}
uint8_t *lzw_compress(uint8_t *input, int width, int height, int min_code_size, size_t *out_size) {
int clear_code = 1 << min_code_size;
int end_code = clear_code + 1;
int next_code = end_code + 1;
int code_size = min_code_size + 1;
DictEntry dict[MAX_DICT_SIZE];
int dict_len = next_code;
BitStream bs;
bitstream_init(&bs);
bitstream_write(&bs, clear_code, code_size);
int prefix = input[0];
for (int i = 1; i < width * height; i++) {
uint8_t c = input[i];
// Search for prefix + c in dictionary
int found = -1;
for (int j = end_code + 1; j < dict_len; j++) {
if (dict[j].prefix == prefix && dict[j].character == c) {
found = j;
break;
}
}
if (found != -1) {
prefix = found; // Extend prefix
} else {
bitstream_write(&bs, prefix, code_size); // Emit current prefix
if (dict_len < MAX_DICT_SIZE) {
if (dict_len == (1 << code_size) && code_size < 12) code_size++;
dict[dict_len].prefix = prefix;
dict[dict_len].character = c;
dict_len++;
} else {
bitstream_write(&bs, clear_code, code_size);
dict_len = end_code + 1;
code_size = min_code_size + 1;
}
prefix = c; // Start new prefix
}
}
// Emit final prefix and end code
bitstream_write(&bs, prefix, code_size);
bitstream_write(&bs, end_code, code_size);
bitstream_flush(&bs);
*out_size = bs.size;
return bs.data;
}
void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
FILE *f = fopen(filename, "wb");
if (!f) {
perror("Failed to open file");
return;
}
// Header
fwrite("GIF89a", 1, 6, f);
// Determine min_code_size from palette_size
int palette_depth = 0;
while ((1 << palette_depth) < palette_size) palette_depth++;
const int min_code_size = palette_depth < 2 ? 2 : palette_depth; // GIF spec requires at least 2
printf("min_code_size: %i\n", palette_depth);
// Logical Screen Descriptor
uint8_t packed_field = palette ? (0x80 | ((palette_depth - 1) << 4) | (palette_depth - 1)) : 0x00;
uint8_t screen_desc[] = {
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
packed_field, // GCT flag + color resolution + size
0x00, // Background color index
0x00 // Pixel aspect ratio
};
fwrite(screen_desc, 1, sizeof(screen_desc), f);
// Global Color Table (if provided)
if (palette) {
int gct_size = 1 << palette_depth;
fwrite(palette, 1, gct_size * 3, f);
}
// Image Descriptor
uint8_t image_desc[] = {
0x2C, 0, 0, 0, 0,
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
0x00 // No local color table
};
fwrite(image_desc, 1, sizeof(image_desc), f);
// LZW-compressed image data
fwrite(&min_code_size, 1, 1, f);
size_t compressed_size;
uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
// Write as sub-blocks
size_t offset = 0;
while (offset < compressed_size) {
uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
fwrite(&block_size, 1, 1, f);
fwrite(compressed + offset, 1, block_size, f);
offset += block_size;
}
fputc(0x00, f); // Block terminator
// Trailer
fputc(0x3B, f);
free(compressed);
fclose(f);
}
}

BIN
icon.res Normal file

Binary file not shown.

507
jail_audio.cpp Normal file
View File

@@ -0,0 +1,507 @@
#ifndef JA_USESDLMIXER
#include "jail_audio.h"
#include "stb_vorbis.h"
#include <SDL3/SDL.h>
#include <stdio.h>
#include "log.h"
#define JA_MAX_SIMULTANEOUS_CHANNELS 5
struct JA_Sound_t
{
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
Uint32 length { 0 };
Uint8 *buffer { NULL };
};
struct JA_Channel_t
{
JA_Sound_t *sound { nullptr };
int pos { 0 };
int times { 0 };
SDL_AudioStream *stream { nullptr };
JA_Channel_state state { JA_CHANNEL_FREE };
};
struct JA_Music_t
{
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
Uint32 length { 0 };
Uint8 *buffer { nullptr };
int pos { 0 };
int times { 0 };
SDL_AudioStream *stream { nullptr };
JA_Music_state state { JA_MUSIC_INVALID };
};
JA_Music_t *current_music { nullptr };
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 };
float JA_musicVolume { 1.0f };
float JA_soundVolume { 0.5f };
bool JA_musicEnabled { true };
bool JA_soundEnabled { true };
SDL_AudioDeviceID sdlAudioDevice { 0 };
SDL_TimerID JA_timerID { 0 };
bool fading = false;
int fade_start_time;
int fade_duration;
int fade_initial_volume;
/*
void audioCallback(void * userdata, uint8_t * stream, int len) {
SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
const int size = SDL_min(len, current_music->samples*2-current_music->pos);
SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, JA_musicVolume);
current_music->pos += size/2;
if (size < len) {
if (current_music->times != 0) {
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, JA_musicVolume);
current_music->pos = (len-size)/2;
if (current_music->times > 0) current_music->times--;
} else {
current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED;
}
}
}
// Mixar els channels mi amol
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].state == JA_CHANNEL_PLAYING) {
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
channels[i].pos += size;
if (size < len) {
if (channels[i].times != 0) {
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
channels[i].pos = len-size;
if (channels[i].times > 0) channels[i].times--;
} else {
JA_StopChannel(i);
}
}
}
}
}
*/
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
{
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING)
{
if (fading) {
int time = SDL_GetTicks();
if (time > (fade_start_time+fade_duration)) {
fading = false;
JA_StopMusic();
return 30;
} else {
const int time_passed = time - fade_start_time;
const float percent = (float)time_passed / (float)fade_duration;
SDL_SetAudioStreamGain(current_music->stream, 1.0 - percent);
}
}
if (current_music->times != 0)
{
if (SDL_GetAudioStreamAvailable(current_music->stream) < int(current_music->length/2)) {
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
}
if (current_music->times>0) current_music->times--;
}
else
{
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic();
}
}
if (JA_soundEnabled)
{
for (int i=0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
if (channels[i].state == JA_CHANNEL_PLAYING)
{
if (channels[i].times != 0)
{
if (SDL_GetAudioStreamAvailable(channels[i].stream) < int(channels[i].sound->length/2))
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
if (channels[i].times>0) channels[i].times--;
}
}
else
{
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i);
}
}
return 30;
}
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{
#ifdef DEBUG
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
JA_audioSpec = {format, channels, freq };
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
if (!sdlAudioDevice) {
log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError());
} else {
log_msg(LOG_OK, "Audio subsytem initialized\n");
}
//SDL_PauseAudioDevice(sdlAudioDevice);
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
}
void JA_Quit()
{
if (JA_timerID) SDL_RemoveTimer(JA_timerID);
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0;
}
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
{
JA_Music_t *music = new JA_Music_t();
int chan, samplerate;
short *output;
music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
music->spec.channels = chan;
music->spec.freq = samplerate;
music->spec.format = SDL_AUDIO_S16;
music->buffer = (Uint8*)SDL_malloc(music->length);
SDL_memcpy(music->buffer, output, music->length);
free(output);
music->pos = 0;
music->state = JA_MUSIC_STOPPED;
return music;
}
JA_Music_t *JA_LoadMusic(const char* filename)
{
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f)!=1) return NULL;
fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
free(buffer);
return music;
}
void JA_PlayMusic(JA_Music_t *music, const int loop)
{
if (!JA_musicEnabled) return;
JA_StopMusic();
current_music = music;
current_music->pos = 0;
current_music->state = JA_MUSIC_PLAYING;
current_music->times = loop;
current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec);
if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n");
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
//SDL_ResumeAudioStreamDevice(current_music->stream);
}
void JA_PauseMusic()
{
if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PAUSED;
//SDL_PauseAudioStreamDevice(current_music->stream);
SDL_UnbindAudioStream(current_music->stream);
}
void JA_ResumeMusic()
{
if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PLAYING;
//SDL_ResumeAudioStreamDevice(current_music->stream);
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
}
void JA_StopMusic()
{
if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED;
//SDL_PauseAudioStreamDevice(current_music->stream);
SDL_DestroyAudioStream(current_music->stream);
current_music->stream = nullptr;
}
void JA_FadeOutMusic(const int milliseconds)
{
if (!JA_musicEnabled) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
fading = true;
fade_start_time = SDL_GetTicks();
fade_duration = milliseconds;
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState()
{
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (!current_music) return JA_MUSIC_INVALID;
return current_music->state;
}
void JA_DeleteMusic(JA_Music_t *music)
{
if (current_music == music) current_music = nullptr;
SDL_free(music->buffer);
if (music->stream) SDL_DestroyAudioStream(music->stream);
delete music;
}
float JA_SetMusicVolume(float volume)
{
JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f );
if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
return JA_musicVolume;
}
void JA_SetMusicPosition(float value)
{
if (!current_music) return;
current_music->pos = value * current_music->spec.freq;
}
float JA_GetMusicPosition()
{
if (!current_music) return 0;
return float(current_music->pos)/float(current_music->spec.freq);
}
void JA_EnableMusic(const bool value)
{
if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic();
JA_musicEnabled = value;
}
const bool JA_IsMusicEnabled()
{
return JA_musicEnabled;
}
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length)
{
JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer;
sound->length = length;
return sound;
}
JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size)
{
JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length);
return sound;
}
JA_Sound_t *JA_LoadSound(const char* filename)
{
JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
return sound;
}
int JA_PlaySound(JA_Sound_t *sound, const int loop)
{
if (!JA_soundEnabled) return -1;
int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
JA_StopChannel(channel);
channels[channel].sound = sound;
channels[channel].times = loop;
channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
return channel;
}
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
{
if (!JA_soundEnabled) return -1;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1;
JA_StopChannel(channel);
channels[channel].sound = sound;
channels[channel].times = loop;
channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
return channel;
}
void JA_DeleteSound(JA_Sound_t *sound)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].sound == sound) JA_StopChannel(i);
}
SDL_free(sound->buffer);
delete sound;
}
void JA_PauseChannel(const int channel)
{
if (!JA_soundEnabled) return;
if (channel == -1)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PLAYING)
{
channels[i].state = JA_CHANNEL_PAUSED;
//SDL_PauseAudioStreamDevice(channels[i].stream);
SDL_UnbindAudioStream(channels[i].stream);
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
{
channels[channel].state = JA_CHANNEL_PAUSED;
//SDL_PauseAudioStreamDevice(channels[channel].stream);
SDL_UnbindAudioStream(channels[channel].stream);
}
}
}
void JA_ResumeChannel(const int channel)
{
if (!JA_soundEnabled) return;
if (channel == -1)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PAUSED)
{
channels[i].state = JA_CHANNEL_PLAYING;
//SDL_ResumeAudioStreamDevice(channels[i].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
{
channels[channel].state = JA_CHANNEL_PLAYING;
//SDL_ResumeAudioStreamDevice(channels[channel].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
}
}
}
void JA_StopChannel(const int channel)
{
if (!JA_soundEnabled) return;
if (channel == -1)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[i].stream);
channels[i].stream = nullptr;
channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0;
channels[i].sound = NULL;
}
}
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[channel].stream);
channels[channel].stream = nullptr;
channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0;
channels[channel].sound = NULL;
}
}
JA_Channel_state JA_GetChannelState(const int channel)
{
if (!JA_soundEnabled) return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return channels[channel].state;
}
float JA_SetSoundVolume(float volume)
{
JA_soundVolume = SDL_clamp( volume, 0.0f, 1.0f );
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if ( (channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED) )
SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume);
return JA_soundVolume;
}
void JA_EnableSound(const bool value)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
}
JA_soundEnabled = value;
}
const bool JA_IsSoundEnabled()
{
return JA_soundEnabled;
}
float JA_SetVolume(float volume)
{
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
return JA_musicVolume;
}
#endif

42
jail_audio.h Normal file
View File

@@ -0,0 +1,42 @@
#pragma once
#include <SDL3/SDL.h>
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
struct JA_Sound_t;
struct JA_Music_t;
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit();
JA_Music_t *JA_LoadMusic(const char* filename);
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length);
void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
void JA_PauseMusic();
void JA_ResumeMusic();
void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music);
float JA_SetMusicVolume(float volume);
void JA_SetMusicPosition(float value);
float JA_GetMusicPosition();
void JA_EnableMusic(const bool value);
const bool JA_IsMusicEnabled();
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char* filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
void JA_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel);
void JA_StopChannel(const int channel);
JA_Channel_state JA_GetChannelState(const int channel);
void JA_DeleteSound(JA_Sound_t *sound);
float JA_SetSoundVolume(float volume);
void JA_EnableSound(const bool value);
const bool JA_IsSoundEnabled();
float JA_SetVolume(float volume);

336
jfile.cpp
View File

@@ -3,39 +3,44 @@
#include <stdio.h>
#include <stdint.h>
#include "jfile.h"
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#define DEFAULT_FILENAME "data.jrf"
#include <algorithm>
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
#ifndef _WIN32
#include <pwd.h>
#endif
#define DEFAULT_FILENAME "data.jf2"
#define DEFAULT_FOLDER "data/"
#define CONFIG_FILENAME "config.txt"
#pragma pack(push,1)
struct DATA_Header {
char magic[4];
uint32_t num_files;
uint32_t index_offset;
struct file_t
{
std::string path;
uint32_t size;
uint32_t offset;
};
struct DATA_Info {
uint32_t offset;
uint32_t length;
char name[13];
};
std::vector<file_t> toc;
struct DATA_Index {
DATA_Info* file_info;
/* 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;
};
struct DATA_File {
DATA_Header header;
DATA_Index index;
};
#pragma pack(pop)
char *resource_filename = NULL;
char *resource_folder = NULL;
DATA_File *data_file = 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);
@@ -56,18 +61,31 @@ void file_setsource(const int src) {
bool file_getdictionary() {
if (resource_filename == NULL) file_setresourcefilename(DEFAULT_FILENAME);
FILE* f = fopen(resource_filename, "rb");
if (f) {
data_file = (DATA_File*)malloc(sizeof(DATA_File));
fread((char*)&data_file->header, sizeof(DATA_Header), 1, f);
fseek(f, data_file->header.index_offset, SEEK_SET);
data_file->index.file_info = (DATA_Info*)malloc(data_file->header.num_files * sizeof(DATA_Info));
fread((char*)data_file->index.file_info, data_file->header.num_files * sizeof(DATA_Info), 1, f);
fclose(f);
return true;
} else {
return false;
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 (uint32_t 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) {
@@ -78,7 +96,7 @@ char *file_getfilenamewithfolder(const char* filename) {
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary) {
if (file_source==SOURCE_FILE and not data_file) {
if (file_source==SOURCE_FILE and toc.size()==0) {
if (not file_getdictionary()) file_setsource(SOURCE_FOLDER);
}
@@ -87,8 +105,8 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
if (file_source==SOURCE_FILE) {
bool found = false;
uint32_t count = 0;
while( !found && count < data_file->header.num_files ) {
found = ( strcmp( resourcename, data_file->index.file_info[count].name ) == 0 );
while( !found && count < toc.size() ) {
found = ( std::string(resourcename) == toc[count].path );
if( !found ) count++;
}
@@ -97,14 +115,14 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
exit(1);
}
filesize = data_file->index.file_info[count].length;
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, data_file->index.file_info[count].offset, SEEK_SET);
fseek(f, toc[count].offset, SEEK_SET);
} else {
f = fopen(file_getfilenamewithfolder(resourcename), binary?"rb":"r");
fseek(f, 0, SEEK_END);
@@ -114,10 +132,248 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
return f;
}
char *file_getfilebuffer(const char *resourcename, int& filesize) {
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
FILE *f = file_getfilepointer(resourcename, filesize, true);
char* buffer = (char*)malloc(filesize);
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
}
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary) {
FILE *f;
f = fopen(filename, binary?"rb":"r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
return f;
}
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
FILE *f = file_getfilepointerex(filename, 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;
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
{
// Intenta crear ".config", per si no existeix
std::string config_base_folder = std::string(homedir) + "/.config";
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
if (ret == -1 && errno != EEXIST)
{
printf("ERROR CREATING CONFIG BASE FOLDER.");
exit(EXIT_FAILURE);
}
}
{
// Intenta crear ".config/jailgames", per si no existeix
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
if (ret == -1 && errno != EEXIST)
{
printf("ERROR CREATING CONFIG BASE FOLDER.");
exit(EXIT_FAILURE);
}
}
#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() {
static std::string folder = config_folder + "/";
return folder.c_str();
}
void file_loadconfigvalues() {
config.clear();
std::string config_file = config_folder + "/config.txt";
FILE *f = fopen(config_file.c_str(), "r");
if (!f) return;
char line[1024];
while (fgets(line, sizeof(line), f)) {
char *value = strchr(line, '=');
if (value) {
*value='\0'; value++;
value[strlen(value)-1] = '\0';
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);
}
}
const char* file_getconfigvalue(const char *key) {
if (config.empty()) file_loadconfigvalues();
for (auto pair : config) {
if (pair.key == std::string(key)) {
strcpy(scratch, pair.value.c_str());
return scratch;
}
}
return NULL;
}
void file_setconfigvalue(const char* key, const char* value) {
if (config.empty()) file_loadconfigvalues();
for (auto &pair : config) {
if (pair.key == std::string(key)) {
pair.value = value;
file_saveconfigvalues();
return;
}
}
config.push_back({key, value});
file_saveconfigvalues();
return;
}
bool file_createFolder(const char* name) {
char tmp[256];
strcpy(tmp, "./");
strcat(tmp, name);
return mkdir(tmp, 0755)==0;
}
static bool has_extension(const std::string &name, const char *ext)
{
if (!ext) return true; // sin filtro
std::string e = ext;
std::string suffix = "." + e;
if (name.size() < suffix.size())
return false;
return (name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0);
}
std::vector<std::string> file_listdir(const char *folder, const char *extension)
{
std::vector<std::string> result;
std::string base(folder);
// Normalizar: quitar "/" final si existe
if (!base.empty() && base.back() == '/')
base.pop_back();
// -------------------------------
// 1. MODO: ARCHIVOS SUELTOS
// -------------------------------
if (file_source == SOURCE_FOLDER)
{
std::string fullpath = std::string(resource_folder) + base;
DIR *dir = opendir(fullpath.c_str());
if (!dir)
return result;
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr)
{
std::string name = entry->d_name;
// Ignorar "." y ".."
if (name == "." || name == "..")
continue;
// Ignorar subdirectorios
std::string full = fullpath + "/" + name;
DIR *test = opendir(full.c_str());
if (test)
{
closedir(test);
continue; // es un directorio
}
// Filtrar por extensión
if (!has_extension(name, extension))
continue;
result.push_back(name);
}
closedir(dir);
return result;
}
// -------------------------------
// 2. MODO: ARCHIVO CONTENEDOR
// -------------------------------
if (file_source == SOURCE_FILE)
{
std::string prefix = base + "/";
for (auto &f : toc)
{
const std::string &path = f.path;
// Debe empezar por "folder/"
if (path.compare(0, prefix.size(), prefix) != 0)
continue;
// Extraer la parte después de "folder/"
std::string rest = path.substr(prefix.size());
// Ignorar subdirectorios
if (rest.find('/') != std::string::npos)
continue;
// Filtrar por extensión
if (!has_extension(rest, extension))
continue;
result.push_back(rest);
}
return result;
}
return result;
}

16
jfile.h
View File

@@ -1,12 +1,26 @@
#pragma once
#include <stdio.h>
#include <vector>
#include <string>
#define SOURCE_FILE 0
#define SOURCE_FOLDER 1
void file_setconfigfolder(const char *foldername);
const char *file_getconfigfolder();
void file_setresourcefilename(const char *str);
void file_setresourcefolder(const char *str);
void file_setsource(const int src);
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false);
char *file_getfilebuffer(const char *resourcename, int& filesize);
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate=false);
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary=false);
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate=false);
const char* file_getconfigvalue(const char *key);
void file_setconfigvalue(const char* key, const char* value);
bool file_createFolder(const char* name);
std::vector<std::string> file_listdir(const char *folder, const char *extension=NULL);

250
jshader.cpp Normal file
View File

@@ -0,0 +1,250 @@
#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_Point win_size = {640, 480};
SDL_FPoint tex_size = {320, 240};
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;
SDL_GetWindowSize(win, &win_size.x, &win_size.y);
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 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(0, 0, win_size.x, win_size.y);
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, NULL);
SDL_RenderPresent(renderer);
}
if (glGetError()) { printf("GLERROR!\n"); exit(1); }
}
}

48
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 enable();
void disable();
void render();
}

5
lagueirtofile Normal file
View File

@@ -0,0 +1,5 @@
libs = -lSDL3 -lGL
cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall
executable = mini_debug
sourcepath = . lua
buildpath = build

27
log.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <stdio.h>
#include <stdarg.h>
#ifdef DEBUG
enum LogLevel { LOG_OK, LOG_FAIL, LOG_WARN, LOG_INFO, LOG_LUART, LOG_LUALD, LOG_VERBOSE, LOG_UNSALTED };
static inline void log_msg(enum LogLevel level, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
switch (level) {
case LOG_OK: printf("[\033[1;32m OK \033[0m] "); break;
case LOG_FAIL: printf("[\033[1;31mFAIL\033[0m] "); break;
case LOG_WARN: printf("[\033[1;33mWARN\033[0m] "); break;
case LOG_INFO: printf("[\033[1;34mINFO\033[0m] "); break;
case LOG_LUART: printf("[\033[1;35mLUA RUNTIME ERROR\033[0m] "); break;
case LOG_LUALD: printf("[\033[1;35mLUA LOADING ERROR\033[0m] "); break;
case LOG_VERBOSE: printf(" - "); break;
case LOG_UNSALTED: break;
}
vprintf(fmt, args);
va_end(args);
}
#else
#define log_msg(...) ((void)0)
#endif

1828
lua.cpp

File diff suppressed because it is too large Load Diff

2
lua.h
View File

@@ -1,7 +1,7 @@
#pragma once
bool lua_is_playing();
void lua_init(char* filenames);
void lua_init(const char* main_lua_file = "main.lua");
void lua_call_init();
void lua_call_update();
void lua_quit();

View File

@@ -653,9 +653,119 @@ static void findloader (lua_State *L, const char *name) {
}
}
// [RZC 12/03/2026] ==================================
// Soport per a rutes relatives i absolutes
//
static void resolve_module_name(lua_State *L, char *out, size_t outsz) {
const char *req = luaL_checkstring(L, 1);
// 1. RUTA ABSOLUTA: empieza por ':'
if (req[0] == ':') {
strncpy(out, req + 1, outsz - 1);
out[outsz - 1] = '\0';
return;
}
// 2. Obtener módulo llamador
lua_Debug ar;
if (!lua_getstack(L, 1, &ar)) {
// No hay llamador → usar nombre tal cual
strncpy(out, req, outsz - 1);
out[outsz - 1] = '\0';
return;
}
lua_getinfo(L, "S", &ar);
// ar.source contiene algo como "@ia.test" o "@main"
const char *src = ar.source;
if (!src) {
// No viene de archivo → usar nombre tal cual
strncpy(out, req, outsz - 1);
out[outsz - 1] = '\0';
return;
}
// Quitar '@'
//src++;
// 3. Extraer directorio del módulo llamador
// Ej: "ia.tools.other" → "ia.tools"
char caller[256];
strncpy(caller, src, sizeof(caller) - 1);
caller[sizeof(caller) - 1] = '\0';
char *lastdot = strrchr(caller, '.');
if (lastdot)
*lastdot = '\0'; // dejar solo el directorio
else
caller[0] = '\0'; // está en la raíz
// 4. RUTA RELATIVA HACIA ARRIBA: empieza por ".."
if (req[0] == '.' && req[1] == '.') {
// Contar cuántos '.' consecutivos hay
int up = 0;
while (req[up] == '.')
up++;
// up = número de puntos → niveles a subir
// Ej: "..test" → up=2 → subir 1 nivel
// "...main" → up=3 → subir 2 niveles
int levels = up - 1;
// Copiar caller a buffer temporal
char temp[256];
strncpy(temp, caller, sizeof(temp) - 1);
temp[sizeof(temp) - 1] = '\0';
// Subir niveles
for (int i = 0; i < levels; i++) {
char *p = strrchr(temp, '.');
if (p)
*p = '\0';
else {
temp[0] = '\0';
break;
}
}
// Concatenar lo que queda después de los puntos
const char *rest = req + up;
if (temp[0] == '\0') {
// Hemos llegado a la raíz
strncpy(out, rest, outsz - 1);
} else {
snprintf(out, outsz, "%s.%s", temp, rest);
}
out[outsz - 1] = '\0';
return;
}
// 5. RUTA RELATIVA NORMAL (no empieza por ':' ni por '..')
if (caller[0] == '\0') {
// Estamos en la raíz
strncpy(out, req, outsz - 1);
} else {
snprintf(out, outsz, "%s.%s", caller, req);
}
out[outsz - 1] = '\0';
}
// ===================================================
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
// [RZC 12/03/2026] ==================================
// Soport per a rutes relatives i absolutes
//
//const char *name = luaL_checkstring(L, 1);
char resolved[256];
resolve_module_name(L, resolved, sizeof(resolved));
const char *name = resolved;
// ===================================================
lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */

1094
mini.cpp

File diff suppressed because it is too large Load Diff

146
mini.h
View File

@@ -1,8 +1,8 @@
#pragma once
#include <SDL2/SDL.h>
#include <SDL3/SDL.h>
#define MINI_VERSION "0.9.32d"
#include "version.h"
#define KEY_UNKNOWN 0
#define KEY_A 4
@@ -112,34 +112,50 @@
#define KEY_RALT 230
#define KEY_RGUI 231
#define DRAWMODE_NORMAL 0
#define DRAWMODE_PATTERN 1
#define DRAWMODE_AND 2
#define DRAWMODE_OR 3
#define DRAWMODE_XOR 4
#define DRAWMODE_NOT 5
void loop();
int scrw();
int scrh();
uint8_t newsurf(int w, int h);
uint8_t loadsurf(const char* filename);
uint8_t loadsurf(const char* filename, const bool external = false);
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
void freesurf(uint8_t surface);
int surfw(uint8_t surface);
int surfh(uint8_t surface);
void setdest(uint8_t surface);
void setsource(uint8_t surface);
void setmap(uint8_t surface);
uint8_t getdest();
uint8_t getsource();
uint8_t getmap();
void shader_init(const char* vshader, const char* fshader);
void shader_enable();
void shader_disable();
void cls(uint8_t color=0);
void color(uint8_t color=6);
void bcolor(uint8_t color=0);
uint32_t *loadpal(const char* filename);
uint32_t *loadpal(const char* filename, uint16_t *palsize=NULL);
void setpal(uint32_t *pal);
void setcolor(uint8_t index, uint32_t color);
uint32_t getcolor(uint8_t index);
void settrans(uint8_t index);
uint8_t gettrans();
void subpal(uint8_t index, uint8_t color);
void reset_subpal();
/*void pal();
void pal(uint8_t c0, uint8_t c1, uint8_t p = 0);
void palt();
void palt(uint16_t bits);
void palt(uint8_t col, bool t);*/
void set_draw_mode(uint8_t mode);
void pset(int x, int y);
void pset(int x, int y, uint8_t color);
@@ -154,11 +170,11 @@ void hline(int x0, int y, int x1, uint8_t color);
void vline(int x, int y0, int y1);
void vline(int x, int y0, int y1, uint8_t color);
void rect(int x0, int y0, int x1, int y1);
void rect(int x0, int y0, int x1, int y1, uint8_t color);
void rect(int x, int y, int w, int h);
void rect(int x, int y, int w, int h, uint8_t color);
void rectfill(int x0, int y0, int x1, int y1);
void rectfill(int x0, int y0, int x1, int y1, uint8_t color);
void rectfill(int x, int y, int w, int h);
void rectfill(int x, int y, int w, int h, uint8_t color);
void fillp(uint16_t pat, bool transparent = false);
@@ -166,7 +182,10 @@ void print(const char *str, int x, int y);
void print(const char *str, int x, int y, uint8_t color);
void clip(int x, int y, int w, int h);
void camera(int x, int y);
void clip();
void origin(int x, int y);
int camx();
int camy();
void circ(int x, int y, uint8_t r = 4);
void circ(int x, int y, uint8_t r, uint8_t color);
@@ -174,6 +193,12 @@ void circ(int x, int y, uint8_t r, uint8_t color);
void circfill(int x, int y, uint8_t r = 4);
void circfill(int x, int y, uint8_t r, uint8_t color);
void roundrect(int x, int y, int w, int h, uint8_t r);
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color);
void roundrectfill(int x, int y, int w, int h, uint8_t r);
void roundrectfill(int x, int y, int w, int h, uint8_t r, uint8_t color);
void oval(int x0, int y0, int x1, int y1);
void oval(int x0, int y0, int x1, int y1, uint8_t color);
@@ -185,86 +210,73 @@ void sset(int x, int y);
void sset(int x, int y, uint8_t color);
void spr(uint8_t n, int x, int y, float w = 1.0f, float h = 1.0f, bool flip_x = false, bool flip_y = false);
void sspr(int sx, int sy, int sw, int sh, int dx, int dy, int dw=0, int dh=0, bool flip_x = false, bool flip_y = false);
void blit(int sx, int sy, int sw, int sh, int dx, int dy, int dw=0, int dh=0, bool flip_x = false, bool flip_y = false, bool invert = false);
void blit_r(int sx, int sy, int sw, int sh, int x, int y, float a);
void tline(int x0, int y0, int x1, int y1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
void thline(int x0, int y, int x1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
void tvline(int x, int y0, int y1, float mx, float my, float mdx=0.0f, float mdy=0.125f);
void cline(int x0, int y0, int x1, int y1, uint8_t c0, uint8_t c1);
void chline(int x0, int y, int x1, uint8_t c0, uint8_t c1);
void cvline(int x, int y0, int y1, uint8_t c0, uint8_t c1);
uint8_t mget(int celx, int cely);
void mset(int celx, int cely, uint8_t snum);
void map(int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
void map(); //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
bool btn(uint8_t i);
int wbtnp();
bool btnp(uint8_t i);
bool anykey();
bool pad(int8_t i);
bool padp(int8_t i);
int wpad();
int mousex();
int mousey();
int mwheel();
bool mbtn(uint8_t i);
bool mbtnp(uint8_t i);
bool doubleclick();
void mdiscard();
bool minside(int x, int y, int w, int h);
float time();
//float abs(float x);
float flr(float x);
float sgn(float x);
#ifdef __WINDOWS__
float ceil(float x);
float sin(float x);
float cos(float x);
float atan2(float dx, float dy);
float sqrt(float x);
#endif
float max(float x, float y);
float mid(float x, float y, float z);
float min(float x, float y);
int utfstrlen(const char *str);
bool beat(int16_t i);
int rnd(int x);
//void srand(int x);
const char* tostr(int val);
//void debug(const char *str);
#define debug printf
uint8_t ascii(const char *str, uint8_t index);
void fopen(const char *filename, uint8_t mode=0);
void fopenres(const char *filename);
void fclose();
bool feof();
void fwritei(int value);
void fwrited(float value);
void fwrites(const char *value);
void fwritew(const char *value);
void fwriteb(bool value);
void fwriteln();
int freadi();
float freadd();
const char *freads();
const char *freadw();
bool freadb();
int getfps();
void playmusic(const char *filename, const int loop=-1);
void pausemusic();
void resumemusic();
void stopmusic();
void stopmusic(const int t=1000);
void musicpos(float value);
float musicpos();
void enablemusic(const bool value);
const bool ismusicenabled();
int loadsound(const char *filename);
void freesound(int soundfile);
int playsound(int soundfile, const int volume=-1);
void stopsound(int soundchannel);
void enablesound(const bool value);
const bool issoundenabled();
int getzoom();
void setzoom(const int value);
void setres(const int w, const int h);
bool getfullscreen();
void setfullscreen(const bool value);
bool getcursor();
void setcursor(const bool value);
const char *getconfig(const char* key);
void setconfig(const char* key, const char* value);
const char *configfolder();
#define UPDATE_ALWAYS 0
#define UPDATE_WAIT 1
#define UPDATE_TIMEOUT 2
void setupdatemode(const int value, const int t=0);
int getupdatemode();
void exit();

View File

@@ -0,0 +1,5 @@
title=FONTED
config=fonted
width=320
height=240
zoom=2

122
tools/fonted/data/main.lua Normal file
View File

@@ -0,0 +1,122 @@
require "ui"
update = nil
protofont_surface = nil
protofont_name = nil
function mini.init()
pal.trans(255)
surf.cls(0)
update = any_update
--ui.filedialog.show(select_file)
end
function select_file(filename)
if protofont_surface then surf.free(protofont_surface) end
protofont_name = filename:match("([^/]+)$")
protofont_surface = surf.loadex(filename)
end
function mini.update()
view.origin(0,0)
for i=0,15 do
draw.rectf(i*8, 0, 8, 8, i)
end
update()
end
seltab = 1
function draw_big_char(x,y,w,h)
if protofont_surface then
surf.source(protofont_surface)
for yy=0,h-1 do
for xx=0,w-1 do
if surf.pixel(x+xx, y+yy)~=0 then
draw.rectf(xx*8, yy*8, 7, 7, 0)
else
draw.rectf(xx*8, yy*8, 7, 7, 12)
end
end
end
end
end
function any_update()
surf.cls(0)
view.origin(4,4)
draw.rrectf(0,0,140,232,3,15)
ui.button("NEW",4,4,30,11, {7,6,5})
ui.button("LOAD",36,4,30,11, {9,10,11})
ui.button("SAVE",68,4,30,11, {2,3,4})
view.origin(8,24)
local w,h = 128,20
if protofont_surface then w,h = surf.size(protofont_surface) end
draw.rrectf(0,0,132,h+35,2,14)
draw.text("SURFACE:",4,4,12)
if protofont_surface then
draw.text(protofont_name,36,4,12)
--local w,h = surf.size(protofont_surface)
local x,y = 6,15
surf.source(protofont_surface)
pal.subpal(1,12)
draw.surf(0,0,w,h,x,y,w,h)
pal.subpal(1)
draw.rect(x-1,y-1,w+2,h+2,0)
draw.rrect(x-2,y-2,w+4,h+4,2,12)
draw.text(tostring(w)..","..tostring(h), 10, 100, 3)
else
draw.text("<none>",36,4,12)
end
if ui.button("LOAD",98,20+h,30,11, {9,10,11}) then
ui.filedialog.show(select_file)
end
--view.origin(4,140)
--draw.rrectf(0,0,140,68,3,15)
view.origin(148,4)
draw.rrectf(0,0,21,12,3,14)
draw.text("BASE",3,2,12)
draw.rrectf(22,0,45,12,3,15)
draw.text("DIACRITICS",25,2,0)
-- acute(Á), grave(À); diaeresis(Ä), circumflex(Â); cedilla(Ç), tilde(Ñ)
draw.rrectf(68,0,49,12,3,15)
draw.text("PRECOMPOSED",71,2,0)
draw.rrectf(0,8,140,140,3,14)
view.origin(152,18)
draw.text("CARÀCTER ACTUAL:65(A)",0,0,0)
view.origin(152,25)
draw_big_char(7,7,7,7)
ui.button("<",70,2,9,9, {9,10,11})
--draw.rrectf(80,2,16,10,2,15)
draw.rrectf(80,2,15,9,2,13)
draw.text("240",82,4,15)
ui.button(">",96,2,9,9, {9,10,11})
view.origin(152,144)
local x,y=0,0
for c=32,127 do
draw.rectf(x,y,7,9,12)
draw.rect(x,y,7,9,0)
draw.text(string.char(c),x+2,y+2,0)
x=x+8
if x>=128 then
x=0
y=y+10
end
end
draw.text("ÁÄÉÍÓÚáéíóúÀÈÌÒÙàèìòùñÑçÇ", x, y+8, 12)
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

146
tools/fonted/data/ui.lua Normal file
View File

@@ -0,0 +1,146 @@
ui = {
button = function(text, x, y, w, h, color)
local text_x = (w-(#text*4))/2
draw.rrectf(x,y+1,w,h,2,color[1])
if mouse.inside(x,y,w,h) then
if mouse.down(mouse.LEFT) then y=y+1 end
draw.rrectf(x,y,w,h,2,color[3])
if mouse.press(mouse.LEFT) then return true end
else
draw.rrectf(x,y,w,h,2,color[2])
end
local text_y = (h-5)/2
draw.text(text,x+text_x+1,y+text_y,color[1])
return false
end,
filedialog = {
folder = nil,
files = nil,
dir = ".",
selected = 0,
offset = 0,
lift_height = -1,
lift_top = 0,
old_update = nil,
callback = nil,
show = function(callback)
if not ui.filedialog.folder then
ui.filedialog.folder=surf.new(5,4)
surf.target(ui.filedialog.folder)
for i=0,4 do for j=0,3 do surf.pixel(i,j,0) end end
for i=2,4 do surf.pixel(i,0,255) end
surf.target(0)
end
ui.filedialog.loadDir(".")
ui.filedialog.callback = callback
ui.filedialog.old_update = update
update = ui.filedialog.update
end,
loadDir = function(path)
ui.filedialog.files = sys.dir(path)
if #ui.filedialog.files > 0 then
ui.filedialog.dir = ui.filedialog.files[1].name:match("(.+)/[^/]+$")
else
ui.filedialog.dir = path
end
table.insert(ui.filedialog.files, 1, { dir=true, name=".." })
ui.filedialog.selected = 0
ui.filedialog.offset = 0
ui.filedialog.lift_height=-1
ui.filedialog.lift_top=0
if #ui.filedialog.files>23 then
ui.filedialog.lift_height=23*161/#ui.filedialog.files
end
end,
goBack = function()
ui.filedialog.dir = ui.filedialog.dir:match("(.+)/[^/]+$")
ui.filedialog.loadDir(ui.filedialog.dir)
end,
select = function()
if ui.filedialog.files[ui.filedialog.selected].dir then
local filename = ui.filedialog.files[ui.filedialog.selected].name:match("([^/]+)$")
ui.filedialog.loadDir(ui.filedialog.dir.."/"..filename)
else
update = ui.filedialog.old_update
ui.filedialog.callback(ui.filedialog.files[ui.filedialog.selected].name)
end
end,
update = function()
pal.trans(255)
view.origin(20, 20)
draw.rrectf(0,0,280,200,3,15)
draw.rrectf(4,4,272,9,2,12)
draw.rrectf(4,17,272,163,2,12)
if ui.filedialog.lift_height>0 then draw.rrectf(271,18+ui.filedialog.lift_top,4,ui.filedialog.lift_height,2,14) end
if ui.button("OK",192,184,40,11,{9,10,11}) then ui.filedialog.select() end
if ui.button("CANCEL",236,184,40,11,{1,2,3}) then update = ui.filedialog.old_update end
local y = 19
draw.text(ui.filedialog.dir, 6, 6, 0)
surf.source(ui.filedialog.folder)
local count = 0
for k,file in ipairs(ui.filedialog.files) do
local filename = file.name:match("([^/]+)$")
if count < ui.filedialog.offset then goto continue end
--if not ui.filedialog.filter or filename:match("%."..ui.filedialog.filter.."$") then
if mouse.inside(4,y-1,272,7) then
--if mx>4 and mx<268 and my>=y-1 and my<y+6 then
draw.rectf(4,y-1,272,7,13)
if mouse.dblclick() then
ui.filedialog.select()
elseif mouse.press(mouse.LEFT) then
ui.filedialog.selected = k
end
end
if ui.filedialog.selected == k then
draw.rectf(4,y-1,272,7,10)
end
if file.dir then
draw.surf(0,0,5,4,7,y+1,5,4)
pal.subpal(0,3)
draw.surf(0,0,5,4,6,y,5,4)
pal.subpal(0)
draw.text(filename, 13, y, 0)
else
draw.text(filename, 6, y, 0)
end
y=y+7
::continue::
count=count+1
if count-ui.filedialog.offset>=23 then break end
end
if key.press(key.RETURN) and ui.filedialog.selected~=-1 then
ui.filedialog.select()
elseif key.press(key.DOWN) and ui.filedialog.selected<#ui.filedialog.files then
ui.filedialog.selected=ui.filedialog.selected+1
elseif key.press(key.UP) then
if ui.filedialog.selected>1 then
ui.filedialog.selected=ui.filedialog.selected-1
else
ui.filedialog.selected = 1
end
end
local scroll = -mouse.wheel()
if scroll~=0 then
ui.filedialog.offset=ui.filedialog.offset+scroll
if ui.filedialog.offset<0 then ui.filedialog.offset=0 end
if ui.filedialog.offset+23 > #ui.filedialog.files then ui.filedialog.offset = #ui.filedialog.files-23 end
ui.filedialog.lift_top=ui.filedialog.offset*161/#ui.filedialog.files
end
end
}
}

3
version.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
#define MINI_VERSION "1.4.1"

890
vscode/library.lua Normal file
View File

@@ -0,0 +1,890 @@
---@meta
---@class mini
mini = {}
---@class surf
surf = {}
---@param w number
---@param h number
---@return number surface
---Create new surface specifying width and height
function surf.new(w, h) end
---@param filename string
---@return number surface
---Load GIF file and return surface
function surf.load(filename) end
---@param filename string
---@return number surface
---Load GIF from external file and return surface
function surf.loadex(filename) end
---@param surface number
---@param filename string
---@optional palette table
---Save surface as GIF file, with optional palette
function surf.save(surface, filename, palette) end
---@param surface number
---Free the specified surface
function surf.free(surface) end
---@param surface number
---@return number w, number h
---Retrieve width and height of surface
function surf.size(surface) end
---@return number surface
---Get current target surface
function surf.target() end
---@param surface number
---Set surface as target
function surf.target(surface) end
---@return number surface
---Get current source surface
function surf.source() end
---@param surface number
---Set surface as source
function surf.source(surface) end
---Erase the current target surface with color 0.
function surf.cls() end
---@param color number
---Erase the current target surface with 'color'
function surf.cls(color) end
---@param x number
---@param y number
---@return number color
---Get color of pixel (x,y) on the source surface.
function surf.pixel(x, y) end
---@param x number
---@param y number
---@param color number
---Set the color for pixel (x,y) on the target surface.
function surf.pixel(x, y, color) end
---@class map
map = {}
---@return number surface
---Get tilemaps current surface
function map.surf() end
---@param surface number
---Set surface as the current tilemap
function map.surf(surface) end
---Draw the tilemap, using the source surface as tile graphics source
function map.draw() end
---@param x number
---@param y number
---@return number tile
---Get tile at the position (x,y) in the current tilemap
function map.tile(x, y) end
---@param x number
---@param y number
---@param tile number
---Set the tile at the position (x,y) in the current tilemap
function map.tile(x, y, tile) end
---@class pal
pal = {}
---@param filename string
---@return table pal
---Load a palette from a GIF file and return it
function pal.load(filename) end
---@param pal table
---Set a specified palette as the current palette
function pal.set(pal) end
---@param index number
---@return number r, number g, number b
---Retrieve (r,g,b) color for the index specified in the current palette
function pal.color(index) end
---@param index number
---@param r number
---@param g number
---@param b number
---Set (r,g,b) color for the specified index in the current palette
function pal.color(index, r, g, b) end
---@param index number
---Set the index specified as transparent color
function pal.trans(index) end
---Reset all the subpalette indices to their default palette index
function pal.subpal() end
---@param index number
---Reset the specified subpalette index to its default palette index
function pal.subpal(index) end
---@param index number
---@param color number
---Set the specified subpalette index to the specified palette index
function pal.subpal(index, color) end
---@param index1 number
---@param index2 number
---@param color number
---Set the specified subpalette range to the specified palette index
function pal.subpal(index1, index2, color) end
---@class view
view = {}
---reset the current clipping region to the entire window
function view.clip() end
---@param x number
---@param y number
---@param w number
---@param h number
---Set the current clipping region
function view.clip(x, y, w, h) end
---@return number x, number y
---Get the current origin position
function view.origin() end
---@param x number
---@param y number
---Set the current origin position
function view.origin(x, y) end
---@param x number
---@param y number
---@return number x, number y
---Convert screen position to viewport position
function view.tolocal(x, y) end
---@class draw
---@field draw.NORMAL number
---@field draw.PATTERN number
---@field draw.AND number
---@field draw.OR number
---@field draw.XOR number
---@field draw.NOT number
draw = {}
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@param color number
---Draw a line from (x1,y1) to (x2,y2) with the given color
function draw.line(x1, y1, x2, y2, color) end
---@param x1 number
---@param y number
---@param x2 number
---@param color number
---Draw an horizontal line from (x1,y) to (x2,y) with the given color
function draw.hline(x1, y, x2, color) end
---@param x number
---@param y1 number
---@param y2 number
---@param color number
---Draw a vertical line from (x,y1) to (x,y2) with the givencolor
function draw.vline(x, y1, y2, color) end
---@param x number
---@param y number
---@param w number
---@param h number
---@param color number
---Draw the ouline of a rectangle at (x,y) of size (w,h) with the given color
function draw.rect(x, y, w, h, color) end
---@param x number
---@param y number
---@param w number
---@param h number
---@param color number
---Draw a filled rectangle at (x,y) of size (w,h) with the given color
function draw.rectf(x, y, w, h, color) end
---@param x number
---@param y number
---@param r number
---@param color number
---Draw the outline of a cicle at position(x,y) with radius r and the given color
function draw.circ(x, y, r, color) end
---@param x number
---@param y number
---@param r number
---@param color number
---Draw a filled cicle at position(x,y) with radius r and the given color
function draw.circf(x, y, r, color) end
---@param x number
---@param y number
---@param w number
---@param h number
---@param r number
---@param color number
---Draw the outline of a round rectangle at (x,y) of size (w,h) with border radius r and the given color
function draw.rrect(x, y, w, h, r, color) end
---@param x number
---@param y number
---@param w number
---@param h number
---@param r number
---@param color number
---Draw a filled round rectangle at (x,y) of size (w,h) with border radius r and the given color
function draw.rrectf(x, y, w, h, r, color) end
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@param color number
---Draw the outline of an oval enclosed in (x1,y1)-(x2,y2) and the given color
function draw.oval(x1, y1, x2, y2, color) end
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@param color number
---Draw a filled oval enclosed in (x1,y1)-(x2,y2) and the given color
function draw.ovalf(x1, y1, x2, y2, color) end
---@param pattern number
---Specify a pattern for the drawing functions
function draw.pattern(pattern) end
---Reset to no pattern for drawing functions
function draw.pattern() end
---@param sx number
---@param sy number
---@param sw number
---@param sh number
---@param dx number
---@param dy number
---@optional dw number
---@optional dh number
---@optional boolean flip_x
---@optional boolean flip_y
---@optional boolean invert
---Blit the region starting at (sx,sy) and size (sw, sh) from the source surface
---to the position (dx, dy) (and optionally of size (dw, dh)) to the target surface,
---optionally flipping it horizontally or vertically, or inverting x and y axes
function draw.surf(sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, invert) end
---@param sx number
---@param sy number
---@param sw number
---@param sh number
---@param x number
---@param y number
---@param a number
---Blit the region starting at (sx,sy) and size (sw, sh) from the source surface
---to the position (dx, dy) of the target surface, rotating it by a degrees
function draw.surfrot(sx, sy, sw, sh, x, y, a) end
---@param text string
---@param x number
---@param y number
---@param color number
---Draw text to (x,y) using the specified color
function draw.text(text, x, y, color) end
---@param text number
---@param x number
---@param y number
---@param color number
---Draw text to (x,y) using the specified color
function draw.text(text, x, y, color) end
---@param mode number
---Specify the mode for the drawing functions
function draw.mode(mode) end
draw.NORMAL = 0
draw.PATTERN = 1
draw.AND = 2
draw.OR = 3
draw.XOR = 4
draw.NOT = 5
---@class shader
shader = {}
---Initialize shaders subsystem, still non functional without shaders
function shader.init() end
---@param shader string
---Initialize shaders subsystem, specifying a file that contains both vertex and fragment shader
function shader.init(shader) end
---@param vshader string
---@param fshader string
---Initialize shaders subsystem, specifying both a vertex shader file and a fragment shader file
function shader.init(vshader, fshader) end
---Enable previously loaded shader
function shader.enable() end
---Disable shaders
function shader.disable() end
---@class music
music = {}
---@param filename string
---Load and play the song in the specified OGG file
function music.play(filename) end
---@param filename string
---@param loop integer
---Load and play the song in the specified OGG file, loop number of times
function music.play(filename, loop) end
---Pause the currently playing song
function music.pause() end
---Resume the currently paused song
function music.resume() end
---Stop the currently playing song
function music.stop() end
---@return number pos
---Get the playing position of the currently loaded song
function music.pos() end
---@param pos number
---Set the playing position of the currently loaded song
function music.pos(pos) end
---@return boolean value
---Get if music is enabled
function music.enabled() end
---@param value boolean
---Set if music is enabled or not
function music.enabled(value) end
---@class sound
sound = {}
---@param filename string
---@return number snd
---Load a sound in WAV format from the specified file and return it
function sound.load(filename) end
---@param snd number
---Free the sound specified
function sound.free(snd) end
---@param snd number
---@return number chl
---Play the sound specified, returns the channel in which it's playing
function sound.play(snd) end
---@param snd number
---@param loop integer
---@return number chl
---Play the sound specified loop number of times, returns the channel in which it's playing
function sound.play(snd, loop) end
---@param chl number
---Stop the channel specified
function sound.stop(chl) end
---@return boolean value
---Get if sound is enabled
function sound.enabled() end
---@param value boolean
---Set if sound is enabled or not
function sound.enabled(value) end
---@class sys
sys = {}
---Get delta time from last update in seconds (with decimals)
function sys.delta() end
---Get current system timer in seconds (with decimals)
function sys.time() end
---@param offset number
---Reset chrono time (with offset in seconds) (with decimals)
function sys.chrono(offset) end
---@return number
---@---Get chrono time since last chrono reset in seconds (with decimals)
function sys.chrono() end
---@return boolean
---Query if a beat has already passed
function sys.beat() end
---@param bts number
---Set number of frames between beats
function sys.beat(bts) end
---@param mode number
---@param ms number
---Sets the update mode.
---UPDATE_ALWAYS: The game will call mini.update as fast as possible
---UPDATE_EVENTS: The game will call mini.update only when a keyboard, mouse or pad event fires
---UPDATE_TIMEOUT: The game will call mini.update on events or after the milliseconds specified passed
function sys.update(mode, ms) end
---@return table
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
---boolean specifying if it's a directory, for each file in the 'data' directory
function sys.dir() end
---@param path string
---@return table
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
---boolean specifying if it's a directory, for each file in the specified path
function sys.dir(path) end
---Exit the game
function sys.quit() end
---@return number
---Gets the frames per second
function sys.fps() end
---@return string
---Gets the content of the clipboard
function sys.clipboard() end
---@param value string
---Sets the content of the clipboard
function sys.clipboard(value) end
---@return boolean
---Returns true if running on debug version of mini. False otherwise.
function sys.debug() end
---@class win
win = {}
---@param value number
---Set the window zoom
function win.zoom(value) end
---@return number value
---Get the window zoom
function win.zoom() end
---@param value boolean
---Specifies if the window must display at fullscreen or not
function win.fullscreen(value) end
---@return boolean value
---Returns if the window is at fullscreen or not
function win.fullscreen() end
---@param value boolean
---Specifies if the cursor must be visible or not
function win.cursor(value) end
---@return number w, number h
---Returns the current window size
function win.res() end
---@param w number
---@param h number
---Sets the window size
function win.res(w, h) end
---@class config
config = {}
---@param key string
---@param value any
---Sets the value of a key in the configuration file
function config.key(key, value) end
---@param key string
---@return string value
---Gets the value of a key in the configuration file
function config.key(key) end
---@return string value
---Returns the folder in which the configuration file resides
function config.folder() end
---@class mouse
---@field mouse.LEFT number
---@field mouse.MIDDLE number
---@field mouse.RIGHT number
mouse = {}
---@return number x, number y
---Returns the current position of the mouse
function mouse.pos() end
---@return number value
---Returns the value of the mouse wheel
function mouse.wheel() end
---@param btn number
---@return boolean
---Returns whether the specified mouse button is down
function mouse.down(btn) end
---@param btn number
---@return boolean
---Returns whether the specified mouse button has just been pressed
function mouse.press(btn) end
---@return boolean
---Returns whether the user performed a double click
function mouse.dblclick() end
---Ignores current down button, effectively not raising the next "press" event
function mouse.discard() end
---@param x number
---@param y number
---@param w number
---@param h number
---@return boolean
---Returns whether the mouse is inside the rectangle specified
function mouse.inside(x,y,w,h) end
mouse.LEFT = 1
mouse.MIDDLE = 2
mouse.RIGHT = 3
---@class key
key = {}
---@param key number
---@return boolean
---Returns whether the specified keyboard key is down
function key.down(key) end
---@return number
---Returns which keyboard key has just been pressed
function key.press() end
---@param key number
---@return boolean
---Returns whether the specified keyboard key has just been pressed
function key.press(key) end
---@return boolean
---Returns whether any keyboard key has just been pressed
function key.any() end
---@class pad
---@field pad.INVALID number
---@field pad.A number
---@field pad.B number
---@field pad.X number
---@field pad.Y number
---@field pad.BACK number
---@field pad.GUIDE number
---@field pad.START number
---@field pad.LEFTSTICK number
---@field pad.RIGHTSTICK number
---@field pad.LEFTSHOULDER number
---@field pad.RIGHTSHOULDER number
---@field pad.UP number
---@field pad.DOWN number
---@field pad.LEFT number
---@field pad.RIGHT number
---@field pad.MISC1 number
---@field pad.PADDLE1 number
---@field pad.PADDLE2 number
---@field pad.PADDLE3 number
---@field pad.PADDLE4 number
---@field pad.TOUCHPAD number
pad = {}
---@param btn number
---@return boolean
---Returns whether the specified gamepad button is down
function pad.down(btn) end
---@return number
---Returns which gamepad button has just been pressed
function pad.press() end
---@param btn number
---@return boolean
---Returns whether the specified gamepad button has just been pressed
function pad.press(btn) end
---@return boolean
---Returns whether any gamepad button has just been pressed
function pad.any() end
pad.INVALID = -1
pad.A = 0
pad.B = 1
pad.X = 2
pad.Y = 3
pad.BACK = 4
pad.GUIDE = 5
pad.START = 6
pad.LEFTSTICK = 7
pad.RIGHTSTICK = 8
pad.LEFTSHOULDER = 9
pad.RIGHTSHOULDER = 10
pad.UP = 11
pad.DOWN = 12
pad.LEFT = 13
pad.RIGHT = 14
pad.MISC1 = 15
pad.PADDLE1 = 16
pad.PADDLE2 = 17
pad.PADDLE3 = 18
pad.PADDLE4 = 19
pad.TOUCHPAD = 20
---@class key
---@field key.UNKNOWN number
---@field key.A number
---@field key.B number
---@field key.C number
---@field key.D number
---@field key.E number
---@field key.F number
---@field key.G number
---@field key.H number
---@field key.I number
---@field key.J number
---@field key.K number
---@field key.L number
---@field key.M number
---@field key.N number
---@field key.O number
---@field key.P number
---@field key.Q number
---@field key.R number
---@field key.S number
---@field key.T number
---@field key.U number
---@field key.V number
---@field key.W number
---@field key.X number
---@field key.Y number
---@field key.Z number
---@field key.N1 number
---@field key.N2 number
---@field key.N3 number
---@field key.N4 number
---@field key.N5 number
---@field key.N6 number
---@field key.N7 number
---@field key.N8 number
---@field key.N9 number
---@field key.N0 number
---@field key.RETURN number
---@field key.ESCAPE number
---@field key.BACKSPACE number
---@field key.TAB number
---@field key.SPACE number
---@field key.MINUS number
---@field key.EQUALS number
---@field key.LEFTBRACKET number
---@field key.RIGHTBRACKET number
---@field key.BACKSLASH number
---@field key.NONUSHASH number
---@field key.SEMICOLON number
---@field key.APOSTROPHE number
---@field key.GRAVE number
---@field key.COMMA number
---@field key.PERIOD number
---@field key.SLASH number
---@field key.CAPSLOCK number
---@field key.F1 number
---@field key.F2 number
---@field key.F3 number
---@field key.F4 number
---@field key.F5 number
---@field key.F6 number
---@field key.F7 number
---@field key.F8 number
---@field key.F9 number
---@field key.F10 number
---@field key.F11 number
---@field key.F12 number
---@field key.PRINTSCREEN number
---@field key.SCROLLLOCK number
---@field key.PAUSE number
---@field key.INSERT number
---@field key.HOME number
---@field key.PAGEUP number
---@field key.DELETE number
---@field key.END number
---@field key.PAGEDOWN number
---@field key.RIGHT number
---@field key.LEFT number
---@field key.DOWN number
---@field key.UP number
---@field key.NUMLOCKCLEAR number
---@field key.KP_DIVIDE number
---@field key.KP_MULTIPLY number
---@field key.KP_MINUS number
---@field key.KP_PLUS number
---@field key.KP_ENTER number
---@field key.KP_1 number
---@field key.KP_2 number
---@field key.KP_3 number
---@field key.KP_4 number
---@field key.KP_5 number
---@field key.KP_6 number
---@field key.KP_7 number
---@field key.KP_8 number
---@field key.KP_9 number
---@field key.KP_0 number
---@field key.KP_PERIOD number
---@field key.NONUSBACKSLASH number
---@field key.APPLICATION number
---@field key.LCTRL number
---@field key.LSHIFT number
---@field key.LALT number
---@field key.LGUI number
---@field key.RCTRL number
---@field key.RSHIFT number
---@field key.RALT number
---@field key.RGUI number
key.UNKNOWN = 0
key.A = 4
key.B = 5
key.C = 6
key.D = 7
key.E = 8
key.F = 9
key.G = 10
key.H = 11
key.I = 12
key.J = 13
key.K = 14
key.L = 15
key.M = 16
key.N = 17
key.O = 18
key.P = 19
key.Q = 20
key.R = 21
key.S = 22
key.T = 23
key.U = 24
key.V = 25
key.W = 26
key.X = 27
key.Y = 28
key.Z = 29
key.N1 = 30
key.N2 = 31
key.N3 = 32
key.N4 = 33
key.N5 = 34
key.N6 = 35
key.N7 = 36
key.N8 = 37
key.N9 = 38
key.N0 = 39
key.RETURN = 40
key.ESCAPE = 41
key.BACKSPACE = 42
key.TAB = 43
key.SPACE = 44
key.MINUS = 45
key.EQUALS = 46
key.LEFTBRACKET = 47
key.RIGHTBRACKET = 48
key.BACKSLASH = 49
key.NONUSHASH = 50
key.SEMICOLON = 51
key.APOSTROPHE = 52
key.GRAVE = 53
key.COMMA = 54
key.PERIOD = 55
key.SLASH = 56
key.CAPSLOCK = 57
key.F1 = 58
key.F2 = 59
key.F3 = 60
key.F4 = 61
key.F5 = 62
key.F6 = 63
key.F7 = 64
key.F8 = 65
key.F9 = 66
key.F10 = 67
key.F11 = 68
key.F12 = 69
key.PRINTSCREEN = 70
key.SCROLLLOCK = 71
key.PAUSE = 72
key.INSERT = 73
key.HOME = 74
key.PAGEUP = 75
key.DELETE = 76
key.END = 77
key.PAGEDOWN = 78
key.RIGHT = 79
key.LEFT = 80
key.DOWN = 81
key.UP = 82
key.NUMLOCKCLEAR = 83
key.KP_DIVIDE = 84
key.KP_MULTIPLY = 85
key.KP_MINUS = 86
key.KP_PLUS = 87
key.KP_ENTER = 88
key.KP_1 = 89
key.KP_2 = 90
key.KP_3 = 91
key.KP_4 = 92
key.KP_5 = 93
key.KP_6 = 94
key.KP_7 = 95
key.KP_8 = 96
key.KP_9 = 97
key.KP_0 = 98
key.KP_PERIOD = 99
key.NONUSBACKSLASH = 100
key.APPLICATION = 101
key.LCTRL = 224
key.LSHIFT = 225
key.LALT = 226
key.LGUI = 227
key.RCTRL = 228
key.RSHIFT = 229
key.RALT = 230
key.RGUI = 231