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/*
info.plist
*.dll
build/*

View File

@@ -3,25 +3,25 @@ source = *.cpp ./lua/*.c
windows:
@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"
windows_debug:
@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:
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:
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:
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:
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)"
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
config=minitest
width=160
height=120
zoom=3
title=TESTS
config=minitests
width=400
height=300
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
function mini.init()
text=other.peiv()
keyRight = tonumber(config.getKey("keyright")) or key.RIGHT
keyLeft = tonumber(config.getKey("keyleft")) or key.LEFT
mini.update=normal_update
--turbo(false)
local perico = "péricòñ"
print(utf8.len(perico))
ants = 0xc936;
s = surface.load("tiles01.gif")
--surface.source(s)
p = palette.load("tiles01.gif")
palette.set(p)
palette.setTransparent(255)
print(#p)
surface.save(s, "data/copy.gif")
s = surface.load("copy.gif")
--draw.source(s)
system.setBeat(4)
s = surf.load("gfx/logo.gif")
surf.source(s)
p = pal.load("gfx/logo.gif")
pal.set(p)
pal.trans(255)
--surf.save(s, "prova.gif", p)
print("=== PACKAGES LOADED ===")
for name, value in pairs(package.loaded) do
print(name, value)
end
print("========================")
end
function mini.update()
if keyboard.keyPressed(key.ESCAPE) then
system.quit()
surf.cls(0)
draw.surf(0, 0, 160, 144, 0, 0)
draw.text("PRESS START", 60, 110, 28)
if key.press(key.ESCAPE) then sys.quit() end
draw.text(sys.fps(), 1, 1, 28)
if key.press(key.N1) then
shader.init("lynx.glsl")
shader.enable()
end
if key.press(key.N2) then
shader.init("gbc.glsl")
shader.enable()
end
if key.press(key.N3) then
shader.disable()
end
if system.isBeat() then
ants = (ants >> 12) | ((ants<<4)&0xffff)
local mx, my = mouse.pos()
draw.rectf(mx, my, 4, 4, 8)
draw.text(mx .. " " .. my, 1, 8, 8)
draw.text(other.peiv(),1,100,4)
end
surface.cls(5)
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
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 )
{
int i, bit;
int code, prev = -1;
dictionary_entry_t *dictionary;
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 );
stop_code = clear_code + 1;
reset_code_length = code_length;
const int clear_code = 1 << ( code_length );
const int stop_code = clear_code + 1;
const int reset_code_length = code_length;
dictionary = ( dictionary_entry_t * )
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
@@ -47,12 +40,15 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
}
dictionary_ind+=2;
int prev = -1;
uint32_t mask = 0x01;
while ( input_length )
{
code = 0x0;
for (i=0; i<(code_length + 1); i++)
int code = 0x0;
for (int i=0; i<(code_length + 1); i++)
{
bit = ( *input & mask ) ? 1 : 0;
const int bit = ( *input & mask ) ? 1 : 0;
mask <<= 1;
if ( mask == 0x100 )
@@ -90,18 +86,9 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
exit( 0 );
}
if ( code == dictionary_ind )
{
int ptr = prev;
int ptr = (code == dictionary_ind) ? prev : code;
while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
}
else
{
int ptr = code;
while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
}
dictionary[ dictionary_ind ].prev = prev;
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
@@ -116,7 +103,7 @@ void uncompress( int code_length, const uint8_t *input, int input_length, uint8_
prev = code;
match_len = dictionary[ code ].len;
const int match_len = dictionary[ code ].len;
while ( code != -1 )
{
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;
buffer += 6; // Ignore header
*w = (uint16_t)*buffer; buffer+=2;
*h = (uint16_t)*buffer; buffer+=2;
*w = *((uint16_t*)buffer); buffer+=2;
*h = *((uint16_t*)buffer); buffer+=2;
const uint8_t fields = *buffer; buffer+=3;
const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1;

366
gifenc.h
View File

@@ -3,226 +3,172 @@
#include <stdint.h>
#include <string.h>
#define MAX_DICT_SIZE 4096
namespace gif
{
struct gif_t {
uint16_t w, h;
int depth;
int bgindex;
FILE *fd;
int offset;
int nframes;
uint8_t *frame, *back;
uint32_t partial;
uint8_t buffer[0xFF];
typedef struct {
int prefix;
uint8_t character;
} DictEntry;
typedef struct {
uint8_t *data;
size_t size;
size_t capacity;
int bit_pos;
uint32_t bit_buffer;
} BitStream;
void bitstream_init(BitStream *bs) {
bs->capacity = 256;
bs->size = 0;
bs->data = (uint8_t*)malloc(bs->capacity);
bs->bit_pos = 0;
bs->bit_buffer = 0;
}
void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
bs->bit_pos += code_size;
while (bs->bit_pos >= 8) {
if (bs->size >= bs->capacity) {
bs->capacity *= 2;
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
}
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
bs->bit_buffer >>= 8;
bs->bit_pos -= 8;
}
}
void bitstream_flush(BitStream *bs) {
if (bs->bit_pos > 0) {
if (bs->size >= bs->capacity) {
bs->capacity *= 2;
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
}
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
}
}
uint8_t *lzw_compress(uint8_t *input, int width, int height, int min_code_size, size_t *out_size) {
int clear_code = 1 << min_code_size;
int end_code = clear_code + 1;
int next_code = end_code + 1;
int code_size = min_code_size + 1;
DictEntry dict[MAX_DICT_SIZE];
int dict_len = next_code;
BitStream bs;
bitstream_init(&bs);
bitstream_write(&bs, clear_code, code_size);
int prefix = input[0];
for (int i = 1; i < width * height; i++) {
uint8_t c = input[i];
// Search for prefix + c in dictionary
int found = -1;
for (int j = end_code + 1; j < dict_len; j++) {
if (dict[j].prefix == prefix && dict[j].character == c) {
found = j;
break;
}
}
if (found != -1) {
prefix = found; // Extend prefix
} else {
bitstream_write(&bs, prefix, code_size); // Emit current prefix
if (dict_len < MAX_DICT_SIZE) {
if (dict_len == (1 << code_size) && code_size < 12) code_size++;
dict[dict_len].prefix = prefix;
dict[dict_len].character = c;
dict_len++;
} else {
bitstream_write(&bs, clear_code, code_size);
dict_len = end_code + 1;
code_size = min_code_size + 1;
}
prefix = c; // Start new prefix
}
}
// Emit final prefix and end code
bitstream_write(&bs, prefix, code_size);
bitstream_write(&bs, end_code, code_size);
bitstream_flush(&bs);
*out_size = bs.size;
return bs.data;
}
void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
FILE *f = fopen(filename, "wb");
if (!f) {
perror("Failed to open file");
return;
}
// Header
fwrite("GIF89a", 1, 6, f);
// Determine min_code_size from palette_size
int palette_depth = 0;
while ((1 << palette_depth) < palette_size) palette_depth++;
const int min_code_size = palette_depth < 2 ? 2 : palette_depth; // GIF spec requires at least 2
printf("min_code_size: %i\n", palette_depth);
// Logical Screen Descriptor
uint8_t packed_field = palette ? (0x80 | ((palette_depth - 1) << 4) | (palette_depth - 1)) : 0x00;
uint8_t screen_desc[] = {
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
packed_field, // GCT flag + color resolution + size
0x00, // Background color index
0x00 // Pixel aspect ratio
};
fwrite(screen_desc, 1, sizeof(screen_desc), f);
struct node_t {
uint16_t key;
node_t *children[];
// Global Color Table (if provided)
if (palette) {
int gct_size = 1 << palette_depth;
fwrite(palette, 1, gct_size * 3, f);
}
// Image Descriptor
uint8_t image_desc[] = {
0x2C, 0, 0, 0, 0,
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
0x00 // No local color table
};
fwrite(image_desc, 1, sizeof(image_desc), f);
static node_t *new_node(uint16_t key, int degree)
{
node_t *node = (node_t*)calloc(1, sizeof(*node) + degree * sizeof(node_t *));
if (node) node->key = key;
return node;
}
// LZW-compressed image data
fwrite(&min_code_size, 1, 1, f);
static node_t *new_trie(int degree, int *nkeys)
{
node_t *root = new_node(0, degree);
/* 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;
}
size_t compressed_size;
uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
static void del_trie(node_t *root, int degree)
{
if (!root) return;
for (int i = 0; i < degree; i++) del_trie(root->children[i], degree);
free(root);
// Write as sub-blocks
size_t offset = 0;
while (offset < compressed_size) {
uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
fwrite(&block_size, 1, 1, f);
fwrite(compressed + offset, 1, block_size, f);
offset += block_size;
}
fputc(0x00, f); // Block terminator
static void put_loop(gif_t *gif, uint16_t loop);
// Trailer
fputc(0x3B, f);
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;
bits_to_write -= 8;
}
gif->offset = (gif->offset + key_size) % (0xFF * 8);
}
static void end_key(gif_t *gif)
{
uint8_t byte_offset;
byte_offset = gif->offset >> 3;
if (gif->offset & 0x07) gif->buffer[byte_offset++] = gif->partial & 0xFF;
if (byte_offset)
{
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)
{
int nkeys, key_size, i, j;
node_t *node, *child, *root;
int degree = 1 << gif->depth;
fputc(',', gif->fd);
fwrite(&x, 2, 1, gif->fd);
fwrite(&y, 2, 1, gif->fd);
fwrite(&w, 2, 1, gif->fd);
fwrite(&h, 2, 1, gif->fd);
fputc(0, gif->fd); fputc(gif->depth, gif->fd);
root = node = new_trie(degree, &nkeys);
key_size = gif->depth + 1;
put_key(gif, degree, key_size); /* clear code */
for (i = y; i < y+h; i++) {
for (j = x; j < x+w; j++) {
uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1);
child = node->children[pixel];
if (child) {
node = child;
} else {
put_key(gif, node->key, key_size);
if (nkeys < 0x1000) {
if (nkeys == (1 << key_size))
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];
free(compressed);
fclose(f);
}
}
}
put_key(gif, node->key, key_size);
put_key(gif, degree + 1, key_size); /* stop code */
end_key(gif);
del_trie(root, degree);
}
static int get_bbox(gif_t *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
{
int i, j, k;
int left, right, top, bottom;
uint8_t back;
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;
*w = right - left + 1;
*h = bottom - top + 1;
return 1;
} else {
return 0;
}
}
static void add_graphics_control_extension(gif_t *gif, uint16_t d)
{
uint8_t flags = ((gif->bgindex >= 0 ? 2 : 1) << 2) + 1;
fputc('!', gif->fd); fputc(0xF9, gif->fd); fputc(0x04, gif->fd); fputc(flags, gif->fd);
fwrite(&d, 2, 1, gif->fd);
fputc(gif->bgindex, gif->fd); fputc(0, gif->fd);
}
void addFrame(gif_t *gif, uint16_t delay)
{
uint16_t w, h, x, y;
uint8_t *tmp;
if (delay || (gif->bgindex >= 0))
add_graphics_control_extension(gif, delay);
if (gif->nframes == 0) {
w = gif->w;
h = gif->h;
x = y = 0;
} else if (!get_bbox(gif, &w, &h, &x, &y)) {
/* image's not changed; save one pixel just to add delay */
w = h = 1;
x = y = 0;
}
put_image(gif, w, h, x, y);
gif->nframes++;
if (gif->bgindex < 0) {
tmp = gif->back;
gif->back = gif->frame;
gif->frame = tmp;
}
}
void close(gif_t* gif)
{
fputc(';', gif->fd);
fclose(gif->fd);
free(gif);
}
}

View File

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

View File

@@ -1,5 +1,5 @@
#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_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_ResumeMusic();
void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume);
float JA_SetMusicVolume(float volume);
void JA_SetMusicPosition(float value);
float JA_GetMusicPosition();
void JA_EnableMusic(const bool value);
const bool JA_IsMusicEnabled();
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char* filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
void JA_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel);
void JA_StopChannel(const int channel);
JA_Channel_state JA_GetChannelState(const int channel);
void JA_DeleteSound(JA_Sound_t *sound);
int JA_SetSoundVolume(int volume);
float JA_SetSoundVolume(float volume);
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 <filesystem>
#include <string>
#include <vector>
#include <algorithm>
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
#ifndef _WIN32
#include <pwd.h>
@@ -130,10 +132,30 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
return f;
}
char *file_getfilebuffer(const char *resourcename, int& filesize) {
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
FILE *f = file_getfilepointer(resourcename, filesize, true);
char* buffer = (char*)malloc(filesize);
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary) {
FILE *f;
f = fopen(filename, binary?"rb":"r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
return f;
}
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
FILE *f = file_getfilepointerex(filename, filesize, true);
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
@@ -151,6 +173,29 @@ void file_setconfigfolder(const char *foldername)
struct passwd *pw = getpwuid(getuid());
const char *homedir = pw->pw_dir;
config_folder = std::string(homedir) + "/." + foldername;
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
{
// Intenta crear ".config", per si no existeix
std::string config_base_folder = std::string(homedir) + "/.config";
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
if (ret == -1 && errno != EEXIST)
{
printf("ERROR CREATING CONFIG BASE FOLDER.");
exit(EXIT_FAILURE);
}
}
{
// Intenta crear ".config/jailgames", per si no existeix
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
if (ret == -1 && errno != EEXIST)
{
printf("ERROR CREATING CONFIG BASE FOLDER.");
exit(EXIT_FAILURE);
}
}
#endif
struct stat st = {0};
@@ -171,7 +216,7 @@ void file_setconfigfolder(const char *foldername)
}
const char *file_getconfigfolder() {
std::string folder = config_folder + "/";
static std::string folder = config_folder + "/";
return folder.c_str();
}
@@ -228,3 +273,107 @@ void file_setconfigvalue(const char* key, const char* value) {
file_saveconfigvalues();
return;
}
bool file_createFolder(const char* name) {
char tmp[256];
strcpy(tmp, "./");
strcat(tmp, name);
return mkdir(tmp, 0755)==0;
}
static bool has_extension(const std::string &name, const char *ext)
{
if (!ext) return true; // sin filtro
std::string e = ext;
std::string suffix = "." + e;
if (name.size() < suffix.size())
return false;
return (name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0);
}
std::vector<std::string> file_listdir(const char *folder, const char *extension)
{
std::vector<std::string> result;
std::string base(folder);
// Normalizar: quitar "/" final si existe
if (!base.empty() && base.back() == '/')
base.pop_back();
// -------------------------------
// 1. MODO: ARCHIVOS SUELTOS
// -------------------------------
if (file_source == SOURCE_FOLDER)
{
std::string fullpath = std::string(resource_folder) + base;
DIR *dir = opendir(fullpath.c_str());
if (!dir)
return result;
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr)
{
std::string name = entry->d_name;
// Ignorar "." y ".."
if (name == "." || name == "..")
continue;
// Ignorar subdirectorios
std::string full = fullpath + "/" + name;
DIR *test = opendir(full.c_str());
if (test)
{
closedir(test);
continue; // es un directorio
}
// Filtrar por extensión
if (!has_extension(name, extension))
continue;
result.push_back(name);
}
closedir(dir);
return result;
}
// -------------------------------
// 2. MODO: ARCHIVO CONTENEDOR
// -------------------------------
if (file_source == SOURCE_FILE)
{
std::string prefix = base + "/";
for (auto &f : toc)
{
const std::string &path = f.path;
// Debe empezar por "folder/"
if (path.compare(0, prefix.size(), prefix) != 0)
continue;
// Extraer la parte después de "folder/"
std::string rest = path.substr(prefix.size());
// Ignorar subdirectorios
if (rest.find('/') != std::string::npos)
continue;
// Filtrar por extensión
if (!has_extension(rest, extension))
continue;
result.push_back(rest);
}
return result;
}
return result;
}

10
jfile.h
View File

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

250
jshader.cpp Normal file
View File

@@ -0,0 +1,250 @@
#include "jshader.h"
#include <iostream>
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#include <OpenGL/OpenGL.h>
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#include <OpenGL/gl3.h>
#else
#include <OpenGL/gl.h>
#endif //!ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#else
#include <SDL3/SDL_opengl.h>
#include <SDL3/SDL_opengl_glext.h>
#endif
namespace shader
{
SDL_Window *win = nullptr;
SDL_Renderer *renderer = nullptr;
GLuint programId = 0;
SDL_Texture* backBuffer = nullptr;
SDL_Point win_size = {640, 480};
SDL_FPoint tex_size = {320, 240};
bool can_use_opengl = false;
bool using_opengl = false;
GLuint texture_number;
GLuint nose;
#ifndef __APPLE__
// I'm avoiding the use of GLEW or some extensions handler, but that
// doesn't mean you should...
PFNGLCREATESHADERPROC glCreateShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
bool initGLExtensions() {
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
glDeleteProgram && glLinkProgram && glValidateProgram && glGetProgramiv &&
glGetProgramInfoLog && glUseProgram && glGetUniformLocation;
}
#endif
GLuint compileShader(const char* source, GLuint shaderType) {
// Create ID for shader
GLuint result = glCreateShader(shaderType);
// Add define depending on shader type
const char *sources[2] = { shaderType==GL_VERTEX_SHADER?"#define VERTEX\n":"#define FRAGMENT\n", source };
// Define shader text
glShaderSource(result, 2, sources, NULL);
// Compile shader
glCompileShader(result);
//Check vertex shader for errors
GLint shaderCompiled = GL_FALSE;
glGetShaderiv( result, GL_COMPILE_STATUS, &shaderCompiled );
if (shaderCompiled != GL_TRUE)
{
std::cout << "Error en la compilación: " << result << "!" << std::endl;
GLint logLength;
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar*)malloc(logLength);
glGetShaderInfoLog(result, logLength, &logLength, log);
std::cout << "Shader compile log:" << log << std::endl;
//std::cout << source << std::endl;
free(log);
}
glDeleteShader(result);
result = 0;
}
return result;
}
GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
{
GLuint programId = 0;
GLuint vtxShaderId, fragShaderId;
if (programId != 0) glDeleteProgram(programId);
programId = glCreateProgram();
vtxShaderId = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
fragShaderId = compileShader(fragmentShaderSource?fragmentShaderSource:vertexShaderSource, GL_FRAGMENT_SHADER);
if(vtxShaderId && fragShaderId)
{
// Associate shader with program
glAttachShader(programId, vtxShaderId);
glAttachShader(programId, fragShaderId);
glLinkProgram(programId);
glValidateProgram(programId);
// Check the status of the compile/link
GLint logLen;
glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logLen);
if (logLen > 0)
{
char* log = (char*) malloc(logLen * sizeof(char));
// Show any errors as appropriate
glGetProgramInfoLog(programId, logLen, &logLen, log);
std::cout << "Prog Info Log: " << std::endl << log << std::endl;
free(log);
}
}
if (vtxShaderId) glDeleteShader(vtxShaderId);
if (fragShaderId) glDeleteShader(fragShaderId);
return programId;
}
const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader)
{
shader::win = win;
shader::renderer = SDL_GetRenderer(win);
shader::backBuffer = backBuffer;
SDL_GetWindowSize(win, &win_size.x, &win_size.y);
SDL_GetTextureSize(backBuffer, &tex_size.x, &tex_size.y);
//printf("tex size: %fx%f\n", tex_size.x, tex_size.y);
SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer);
texture_number = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER, -1);
//printf("texture number: %i\n", texture_number);
int access = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_ACCESS_NUMBER, -1);
nose = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER, -1);
//printf("texture target number: %i\n", nose);
if (access != SDL_TEXTUREACCESS_TARGET)
{
std::cout << "ERROR FATAL: La textura per al render ha de tindre SDL_TEXTUREACCESS_TARGET definit." << std::endl;
exit(1);
}
const char * renderer_name = SDL_GetRendererName(renderer);
//printf("rendererInfo.name: %s\n", renderer_name);
if(!strncmp(renderer_name, "opengl", 6)) {
#ifndef __APPLE__
static bool gl_extensions_initialized = false;
if (!gl_extensions_initialized) {
if (!initGLExtensions()) {
std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl;
can_use_opengl = false;
return false;
}
gl_extensions_initialized = true;
}
#endif
// Compilar el shader y dejarlo listo para usar.
if (!vertexShader) {
can_use_opengl = false;
return false;
}
programId = compileProgram(vertexShader, fragmentShader);
} else {
std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl;
can_use_opengl = false;
return false;
}
can_use_opengl = true;
return true;
}
unsigned char pixels[512*240*4];
void enable() { if (can_use_opengl) using_opengl = true; }
void disable() { using_opengl = false; }
void render()
{
SDL_FlushRenderer(renderer);
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_FlushRenderer(renderer);
if (using_opengl)
{
GLint oldProgramId;
if (programId != 0)
{
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
glUseProgram(programId);
}
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 1);
//glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
//if (glGetError()) { printf("GLGETERROR!\n"); exit(1);}
//GLint param;
//glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &param);
//printf("tex width: %i\n", param);
glViewport(0, 0, win_size.x, win_size.y);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
glTexCoord2f(tex_size.x, 0.0f);
glVertex2f(1.0f, -1.0f);
glTexCoord2f(0.0f, tex_size.y);
glVertex2f(-1.0f, 1.0f);
glTexCoord2f(tex_size.x, tex_size.y);
glVertex2f(1.0f, 1.0f);
glEnd();
SDL_GL_SwapWindow(win);
if (programId != 0) glUseProgram(oldProgramId);
} else {
SDL_RenderTexture(renderer, backBuffer, NULL, NULL);
SDL_RenderPresent(renderer);
}
if (glGetError()) { printf("GLERROR!\n"); exit(1); }
}
}

48
jshader.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <SDL3/SDL.h>
// TIPS:
// =======================================================================
// Abans de crear el renderer, cridar a la següent funció:
//
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
//
// Aixó li diu que volem un renderer que use especificament opengl. A més,
// al crear el renderer li tenim que dir que el volem que use acceeració
// per hardware, i que soporte render a textura. Per exemple:
//
// SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED |
// SDL_RENDERER_TARGETTEXTURE);
//
// Per altra part, al crear la textura tenim que definir que puga ser target
// de renderitzat (SDL_TEXTUREACCESS_TARGET), per exemple:
//
// SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
// SDL_TEXTUREACCESS_TARGET, 320, 240);
//
// Els shaders li'ls passem com una cadena, som nosaltres els que s'encarreguem
// de carregarlos de disc, amb fopen, ifstream, jfile o el que vullgues.
// Si els tens en un std::string, passa-li-la com "cadena.c_str()".
//
// Poden ser els dos el mateix arxiu, com fa libRetro, jo desde dins ja fique
// els defines necessaris. Si es el mateix arxiu, pots no ficar el quart paràmetre.
//
// Els shaders de libRetro no funcionen directament, hi ha que fer algunes modificacions.
//
// El pintat final de la teua escena l'has de fer com si "backBuffer" fora la pantalla.
//
// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32".
// En Mac ni idea
namespace shader
{
const bool init(SDL_Window* win, SDL_Texture* backBuffer,
const char* vertexShader, const char* fragmentShader=nullptr);
void enable();
void disable();
void render();
}

5
lagueirtofile Normal file
View File

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

27
log.h Normal file
View File

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

783
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) {
const char *name = luaL_checkstring(L, 1);
// [RZC 12/03/2026] ==================================
// Soport per a rutes relatives i absolutes
//
//const char *name = luaL_checkstring(L, 1);
char resolved[256];
resolve_module_name(L, resolved, sizeof(resolved));
const char *name = resolved;
// ===================================================
lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */

561
mini.cpp
View File

@@ -2,12 +2,14 @@
#include "jfile.h"
#include <string.h>
#include "lua.h"
#include "gif.c"
#include "gif.h"
#include "gifenc.h"
//#include "SDL2/SDL_mixer.h"
#include "jail_audio.h"
#include "jshader.h"
//#include <vector>
#include "log.h"
#define MAX_TEXTURES 10
#define MAX_SURFACES 100
#ifdef MACOS_BUNDLE
#include <libgen.h>
@@ -18,12 +20,22 @@
#pragma pack(1)
struct surface_t {
uint8_t *p;
char *name {nullptr};
uint8_t *p {nullptr};
uint16_t w, h;
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 config_folder[256];
uint16_t screen_width = 160;
@@ -35,7 +47,7 @@ bool screen_cursor = true;
int desktop_width = 0;
int desktop_height = 0;
surface_t surfaces[MAX_TEXTURES];
surface_t surfaces[MAX_SURFACES];
surface_t *screen_surface = &surfaces[0];
surface_t *dest_surface = screen_surface;
surface_t *source_surface = NULL;
@@ -66,6 +78,7 @@ namespace ds {
uint16_t fill_pattern = 0b1111111111111111;
bool fill_trans = false;
uint8_t draw_palette[256];
uint8_t mode = DRAWMODE_NORMAL;
}
int update_mode = UPDATE_ALWAYS;
@@ -76,12 +89,13 @@ bool should_quit = false;
SDL_Window *mini_win;
SDL_Renderer *mini_ren;
SDL_Texture *mini_bak;
SDL_Texture *mini_shadertex;
Uint32 windowID;
Uint32 *pixels;
int pitch;
uint32_t palette[256] = { 0x001a1c2c, 0x005d275d, 0x00b13e53, 0x00ef7d57, 0x00ffcd75, 0x00a7f070, 0x0038b764, 0x00257179,
0x0029366f, 0x003b5dc9, 0x0041a6f6, 0x0073eff7, 0x00f4f4f4, 0x0094b0c2, 0x00566c86, 0x00333c57 };
uint32_t palette[256] = { 0xFF1a1c2c, 0xFF5d275d, 0xFFb13e53, 0xFFef7d57, 0xFFffcd75, 0xFFa7f070, 0xFF38b764, 0xFF257179,
0xFF29366f, 0xFF3b5dc9, 0xFF41a6f6, 0xFF73eff7, 0xFFf4f4f4, 0xFF94b0c2, 0xFF566c86, 0xFF333c57 };
const char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -93,15 +107,17 @@ char base64glyphs[193] = "/h/AqV/hhhh/GMYYMGz/t/eS33H477wsjjswY4IOPHEFFVVVAVAVAV
"AMShAAAQsjAAAwsjAAAeSzAAAcU3AAAEqRAAABVaiAAMezhAAAAAMAADH4wAASb2SAAMAttAQYcefACGOe+AAAVVAAAAbbAA";
//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;
int mouse_x, mouse_y, mouse_wheel;
Uint32 mouse_buttons;
uint8_t mouse_just_pressed = 0;
bool double_click = false;
bool mouse_discard = false;
SDL_GameController *gamepad = NULL;
int8_t pad_just_pressed = SDL_CONTROLLER_BUTTON_INVALID;
SDL_Gamepad *gamepad = NULL;
int8_t pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
#define MAX_SOUNDS 50
JA_Music_t *music = NULL;
@@ -109,6 +125,8 @@ JA_Sound_t *sounds[MAX_SOUNDS];
int16_t beats, num_beats = 0;
void createNewProject();
char* get_value_from_line(char* line) {
char* equal_character = strchr(line, '=');
if (equal_character == NULL) return NULL;
@@ -118,21 +136,20 @@ char* get_value_from_line(char* line) {
void read_ini() {
int size;
SDL_Log("Carregant 'game.ini'...");
FILE *f = file_getfilepointer("game.ini", size); // fopen("game.ini", "r");
char line[1024];
if (f == NULL) { SDL_Log("FAIL!\n"); return; }
SDL_Log("OK!\n");
if (f == NULL) { log_msg(LOG_FAIL, "No s'ha pogut obrir 'game.ini'\n"); exit(-1); }
log_msg(LOG_OK, "'game.ini' carregat\n");
while (fgets(line, sizeof(line), f)) {
char *value = get_value_from_line(line);
if (value != NULL) {
value[strlen(value)-1] = '\0';
if (strcmp(line, "title") == 0) { strcpy(window_title, value); SDL_Log("-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, "width") == 0) { screen_width = atoi(value); SDL_Log("-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, "zoom") == 0) { screen_zoom = atoi(value); SDL_Log("-screen zoom=%i\n", screen_zoom); }
else if (strcmp(line, "fullscreen") == 0) { screen_fullscreen = atoi(value); SDL_Log("-screen sullscreen=%i\n", screen_fullscreen); }
if (strcmp(line, "title") == 0) { strcpy(window_title, value); log_msg(LOG_VERBOSE, "title = %s\n", window_title); }
else if (strcmp(line, "config") == 0) { strcpy(config_folder, value); log_msg(LOG_VERBOSE, "config = %s\n", config_folder); }
else if (strcmp(line, "width") == 0) { screen_width = atoi(value); log_msg(LOG_VERBOSE, "screen width = %i\n", screen_width); }
else if (strcmp(line, "height") == 0) { screen_height = atoi(value); log_msg(LOG_VERBOSE, "screen height = %i\n", screen_height); }
else if (strcmp(line, "zoom") == 0) { screen_zoom = atoi(value); log_msg(LOG_VERBOSE, "screen zoom = %i\n", screen_zoom); }
else if (strcmp(line, "fullscreen") == 0) { screen_fullscreen = atoi(value); log_msg(LOG_VERBOSE, "screen sullscreen = %i\n", screen_fullscreen); }
//else if (strcmp(line, "files") == 0) {
//lua_files = (char*)malloc(strlen(value));
// strcpy(lua_files, value);
@@ -140,13 +157,32 @@ void read_ini() {
}
}
fclose(f);
SDL_Log("'game.ini' carregat!\n");
//SDL_Log("'game.ini' carregat!\n");
}
void pset_fast(int x, int y) {
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) {
int pbx = x % 4, pby = y % 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() {
SDL_Log("REINIT\n");
log_msg(LOG_INFO, "STARTING A SYSTEM REINITIALIZATION\n");
do_pset = pset_fast;
ds::pen_color = 6;
ds::back_color = 0;
@@ -168,17 +225,23 @@ void reinit() {
ds::trans=0;
ds::fill_pattern = 0b1111111111111111;
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);
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;
if (file!=NULL) fclose(file);
file = NULL;
}
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;
}
@@ -197,42 +260,69 @@ int scrh() {
}
uint8_t newsurf(int w, int h) {
int i = 0;
while (i<MAX_TEXTURES && surfaces[i].p != NULL) ++i;
//[TODO] Gestionar el cas en que no queden surfaces lliures
unsigned int i = 0;
while (i<MAX_SURFACES && surfaces[i].p != NULL) ++i;
if (i==MAX_SURFACES) return 255;
surfaces[i].name = nullptr;
surfaces[i].w = w;
surfaces[i].h = 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;
}
uint8_t loadsurf(const char* filename) {
int i = 0;
while (i<MAX_TEXTURES && surfaces[i].p != NULL) ++i;
//[TODO] Gestionar el cas en que no queden surfaces lliures
uint8_t loadsurf(const char* filename, const bool external) {
// Si el gif ja s'ha carregat en una textura, tornem eixa textura
for (unsigned int i=0; i<MAX_SURFACES; ++i)
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;
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].size = surfaces[i].w*surfaces[i].h;
surfaces[i].name = (char*)malloc(strlen(filename)+1);
strcpy(surfaces[i].name, filename);
free(buffer);
log_msg(LOG_INFO, "Arxiu '%s' carregat en surface: %i.\n", filename, i);
return i;
}
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors)
{
uint8_t depth=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);
gif::write_gif(filename, surfaces[surface].p, surfaces[surface].w, surfaces[surface].h, pal, colors);
}
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;
}
@@ -246,7 +336,10 @@ int surfh(uint8_t surface) {
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[1]<0) ds::clip[1]=0;
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];
}
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;
}
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() {
if (screen_zoom <= 0) screen_zoom = 1;
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);
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_RenderSetLogicalSize(mini_ren, screen_width, screen_height);
SDL_ShowCursor(screen_cursor?SDL_ENABLE:SDL_DISABLE);
//SDL_SetRenderLogicalPresentation(mini_ren, screen_width, screen_height);
if (screen_cursor) SDL_ShowCursor(); else SDL_HideCursor();
mini_bak = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height);
SDL_SetTextureScaleMode(mini_bak, SDL_SCALEMODE_NEAREST);
SDL_PropertiesID props = SDL_GetTextureProperties(mini_bak);
int real_pixelformat = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_FORMAT_NUMBER, -1);
if (real_pixelformat != SDL_PIXELFORMAT_ARGB8888) {
log_msg(LOG_FAIL, "Pixelformat incorrecte: %i\n", real_pixelformat);
exit(1);
}
mini_shadertex = SDL_CreateTexture(mini_ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, screen_width*screen_zoom, screen_height*screen_zoom);
SDL_SetTextureScaleMode(mini_shadertex, SDL_SCALEMODE_NEAREST);
//int filesize;
//char *shaderfile = file_getfilebuffer("lynx.glsl", filesize);
shader::init(mini_win, mini_shadertex, nullptr);
//SDL_GetWindowPosition(mini_win, &windowpos_x, &windowpos_y);
log_msg(LOG_OK, "Graphics subsystem initialized\n");
}
void destroyDisplay() {
@@ -293,13 +426,15 @@ void destroyDisplay() {
}
void initGamePad() {
const int num_joysticks = SDL_NumJoysticks();
if (num_joysticks>=1) {
int num_joysticks;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
if (joysticks) {
for (int i=0; i<num_joysticks; ++i) {
if (SDL_IsGameController(i)) {
gamepad = SDL_GameControllerOpen(i);
if (SDL_GameControllerGetAttached(gamepad) == SDL_TRUE) {
SDL_GameControllerEventState(SDL_ENABLE);
if (SDL_IsGamepad(joysticks[i])) {
gamepad = SDL_OpenGamepad(joysticks[i]);
if (SDL_GamepadConnected(gamepad)) {
SDL_SetGamepadEventsEnabled(true);
log_msg(LOG_OK, "Gamepad found and initialized");
return;
}
}
@@ -310,12 +445,22 @@ void initGamePad() {
int main(int argc,char*argv[]){
#ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
#ifdef DEBUG
log_msg(LOG_UNSALTED, "MINI v%s\n",MINI_VERSION);
#endif
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_setsource(SOURCE_FOLDER);
strcpy(main_lua_file, argv[1]);
@@ -328,6 +473,7 @@ int main(int argc,char*argv[]){
}
}
//screen_surface = &surfaces.emplace_back();
while (!should_quit) {
should_exit=false;
@@ -355,20 +501,19 @@ int main(int argc,char*argv[]){
if (fullscreen) screen_fullscreen=strcmp(fullscreen, "true")==0?true:false;
const char *cursor = file_getconfigvalue("cursor");
if (cursor) screen_cursor=strcmp(cursor, "true")?true:false;
const char *music_enabled = file_getconfigvalue("music");
if (music_enabled) JA_EnableMusic(strcmp(music_enabled, "true")==0?true:false);
const char *sound_enabled = file_getconfigvalue("sound");
if (sound_enabled) JA_EnableSound(strcmp(sound_enabled, "true")==0?true:false);
}
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;
if (SDL_GetDesktopDisplayMode(0, &dm) != 0)
{
SDL_Log("SDL_GetDesktopDisplayMode failed: %s", SDL_GetError());
return 1;
}
desktop_width = dm.w;
desktop_height = dm.h;
const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
desktop_width = dm->w;
desktop_height = dm->h;
createDisplay();
@@ -380,23 +525,22 @@ int main(int argc,char*argv[]){
reinit();
initaudio();
#ifdef DEBUG
debug("MINI v%s\n",MINI_VERSION);
#endif
lua_init(main_lua_file);
lua_call_init();
Uint32 dt=SDL_GetTicks();
key_just_pressed = 0;
pad_just_pressed = SDL_CONTROLLER_BUTTON_INVALID;
pad_just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
mouse_just_pressed = 0;
while(!should_exit) {
mouse_wheel = 0;
double_click = false;
while(!should_exit) {
if (update_mode==UPDATE_WAIT) SDL_WaitEvent(NULL);
else if (update_mode==UPDATE_TIMEOUT) SDL_WaitEventTimeout(NULL, timeout);
while(SDL_PollEvent(&mini_eve)) {
if (mini_eve.type == SDL_QUIT) { should_exit=true; should_quit=true; break; }
if (mini_eve.type == SDL_KEYDOWN) {
if (mini_eve.type == SDL_EVENT_QUIT) { should_exit=true; should_quit=true; break; }
if (mini_eve.type == SDL_EVENT_KEY_DOWN) {
/*
if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F2) {
screen_zoom+=2; if (screen_zoom>=10) screen_zoom=2;
@@ -412,7 +556,7 @@ int main(int argc,char*argv[]){
}
*/
#ifdef DEBUG
if (mini_eve.key.keysym.scancode == SDL_SCANCODE_F12) {
if (mini_eve.key.scancode == SDL_SCANCODE_F12) {
if (lua_is_playing()) {
lua_quit();
quitaudio();
@@ -420,23 +564,30 @@ int main(int argc,char*argv[]){
} else {
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;
} else {
key_just_pressed = mini_eve.key.keysym.scancode;
key_just_pressed = mini_eve.key.scancode;
}
#else
key_just_pressed = mini_eve.key.keysym.scancode;
key_just_pressed = mini_eve.key.scancode;
#endif
}
if (mini_eve.type == SDL_MOUSEBUTTONUP) {
if (mini_eve.type == SDL_EVENT_MOUSE_BUTTON_UP) {
if (mouse_discard)
mouse_discard = false;
else
if (mini_eve.button.clicks==2 && mini_eve.button.button==SDL_BUTTON_LEFT) {
double_click = true;
} else {
mouse_just_pressed = mini_eve.button.button;
}
if (mini_eve.type == SDL_MOUSEWHEEL) {
}
if (mini_eve.type == SDL_EVENT_MOUSE_WHEEL) {
mouse_wheel = mini_eve.wheel.y;
}
if (mini_eve.type == SDL_CONTROLLERBUTTONDOWN) {
pad_just_pressed = mini_eve.cbutton.button;
if (mini_eve.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
pad_just_pressed = mini_eve.gbutton.button;
}
/*if ( (mini_eve.type == SDL_WINDOWEVENT) &&
(mini_eve.window.windowID == windowID) &&
@@ -447,12 +598,12 @@ int main(int argc,char*argv[]){
}*/
}
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);
float mx, my;
SDL_RenderWindowToLogical(mini_ren, real_mouse_x, real_mouse_y, &mx, &my);
mouse_x = int(mx);
mouse_y = int(my);
SDL_RenderCoordinatesFromWindow(mini_ren, real_mouse_x, real_mouse_y, &mx, &my);
mouse_x = int(mx/screen_zoom);
mouse_y = int(my/screen_zoom);
//mouse_x /= screen_zoom; mouse_y /= screen_zoom;
if (SDL_GetTicks()-dt>13) {
@@ -466,22 +617,35 @@ int main(int argc,char*argv[]){
if (beats>0)beats--;
key_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_RenderClear(mini_ren);
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]];
SDL_UnlockTexture(mini_bak);
SDL_RenderCopy(mini_ren, mini_bak, NULL, NULL);
SDL_RenderPresent(mini_ren);
SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL); //NEW
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();
quitaudio();
//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;
destroyDisplay();
SDL_Quit();
@@ -491,7 +655,7 @@ int main(int argc,char*argv[]){
}
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 < 0 || x >= dest_surface->w || y < 0 || y >= dest_surface->h) return;
DEST(x, y) = color;
@@ -499,12 +663,13 @@ void simple_pset(int x, int y, uint8_t color) {
void cls(uint8_t 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) {
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) {
@@ -540,11 +705,12 @@ uint32_t *loadpal(const char* filename, uint16_t *palsize) {
}
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) {
palette[index] = color;
palette[index] = color | 0xff000000;
}
uint32_t getcolor(uint8_t index) {
@@ -560,7 +726,7 @@ uint8_t gettrans() {
}
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() {
@@ -594,7 +760,7 @@ void palt(uint8_t col, bool t) {
*/
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;
do_pset(x,y);
}
@@ -605,7 +771,7 @@ void pset(int x, int y, uint8_t color) {
}
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 < ds::clip[0] || x > ds::clip[2] || y < ds::clip[1] || y > ds::clip[3]) return 0;
return DEST(x, y);
@@ -675,31 +841,34 @@ void vline(int x, int y0, int y1, uint8_t color) {
vline(x, y0, y1);
}
void rect(int x0, int y0, int x1, int y1) {
hline(x0, y0, x1);
hline(x0, y1, x1);
vline(x0, y0, y1);
vline(x1, y0, y1);
void rect(int x, int y, int w, int h) {
int x1 = w+x-1;
int y1 = h+y-1;
hline(x, y, x1);
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;
rect(x0, y0, x1, y1);
rect(x, y, w, h);
}
void rectfill(int x0, int y0, int x1, int y1) {
for (int y=y0; y<=y1; ++y) hline(x0, y, x1);
void rectfill(int x, int y, int w, int h) {
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;
rectfill(x0, y0, x1, y1);
rectfill(x, y, w, h);
}
void fillp(uint16_t pat, bool transparent) {
ds::fill_trans = true; //transparent;
ds::fill_pattern = pat;
do_pset=(pat==0xffff?pset_fast:pset_pattern);
}
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);
}
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) {
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) {
if (!source_surface) return 0;
if (x < 0 || x > (source_surface->w-1) || y < 0 || y > (source_surface->h-1)) return 0;
return SOURCE(x, y);
}
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;
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) {
if (!source_surface) return;
int tx = (n%(source_surface->w >> 3))<<3;
int ty = (n/(source_surface->w >> 3))<<3;
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) {
if (!map_surface) return 0;
if (celx < 0 || celx > (map_surface->w-1) || cely < 0 || cely > (map_surface->h-1)) return 0;
return TILES(celx, cely);
}
void 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;
TILES(celx, cely) = snum;
}
void map() { //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer) {
if (map_surface==NULL) return;
uint8_t celw = map_surface->w >> 3;
uint8_t celh = map_surface->h >> 3;
int celw = map_surface->w;// >> 3;
int celh = map_surface->h;// >> 3;
int celx = 0;
int cely = 0;
//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<0) {
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;
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 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) {
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) {
@@ -1103,11 +1353,11 @@ int wpad() {
}
int mousex() {
return mouse_x;
return mouse_x-ds::origin[0];
}
int mousey() {
return mouse_y;
return mouse_y-ds::origin[1];
}
int mwheel() {
@@ -1115,13 +1365,28 @@ int mwheel() {
}
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) {
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() {
return float(SDL_GetTicks())/1000.0f;
}
@@ -1139,6 +1404,10 @@ int rnd(int x) {
return rand()%x;
}
int getfps() {
return fps;
}
void playmusic(const char *filename, const int loop) {
int size;
char *buffer = file_getfilebuffer(filename, size);
@@ -1169,6 +1438,18 @@ float musicpos()
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 size;
char *buffer = file_getfilebuffer(filename, size);
@@ -1196,6 +1477,17 @@ void stopsound(int 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() {
return screen_zoom;
}
@@ -1232,7 +1524,7 @@ bool getcursor() {
void setcursor(const bool 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) {
@@ -1252,7 +1544,42 @@ void setupdatemode(const int value, const int t) {
timeout = t;
}
int getupdatemode() {
return update_mode;
}
void exit() {
should_exit = 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
#include <SDL2/SDL.h>
#include <SDL3/SDL.h>
#include "version.h"
@@ -112,13 +112,20 @@
#define KEY_RALT 230
#define KEY_RGUI 231
#define DRAWMODE_NORMAL 0
#define DRAWMODE_PATTERN 1
#define DRAWMODE_AND 2
#define DRAWMODE_OR 3
#define DRAWMODE_XOR 4
#define DRAWMODE_NOT 5
void loop();
int scrw();
int scrh();
uint8_t newsurf(int w, int h);
uint8_t loadsurf(const char* filename);
uint8_t loadsurf(const char* filename, const bool external = false);
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
void freesurf(uint8_t surface);
int surfw(uint8_t surface);
@@ -127,8 +134,14 @@ int surfh(uint8_t surface);
void setdest(uint8_t surface);
void setsource(uint8_t surface);
void setmap(uint8_t surface);
uint8_t getdest();
uint8_t getsource();
uint8_t getmap();
void shader_init(const char* vshader, const char* fshader);
void shader_enable();
void shader_disable();
void cls(uint8_t color=0);
void color(uint8_t color=6);
void bcolor(uint8_t color=0);
@@ -142,6 +155,7 @@ uint8_t gettrans();
void subpal(uint8_t index, uint8_t color);
void reset_subpal();
void set_draw_mode(uint8_t mode);
void pset(int x, int y);
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, uint8_t color);
void rect(int x0, int y0, int x1, int y1);
void rect(int x0, int y0, int x1, int y1, uint8_t color);
void rect(int x, int y, int w, int h);
void rect(int x, int y, int w, int h, uint8_t color);
void rectfill(int x0, int y0, int x1, int y1);
void rectfill(int x0, int y0, int x1, int y1, uint8_t color);
void rectfill(int x, int y, int w, int h);
void rectfill(int x, int y, int w, int h, uint8_t color);
void fillp(uint16_t pat, bool transparent = false);
@@ -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, uint8_t color);
void roundrect(int x, int y, int w, int h, uint8_t r);
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color);
void roundrectfill(int x, int y, int w, int h, uint8_t r);
void roundrectfill(int x, int y, int w, int h, uint8_t r, uint8_t color);
void oval(int x0, int y0, int x1, int y1);
void oval(int x0, int y0, int x1, int y1, uint8_t color);
@@ -215,13 +235,15 @@ int mousey();
int mwheel();
bool mbtn(uint8_t i);
bool mbtnp(uint8_t i);
bool doubleclick();
void mdiscard();
bool minside(int x, int y, int w, int h);
float time();
bool beat(int16_t i);
int rnd(int x);
#define debug printf
int getfps();
void playmusic(const char *filename, const int loop=-1);
void pausemusic();
@@ -229,11 +251,15 @@ void resumemusic();
void stopmusic(const int t=1000);
void musicpos(float value);
float musicpos();
void enablemusic(const bool value);
const bool ismusicenabled();
int loadsound(const char *filename);
void freesound(int soundfile);
int playsound(int soundfile, const int volume=-1);
void stopsound(int soundchannel);
void enablesound(const bool value);
const bool issoundenabled();
int getzoom();
void setzoom(const int value);
@@ -251,5 +277,6 @@ const char *configfolder();
#define UPDATE_WAIT 1
#define UPDATE_TIMEOUT 2
void setupdatemode(const int value, const int t=0);
int getupdatemode();
void exit();

View File

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

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

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

View File

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

View File

@@ -3,183 +3,184 @@
---@class mini
mini = {}
---@class surface
surface = {}
---@class surf
surf = {}
---@param w number
---@param h number
---@return number surface
---Create new surface specifying width and height
function surface.new(w, h) end
function surf.new(w, h) end
---@param filename string
---@return number 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 filename string
---@optional palette table
---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
---Free the specified surface
function surface.free(surface) end
function surf.free(surface) end
---@param surface number
---@return number w, number h
---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
---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
---Erase the current target surface with 'color'
function surface.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
function surf.cls(color) end
---@param x number
---@param y number
---@return number color
---Get color of pixel (x,y) in the current target
function surface.getPixel(x, y) end
---Get color of pixel (x,y) on the source surface.
function surf.pixel(x, y) end
---@class tilemap
tilemap = {}
---@param x number
---@param y number
---@param color number
---Set the color for pixel (x,y) on the target surface.
function surf.pixel(x, y, color) end
---@class map
map = {}
---@param filename string
---@return number surface
---Load a tilemap from a file and set it as current tilemap
function tilemap.load(filename) end
---@param filename string
---Save the current tilemap in a file
function tilemap.save(filename) end
---Get tilemaps current surface
function map.surf() end
---@param surface number
---Set surface as the current tilemap
function tilemap.set(surface) end
function map.surf(surface) end
---Draw the tilemap
function tilemap.draw() end
---Draw the tilemap, using the source surface as tile graphics source
function map.draw() end
---@param x number
---@param y number
---@return number color
---@return number tile
---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 y number
---@param tile number
---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
palette = {}
---@class pal
pal = {}
---@param filename string
---@return table pal
---Load a palette from a GIF file and return it
function palette.load(filename) end
function pal.load(filename) end
---@param pal table
---Set a specified palette as the current palette
function palette.set(pal) end
function pal.set(pal) end
---@param index number
---@return number r, number g, number b
---Retrieve (r,g,b) color for the index specified in the current palette
function palette.getColor(index) end
function pal.color(index) end
---@param index number
---@param r number
---@param g number
---@param b number
---Set (r,g,b) color for the specified index in the current palette
function palette.setColor(index, r, g, b) end
function pal.color(index, r, g, b) end
---@param index number
---Set the index specified as transparent color
function palette.setTransparent(index) end
---@class subpalette
subpalette = {}
function pal.trans(index) end
---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 color number
---Set the specified subpalette index to the specified palette index
function subpalette.set(index, color) end
---@param index number
---Reset the specified subpalette index to its default palette index
function subpalette.reset(index) end
function pal.subpal(index, color) end
---@param index1 number
---@param index2 number
---@param color number
---Set the specified subpalette range to the specified palette index
function subpalette.setRange(index1, index2, color) end
function pal.subpal(index1, index2, color) end
---@param index1 number
---@param index2 number
---Reset the specified subpalette range to its default palette index
function subpalette.resetRange(index1, index2) end
---@class view
view = {}
---@class viewport
viewport = {}
---reset the current clipping region to the entire window
function view.clip() end
---@param x number
---@param y number
---@param w number
---@param h number
---Set the current clipping region
function viewport.setClipping(x, y, w, h) end
function view.clip(x, y, w, h) end
---reset the current clipping region to the entire window
function viewport.resetClipping() end
---@return number x, number y
---Get the current origin position
function view.origin() end
---@param x number
---@param y number
---Set the current origin position
function viewport.setOrigin(x, y) end
---@return number x, number y
---Get the current origin position
function viewport.getOrigin() end
function view.origin(x, y) end
---@param x number
---@param y number
---@return number x, number y
---Convert screen position to viewport position
function viewport.toLocal(x, y) end
function view.tolocal(x, y) end
---@class draw
---@field draw.NORMAL number
---@field draw.PATTERN number
---@field draw.AND number
---@field draw.OR number
---@field draw.XOR number
---@field draw.NOT number
draw = {}
---@param x1 number
@@ -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
function draw.vline(x, y1, y2, color) end
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@param x number
---@param y number
---@param w number
---@param h number
---@param color number
---Draw the ouline of a rectangle from (x1,y1) to (x2,y2) with the given color
function draw.rect(x1, y1, x2, y2, color) end
---Draw the ouline of a rectangle at (x,y) of size (w,h) with the given color
function draw.rect(x, y, w, h, color) end
---@param x1 number
---@param y1 number
---@param x2 number
---@param y2 number
---@param x number
---@param y number
---@param w number
---@param h number
---@param color number
---Draw a filled rectangle from (x1,y1) to (x2,y2) with the given color
function draw.rectFill(x1, y1, x2, y2, color) end
---Draw a filled rectangle at (x,y) of size (w,h) with the given color
function draw.rectf(x, y, w, h, color) end
---@param x number
---@param y number
@@ -232,7 +233,25 @@ function draw.circ(x, y, r, color) end
---@param r number
---@param color number
---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 y1 number
@@ -248,13 +267,15 @@ function draw.oval(x1, y1, x2, y2, color) end
---@param y2 number
---@param color number
---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
---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 sy number
---@param sw number
@@ -266,12 +287,11 @@ function draw.setPattern(pattern) end
---@optional boolean flip_x
---@optional boolean flip_y
---@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,
---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 sy 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 y 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
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 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
function draw.text(text, x, y, color) end
---@param text number
---@param x number
---@param y number
---@param color number
---Draw text to (x,y) using the specified color
function draw.text(text, x, y, color) end
---@param mode number
---Specify the mode for the drawing functions
function draw.mode(mode) end
draw.NORMAL = 0
draw.PATTERN = 1
draw.AND = 2
draw.OR = 3
draw.XOR = 4
draw.NOT = 5
---@class shader
shader = {}
---Initialize shaders subsystem, still non functional without shaders
function shader.init() end
---@param shader string
---Initialize shaders subsystem, specifying a file that contains both vertex and fragment shader
function shader.init(shader) end
---@param vshader string
---@param fshader string
---Initialize shaders subsystem, specifying both a vertex shader file and a fragment shader file
function shader.init(vshader, fshader) end
---Enable previously loaded shader
function shader.enable() end
---Disable shaders
function shader.disable() end
---@class music
music = {}
@@ -297,6 +357,11 @@ music = {}
---Load and play the song in the specified OGG file
function music.play(filename) end
---@param filename string
---@param loop integer
---Load and play the song in the specified OGG file, loop number of times
function music.play(filename, loop) end
---Pause the currently playing song
function music.pause() end
@@ -306,13 +371,22 @@ function music.resume() end
---Stop the currently playing song
function music.stop() end
---@param pos number
---Set the playing position of the currently loaded song
function music.setPosition(pos) end
---@return number pos
---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
sound = {}
@@ -331,155 +405,272 @@ function sound.free(snd) end
---Play the sound specified, returns the channel in which it's playing
function sound.play(snd) end
---@param snd number
---@param loop integer
---@return number chl
---Play the sound specified loop number of times, returns the channel in which it's playing
function sound.play(snd, loop) end
---@param chl number
---Stop the channel specified
function sound.stop(chl) end
---@class system
system = {}
---@return boolean value
---Get if sound is enabled
function sound.enabled() end
---@param value boolean
---Set if sound is enabled or not
function sound.enabled(value) end
---@class sys
sys = {}
---Get delta time from last update in seconds (with decimals)
function sys.delta() end
---Get current system timer in seconds (with decimals)
function system.getTime() end
function sys.time() end
---@param bts number
---Set number of frames between beats
function system.setBeat(bts) end
---@param offset number
---Reset chrono time (with offset in seconds) (with decimals)
function sys.chrono(offset) end
---@return number
---@---Get chrono time since last chrono reset in seconds (with decimals)
function sys.chrono() end
---@return boolean
---Query if a beat has already passed
function system.isBeat() end
function sys.beat() end
---The game will call mini.update as fast as possible
function system.updateAtFullSpeed() end
---The game will call mini.update only when a keyboard, mouse or pad event fires
function system.updateOnlyOnEvents() end
---@param bts number
---Set number of frames between beats
function sys.beat(bts) end
---@param mode number
---@param ms number
---The game will call mini.update on events or after the milliseconds specified passed
function system.updateOnEventsAndTimeout(ms) end
---Sets the update mode.
---UPDATE_ALWAYS: The game will call mini.update as fast as possible
---UPDATE_EVENTS: The game will call mini.update only when a keyboard, mouse or pad event fires
---UPDATE_TIMEOUT: The game will call mini.update on events or after the milliseconds specified passed
function sys.update(mode, ms) end
---@return table
---Gets a table with the name of each file in the data directory
function system.getFilesInDataDirectory() end
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
---boolean specifying if it's a directory, for each file in the 'data' directory
function sys.dir() end
---@param path string
---@return table
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
---boolean specifying if it's a directory, for each file in the specified path
function sys.dir(path) end
---Exit the game
function system.quit() end
function sys.quit() end
---@class window
window = {}
---@return number
---Gets the frames per second
function sys.fps() end
---@return string
---Gets the content of the clipboard
function sys.clipboard() end
---@param value string
---Sets the content of the clipboard
function sys.clipboard(value) end
---@return boolean
---Returns true if running on debug version of mini. False otherwise.
function sys.debug() end
---@class win
win = {}
---@param value number
---Set the window zoom
function window.setZoom(value) end
function win.zoom(value) end
---@return number value
---Get the window zoom
function window.getZoom() end
function win.zoom() end
---@param value boolean
---Specifies if the window must display at fullscreen or not
function window.setFullscreen(value) end
function win.fullscreen(value) end
---@return boolean value
---Returns if the window is at fullscreen or not
function window.getFullscreen() end
function win.fullscreen() end
---@param value boolean
---Specifies if the cursor must be visible or not
function window.showCursor(value) end
function win.cursor(value) end
---@return number w, number h
---Returns the current window size
function window.getResolution() end
function win.res() end
---@param w number
---@param h number
---Sets the window size
function window.setResolution(w, h) end
function win.res(w, h) end
---@class config
config = {}
---@param key string
---@param value string
---@param value any
---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
---@return string value
---Gets the value of a key in the configuration file
function config.getKey(key) end
function config.key(key) end
---@return string value
---Returns the folder in which the configuration file resides
function config.getConfigFolder() end
function config.folder() end
---@class mouse
---@field mouse.LEFT number
---@field mouse.MIDDLE number
---@field mouse.RIGHT number
mouse = {}
---@return number x, number y
---Returns the current position of the mouse
function mouse.getPos() end
function mouse.pos() end
---@return number value
---Returns the value of the mouse wheel
function mouse.getWheel() end
function mouse.wheel() end
---@param btn number
---@return boolean
---Returns whether the specified mouse button is down
function mouse.buttonDown(btn) end
function mouse.down(btn) end
---@param btn number
---@return boolean
---Returns whether the specified mouse button has just been pressed
function mouse.buttonPressed(btn) end
function mouse.press(btn) end
---@class keyboard
keyboard = {}
---@return boolean
---Returns whether the user performed a double click
function mouse.dblclick() end
---Ignores current down button, effectively not raising the next "press" event
function mouse.discard() end
---@param x number
---@param y number
---@param w number
---@param h number
---@return boolean
---Returns whether the mouse is inside the rectangle specified
function mouse.inside(x,y,w,h) end
mouse.LEFT = 1
mouse.MIDDLE = 2
mouse.RIGHT = 3
---@class key
key = {}
---@param key number
---@return boolean
---Returns whether the specified keyboard key is down
function keyboard.keyDown(key) end
function key.down(key) end
---@return number
---Returns which keyboard key has just been pressed
function keyboard.keyPressed() end
function key.press() end
---@param key number
---@return boolean
---Returns whether the specified keyboard key has just been pressed
function keyboard.keyPressed(key) end
function key.press(key) end
---@return boolean
---Returns whether any keyboard key has just been pressed
function keyboard.anyKeyPressed() end
function key.any() end
---@class gamepad
gamepad = {}
---@class pad
---@field pad.INVALID number
---@field pad.A number
---@field pad.B number
---@field pad.X number
---@field pad.Y number
---@field pad.BACK number
---@field pad.GUIDE number
---@field pad.START number
---@field pad.LEFTSTICK number
---@field pad.RIGHTSTICK number
---@field pad.LEFTSHOULDER number
---@field pad.RIGHTSHOULDER number
---@field pad.UP number
---@field pad.DOWN number
---@field pad.LEFT number
---@field pad.RIGHT number
---@field pad.MISC1 number
---@field pad.PADDLE1 number
---@field pad.PADDLE2 number
---@field pad.PADDLE3 number
---@field pad.PADDLE4 number
---@field pad.TOUCHPAD number
pad = {}
---@param btn number
---@return boolean
---Returns whether the specified gamepad button is down
function gamepad.buttonDown(btn) end
function pad.down(btn) end
---@return number
---Returns which gamepad button has just been pressed
function gamepad.buttonPressed() end
function pad.press() end
---@param btn number
---@return boolean
---Returns whether the specified gamepad button has just been pressed
function gamepad.buttonPressed(btn) end
function pad.press(btn) end
---@return boolean
---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
---@field key.UNKNOWN number
@@ -509,16 +700,16 @@ function gamepad.anybuttonPressed() end
---@field key.X number
---@field key.Y number
---@field key.Z number
---@field key.1 number
---@field key.2 number
---@field key.3 number
---@field key.4 number
---@field key.5 number
---@field key.6 number
---@field key.7 number
---@field key.8 number
---@field key.9 number
---@field key.0 number
---@field key.N1 number
---@field key.N2 number
---@field key.N3 number
---@field key.N4 number
---@field key.N5 number
---@field key.N6 number
---@field key.N7 number
---@field key.N8 number
---@field key.N9 number
---@field key.N0 number
---@field key.RETURN number
---@field key.ESCAPE number
---@field key.BACKSPACE number
@@ -589,7 +780,7 @@ function gamepad.anybuttonPressed() end
---@field key.RSHIFT number
---@field key.RALT number
---@field key.RGUI number
key = {}
key.UNKNOWN = 0
key.A = 4
key.B = 5
@@ -697,52 +888,3 @@ key.RCTRL = 228
key.RSHIFT = 229
key.RALT = 230
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