55 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
31 changed files with 2871 additions and 1154 deletions

1
.gitignore vendored
View File

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

View File

@@ -3,25 +3,25 @@ source = *.cpp ./lua/*.c
windows: windows:
@echo off @echo off
g++ $(source) icon.res -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lmingw32 -lSDL2main -lSDL2 -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" strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable).exe"
windows_debug: windows_debug:
@echo off @echo off
g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL2main -lSDL2 -o "$(executable)_debug.exe" g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL3 -lopengl32 -o "$(executable)_debug.exe"
macos: macos:
clang++ $(source) -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL2 -o "$(executable)" clang++ $(source) -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)"
macos_debug: macos_debug:
clang++ $(source) -D DEBUG -g -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL2 -o "$(executable)_debug" clang++ $(source) -D DEBUG -g -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)_debug"
macos_bundle: macos_bundle:
clang++ $(source) -D MACOS_BUNDLE -Wall -Os -std=c++11 -framework SDL2 -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: linux:
g++ $(source) -D LUA_USE_LINUX -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL2 -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)" strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable)"
linux_debug: linux_debug:
g++ $(source) -D LUA_USE_LINUX -D DEBUG -g -Wall -lSDL2 -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 title=TESTS
config=minitest config=minitests
width=160 width=400
height=120 height=300
zoom=3 zoom=2

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

View File

@@ -1,106 +1,45 @@
other = require "other" require "ia.other"
x=0 x=0
function mini.init() function mini.init()
text=other.peiv() s = surf.load("gfx/logo.gif")
keyRight = tonumber(config.getKey("keyright")) or key.RIGHT surf.source(s)
keyLeft = tonumber(config.getKey("keyleft")) or key.LEFT p = pal.load("gfx/logo.gif")
mini.update=normal_update pal.set(p)
--turbo(false) pal.trans(255)
local perico = "péricòñ" --surf.save(s, "prova.gif", p)
print(utf8.len(perico))
ants = 0xc936; print("=== PACKAGES LOADED ===")
s = surface.load("tiles01.gif") for name, value in pairs(package.loaded) do
--surface.source(s) print(name, value)
p = palette.load("tiles01.gif") end
palette.set(p) print("========================")
palette.setTransparent(255)
print(#p)
surface.save(s, "data/copy.gif")
s = surface.load("copy.gif")
--draw.source(s)
system.setBeat(4)
end end
function mini.update() function mini.update()
if keyboard.keyPressed(key.ESCAPE) then surf.cls(0)
system.quit() 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 end
if system.isBeat() then local mx, my = mouse.pos()
ants = (ants >> 12) | ((ants<<4)&0xffff) draw.rectf(mx, my, 4, 4, 8)
end draw.text(mx .. " " .. my, 1, 8, 8)
surface.cls(5) draw.text(other.peiv(),1,100,4)
draw.surface(s, 0, 0, 64, 64, 10, 10)
draw.rect(10, 10, 73, 73, 8)
draw.setPattern(ants)
draw.rect(10, 10, 73, 73, 0)
draw.setPattern(0xffff)
--draw.text(#p,0,0,2)
end end
function normal_update()
if keyboard.keyPressed(key.RIGHT) then x=x+1 end
if keyboard.keyPressed(key.LEFT) then x=x-1 end
if keyboard.keyPressed(key.SPACE) then
redefinekeys.init()
end
if keyboard.keyPressed(key.ESCAPE) then
system.quit()
end
if keyboard.keyPressed(key.F2) or mouse.buttonPressed(1) then
local val = window.getZoom() + 2
if val >= 10 then val = 2 end
window.setZoom(val)
elseif keyboard.keyPressed(key.F3) then
window.setFullscreen(not window.getFullscreen())
end
if x>160 then x=-utf8.len(text)*4 end
viewport.resetClipping()
viewport.setOrigin(0,0)
surface.cls(20)
viewport.setClipping(10,10,140,100)
surface.cls(3)
draw.text("HOLA",0,0,5)
viewport.setOrigin(-70,-50)
draw.text("ORÍGIN",0,0,5)
draw.text(text,x,10,5)
draw.circFill(20,20,10,15);
draw.setPattern(0x5a5a);
draw.circFill(20,20,10,10);
draw.setPattern(0xffff);
end
redefinekeys = {
state = 0,
init = function ()
redefinekeys.state=0
_update=redefinekeys.update
end,
update = function()
surface.cls(20)
if redefinekeys.state == 0 then
draw.text("PULSA TECLA PER A DRETA...",0,0,10)
local key = keyboard.keyPressed();
if key ~= 0 then
redefinekeys.state = 1
keyRight=key
config.setKey("keyright", keyRight)
end
elseif redefinekeys.state == 1 then
draw.text("PULSA TECLA PER A ESQUERRA...",0,0,10)
local key = keyboard.keyPressed();
if key ~= 0 then
keyLeft=key
config.setKey("keyleft", keyLeft)
_update=normal_update
end
end
end
}

View File

@@ -1,6 +0,0 @@
return {
peiv = function()
palette.setColor(1, 1, 1, 1)
return "HOLA OTHER UNIT"
end
}

View File

@@ -22,19 +22,12 @@ struct dictionary_entry_t
void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out ) void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out )
{ {
int i, bit;
int code, prev = -1;
dictionary_entry_t *dictionary; dictionary_entry_t *dictionary;
int dictionary_ind; int dictionary_ind;
uint32_t 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 ); const int clear_code = 1 << ( code_length );
stop_code = clear_code + 1; const int stop_code = clear_code + 1;
reset_code_length = code_length; const int reset_code_length = code_length;
dictionary = ( dictionary_entry_t * ) dictionary = ( dictionary_entry_t * )
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
@@ -47,12 +40,15 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
} }
dictionary_ind+=2; dictionary_ind+=2;
int prev = -1;
uint32_t mask = 0x01;
while ( input_length ) while ( input_length )
{ {
code = 0x0; int code = 0x0;
for (i=0; i<(code_length + 1); i++)
for (int i=0; i<(code_length + 1); i++)
{ {
bit = ( *input & mask ) ? 1 : 0; const int bit = ( *input & mask ) ? 1 : 0;
mask <<= 1; mask <<= 1;
if ( mask == 0x100 ) if ( mask == 0x100 )
@@ -90,18 +86,9 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
exit( 0 ); exit( 0 );
} }
if ( code == dictionary_ind ) int ptr = (code == dictionary_ind) ? prev : code;
{ while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
int ptr = prev; dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
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 ].prev = prev;
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1; dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
@@ -116,7 +103,7 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
prev = code; prev = code;
match_len = dictionary[ code ].len; const int match_len = dictionary[ code ].len;
while ( code != -1 ) while ( code != -1 )
{ {
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte; out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
@@ -197,8 +184,8 @@ static uint8_t* LoadGif(uint8_t *buffer, uint16_t* w, uint16_t* h)
rgb *global_color_table = NULL; rgb *global_color_table = NULL;
buffer += 6; // Ignore header buffer += 6; // Ignore header
*w = (uint16_t)*buffer; buffer+=2; *w = *((uint16_t*)buffer); buffer+=2;
*h = (uint16_t)*buffer; buffer+=2; *h = *((uint16_t*)buffer); buffer+=2;
const uint8_t fields = *buffer; buffer+=3; const uint8_t fields = *buffer; buffer+=3;
const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1; const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1;

332
gifenc.h
View File

@@ -3,226 +3,172 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#define MAX_DICT_SIZE 4096
namespace gif namespace gif
{ {
struct gif_t { typedef struct {
uint16_t w, h; int prefix;
int depth; uint8_t character;
int bgindex; } DictEntry;
FILE *fd;
int offset;
int nframes;
uint8_t *frame, *back;
uint32_t partial;
uint8_t buffer[0xFF];
};
struct node_t { typedef struct {
uint16_t key; uint8_t *data;
node_t *children[]; size_t size;
}; size_t capacity;
int bit_pos;
uint32_t bit_buffer;
} BitStream;
static node_t *new_node(uint16_t key, int degree) void bitstream_init(BitStream *bs) {
{ bs->capacity = 256;
node_t *node = (node_t*)calloc(1, sizeof(*node) + degree * sizeof(node_t *)); bs->size = 0;
if (node) node->key = key; bs->data = (uint8_t*)malloc(bs->capacity);
return node; bs->bit_pos = 0;
bs->bit_buffer = 0;
} }
static node_t *new_trie(int degree, int *nkeys) void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
{ bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
node_t *root = new_node(0, degree); bs->bit_pos += code_size;
/* Create nodes for single pixels. */
for (*nkeys = 0; *nkeys < degree; (*nkeys)++) root->children[*nkeys] = new_node(*nkeys, degree);
*nkeys += 2; /* skip clear code and stop code */
return root;
}
static void del_trie(node_t *root, int degree) while (bs->bit_pos >= 8) {
{ if (bs->size >= bs->capacity) {
if (!root) return; bs->capacity *= 2;
for (int i = 0; i < degree; i++) del_trie(root->children[i], degree); bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
free(root);
}
static void put_loop(gif_t *gif, uint16_t loop);
gif_t *create(const char *fname, uint16_t width, uint16_t height, uint8_t *palette, uint8_t depth, int16_t bgindex, int loop)
{
gif_t *gif = (gif_t*)calloc(1, sizeof(*gif) + (bgindex < 0 ? 2 : 1)*width*height);
gif->w = width; gif->h = height;
gif->bgindex = bgindex;
gif->frame = (uint8_t *) &gif[1];
gif->back = &gif->frame[width*height];
gif->fd = fopen(fname, "wb");
if (!gif->fd) { free(gif); return NULL; }
fwrite("GIF89a", 6, 1, gif->fd);
fwrite(&width, 2, 1, gif->fd);
fwrite(&height, 2, 1, gif->fd);
gif->depth = depth;
fputc((!palette?0x70:0xF0|(depth-1)), gif->fd);
fputc(bgindex, gif->fd); fputc(0, gif->fd);
if (palette) fwrite(palette, 3 << depth, 1, gif->fd);
if (loop >= 0 && loop <= 0xFFFF) put_loop(gif, (uint16_t)loop);
return gif;
}
static void put_loop(gif_t *gif, uint16_t loop)
{
fputc('!', gif->fd); fputc(0xFF, gif->fd); fputc(0x0B, gif->fd);
fwrite("NETSCAPE2.0", 11, 1, gif->fd);
fputc(0x03, gif->fd); fputc(0x01, gif->fd);
fwrite(&loop, 2, 1, gif->fd);
fputc(0, gif->fd);
}
/* Add packed key to buffer, updating offset and partial.
* gif->offset holds position to put next *bit*
* gif->partial holds bits to include in next byte */
static void put_key(gif_t *gif, uint16_t key, int key_size)
{
int byte_offset, bit_offset, bits_to_write;
byte_offset = gif->offset / 8;
bit_offset = gif->offset % 8;
gif->partial |= ((uint32_t) key) << bit_offset;
bits_to_write = bit_offset + key_size;
while (bits_to_write >= 8) {
gif->buffer[byte_offset++] = gif->partial & 0xFF;
if (byte_offset == 0xFF) {
fputc(0xFF, gif->fd);
fwrite(gif->buffer, 0xFF, 1, gif->fd);
byte_offset = 0;
} }
gif->partial >>= 8; bs->data[bs->size++] = bs->bit_buffer & 0xFF;
bits_to_write -= 8; bs->bit_buffer >>= 8;
bs->bit_pos -= 8;
} }
gif->offset = (gif->offset + key_size) % (0xFF * 8);
} }
static void end_key(gif_t *gif) void bitstream_flush(BitStream *bs) {
{ if (bs->bit_pos > 0) {
uint8_t byte_offset; if (bs->size >= bs->capacity) {
byte_offset = gif->offset >> 3; bs->capacity *= 2;
if (gif->offset & 0x07) gif->buffer[byte_offset++] = gif->partial & 0xFF; bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
if (byte_offset) }
{ bs->data[bs->size++] = bs->bit_buffer & 0xFF;
fputc(byte_offset, gif->fd);
fwrite(gif->buffer, byte_offset, 1, gif->fd);
} }
fputc(0, gif->fd);
gif->offset = gif->partial = 0;
} }
static void put_image(gif_t *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y) 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 nkeys, key_size, i, j; int end_code = clear_code + 1;
node_t *node, *child, *root; int next_code = end_code + 1;
int degree = 1 << gif->depth; int code_size = min_code_size + 1;
fputc(',', gif->fd); DictEntry dict[MAX_DICT_SIZE];
fwrite(&x, 2, 1, gif->fd); int dict_len = next_code;
fwrite(&y, 2, 1, gif->fd);
fwrite(&w, 2, 1, gif->fd); BitStream bs;
fwrite(&h, 2, 1, gif->fd); bitstream_init(&bs);
fputc(0, gif->fd); fputc(gif->depth, gif->fd); bitstream_write(&bs, clear_code, code_size);
root = node = new_trie(degree, &nkeys);
key_size = gif->depth + 1; int prefix = input[0];
put_key(gif, degree, key_size); /* clear code */ for (int i = 1; i < width * height; i++) {
for (i = y; i < y+h; i++) { uint8_t c = input[i];
for (j = x; j < x+w; j++) {
uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1); // Search for prefix + c in dictionary
child = node->children[pixel]; int found = -1;
if (child) { for (int j = end_code + 1; j < dict_len; j++) {
node = child; 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 { } else {
put_key(gif, node->key, key_size); bitstream_write(&bs, clear_code, code_size);
if (nkeys < 0x1000) { dict_len = end_code + 1;
if (nkeys == (1 << key_size)) code_size = min_code_size + 1;
key_size++;
node->children[pixel] = new_node(nkeys++, degree);
} else {
put_key(gif, degree, key_size); /* clear code */
del_trie(root, degree);
root = node = new_trie(degree, &nkeys);
key_size = gif->depth + 1;
}
node = root->children[pixel];
} }
prefix = c; // Start new prefix
} }
} }
put_key(gif, node->key, key_size);
put_key(gif, degree + 1, key_size); /* stop code */ // Emit final prefix and end code
end_key(gif); bitstream_write(&bs, prefix, code_size);
del_trie(root, degree); bitstream_write(&bs, end_code, code_size);
bitstream_flush(&bs);
*out_size = bs.size;
return bs.data;
} }
static int get_bbox(gif_t *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y) void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
{ FILE *f = fopen(filename, "wb");
int i, j, k; if (!f) {
int left, right, top, bottom; perror("Failed to open file");
uint8_t back; return;
left = gif->w; right = 0;
top = gif->h; bottom = 0;
k = 0;
for (i = 0; i < gif->h; i++) {
for (j = 0; j < gif->w; j++, k++) {
back = gif->bgindex >= 0 ? gif->bgindex : gif->back[k];
if (gif->frame[k] != back) {
if (j < left) left = j;
if (j > right) right = j;
if (i < top) top = i;
if (i > bottom) bottom = i;
}
}
} }
if (left != gif->w && top != gif->h) {
*x = left; *y = top; // Header
*w = right - left + 1; fwrite("GIF89a", 1, 6, f);
*h = bottom - top + 1;
return 1; // Determine min_code_size from palette_size
} else { int palette_depth = 0;
return 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);
} }
}
static void add_graphics_control_extension(gif_t *gif, uint16_t d) // Image Descriptor
{ uint8_t image_desc[] = {
uint8_t flags = ((gif->bgindex >= 0 ? 2 : 1) << 2) + 1; 0x2C, 0, 0, 0, 0,
fputc('!', gif->fd); fputc(0xF9, gif->fd); fputc(0x04, gif->fd); fputc(flags, gif->fd); uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
fwrite(&d, 2, 1, gif->fd); uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
fputc(gif->bgindex, gif->fd); fputc(0, gif->fd); 0x00 // No local color table
} };
fwrite(image_desc, 1, sizeof(image_desc), f);
void addFrame(gif_t *gif, uint16_t delay) // LZW-compressed image data
{ fwrite(&min_code_size, 1, 1, f);
uint16_t w, h, x, y;
uint8_t *tmp;
if (delay || (gif->bgindex >= 0)) size_t compressed_size;
add_graphics_control_extension(gif, delay); uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
if (gif->nframes == 0) {
w = gif->w; // Write as sub-blocks
h = gif->h; size_t offset = 0;
x = y = 0; while (offset < compressed_size) {
} else if (!get_bbox(gif, &w, &h, &x, &y)) { uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
/* image's not changed; save one pixel just to add delay */ fwrite(&block_size, 1, 1, f);
w = h = 1; fwrite(compressed + offset, 1, block_size, f);
x = y = 0; offset += block_size;
} }
put_image(gif, w, h, x, y); fputc(0x00, f); // Block terminator
gif->nframes++;
if (gif->bgindex < 0) {
tmp = gif->back;
gif->back = gif->frame;
gif->frame = tmp;
}
}
void close(gif_t* gif) // Trailer
{ fputc(0x3B, f);
fputc(';', gif->fd);
fclose(gif->fd);
free(gif);
}
free(compressed);
fclose(f);
}
} }

View File

@@ -1,47 +1,61 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include "stb_vorbis.c" #include "stb_vorbis.h"
#include <SDL2/SDL.h> #include <SDL3/SDL.h>
#include <stdio.h> #include <stdio.h>
#include "log.h"
#define JA_MAX_SIMULTANEOUS_CHANNELS 5 #define JA_MAX_SIMULTANEOUS_CHANNELS 5
struct JA_Sound_t { struct JA_Sound_t
Uint32 length {0}; {
Uint8* buffer {NULL}; SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
Uint32 length { 0 };
Uint8 *buffer { NULL };
}; };
struct JA_Channel_t { struct JA_Channel_t
JA_Sound_t *sound; {
int pos {0}; JA_Sound_t *sound { nullptr };
int times {0}; int pos { 0 };
JA_Channel_state state { JA_CHANNEL_FREE }; int times { 0 };
SDL_AudioStream *stream { nullptr };
JA_Channel_state state { JA_CHANNEL_FREE };
}; };
struct JA_Music_t { struct JA_Music_t
int samples {0}; {
int pos {0}; SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
int times {0}; Uint32 length { 0 };
short* output {NULL}; Uint8 *buffer { nullptr };
JA_Music_state state {JA_MUSIC_INVALID};
int pos { 0 };
int times { 0 };
SDL_AudioStream *stream { nullptr };
JA_Music_state state { JA_MUSIC_INVALID };
}; };
JA_Music_t *current_music{NULL}; JA_Music_t *current_music { nullptr };
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
int JA_freq {48000}; SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 };
SDL_AudioFormat JA_format {AUDIO_S16}; float JA_musicVolume { 1.0f };
Uint8 JA_channels {2}; float JA_soundVolume { 0.5f };
int JA_musicVolume = 128; bool JA_musicEnabled { true };
int JA_soundVolume = 64; bool JA_soundEnabled { true };
bool JA_musicEnabled = true; SDL_AudioDeviceID sdlAudioDevice { 0 };
bool JA_soundEnabled = true; SDL_TimerID JA_timerID { 0 };
SDL_AudioDeviceID sdlAudioDevice = 0;
bool fading = false;
int fade_start_time;
int fade_duration;
int fade_initial_volume;
/*
void audioCallback(void * userdata, uint8_t * stream, int len) { void audioCallback(void * userdata, uint8_t * stream, int len) {
SDL_memset(stream, 0, len); SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) { if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
const int size = SDL_min(len, (current_music->samples-current_music->pos)*2); 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); SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, JA_musicVolume);
current_music->pos += size/2; current_music->pos += size/2;
if (size < len) { if (size < len) {
@@ -73,56 +87,100 @@ void audioCallback(void * userdata, uint8_t * stream, int len) {
} }
} }
} }
*/
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) void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{ {
#ifdef DEBUG #ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif #endif
SDL_Log("Iniciant JailAudio..."); JA_audioSpec = {format, channels, freq };
JA_freq = freq; if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
JA_format = format; sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
JA_channels = channels; if (!sdlAudioDevice) {
SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError());
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
if (sdlAudioDevice==0)
{
SDL_Log("FAILED!\n");
SDL_Log("Failed to initialize SDL audio!\n");
} else { } else {
SDL_Log("OK!\n"); log_msg(LOG_OK, "Audio subsytem initialized\n");
} }
SDL_PauseAudioDevice(sdlAudioDevice, 0); //SDL_PauseAudioDevice(sdlAudioDevice);
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
} }
void JA_Quit() { void JA_Quit()
SDL_PauseAudioDevice(sdlAudioDevice, 1); {
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice); if (JA_timerID) SDL_RemoveTimer(JA_timerID);
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length) JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
{ {
int chan, samplerate;
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output); int chan, samplerate;
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert short *output;
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output); music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
SDL_AudioCVT cvt; music->spec.channels = chan;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); music->spec.freq = samplerate;
SDL_Log("Music length: %f\n", float(music->samples)/float(JA_freq)); music->spec.format = SDL_AUDIO_S16;
if (cvt.needed) { music->buffer = (Uint8*)SDL_malloc(music->length);
cvt.len = music->samples * chan * 2; SDL_memcpy(music->buffer, output, music->length);
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult); free(output);
SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt);
free(music->output);
music->output = (short*)cvt.buf;
}
music->pos = 0; music->pos = 0;
music->state = JA_MUSIC_STOPPED; music->state = JA_MUSIC_STOPPED;
@@ -151,122 +209,133 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (current_music != NULL) { JA_StopMusic();
current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED;
}
current_music = music; current_music = music;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
current_music->times = loop; 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() void JA_PauseMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
//SDL_PauseAudioStreamDevice(current_music->stream);
SDL_UnbindAudioStream(current_music->stream);
} }
void JA_ResumeMusic() void JA_ResumeMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
//SDL_ResumeAudioStreamDevice(current_music->stream);
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
} }
void JA_StopMusic() void JA_StopMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
//SDL_PauseAudioStreamDevice(current_music->stream);
SDL_DestroyAudioStream(current_music->stream);
current_music->stream = nullptr;
} }
JA_Music_state JA_GetMusicState() { void JA_FadeOutMusic(const int milliseconds)
if (!JA_musicEnabled) return JA_MUSIC_DISABLED; {
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;
if (current_music == NULL) return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) { void JA_DeleteMusic(JA_Music_t *music)
if (current_music == music) current_music = NULL; {
free(music->output); if (current_music == music) current_music = nullptr;
SDL_free(music->buffer);
if (music->stream) SDL_DestroyAudioStream(music->stream);
delete music; delete music;
} }
int JA_SetMusicVolume(int volume) float JA_SetMusicVolume(float volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f );
if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value) void JA_SetMusicPosition(float value)
{ {
if (!current_music) return; if (!current_music) return;
current_music->pos = value * JA_freq; current_music->pos = value * current_music->spec.freq;
} }
float JA_GetMusicPosition() float JA_GetMusicPosition()
{ {
if (!current_music) return 0; if (!current_music) return 0;
return float(current_music->pos)/float(JA_freq); return float(current_music->pos)/float(current_music->spec.freq);
} }
void JA_EnableMusic(const bool value) void JA_EnableMusic(const bool value)
{ {
if (!value && current_music != NULL && current_music->state==JA_MUSIC_PLAYING) JA_StopMusic(); if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
const bool JA_IsMusicEnabled()
{
return JA_musicEnabled;
}
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length)
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) { {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) { JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size)
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length);
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size),1, &wavSpec, &sound->buffer, &sound->length);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char* filename) { JA_Sound_t *JA_LoadSound(const char* filename)
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
return sound; return sound;
} }
@@ -278,11 +347,36 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0; if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
JA_StopChannel(channel);
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING; 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; return channel;
} }
@@ -299,12 +393,24 @@ void JA_PauseChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled) return;
if (channel == -1) { 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; 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);
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED;
} }
} }
@@ -312,12 +418,24 @@ void JA_ResumeChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled) return;
if (channel == -1) { 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; 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);
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING;
} }
} }
@@ -325,13 +443,20 @@ void JA_StopChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled) return;
if (channel == -1) { if (channel == -1)
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { 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].state = JA_CHANNEL_FREE;
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { }
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].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].sound = NULL; channels[channel].sound = NULL;
@@ -343,12 +468,18 @@ JA_Channel_state JA_GetChannelState(const int channel)
if (!JA_soundEnabled) return JA_SOUND_DISABLED; if (!JA_soundEnabled) return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
int JA_SetSoundVolume(int volume) float JA_SetSoundVolume(float volume)
{ {
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : 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; return JA_soundVolume;
} }
@@ -361,10 +492,15 @@ void JA_EnableSound(const bool value)
JA_soundEnabled = value; JA_soundEnabled = value;
} }
int JA_SetVolume(int volume) const bool JA_IsSoundEnabled()
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; return JA_soundEnabled;
JA_soundVolume = JA_musicVolume/2; }
float JA_SetVolume(float volume)
{
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
return JA_musicVolume; return JA_musicVolume;
} }

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include <SDL2/SDL.h> #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_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 }; enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
@@ -16,23 +16,27 @@ void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
void JA_PauseMusic(); void JA_PauseMusic();
void JA_ResumeMusic(); void JA_ResumeMusic();
void JA_StopMusic(); void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState(); JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music); void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume); float JA_SetMusicVolume(float volume);
void JA_SetMusicPosition(float value); void JA_SetMusicPosition(float value);
float JA_GetMusicPosition(); float JA_GetMusicPosition();
void JA_EnableMusic(const bool value); void JA_EnableMusic(const bool value);
const bool JA_IsMusicEnabled();
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length); JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length); JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char* filename); JA_Sound_t *JA_LoadSound(const char* filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0); 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_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel); void JA_ResumeChannel(const int channel);
void JA_StopChannel(const int channel); void JA_StopChannel(const int channel);
JA_Channel_state JA_GetChannelState(const int channel); JA_Channel_state JA_GetChannelState(const int channel);
void JA_DeleteSound(JA_Sound_t *sound); void JA_DeleteSound(JA_Sound_t *sound);
int JA_SetSoundVolume(int volume); float JA_SetSoundVolume(float volume);
void JA_EnableSound(const bool value); void JA_EnableSound(const bool value);
const bool JA_IsSoundEnabled();
int JA_SetVolume(int volume); float JA_SetVolume(float volume);

157
jfile.cpp
View File

@@ -9,7 +9,9 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <string> #include <string>
#include <vector>
#include <algorithm>
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
#ifndef _WIN32 #ifndef _WIN32
#include <pwd.h> #include <pwd.h>
@@ -130,10 +132,30 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
return f; 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); 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); 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); fclose(f);
return buffer; return buffer;
} }
@@ -151,6 +173,29 @@ void file_setconfigfolder(const char *foldername)
struct passwd *pw = getpwuid(getuid()); struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir; const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/." + foldername; 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 #endif
struct stat st = {0}; struct stat st = {0};
@@ -171,7 +216,7 @@ void file_setconfigfolder(const char *foldername)
} }
const char *file_getconfigfolder() { const char *file_getconfigfolder() {
std::string folder = config_folder + "/"; static std::string folder = config_folder + "/";
return folder.c_str(); return folder.c_str();
} }
@@ -228,3 +273,107 @@ void file_setconfigvalue(const char* key, const char* value) {
file_saveconfigvalues(); file_saveconfigvalues();
return; 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;
}

10
jfile.h
View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <stdio.h> #include <stdio.h>
#include <vector>
#include <string>
#define SOURCE_FILE 0 #define SOURCE_FILE 0
#define SOURCE_FOLDER 1 #define SOURCE_FOLDER 1
@@ -12,7 +14,13 @@ void file_setresourcefolder(const char *str);
void file_setsource(const int src); void file_setsource(const int src);
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false); 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); const char* file_getconfigvalue(const char *key);
void file_setconfigvalue(const char* key, const char* value); 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

953
lua.cpp

File diff suppressed because it is too large Load Diff

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) { 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_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */ lua_getfield(L, 2, name); /* LOADED[name] */

563
mini.cpp
View File

@@ -2,12 +2,14 @@
#include "jfile.h" #include "jfile.h"
#include <string.h> #include <string.h>
#include "lua.h" #include "lua.h"
#include "gif.c" #include "gif.h"
#include "gifenc.h" #include "gifenc.h"
//#include "SDL2/SDL_mixer.h"
#include "jail_audio.h" #include "jail_audio.h"
#include "jshader.h"
//#include <vector>
#include "log.h"
#define MAX_TEXTURES 10 #define MAX_SURFACES 100
#ifdef MACOS_BUNDLE #ifdef MACOS_BUNDLE
#include <libgen.h> #include <libgen.h>
@@ -18,12 +20,22 @@
#pragma pack(1) #pragma pack(1)
struct surface_t { struct surface_t {
uint8_t *p; char *name {nullptr};
uint8_t *p {nullptr};
uint16_t w, h; uint16_t w, h;
uint32_t size; uint32_t size;
}; };
struct font_t {
struct special_char_t { uint8_t character; SDL_Rect glyph; SDL_Point displacement; };
int8_t spacing;
SDL_Rect characters[96];
special_char_t specials[64];
};
int fps=0;
int fps_counter=0;
uint32_t fps_timer=0;
char window_title[256]; char window_title[256];
char config_folder[256]; char config_folder[256];
uint16_t screen_width = 160; uint16_t screen_width = 160;
@@ -35,7 +47,7 @@ bool screen_cursor = true;
int desktop_width = 0; int desktop_width = 0;
int desktop_height = 0; int desktop_height = 0;
surface_t surfaces[MAX_TEXTURES]; surface_t surfaces[MAX_SURFACES];
surface_t *screen_surface = &surfaces[0]; surface_t *screen_surface = &surfaces[0];
surface_t *dest_surface = screen_surface; surface_t *dest_surface = screen_surface;
surface_t *source_surface = NULL; surface_t *source_surface = NULL;
@@ -66,6 +78,7 @@ namespace ds {
uint16_t fill_pattern = 0b1111111111111111; uint16_t fill_pattern = 0b1111111111111111;
bool fill_trans = false; bool fill_trans = false;
uint8_t draw_palette[256]; uint8_t draw_palette[256];
uint8_t mode = DRAWMODE_NORMAL;
} }
int update_mode = UPDATE_ALWAYS; int update_mode = UPDATE_ALWAYS;
@@ -76,12 +89,13 @@ bool should_quit = false;
SDL_Window *mini_win; SDL_Window *mini_win;
SDL_Renderer *mini_ren; SDL_Renderer *mini_ren;
SDL_Texture *mini_bak; SDL_Texture *mini_bak;
SDL_Texture *mini_shadertex;
Uint32 windowID; Uint32 windowID;
Uint32 *pixels; Uint32 *pixels;
int pitch; int pitch;
uint32_t palette[256] = { 0x001a1c2c, 0x005d275d, 0x00b13e53, 0x00ef7d57, 0x00ffcd75, 0x00a7f070, 0x0038b764, 0x00257179, uint32_t palette[256] = { 0xFF1a1c2c, 0xFF5d275d, 0xFFb13e53, 0xFFef7d57, 0xFFffcd75, 0xFFa7f070, 0xFF38b764, 0xFF257179,
0x0029366f, 0x003b5dc9, 0x0041a6f6, 0x0073eff7, 0x00f4f4f4, 0x0094b0c2, 0x00566c86, 0x00333c57 }; 0xFF29366f, 0xFF3b5dc9, 0xFF41a6f6, 0xFF73eff7, 0xFFf4f4f4, 0xFF94b0c2, 0xFF566c86, 0xFF333c57 };
const char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -93,15 +107,17 @@ char base64glyphs[193] = "/h/AqV/hhhh/GMYYMGz/t/eS33H477wsjjswY4IOPHEFFVVVAVAVAV
"AMShAAAQsjAAAwsjAAAeSzAAAcU3AAAEqRAAABVaiAAMezhAAAAAMAADH4wAASb2SAAMAttAQYcefACGOe+AAAVVAAAAbbAA"; "AMShAAAQsjAAAwsjAAAeSzAAAcU3AAAEqRAAABVaiAAMezhAAAAAMAADH4wAASb2SAAMAttAQYcefACGOe+AAAVVAAAAbbAA";
//Uint8 keymapping[6] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_Z, SDL_SCANCODE_X }; //Uint8 keymapping[6] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_Z, SDL_SCANCODE_X };
const Uint8 *keys; const bool *keys;
Uint8 key_just_pressed = 0; Uint8 key_just_pressed = 0;
int mouse_x, mouse_y, mouse_wheel; int mouse_x, mouse_y, mouse_wheel;
Uint32 mouse_buttons; Uint32 mouse_buttons;
uint8_t mouse_just_pressed = 0; uint8_t mouse_just_pressed = 0;
bool double_click = false;
bool mouse_discard = false;
SDL_GameController *gamepad = NULL; SDL_Gamepad *gamepad = NULL;
int8_t pad_just_pressed = SDL_CONTROLLER_BUTTON_INVALID; int8_t pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
#define MAX_SOUNDS 50 #define MAX_SOUNDS 50
JA_Music_t *music = NULL; JA_Music_t *music = NULL;
@@ -109,6 +125,8 @@ JA_Sound_t *sounds[MAX_SOUNDS];
int16_t beats, num_beats = 0; int16_t beats, num_beats = 0;
void createNewProject();
char* get_value_from_line(char* line) { char* get_value_from_line(char* line) {
char* equal_character = strchr(line, '='); char* equal_character = strchr(line, '=');
if (equal_character == NULL) return NULL; if (equal_character == NULL) return NULL;
@@ -118,21 +136,20 @@ char* get_value_from_line(char* line) {
void read_ini() { void read_ini() {
int size; int size;
SDL_Log("Carregant 'game.ini'...");
FILE *f = file_getfilepointer("game.ini", size); // fopen("game.ini", "r"); FILE *f = file_getfilepointer("game.ini", size); // fopen("game.ini", "r");
char line[1024]; char line[1024];
if (f == NULL) { SDL_Log("FAIL!\n"); return; } if (f == NULL) { log_msg(LOG_FAIL, "No s'ha pogut obrir 'game.ini'\n"); exit(-1); }
SDL_Log("OK!\n"); log_msg(LOG_OK, "'game.ini' carregat\n");
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
char *value = get_value_from_line(line); char *value = get_value_from_line(line);
if (value != NULL) { if (value != NULL) {
value[strlen(value)-1] = '\0'; value[strlen(value)-1] = '\0';
if (strcmp(line, "title") == 0) { strcpy(window_title, value); SDL_Log("-title=%s\n", window_title); } if (strcmp(line, "title") == 0) { strcpy(window_title, value); log_msg(LOG_VERBOSE, "title = %s\n", window_title); }
else if (strcmp(line, "config") == 0) { strcpy(config_folder, value); SDL_Log("-config=%s\n", config_folder); } else if (strcmp(line, "config") == 0) { strcpy(config_folder, value); log_msg(LOG_VERBOSE, "config = %s\n", config_folder); }
else if (strcmp(line, "width") == 0) { screen_width = atoi(value); SDL_Log("-screen width=%i\n", screen_width); } else if (strcmp(line, "width") == 0) { screen_width = atoi(value); log_msg(LOG_VERBOSE, "screen width = %i\n", screen_width); }
else if (strcmp(line, "height") == 0) { screen_height = atoi(value); SDL_Log("-screen height=%i\n", screen_height); } else if (strcmp(line, "height") == 0) { screen_height = atoi(value); log_msg(LOG_VERBOSE, "screen height = %i\n", screen_height); }
else if (strcmp(line, "zoom") == 0) { screen_zoom = atoi(value); SDL_Log("-screen zoom=%i\n", screen_zoom); } else if (strcmp(line, "zoom") == 0) { screen_zoom = atoi(value); log_msg(LOG_VERBOSE, "screen zoom = %i\n", screen_zoom); }
else if (strcmp(line, "fullscreen") == 0) { screen_fullscreen = atoi(value); SDL_Log("-screen sullscreen=%i\n", screen_fullscreen); } else if (strcmp(line, "fullscreen") == 0) { screen_fullscreen = atoi(value); log_msg(LOG_VERBOSE, "screen sullscreen = %i\n", screen_fullscreen); }
//else if (strcmp(line, "files") == 0) { //else if (strcmp(line, "files") == 0) {
//lua_files = (char*)malloc(strlen(value)); //lua_files = (char*)malloc(strlen(value));
// strcpy(lua_files, value); // strcpy(lua_files, value);
@@ -140,13 +157,32 @@ void read_ini() {
} }
} }
fclose(f); fclose(f);
SDL_Log("'game.ini' carregat!\n"); //SDL_Log("'game.ini' carregat!\n");
} }
void pset_fast(int x, int y) { void pset_fast(int x, int y) {
if (ds::trans != ds::pen_color) DEST(x, y) = ds::draw_palette[ds::pen_color]; if (ds::trans != ds::pen_color) DEST(x, y) = ds::draw_palette[ds::pen_color];
} }
void pset_bool(int x, int y) {
if (ds::trans != ds::pen_color) {
switch (ds::mode) {
case DRAWMODE_AND:
DEST(x, y) = DEST(x, y) & ds::draw_palette[ds::pen_color];
break;
case DRAWMODE_OR:
DEST(x, y) = DEST(x, y) | ds::draw_palette[ds::pen_color];
break;
case DRAWMODE_XOR:
DEST(x, y) = DEST(x, y) ^ ds::draw_palette[ds::pen_color];
break;
case DRAWMODE_NOT:
DEST(x, y) = ~DEST(x, y);
break;
}
}
}
void pset_pattern(int x, int y) { void pset_pattern(int x, int y) {
int pbx = x % 4, pby = y % 4; int pbx = x % 4, pby = y % 4;
int pb = pbx+pby*4; int pb = pbx+pby*4;
@@ -157,8 +193,29 @@ void pset_pattern(int x, int y) {
} }
} }
void set_draw_mode(uint8_t mode) {
ds::mode = mode;
switch (mode) {
case DRAWMODE_NORMAL:
do_pset = pset_fast;
break;
case DRAWMODE_PATTERN:
do_pset = pset_pattern;
break;
case DRAWMODE_AND:
case DRAWMODE_OR:
case DRAWMODE_XOR:
case DRAWMODE_NOT:
do_pset = pset_bool;
break;
default:
do_pset = pset_fast;
break;
}
}
void reinit() { void reinit() {
SDL_Log("REINIT\n"); log_msg(LOG_INFO, "STARTING A SYSTEM REINITIALIZATION\n");
do_pset = pset_fast; do_pset = pset_fast;
ds::pen_color = 6; ds::pen_color = 6;
ds::back_color = 0; ds::back_color = 0;
@@ -168,17 +225,23 @@ void reinit() {
ds::trans=0; ds::trans=0;
ds::fill_pattern = 0b1111111111111111; ds::fill_pattern = 0b1111111111111111;
ds::fill_trans = false; ds::fill_trans = false;
for (int i=1; i<MAX_TEXTURES; ++i) { for (unsigned int i=1; i<MAX_SURFACES; ++i) freesurf(i);
/*{
if (surfaces[i].p != NULL) free(surfaces[i].p); if (surfaces[i].p != NULL) free(surfaces[i].p);
surfaces[i].p = NULL; surfaces[i].p = NULL;
if (surfaces[i].name != NULL) free(surfaces[i].name);
surfaces[i].name = NULL;
} }
surfaces.clear();*/
dest_surface = screen_surface;
for (int i=0;i<256;++i) ds::draw_palette[i]=i; for (int i=0;i<256;++i) ds::draw_palette[i]=i;
if (file!=NULL) fclose(file); if (file!=NULL) fclose(file);
file = NULL; file = NULL;
} }
void initaudio() { void initaudio() {
JA_Init(48000, AUDIO_S16, 1); JA_Init(48000, SDL_AUDIO_S16, 1);
for (int i=0;i<MAX_SOUNDS;++i) sounds[i] = NULL; for (int i=0;i<MAX_SOUNDS;++i) sounds[i] = NULL;
} }
@@ -197,42 +260,69 @@ int scrh() {
} }
uint8_t newsurf(int w, int h) { uint8_t newsurf(int w, int h) {
int i = 0; unsigned int i = 0;
while (i<MAX_TEXTURES && surfaces[i].p != NULL) ++i; while (i<MAX_SURFACES && surfaces[i].p != NULL) ++i;
//[TODO] Gestionar el cas en que no queden surfaces lliures if (i==MAX_SURFACES) return 255;
surfaces[i].name = nullptr;
surfaces[i].w = w; surfaces[i].w = w;
surfaces[i].h = h; surfaces[i].h = h;
surfaces[i].size = w*h; surfaces[i].size = w*h;
surfaces[i].p = (uint8_t*)malloc(surfaces[i].size); surfaces[i].p = (uint8_t*)calloc(surfaces[i].size,1);
log_msg(LOG_INFO, "Surface %i creada.\n", i);
return i; return i;
} }
uint8_t loadsurf(const char* filename) { uint8_t loadsurf(const char* filename, const bool external) {
int i = 0; // Si el gif ja s'ha carregat en una textura, tornem eixa textura
while (i<MAX_TEXTURES && surfaces[i].p != NULL) ++i; for (unsigned int i=0; i<MAX_SURFACES; ++i)
//[TODO] Gestionar el cas en que no queden surfaces lliures if (surfaces[i].name && strcmp(surfaces[i].name, filename)==0) {
log_msg(LOG_INFO, "Carrega de '%s' abortada: Reusant: %i.\n", filename, i);
return i;
}
// Agafar la pròxima textura lliure
unsigned int i = 0;
while (i<MAX_SURFACES && surfaces[i].p != NULL) ++i;
if (i==MAX_SURFACES) return 255;
// Carregar l'arxiu de disc
int size; int size;
uint8_t *buffer = (uint8_t*)file_getfilebuffer(filename, size); uint8_t *buffer;
if (external) {
buffer = (uint8_t*)file_getfilebufferex(filename, size);
} else {
buffer = (uint8_t*)file_getfilebuffer(filename, size);
}
// Si no s'ha pogut, petar
if (!buffer) {
log_msg(LOG_FAIL, "Error al intentar obrir l'arxiu '%s'\n", filename);
exit(-1);
return 255;
}
surfaces[i].p = LoadGif(buffer, &surfaces[i].w, &surfaces[i].h); surfaces[i].p = LoadGif(buffer, &surfaces[i].w, &surfaces[i].h);
surfaces[i].size = surfaces[i].w*surfaces[i].h; surfaces[i].size = surfaces[i].w*surfaces[i].h;
surfaces[i].name = (char*)malloc(strlen(filename)+1);
strcpy(surfaces[i].name, filename);
free(buffer); free(buffer);
log_msg(LOG_INFO, "Arxiu '%s' carregat en surface: %i.\n", filename, i);
return i; return i;
} }
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors) void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors)
{ {
uint8_t depth=colors; gif::write_gif(filename, surfaces[surface].p, surfaces[surface].w, surfaces[surface].h, pal, colors);
do { depth = depth >> 1; } while (depth!=0);
gif::gif_t *file = gif::create(filename, surfaces[surface].w, surfaces[surface].h, pal, (pal?depth:0), -1, -1);
memcpy(file->frame, surfaces[surface].p, surfaces[surface].w*surfaces[surface].h);
gif::addFrame(file, 0);
gif::close(file);
} }
void freesurf(uint8_t surface) { void freesurf(uint8_t surface) {
if (surfaces[surface].p != NULL) free(surfaces[surface].p); if (surfaces[surface].name != NULL) free(surfaces[surface].name);
surfaces[surface].name = NULL;
if (surfaces[surface].p != NULL) {
free(surfaces[surface].p);
log_msg(LOG_INFO, "Surface %i alliberada.\n", surface);
}
surfaces[surface].p = NULL; surfaces[surface].p = NULL;
} }
@@ -246,7 +336,10 @@ int surfh(uint8_t surface) {
void recalculate_clip() void recalculate_clip()
{ {
ds::clip[0] = ds::clp[0]; ds::clip[1] = ds::clp[1]; ds::clip[2] = ds::clp[2]-ds::clp[0]-1; ds::clip[3] = ds::clp[3]-ds::clp[1]-1; ds::clip[0] = ds::clp[0];
ds::clip[1] = ds::clp[1];
ds::clip[2] = ds::clp[2]+ds::clp[0]-1;
ds::clip[3] = ds::clp[3]+ds::clp[1]-1;
if (ds::clip[0]<0) ds::clip[0]=0; if (ds::clip[0]<0) ds::clip[0]=0;
if (ds::clip[1]<0) ds::clip[1]=0; if (ds::clip[1]<0) ds::clip[1]=0;
if (ds::clip[2]>=dest_surface->w) ds::clip[2]=dest_surface->w-1; if (ds::clip[2]>=dest_surface->w) ds::clip[2]=dest_surface->w-1;
@@ -266,24 +359,64 @@ void setmap(uint8_t surface) {
map_surface = &surfaces[surface]; map_surface = &surfaces[surface];
} }
uint8_t getmap() uint8_t getdest()
{ {
for (int i=0; i<MAX_TEXTURES; ++i) if (map_surface == &surfaces[i]) return i; for (unsigned int i=0; i<MAX_SURFACES; ++i) if (dest_surface == &surfaces[i]) return i;
return 0; return 0;
} }
uint8_t getsource()
{
for (unsigned int i=0; i<MAX_SURFACES; ++i) if (source_surface == &surfaces[i]) return i;
return 0;
}
uint8_t getmap()
{
for (unsigned int i=0; i<MAX_SURFACES; ++i) if (map_surface == &surfaces[i]) return i;
return 0;
}
void shader_init(const char* vshader, const char* fshader)
{
int filesize;
char *vshaderfile = file_getfilebuffer(vshader, filesize, true);
char *fshaderfile = nullptr;
if (fshader) { fshaderfile = file_getfilebuffer(fshader, filesize, true); }
shader::init(mini_win, mini_shadertex, vshaderfile, fshaderfile);
}
void shader_enable() { shader::enable(); }
void shader_disable() { shader::disable(); }
void createDisplay() { void createDisplay() {
if (screen_zoom <= 0) screen_zoom = 1; if (screen_zoom <= 0) screen_zoom = 1;
while (screen_width*screen_zoom > desktop_width || screen_height*screen_zoom > desktop_height) screen_zoom--; while (screen_width*screen_zoom > desktop_width || screen_height*screen_zoom > desktop_height) screen_zoom--;
mini_win = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width*screen_zoom, screen_height*screen_zoom, screen_fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:SDL_WINDOW_RESIZABLE); mini_win = SDL_CreateWindow(window_title, screen_width*screen_zoom, screen_height*screen_zoom, SDL_WINDOW_OPENGL|(screen_fullscreen?SDL_WINDOW_FULLSCREEN:0));
windowID = SDL_GetWindowID(mini_win); windowID = SDL_GetWindowID(mini_win);
mini_ren = SDL_CreateRenderer(mini_win, -1, 0); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
mini_ren = SDL_CreateRenderer(mini_win, NULL);
//SDL_CreateWindowAndRenderer(512,512,0,&mini_win,&mini_ren); //SDL_CreateWindowAndRenderer(512,512,0,&mini_win,&mini_ren);
SDL_RenderSetLogicalSize(mini_ren, screen_width, screen_height); //SDL_SetRenderLogicalPresentation(mini_ren, screen_width, screen_height);
SDL_ShowCursor(screen_cursor?SDL_ENABLE:SDL_DISABLE); if (screen_cursor) SDL_ShowCursor(); else SDL_HideCursor();
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height); mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height);
SDL_SetTextureScaleMode(mini_bak, SDL_SCALEMODE_NEAREST);
SDL_PropertiesID props = SDL_GetTextureProperties(mini_bak);
int real_pixelformat = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_FORMAT_NUMBER, -1);
if (real_pixelformat != SDL_PIXELFORMAT_ARGB8888) {
log_msg(LOG_FAIL, "Pixelformat incorrecte: %i\n", real_pixelformat);
exit(1);
}
mini_shadertex = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, screen_width*screen_zoom, screen_height*screen_zoom);
SDL_SetTextureScaleMode(mini_shadertex, SDL_SCALEMODE_NEAREST);
//int filesize;
//char *shaderfile = file_getfilebuffer("lynx.glsl", filesize);
shader::init(mini_win, mini_shadertex, nullptr);
//SDL_GetWindowPosition(mini_win, &windowpos_x, &windowpos_y); //SDL_GetWindowPosition(mini_win, &windowpos_x, &windowpos_y);
log_msg(LOG_OK, "Graphics subsystem initialized\n");
} }
void destroyDisplay() { void destroyDisplay() {
@@ -293,13 +426,15 @@ void destroyDisplay() {
} }
void initGamePad() { void initGamePad() {
const int num_joysticks = SDL_NumJoysticks(); int num_joysticks;
if (num_joysticks>=1) { SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
if (joysticks) {
for (int i=0; i<num_joysticks; ++i) { for (int i=0; i<num_joysticks; ++i) {
if (SDL_IsGameController(i)) { if (SDL_IsGamepad(joysticks[i])) {
gamepad = SDL_GameControllerOpen(i); gamepad = SDL_OpenGamepad(joysticks[i]);
if (SDL_GameControllerGetAttached(gamepad) == SDL_TRUE) { if (SDL_GamepadConnected(gamepad)) {
SDL_GameControllerEventState(SDL_ENABLE); SDL_SetGamepadEventsEnabled(true);
log_msg(LOG_OK, "Gamepad found and initialized");
return; return;
} }
} }
@@ -310,12 +445,22 @@ void initGamePad() {
int main(int argc,char*argv[]){ int main(int argc,char*argv[]){
#ifdef DEBUG #ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif #endif
#ifdef DEBUG
log_msg(LOG_UNSALTED, "MINI v%s\n",MINI_VERSION);
#endif
if (argc>1) if (argc>1)
{ {
if (strstr(argv[1], ".lua")!=nullptr) { if (argv[1][0]=='-' && argv[1][1]=='-') {
const char *command = &argv[1][2];
if (strcmp(command, "new")==0) {
createNewProject();
exit(0);
}
} else if (strstr(argv[1], ".lua")!=nullptr) {
file_setresourcefolder("./"); file_setresourcefolder("./");
file_setsource(SOURCE_FOLDER); file_setsource(SOURCE_FOLDER);
strcpy(main_lua_file, argv[1]); strcpy(main_lua_file, argv[1]);
@@ -328,6 +473,7 @@ int main(int argc,char*argv[]){
} }
} }
//screen_surface = &surfaces.emplace_back();
while (!should_quit) { while (!should_quit) {
should_exit=false; should_exit=false;
@@ -355,20 +501,19 @@ int main(int argc,char*argv[]){
if (fullscreen) screen_fullscreen=strcmp(fullscreen, "true")==0?true:false; if (fullscreen) screen_fullscreen=strcmp(fullscreen, "true")==0?true:false;
const char *cursor = file_getconfigvalue("cursor"); const char *cursor = file_getconfigvalue("cursor");
if (cursor) screen_cursor=strcmp(cursor, "true")?true:false; if (cursor) screen_cursor=strcmp(cursor, "true")?true:false;
const char *music_enabled = file_getconfigvalue("music");
if (music_enabled) JA_EnableMusic(strcmp(music_enabled, "true")==0?true:false);
const char *sound_enabled = file_getconfigvalue("sound");
if (sound_enabled) JA_EnableSound(strcmp(sound_enabled, "true")==0?true:false);
} }
setdest(newsurf(screen_width, screen_height)); setdest(newsurf(screen_width, screen_height));
SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD);
SDL_DisplayMode dm; const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
if (SDL_GetDesktopDisplayMode(0, &dm) != 0) desktop_width = dm->w;
{ desktop_height = dm->h;
SDL_Log("SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
return 1;
}
desktop_width = dm.w;
desktop_height = dm.h;
createDisplay(); createDisplay();
@@ -380,23 +525,22 @@ int main(int argc,char*argv[]){
reinit(); reinit();
initaudio(); initaudio();
#ifdef DEBUG
debug("MINI v%s\n",MINI_VERSION);
#endif
lua_init(main_lua_file); lua_init(main_lua_file);
lua_call_init(); lua_call_init();
Uint32 dt=SDL_GetTicks(); Uint32 dt=SDL_GetTicks();
key_just_pressed = 0; key_just_pressed = 0;
pad_just_pressed = SDL_CONTROLLER_BUTTON_INVALID; pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
mouse_just_pressed = 0; mouse_just_pressed = 0;
mouse_wheel = 0;
double_click = false;
while(!should_exit) { while(!should_exit) {
mouse_wheel = 0;
if (update_mode==UPDATE_WAIT) SDL_WaitEvent(NULL); if (update_mode==UPDATE_WAIT) SDL_WaitEvent(NULL);
else if (update_mode==UPDATE_TIMEOUT) SDL_WaitEventTimeout(NULL, timeout); else if (update_mode==UPDATE_TIMEOUT) SDL_WaitEventTimeout(NULL, timeout);
while(SDL_PollEvent(&mini_eve)) { while(SDL_PollEvent(&mini_eve)) {
if (mini_eve.type == SDL_QUIT) { should_exit=true; should_quit=true; break; } if (mini_eve.type == SDL_EVENT_QUIT) { should_exit=true; should_quit=true; break; }
if (mini_eve.type == SDL_KEYDOWN) { if (mini_eve.type == SDL_EVENT_KEY_DOWN) {
/* /*
if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F2) { if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F2) {
screen_zoom+=2; if (screen_zoom>=10) screen_zoom=2; screen_zoom+=2; if (screen_zoom>=10) screen_zoom=2;
@@ -412,7 +556,7 @@ int main(int argc,char*argv[]){
} }
*/ */
#ifdef DEBUG #ifdef DEBUG
if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F12) { if (mini_eve.key.scancode == SDL_SCANCODE_F12) {
if (lua_is_playing()) { if (lua_is_playing()) {
lua_quit(); lua_quit();
quitaudio(); quitaudio();
@@ -420,23 +564,30 @@ int main(int argc,char*argv[]){
} else { } else {
should_exit=true; should_exit=true;
} }
} else if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F5) { } else if (mini_eve.key.scancode == SDL_SCANCODE_F5) {
should_exit=true; should_exit=true;
} else { } else {
key_just_pressed = mini_eve.key.keysym.scancode; key_just_pressed = mini_eve.key.scancode;
} }
#else #else
key_just_pressed = mini_eve.key.keysym.scancode; key_just_pressed = mini_eve.key.scancode;
#endif #endif
} }
if (mini_eve.type == SDL_MOUSEBUTTONUP) { if (mini_eve.type == SDL_EVENT_MOUSE_BUTTON_UP) {
mouse_just_pressed = mini_eve.button.button; if (mouse_discard)
mouse_discard = false;
else
if (mini_eve.button.clicks==2 && mini_eve.button.button==SDL_BUTTON_LEFT) {
double_click = true;
} else {
mouse_just_pressed = mini_eve.button.button;
}
} }
if (mini_eve.type == SDL_MOUSEWHEEL) { if (mini_eve.type == SDL_EVENT_MOUSE_WHEEL) {
mouse_wheel = mini_eve.wheel.y; mouse_wheel = mini_eve.wheel.y;
} }
if (mini_eve.type == SDL_CONTROLLERBUTTONDOWN) { if (mini_eve.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
pad_just_pressed = mini_eve.cbutton.button; pad_just_pressed = mini_eve.gbutton.button;
} }
/*if ( (mini_eve.type == SDL_WINDOWEVENT) && /*if ( (mini_eve.type == SDL_WINDOWEVENT) &&
(mini_eve.window.windowID == windowID) && (mini_eve.window.windowID == windowID) &&
@@ -447,12 +598,12 @@ int main(int argc,char*argv[]){
}*/ }*/
} }
keys = SDL_GetKeyboardState(NULL); keys = SDL_GetKeyboardState(NULL);
int real_mouse_x, real_mouse_y; float real_mouse_x, real_mouse_y;
mouse_buttons = SDL_GetMouseState(&real_mouse_x, &real_mouse_y); mouse_buttons = SDL_GetMouseState(&real_mouse_x, &real_mouse_y);
float mx, my; float mx, my;
SDL_RenderWindowToLogical(mini_ren, real_mouse_x, real_mouse_y, &mx, &my); SDL_RenderCoordinatesFromWindow(mini_ren, real_mouse_x, real_mouse_y, &mx, &my);
mouse_x = int(mx); mouse_x = int(mx/screen_zoom);
mouse_y = int(my); mouse_y = int(my/screen_zoom);
//mouse_x /= screen_zoom; mouse_y /= screen_zoom; //mouse_x /= screen_zoom; mouse_y /= screen_zoom;
if (SDL_GetTicks()-dt>13) { if (SDL_GetTicks()-dt>13) {
@@ -466,22 +617,35 @@ int main(int argc,char*argv[]){
if (beats>0)beats--; if (beats>0)beats--;
key_just_pressed = 0; key_just_pressed = 0;
mouse_just_pressed = 0; mouse_just_pressed = 0;
pad_just_pressed = SDL_CONTROLLER_BUTTON_INVALID; double_click = false;
mouse_wheel = 0;
pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
} }
SDL_SetRenderTarget(mini_ren, mini_shadertex);
SDL_SetRenderDrawColor(mini_ren, 0, 0, 0, 255); SDL_SetRenderDrawColor(mini_ren, 0, 0, 0, 255);
SDL_RenderClear(mini_ren); SDL_RenderClear(mini_ren);
SDL_LockTexture(mini_bak, NULL, (void**)&pixels, &pitch); SDL_LockTexture(mini_bak, NULL, (void**)&pixels, &pitch);
for (uint32_t i=0;i<screen_surface->size;++i) pixels[i] = palette[screen_surface->p[i]]; for (uint32_t i=0;i<screen_surface->size;++i) pixels[i] = palette[screen_surface->p[i]];
SDL_UnlockTexture(mini_bak); SDL_UnlockTexture(mini_bak);
SDL_RenderCopy(mini_ren, mini_bak, NULL, NULL); SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); //NEW
SDL_RenderPresent(mini_ren);
shader::render();
//SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL);
//SDL_RenderPresent(mini_ren);
fps_counter++;
if (SDL_GetTicks()>=(fps_timer+1000)) {
fps = fps_counter;
fps_counter=0;
fps_timer = SDL_GetTicks();
}
} }
lua_quit(); lua_quit();
quitaudio(); quitaudio();
//Mix_Quit(); //Mix_Quit();
for (int i=0;i<MAX_TEXTURES;++i) freesurf(i); for (unsigned int i=0;i<MAX_SURFACES;++i) freesurf(i);
dest_surface = source_surface = map_surface = NULL; dest_surface = source_surface = map_surface = NULL;
destroyDisplay(); destroyDisplay();
SDL_Quit(); SDL_Quit();
@@ -491,7 +655,7 @@ int main(int argc,char*argv[]){
} }
void simple_pset(int x, int y, uint8_t color) { void simple_pset(int x, int y, uint8_t color) {
x -= ds::origin[0]; y -= ds::origin[1]; x += ds::origin[0]; y += ds::origin[1];
if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return;
if (x < 0 || x >= dest_surface->w || y < 0 || y >= dest_surface->h) return; if (x < 0 || x >= dest_surface->w || y < 0 || y >= dest_surface->h) return;
DEST(x, y) = color; DEST(x, y) = color;
@@ -499,12 +663,13 @@ void simple_pset(int x, int y, uint8_t color) {
void cls(uint8_t color) { void cls(uint8_t color) {
const uint8_t col = ds::draw_palette[color]; const uint8_t col = ds::draw_palette[color];
for (int y=ds::clip[1]; y<=ds::clip[3];++y) { /*for (int y=ds::clip[1]; y<=ds::clip[3];++y) {
for (int x=ds::clip[0]; x<=ds::clip[2];++x) { for (int x=ds::clip[0]; x<=ds::clip[2];++x) {
simple_pset(x,y,col); simple_pset(x,y,col);
} }
} }*/
//SDL_memset(dest_surface->p, color, dest_surface->size);
SDL_memset(dest_surface->p, col, dest_surface->size);
} }
void color(uint8_t color) { void color(uint8_t color) {
@@ -540,11 +705,12 @@ uint32_t *loadpal(const char* filename, uint16_t *palsize) {
} }
void setpal(uint32_t *pal) { void setpal(uint32_t *pal) {
memcpy(palette, pal, 1024); for (int i=0; i<256; ++i) palette[i] = pal[i] | 0xff000000;
//memcpy(palette, pal, 1024);
} }
void setcolor(uint8_t index, uint32_t color) { void setcolor(uint8_t index, uint32_t color) {
palette[index] = color; palette[index] = color | 0xff000000;
} }
uint32_t getcolor(uint8_t index) { uint32_t getcolor(uint8_t index) {
@@ -560,7 +726,7 @@ uint8_t gettrans() {
} }
void subpal(uint8_t index, uint8_t color) { void subpal(uint8_t index, uint8_t color) {
ds::draw_palette[index] = color; ds::draw_palette[SDL_clamp(index,0,255)] = SDL_clamp(color,0,255);
} }
void reset_subpal() { void reset_subpal() {
@@ -594,7 +760,7 @@ void palt(uint8_t col, bool t) {
*/ */
void pset(int x, int y) { void pset(int x, int y) {
x -= ds::origin[0]; y -= ds::origin[1]; x += ds::origin[0]; y += ds::origin[1];
if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return; if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return;
do_pset(x,y); do_pset(x,y);
} }
@@ -605,7 +771,7 @@ void pset(int x, int y, uint8_t color) {
} }
uint8_t pget(int x, int y) { uint8_t pget(int x, int y) {
x -= ds::origin[0]; y -= ds::origin[1]; x += ds::origin[0]; y += ds::origin[1];
//if (x < 0 || x > (dest_surface->w-1) || y < 0 || y > (dest_surface->h-1)) return 0; //if (x < 0 || x > (dest_surface->w-1) || y < 0 || y > (dest_surface->h-1)) return 0;
if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return 0; if (x < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return 0;
return DEST(x, y); return DEST(x, y);
@@ -675,31 +841,34 @@ void vline(int x, int y0, int y1, uint8_t color) {
vline(x, y0, y1); vline(x, y0, y1);
} }
void rect(int x0, int y0, int x1, int y1) { void rect(int x, int y, int w, int h) {
hline(x0, y0, x1); int x1 = w+x-1;
hline(x0, y1, x1); int y1 = h+y-1;
vline(x0, y0, y1); hline(x, y, x1);
vline(x1, y0, y1); hline(x, y1, x1);
vline(x, y, y1);
vline(x1, y, y1);
} }
void rect(int x0, int y0, int x1, int y1, uint8_t color) { void rect(int x, int y, int w, int h, uint8_t color) {
ds::pen_color = color; ds::pen_color = color;
rect(x0, y0, x1, y1); rect(x, y, w, h);
} }
void rectfill(int x0, int y0, int x1, int y1) { void rectfill(int x, int y, int w, int h) {
for (int y=y0; y<=y1; ++y) hline(x0, y, x1); int x1 = w+x-1;
int y1 = h+y-1;
for (int i=y; i<=y1; ++i) hline(x, i, x1);
} }
void rectfill(int x0, int y0, int x1, int y1, uint8_t color) { void rectfill(int x, int y, int w, int h, uint8_t color) {
ds::pen_color = color; ds::pen_color = color;
rectfill(x0, y0, x1, y1); rectfill(x, y, w, h);
} }
void fillp(uint16_t pat, bool transparent) { void fillp(uint16_t pat, bool transparent) {
ds::fill_trans = true; //transparent; ds::fill_trans = true; //transparent;
ds::fill_pattern = pat; ds::fill_pattern = pat;
do_pset=(pat==0xffff?pset_fast:pset_pattern);
} }
void print_symbol(char sym, int x, int y) { void print_symbol(char sym, int x, int y) {
@@ -828,6 +997,77 @@ void circfill(int x, int y, uint8_t r, uint8_t color) {
circfill(x, y, r); circfill(x, y, r);
} }
void roundrect(int x, int y, int w, int h, uint8_t r) {
int xi=0, yi=r;
int d=3-2*r;
int xf = w+x-1;
int yf = h+y-1;
int x1 = x+r, y1 = y+r;
int x2 = xf-r, y2 = yf-r;
hline(x1, y, x2);
hline(x1, yf, x2);
vline(x, y1, y2);
vline(xf, y1, y2);
while (yi>=xi++) {
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
pset(x2+xi, y2+yi);
pset(x1-xi, y2+yi);
pset(x2+xi, y1-yi);
pset(x1-xi, y1-yi);
pset(x2+yi, y2+xi);
pset(x1-yi, y2+xi);
pset(x2+yi, y1-xi);
pset(x1-yi, y1-xi);
}
}
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) {
ds::pen_color=color;
roundrect(x, y, w, h, r);
}
void roundrectfill(int x, int y, int w, int h, uint8_t r) {
int xi=0, yi=r;
int d=3-2*r;
int xf = w+x-1;
int yf = h+y-1;
int x1 = x+r, y1 = y+r;
int x2 = xf-r, y2 = yf-r;
for (int i=y1; i<=y2; ++i) hline(x, i, xf);
while (yi>=xi++) {
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
hline(x1-xi, y2+yi, x2+xi);
hline(x1-xi, y1-yi, x2+xi);
hline(x1-yi, y2+xi, x2+yi);
hline(x1-yi, y1-xi, x2+yi);
}
}
void roundrectfill(int x, int y, int w, int h, uint8_t r, uint8_t color) {
ds::pen_color=color;
roundrectfill(x, y, w, h, r);
}
/*
void roundrectfill(int x, int y, uint8_t r) {
int xi=0, yi=r;
int d=3-2*r;
(*fun_ptr)(x, y, xi, yi);
while (yi>=xi++) {
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
(*fun_ptr)(x, y, xi, yi);
}
}
void roundrectfill(int x, int y, uint8_t r, uint8_t color) {
ds::pen_color=color;
roundrectfill(x, y, r);
}
*/
void _drawoval(int xc, int yc, int x, int y, float xf, float yf) { void _drawoval(int xc, int yc, int x, int y, float xf, float yf) {
pset((xc+x)*xf, (yc+y)*yf); pset((xc+x)*xf, (yc+y)*yf);
pset((xc-x)*xf, (yc+y)*yf); pset((xc-x)*xf, (yc+y)*yf);
@@ -882,11 +1122,13 @@ void ovalfill(int x0, int y0, int x1, int y1, uint8_t color) {
} }
uint8_t sget(int x, int y) { uint8_t sget(int x, int y) {
if (!source_surface) return 0;
if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0; if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0;
return SOURCE(x, y); return SOURCE(x, y);
} }
void sset(int x, int y) { void sset(int x, int y) {
if (!source_surface) return;
if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return; if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return;
SOURCE(x, y) = ds::pen_color; SOURCE(x, y) = ds::pen_color;
} }
@@ -897,6 +1139,7 @@ void sset(int x, int y, uint8_t color) {
} }
void spr(uint8_t n, int x, int y, float w, float h, bool flip_x, bool flip_y) { void spr(uint8_t n, int x, int y, float w, float h, bool flip_x, bool flip_y) {
if (!source_surface) return;
int tx = (n%(source_surface->w >> 3))<<3; int tx = (n%(source_surface->w >> 3))<<3;
int ty = (n/(source_surface->w >> 3))<<3; int ty = (n/(source_surface->w >> 3))<<3;
int tw = w*8 - 1; int tw = w*8 - 1;
@@ -1022,23 +1265,25 @@ void tvline(int x, int y0, int y1, float mx, float my, float mdx, float mdy) {
} }
uint8_t mget(int celx, int cely) { uint8_t mget(int celx, int cely) {
if (!map_surface) return 0;
if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0; if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0;
return TILES(celx, cely); return TILES(celx, cely);
} }
void mset(int celx, int cely, uint8_t snum) { void mset(int celx, int cely, uint8_t snum) {
if (!map_surface) return;
if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return; if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return;
TILES(celx, cely) = snum; TILES(celx, cely) = snum;
} }
void map() { //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer) { void map() { //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer) {
if (map_surface==NULL) return; if (map_surface==NULL) return;
uint8_t celw = map_surface->w >> 3; int celw = map_surface->w;// >> 3;
uint8_t celh = map_surface->h >> 3; int celh = map_surface->h;// >> 3;
int celx = 0; int celx = 0;
int cely = 0; int cely = 0;
//if (celw <= 0 || celh <= 0 || celw >= TILES_WIDTH || celh >= TILES_HEIGHT) return; //if (celw <= 0 || celh <= 0 || celw >= TILES_WIDTH || celh >= TILES_HEIGHT) return;
int sx = -ds::origin[0]; int sy = -ds::origin[1]; int sx = ds::origin[0]; int sy = ds::origin[1];
if (sx+celw*8 < ds::clip[0] || sx > ds::clip[2] || sy+celh*8 < ds::clip[1] || sy > ds::clip[3]) return; if (sx+celw*8 < ds::clip[0] || sx > ds::clip[2] || sy+celh*8 < ds::clip[1] || sy > ds::clip[3]) return;
if (sx<0) { if (sx<0) {
int diff = -sx/8; int diff = -sx/8;
@@ -1052,10 +1297,15 @@ void map() { //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, u
celh -= diff; celh -= diff;
sy += diff*8; sy += diff*8;
} }
sx += ds::origin[0]; sy += ds::origin[1]; sx -= ds::origin[0]; sy -= ds::origin[1];
for (int y=0; y<celh; ++y) { for (int y=0; y<celh; ++y) {
for (int x=0; x<celw; ++x) { for (int x=0; x<celw; ++x) {
spr(mget(celx+x, cely+y), sx+x*8, sy+y*8); const uint8_t tile = mget(celx+x, cely+y);
if (tile==0) continue;
const int fx = sx+(x*8)+ds::origin[0];
const int fy = sy+(y*8)+ds::origin[1];
if ( (fx+8<ds::clip[0]) || (fy+8<ds::clip[1]) || (fx>ds::clip[2]) || (fy>ds::clip[3]) ) continue;
spr(tile, sx+x*8, sy+y*8);
} }
} }
} }
@@ -1086,7 +1336,7 @@ bool anykey() {
bool pad(int8_t i) { bool pad(int8_t i) {
if (!gamepad) return false; if (!gamepad) return false;
return SDL_GameControllerGetButton(gamepad, SDL_GameControllerButton(i)) == 1; return SDL_GetGamepadButton(gamepad, SDL_GamepadButton(i)) == 1;
} }
bool padp(int8_t i) { bool padp(int8_t i) {
@@ -1103,11 +1353,11 @@ int wpad() {
} }
int mousex() { int mousex() {
return mouse_x; return mouse_x-ds::origin[0];
} }
int mousey() { int mousey() {
return mouse_y; return mouse_y-ds::origin[1];
} }
int mwheel() { int mwheel() {
@@ -1115,13 +1365,28 @@ int mwheel() {
} }
bool mbtn(uint8_t i) { bool mbtn(uint8_t i) {
return mouse_buttons & SDL_BUTTON(i); if (mouse_discard) return false;
return mouse_buttons & SDL_BUTTON_MASK(i);
} }
bool mbtnp(uint8_t i) { bool mbtnp(uint8_t i) {
return mouse_just_pressed == i; return mouse_just_pressed == i;
} }
bool doubleclick() {
return double_click;
}
void mdiscard() {
mouse_discard = true;
}
bool minside(int x, int y, int w, int h) {
const int mx = mouse_x-ds::origin[0];
const int my = mouse_y-ds::origin[1];
return (mx>=x) && (my>=y) && (mx<x+w) && (my<y+h);
}
float time() { float time() {
return float(SDL_GetTicks())/1000.0f; return float(SDL_GetTicks())/1000.0f;
} }
@@ -1139,6 +1404,10 @@ int rnd(int x) {
return rand()%x; return rand()%x;
} }
int getfps() {
return fps;
}
void playmusic(const char *filename, const int loop) { void playmusic(const char *filename, const int loop) {
int size; int size;
char *buffer = file_getfilebuffer(filename, size); char *buffer = file_getfilebuffer(filename, size);
@@ -1169,6 +1438,18 @@ float musicpos()
return JA_GetMusicPosition(); return JA_GetMusicPosition();
} }
void enablemusic(const bool value)
{
JA_EnableMusic(value);
file_setconfigvalue("music", value?"true":"false");
}
const bool ismusicenabled()
{
return JA_IsMusicEnabled();
}
int loadsound(const char *filename) { int loadsound(const char *filename) {
int size; int size;
char *buffer = file_getfilebuffer(filename, size); char *buffer = file_getfilebuffer(filename, size);
@@ -1196,6 +1477,17 @@ void stopsound(int soundchannel) {
//Mix_HaltChannel(soundchannel); //Mix_HaltChannel(soundchannel);
} }
void enablesound(const bool value)
{
JA_EnableSound(value);
file_setconfigvalue("sound", value?"true":"false");
}
const bool issoundenabled()
{
return JA_IsSoundEnabled();
}
int getzoom() { int getzoom() {
return screen_zoom; return screen_zoom;
} }
@@ -1232,7 +1524,7 @@ bool getcursor() {
void setcursor(const bool value) { void setcursor(const bool value) {
screen_cursor=value; screen_cursor=value;
SDL_ShowCursor(screen_cursor?SDL_ENABLE:SDL_DISABLE); if (screen_cursor) SDL_ShowCursor(); else SDL_HideCursor();
} }
const char* getconfig(const char* key) { const char* getconfig(const char* key) {
@@ -1252,7 +1544,42 @@ void setupdatemode(const int value, const int t) {
timeout = t; timeout = t;
} }
int getupdatemode() {
return update_mode;
}
void exit() { void exit() {
should_exit = true; should_exit = true;
should_quit = true; should_quit = true;
} }
void createNewProject() {
if (file_createFolder("data")) {
log_msg(LOG_OK, "Directori 'data' creat\n");
} else {
log_msg(LOG_FAIL, "No s'ha pogut crear la carpeta 'data'\n");
exit(-1);
}
FILE *f = fopen("./data/game.ini", "w");
if (f) {
log_msg(LOG_OK, "Arxiu 'data/game.ini' creat\n");
} else {
log_msg(LOG_FAIL, "No s'ha pogut crear l'arxiu 'data/game.ini'\n");
exit(-1);
}
fprintf(f, "title=NEW MINI PROJECT\nconfig=newminiproject\nwidth=320\nheight=240\nzoom=2\n");
fclose(f);
f = fopen("./data/main.lua", "w");
if (f) {
log_msg(LOG_OK, "Arxiu 'data/main.lua' creat\n");
} else {
log_msg(LOG_FAIL, "No s'ha pogut crear l'arxiu 'data/main.lua'\n");
exit(-1);
}
fprintf(f, "function mini.init()\n\nend\n\nfunction mini.update()\n surf.cls(0)\nend\n");
fclose(f);
log_msg(LOG_OK, "Projecte nou creat. Ja està fet lo més dificil del jailgame!\n");
}

43
mini.h
View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <SDL2/SDL.h> #include <SDL3/SDL.h>
#include "version.h" #include "version.h"
@@ -112,13 +112,20 @@
#define KEY_RALT 230 #define KEY_RALT 230
#define KEY_RGUI 231 #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(); void loop();
int scrw(); int scrw();
int scrh(); int scrh();
uint8_t newsurf(int w, int h); 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 savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
void freesurf(uint8_t surface); void freesurf(uint8_t surface);
int surfw(uint8_t surface); int surfw(uint8_t surface);
@@ -127,8 +134,14 @@ int surfh(uint8_t surface);
void setdest(uint8_t surface); void setdest(uint8_t surface);
void setsource(uint8_t surface); void setsource(uint8_t surface);
void setmap(uint8_t surface); void setmap(uint8_t surface);
uint8_t getdest();
uint8_t getsource();
uint8_t getmap(); 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 cls(uint8_t color=0);
void color(uint8_t color=6); void color(uint8_t color=6);
void bcolor(uint8_t color=0); void bcolor(uint8_t color=0);
@@ -142,6 +155,7 @@ uint8_t gettrans();
void subpal(uint8_t index, uint8_t color); void subpal(uint8_t index, uint8_t color);
void reset_subpal(); void reset_subpal();
void set_draw_mode(uint8_t mode);
void pset(int x, int y); void pset(int x, int y);
void pset(int x, int y, uint8_t color); void pset(int x, int y, uint8_t color);
@@ -156,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);
void vline(int x, int y0, int y1, uint8_t color); void vline(int x, int y0, int y1, uint8_t color);
void rect(int x0, int y0, int x1, int y1); void rect(int x, int y, int w, int h);
void rect(int x0, int y0, int x1, int y1, uint8_t color); 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 x, int y, int w, int h);
void rectfill(int x0, int y0, int x1, int y1, uint8_t color); void rectfill(int x, int y, int w, int h, uint8_t color);
void fillp(uint16_t pat, bool transparent = false); void fillp(uint16_t pat, bool transparent = false);
@@ -179,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 = 4);
void circfill(int x, int y, uint8_t r, uint8_t color); 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);
void oval(int x0, int y0, int x1, int y1, uint8_t color); void oval(int x0, int y0, int x1, int y1, uint8_t color);
@@ -215,13 +235,15 @@ int mousey();
int mwheel(); int mwheel();
bool mbtn(uint8_t i); bool mbtn(uint8_t i);
bool mbtnp(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 time();
bool beat(int16_t i); bool beat(int16_t i);
int rnd(int x); int rnd(int x);
int getfps();
#define debug printf
void playmusic(const char *filename, const int loop=-1); void playmusic(const char *filename, const int loop=-1);
void pausemusic(); void pausemusic();
@@ -229,11 +251,15 @@ void resumemusic();
void stopmusic(const int t=1000); void stopmusic(const int t=1000);
void musicpos(float value); void musicpos(float value);
float musicpos(); float musicpos();
void enablemusic(const bool value);
const bool ismusicenabled();
int loadsound(const char *filename); int loadsound(const char *filename);
void freesound(int soundfile); void freesound(int soundfile);
int playsound(int soundfile, const int volume=-1); int playsound(int soundfile, const int volume=-1);
void stopsound(int soundchannel); void stopsound(int soundchannel);
void enablesound(const bool value);
const bool issoundenabled();
int getzoom(); int getzoom();
void setzoom(const int value); void setzoom(const int value);
@@ -251,5 +277,6 @@ const char *configfolder();
#define UPDATE_WAIT 1 #define UPDATE_WAIT 1
#define UPDATE_TIMEOUT 2 #define UPDATE_TIMEOUT 2
void setupdatemode(const int value, const int t=0); void setupdatemode(const int value, const int t=0);
int getupdatemode();
void exit(); 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
}
}

View File

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

View File

@@ -3,183 +3,184 @@
---@class mini ---@class mini
mini = {} mini = {}
---@class surface ---@class surf
surface = {} surf = {}
---@param w number ---@param w number
---@param h number ---@param h number
---@return number surface ---@return number surface
---Create new surface specifying width and height ---Create new surface specifying width and height
function surface.new(w, h) end function surf.new(w, h) end
---@param filename string ---@param filename string
---@return number surface ---@return number surface
---Load GIF file and return surface ---Load GIF file and return surface
function surface.load(filename) end 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 surface number
---@param filename string ---@param filename string
---@optional palette table ---@optional palette table
---Save surface as GIF file, with optional palette ---Save surface as GIF file, with optional palette
function surface.save(surface, filename, palette) end function surf.save(surface, filename, palette) end
---@param surface number ---@param surface number
---Free the specified surface ---Free the specified surface
function surface.free(surface) end function surf.free(surface) end
---@param surface number ---@param surface number
---@return number w, number h ---@return number w, number h
---Retrieve width and height of surface ---Retrieve width and height of surface
function surface.getSize(surface) end function surf.size(surface) end
---@return number surface
---Get current target surface
function surf.target() end
---@param surface number ---@param surface number
---Set surface as target ---Set surface as target
function surface.setTarget(surface) end 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 ---@param color number
---Erase the current target surface with 'color' ---Erase the current target surface with 'color'
function surface.cls(color) end function surf.cls(color) end
---@param surface number
---@param x number
---@param y number
---@param color number
---Set the color for pixel (x,y) in the specified surface.
function surface.setPixel(surface, x, y, color) end
---@param surface number
---@param x number
---@param y number
---@return number color
---Get color of pixel (x,y) in the specified surface.
function surface.getPixel(surface, x, y) end
---@param x number
---@param y number
---@param color number
---Set the color for pixel (x,y) in the current target surface.
function surface.setPixel(x, y, color) end
---@param x number ---@param x number
---@param y number ---@param y number
---@return number color ---@return number color
---Get color of pixel (x,y) in the current target ---Get color of pixel (x,y) on the source surface.
function surface.getPixel(x, y) end function surf.pixel(x, y) end
---@class tilemap ---@param x number
tilemap = {} ---@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 = {}
---@param filename string
---@return number surface ---@return number surface
---Load a tilemap from a file and set it as current tilemap ---Get tilemaps current surface
function tilemap.load(filename) end function map.surf() end
---@param filename string
---Save the current tilemap in a file
function tilemap.save(filename) end
---@param surface number ---@param surface number
---Set surface as the current tilemap ---Set surface as the current tilemap
function tilemap.set(surface) end function map.surf(surface) end
---Draw the tilemap ---Draw the tilemap, using the source surface as tile graphics source
function tilemap.draw() end function map.draw() end
---@param x number ---@param x number
---@param y number ---@param y number
---@return number color ---@return number tile
---Get tile at the position (x,y) in the current tilemap ---Get tile at the position (x,y) in the current tilemap
function tilemap.getTile(x, y) end function map.tile(x, y) end
---@param x number ---@param x number
---@param y number ---@param y number
---@param tile number ---@param tile number
---Set the tile at the position (x,y) in the current tilemap ---Set the tile at the position (x,y) in the current tilemap
function tilemap.setTile(x, y, tile) end function map.tile(x, y, tile) end
---@class palette ---@class pal
palette = {} pal = {}
---@param filename string ---@param filename string
---@return table pal ---@return table pal
---Load a palette from a GIF file and return it ---Load a palette from a GIF file and return it
function palette.load(filename) end function pal.load(filename) end
---@param pal table ---@param pal table
---Set a specified palette as the current palette ---Set a specified palette as the current palette
function palette.set(pal) end function pal.set(pal) end
---@param index number ---@param index number
---@return number r, number g, number b ---@return number r, number g, number b
---Retrieve (r,g,b) color for the index specified in the current palette ---Retrieve (r,g,b) color for the index specified in the current palette
function palette.getColor(index) end function pal.color(index) end
---@param index number ---@param index number
---@param r number ---@param r number
---@param g number ---@param g number
---@param b number ---@param b number
---Set (r,g,b) color for the specified index in the current palette ---Set (r,g,b) color for the specified index in the current palette
function palette.setColor(index, r, g, b) end function pal.color(index, r, g, b) end
---@param index number ---@param index number
---Set the index specified as transparent color ---Set the index specified as transparent color
function palette.setTransparent(index) end function pal.trans(index) end
---@class subpalette
subpalette = {}
---Reset all the subpalette indices to their default palette index ---Reset all the subpalette indices to their default palette index
function subpalette.resetAll() end 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 index number
---@param color number ---@param color number
---Set the specified subpalette index to the specified palette index ---Set the specified subpalette index to the specified palette index
function subpalette.set(index, color) end function pal.subpal(index, color) end
---@param index number
---Reset the specified subpalette index to its default palette index
function subpalette.reset(index) end
---@param index1 number ---@param index1 number
---@param index2 number ---@param index2 number
---@param color number ---@param color number
---Set the specified subpalette range to the specified palette index ---Set the specified subpalette range to the specified palette index
function subpalette.setRange(index1, index2, color) end function pal.subpal(index1, index2, color) end
---@param index1 number ---@class view
---@param index2 number view = {}
---Reset the specified subpalette range to its default palette index
function subpalette.resetRange(index1, index2) end
---@class viewport ---reset the current clipping region to the entire window
viewport = {} function view.clip() end
---@param x number ---@param x number
---@param y number ---@param y number
---@param w number ---@param w number
---@param h number ---@param h number
---Set the current clipping region ---Set the current clipping region
function viewport.setClipping(x, y, w, h) end function view.clip(x, y, w, h) end
---reset the current clipping region to the entire window ---@return number x, number y
function viewport.resetClipping() end ---Get the current origin position
function view.origin() end
---@param x number ---@param x number
---@param y number ---@param y number
---Set the current origin position ---Set the current origin position
function viewport.setOrigin(x, y) end function view.origin(x, y) end
---@return number x, number y
---Get the current origin position
function viewport.getOrigin() end
---@param x number ---@param x number
---@param y number ---@param y number
---@return number x, number y ---@return number x, number y
---Convert screen position to viewport position ---Convert screen position to viewport position
function viewport.toLocal(x, y) end function view.tolocal(x, y) end
---@class draw ---@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 = {} draw = {}
---@param x1 number ---@param x1 number
@@ -204,21 +205,21 @@ function draw.hline(x1, y, x2, color) end
---Draw a vertical line from (x,y1) to (x,y2) with the givencolor ---Draw a vertical line from (x,y1) to (x,y2) with the givencolor
function draw.vline(x, y1, y2, color) end function draw.vline(x, y1, y2, color) end
---@param x1 number ---@param x number
---@param y1 number ---@param y number
---@param x2 number ---@param w number
---@param y2 number ---@param h number
---@param color number ---@param color number
---Draw the ouline of a rectangle from (x1,y1) to (x2,y2) with the given color ---Draw the ouline of a rectangle at (x,y) of size (w,h) with the given color
function draw.rect(x1, y1, x2, y2, color) end function draw.rect(x, y, w, h, color) end
---@param x1 number ---@param x number
---@param y1 number ---@param y number
---@param x2 number ---@param w number
---@param y2 number ---@param h number
---@param color number ---@param color number
---Draw a filled rectangle from (x1,y1) to (x2,y2) with the given color ---Draw a filled rectangle at (x,y) of size (w,h) with the given color
function draw.rectFill(x1, y1, x2, y2, color) end function draw.rectf(x, y, w, h, color) end
---@param x number ---@param x number
---@param y number ---@param y number
@@ -232,7 +233,25 @@ function draw.circ(x, y, r, color) end
---@param r number ---@param r number
---@param color number ---@param color number
---Draw a filled cicle at position(x,y) with radius r and the given color ---Draw a filled cicle at position(x,y) with radius r and the given color
function draw.circFill(x, y, r, color) end 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 x1 number
---@param y1 number ---@param y1 number
@@ -248,13 +267,15 @@ function draw.oval(x1, y1, x2, y2, color) end
---@param y2 number ---@param y2 number
---@param color number ---@param color number
---Draw a filled oval enclosed in (x1,y1)-(x2,y2) and the given color ---Draw a filled oval enclosed in (x1,y1)-(x2,y2) and the given color
function draw.ovalFill(x1, y1, x2, y2, color) end function draw.ovalf(x1, y1, x2, y2, color) end
---@param pattern number ---@param pattern number
---Specify a pattern for the drawing functions ---Specify a pattern for the drawing functions
function draw.setPattern(pattern) end function draw.pattern(pattern) end
---Reset to no pattern for drawing functions
function draw.pattern() end
---@param surface number
---@param sx number ---@param sx number
---@param sy number ---@param sy number
---@param sw number ---@param sw number
@@ -266,12 +287,11 @@ function draw.setPattern(pattern) end
---@optional boolean flip_x ---@optional boolean flip_x
---@optional boolean flip_y ---@optional boolean flip_y
---@optional boolean invert ---@optional boolean invert
---Blit the region starting at (sx,sy) and size (sw, sh) from the specified surface ---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, ---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 ---optionally flipping it horizontally or vertically, or inverting x and y axes
function draw.surface(surface, sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, invert) end function draw.surf(sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, invert) end
---@param surface number
---@param sx number ---@param sx number
---@param sy number ---@param sy number
---@param sw number ---@param sw number
@@ -279,9 +299,9 @@ function draw.surface(surface, sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, i
---@param x number ---@param x number
---@param y number ---@param y number
---@param a number ---@param a number
---Blit the region starting at (sx,sy) and size (sw, sh) from the specified surface ---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 ---to the position (dx, dy) of the target surface, rotating it by a degrees
function draw.surfaceRotated(surface, sx, sy, sw, sh, x, y, a) end function draw.surfrot(sx, sy, sw, sh, x, y, a) end
---@param text string ---@param text string
---@param x number ---@param x number
@@ -290,6 +310,46 @@ function draw.surfaceRotated(surface, sx, sy, sw, sh, x, y, a) end
---Draw text to (x,y) using the specified color ---Draw text to (x,y) using the specified color
function draw.text(text, x, y, color) end 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 ---@class music
music = {} music = {}
@@ -297,6 +357,11 @@ music = {}
---Load and play the song in the specified OGG file ---Load and play the song in the specified OGG file
function music.play(filename) end 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 ---Pause the currently playing song
function music.pause() end function music.pause() end
@@ -306,13 +371,22 @@ function music.resume() end
---Stop the currently playing song ---Stop the currently playing song
function music.stop() end function music.stop() end
---@param pos number
---Set the playing position of the currently loaded song
function music.setPosition(pos) end
---@return number pos ---@return number pos
---Get the playing position of the currently loaded song ---Get the playing position of the currently loaded song
function music.getPosition() end 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 ---@class sound
sound = {} sound = {}
@@ -331,155 +405,272 @@ function sound.free(snd) end
---Play the sound specified, returns the channel in which it's playing ---Play the sound specified, returns the channel in which it's playing
function sound.play(snd) end 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 ---@param chl number
---Stop the channel specified ---Stop the channel specified
function sound.stop(chl) end function sound.stop(chl) end
---@class system ---@return boolean value
system = {} ---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) ---Get current system timer in seconds (with decimals)
function system.getTime() end function sys.time() end
---@param bts number ---@param offset number
---Set number of frames between beats ---Reset chrono time (with offset in seconds) (with decimals)
function system.setBeat(bts) end function sys.chrono(offset) end
---@return number
---@---Get chrono time since last chrono reset in seconds (with decimals)
function sys.chrono() end
---@return boolean ---@return boolean
---Query if a beat has already passed ---Query if a beat has already passed
function system.isBeat() end function sys.beat() end
---The game will call mini.update as fast as possible ---@param bts number
function system.updateAtFullSpeed() end ---Set number of frames between beats
function sys.beat(bts) end
---The game will call mini.update only when a keyboard, mouse or pad event fires
function system.updateOnlyOnEvents() end
---@param mode number
---@param ms number ---@param ms number
---The game will call mini.update on events or after the milliseconds specified passed ---Sets the update mode.
function system.updateOnEventsAndTimeout(ms) end ---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 ---@return table
---Gets a table with the name of each file in the data directory ---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
function system.getFilesInDataDirectory() end ---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 ---Exit the game
function system.quit() end function sys.quit() end
---@class window ---@return number
window = {} ---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 ---@param value number
---Set the window zoom ---Set the window zoom
function window.setZoom(value) end function win.zoom(value) end
---@return number value ---@return number value
---Get the window zoom ---Get the window zoom
function window.getZoom() end function win.zoom() end
---@param value boolean ---@param value boolean
---Specifies if the window must display at fullscreen or not ---Specifies if the window must display at fullscreen or not
function window.setFullscreen(value) end function win.fullscreen(value) end
---@return boolean value ---@return boolean value
---Returns if the window is at fullscreen or not ---Returns if the window is at fullscreen or not
function window.getFullscreen() end function win.fullscreen() end
---@param value boolean ---@param value boolean
---Specifies if the cursor must be visible or not ---Specifies if the cursor must be visible or not
function window.showCursor(value) end function win.cursor(value) end
---@return number w, number h ---@return number w, number h
---Returns the current window size ---Returns the current window size
function window.getResolution() end function win.res() end
---@param w number ---@param w number
---@param h number ---@param h number
---Sets the window size ---Sets the window size
function window.setResolution(w, h) end function win.res(w, h) end
---@class config ---@class config
config = {} config = {}
---@param key string ---@param key string
---@param value string ---@param value any
---Sets the value of a key in the configuration file ---Sets the value of a key in the configuration file
function config.setKey(key, value) end function config.key(key, value) end
---@param key string ---@param key string
---@return string value ---@return string value
---Gets the value of a key in the configuration file ---Gets the value of a key in the configuration file
function config.getKey(key) end function config.key(key) end
---@return string value ---@return string value
---Returns the folder in which the configuration file resides ---Returns the folder in which the configuration file resides
function config.getConfigFolder() end function config.folder() end
---@class mouse ---@class mouse
---@field mouse.LEFT number
---@field mouse.MIDDLE number
---@field mouse.RIGHT number
mouse = {} mouse = {}
---@return number x, number y ---@return number x, number y
---Returns the current position of the mouse ---Returns the current position of the mouse
function mouse.getPos() end function mouse.pos() end
---@return number value ---@return number value
---Returns the value of the mouse wheel ---Returns the value of the mouse wheel
function mouse.getWheel() end function mouse.wheel() end
---@param btn number ---@param btn number
---@return boolean ---@return boolean
---Returns whether the specified mouse button is down ---Returns whether the specified mouse button is down
function mouse.buttonDown(btn) end function mouse.down(btn) end
---@param btn number ---@param btn number
---@return boolean ---@return boolean
---Returns whether the specified mouse button has just been pressed ---Returns whether the specified mouse button has just been pressed
function mouse.buttonPressed(btn) end function mouse.press(btn) end
---@class keyboard ---@return boolean
keyboard = {} ---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 ---@param key number
---@return boolean ---@return boolean
---Returns whether the specified keyboard key is down ---Returns whether the specified keyboard key is down
function keyboard.keyDown(key) end function key.down(key) end
---@return number ---@return number
---Returns which keyboard key has just been pressed ---Returns which keyboard key has just been pressed
function keyboard.keyPressed() end function key.press() end
---@param key number ---@param key number
---@return boolean ---@return boolean
---Returns whether the specified keyboard key has just been pressed ---Returns whether the specified keyboard key has just been pressed
function keyboard.keyPressed(key) end function key.press(key) end
---@return boolean ---@return boolean
---Returns whether any keyboard key has just been pressed ---Returns whether any keyboard key has just been pressed
function keyboard.anyKeyPressed() end function key.any() end
---@class gamepad ---@class pad
gamepad = {} ---@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 ---@param btn number
---@return boolean ---@return boolean
---Returns whether the specified gamepad button is down ---Returns whether the specified gamepad button is down
function gamepad.buttonDown(btn) end function pad.down(btn) end
---@return number ---@return number
---Returns which gamepad button has just been pressed ---Returns which gamepad button has just been pressed
function gamepad.buttonPressed() end function pad.press() end
---@param btn number ---@param btn number
---@return boolean ---@return boolean
---Returns whether the specified gamepad button has just been pressed ---Returns whether the specified gamepad button has just been pressed
function gamepad.buttonPressed(btn) end function pad.press(btn) end
---@return boolean ---@return boolean
---Returns whether any gamepad button has just been pressed ---Returns whether any gamepad button has just been pressed
function gamepad.anybuttonPressed() end 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 ---@class key
---@field key.UNKNOWN number ---@field key.UNKNOWN number
@@ -509,16 +700,16 @@ function gamepad.anybuttonPressed() end
---@field key.X number ---@field key.X number
---@field key.Y number ---@field key.Y number
---@field key.Z number ---@field key.Z number
---@field key.1 number ---@field key.N1 number
---@field key.2 number ---@field key.N2 number
---@field key.3 number ---@field key.N3 number
---@field key.4 number ---@field key.N4 number
---@field key.5 number ---@field key.N5 number
---@field key.6 number ---@field key.N6 number
---@field key.7 number ---@field key.N7 number
---@field key.8 number ---@field key.N8 number
---@field key.9 number ---@field key.N9 number
---@field key.0 number ---@field key.N0 number
---@field key.RETURN number ---@field key.RETURN number
---@field key.ESCAPE number ---@field key.ESCAPE number
---@field key.BACKSPACE number ---@field key.BACKSPACE number
@@ -589,7 +780,7 @@ function gamepad.anybuttonPressed() end
---@field key.RSHIFT number ---@field key.RSHIFT number
---@field key.RALT number ---@field key.RALT number
---@field key.RGUI number ---@field key.RGUI number
key = {}
key.UNKNOWN = 0 key.UNKNOWN = 0
key.A = 4 key.A = 4
key.B = 5 key.B = 5
@@ -697,52 +888,3 @@ key.RCTRL = 228
key.RSHIFT = 229 key.RSHIFT = 229
key.RALT = 230 key.RALT = 230
key.RGUI = 231 key.RGUI = 231
---@class button
---@field button.INVALID number
---@field button.A number
---@field button.B number
---@field button.X number
---@field button.Y number
---@field button.BACK number
---@field button.GUIDE number
---@field button.START number
---@field button.LEFTSTICK number
---@field button.RIGHTSTICK number
---@field button.LEFTSHOULDER number
---@field button.RIGHTSHOULDER number
---@field button.UP number
---@field button.DOWN number
---@field button.LEFT number
---@field button.RIGHT number
---@field button.MISC1 number
---@field button.PADDLE1 number
---@field button.PADDLE2 number
---@field button.PADDLE3 number
---@field button.PADDLE4 number
---@field button.TOUCHPAD number
button = {}
button.INVALID = -1
button.A = 0
button.B = 1
button.X = 2
button.Y = 3
button.BACK = 4
button.GUIDE = 5
button.START = 6
button.LEFTSTICK = 7
button.RIGHTSTICK = 8
button.LEFTSHOULDER = 9
button.RIGHTSHOULDER = 10
button.UP = 11
button.DOWN = 12
button.LEFT = 13
button.RIGHT = 14
button.MISC1 = 15
button.PADDLE1 = 16
button.PADDLE2 = 17
button.PADDLE3 = 18
button.PADDLE4 = 19
button.TOUCHPAD = 20