Compare commits
84 Commits
dab7a96ec2
...
v1.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 536987f89b | |||
| 4084cb64f2 | |||
| 33bbf940ea | |||
| f12e46db1b | |||
| 681cbc2207 | |||
| 5db06a0645 | |||
| a17a1bb517 | |||
| fc962b4e18 | |||
| 9581ce67fd | |||
| 7c3b58c5f0 | |||
| 6e15fe7231 | |||
| eac20bbbe0 | |||
| 7fac42c9fe | |||
| 4858d94378 | |||
| 3e524fd32d | |||
| ace4a0f9f0 | |||
| 839c1e82eb | |||
| 33d7cc3b6d | |||
| a7cbdea4c5 | |||
| 3383b415cd | |||
| 02dc0a4953 | |||
| 091c2617a4 | |||
| c7559f0d29 | |||
| 327453b02c | |||
| 62ac5ae92d | |||
| 4172c6af3d | |||
| 7bff57c6fa | |||
| f154e1a36b | |||
| 0471bcbdda | |||
| 76e2925791 | |||
| 34a56fedcf | |||
| 9cd991cb44 | |||
| e1d5eb051c | |||
| 79781bbed1 | |||
| 0cb1296ad3 | |||
| 16be589a72 | |||
| 2a4195c839 | |||
| 5e24117266 | |||
| 88609465cb | |||
| 8f8009e8af | |||
| 150cb9f4ff | |||
| 4bda9cbd39 | |||
| adcc44ddab | |||
| 8e855fa2c1 | |||
| 8f98d52385 | |||
| b6e5dca277 | |||
| 3d14c33971 | |||
| 61b02fdeef | |||
| 7abc8648a1 | |||
| 2f0817d20c | |||
| ecb493f9c8 | |||
| 9c3baebc1e | |||
| 173654e0bd | |||
| ba1daf810d | |||
| 45d31579d2 | |||
| 5306e82897 | |||
| 6c9221cd20 | |||
| 99a29cf2e0 | |||
| 88e406dae0 | |||
| 29a90f4b46 | |||
| 40e98737ce | |||
| b56a0c0f71 | |||
| e36caf566c | |||
| c07e09cebd | |||
| 802f32f1b8 | |||
| 377f0a238b | |||
| 916a24230e | |||
| cddd79f05e | |||
| 4b6a9d8188 | |||
| 9e08a693c7 | |||
| 8618e922c8 | |||
| 63eaaa857e | |||
| 7569c24d04 | |||
| b29c6c873d | |||
| 1fe151ee1e | |||
| 0b6e30c01b | |||
| 663a4af6cb | |||
| d1f13a0036 | |||
| 135db2c5e0 | |||
| d16f0fef07 | |||
| 040697fcbd | |||
| 4fd9a443f2 | |||
| 88237804f7 | |||
| 9b99aa23cf |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ mini_debug
|
||||
.vscode/*
|
||||
info.plist
|
||||
*.dll
|
||||
build/*
|
||||
14
Makefile
14
Makefile
@@ -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 -lSDL2_mixer -mwindows -o "$(executable).exe"
|
||||
g++ $(source) icon.res -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lmingw32 -lSDL3 -lopengl32 -mwindows -o "$(executable).exe"
|
||||
strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable).exe"
|
||||
|
||||
windows_debug:
|
||||
@echo off
|
||||
g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL2main -lSDL2 -lSDL2_mixer -o "$(executable)_debug.exe"
|
||||
g++ $(source) -D DEBUG -g -Wall -Os -lmingw32 -lSDL3 -lopengl32 -o "$(executable)_debug.exe"
|
||||
|
||||
macos:
|
||||
clang++ $(source) -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL2 -lSDL2_mixer -o "$(executable)"
|
||||
clang++ $(source) -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)"
|
||||
|
||||
macos_debug:
|
||||
clang++ $(source) -D DEBUG -g -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL2 -lSDL2_mixer -o "$(executable)_debug"
|
||||
clang++ $(source) -D DEBUG -g -Wall -Os -std=c++11 -ffunction-sections -fdata-sections -lSDL3 -o "$(executable)_debug"
|
||||
|
||||
macos_bundle:
|
||||
clang++ $(source) -D MACOS_BUNDLE -Wall -Os -std=c++11 -framework SDL2 -framework SDL2_mixer -F /Library/Frameworks -ffunction-sections -fdata-sections -o mini_bundle -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
|
||||
clang++ $(source) -D MACOS_BUNDLE -Wall -Os -std=c++11 -framework SDL3 -F /Library/Frameworks -ffunction-sections -fdata-sections -o mini_bundle -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
|
||||
|
||||
linux:
|
||||
g++ $(source) -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL2 -lSDL2_mixer -o "$(executable)"
|
||||
g++ $(source) -D LUA_USE_LINUX -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL3 -lGL -o "$(executable)"
|
||||
strip -s -R .comment -R .gnu.version --strip-unneeded "$(executable)"
|
||||
|
||||
linux_debug:
|
||||
g++ $(source) -D DEBUG -g -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -lSDL2 -lSDL2_mixer -o "$(executable)_debug"
|
||||
g++ $(source) -D LUA_USE_LINUX -D DEBUG -g -Wall -lSDL3 -lGL -o "$(executable)_debug"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
title=HOLA MINI
|
||||
config=minitest
|
||||
width=160
|
||||
height=120
|
||||
zoom=3
|
||||
files=game.lua
|
||||
title=TESTS
|
||||
config=minitests
|
||||
width=400
|
||||
height=300
|
||||
zoom=2
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
x=0
|
||||
|
||||
function _init()
|
||||
text="HOLA MINI"
|
||||
keyRight = tonumber(getconf("keyright")) or KEY_RIGHT
|
||||
keyLeft = tonumber(getconf("keyleft")) or KEY_LEFT
|
||||
_update=normal_update
|
||||
end
|
||||
|
||||
function _update()
|
||||
end
|
||||
|
||||
function normal_update()
|
||||
view()
|
||||
|
||||
cls(20)
|
||||
view(10,10,140,100)
|
||||
cls(3)
|
||||
prnt("HOLA",0,0)
|
||||
prnt(text,x,60)
|
||||
if btnp(keyRight) then x=x+1 end
|
||||
if btnp(keyLeft) then x=x-1 end
|
||||
if btnp(KEY_SPACE) then
|
||||
redefinekeys.init()
|
||||
end
|
||||
if btnp(KEY_ESCAPE) then
|
||||
quit()
|
||||
end
|
||||
|
||||
if btnp(KEY_F2) or mbtnp(1) then
|
||||
local val = zoom() + 2
|
||||
if val >= 10 then val = 2 end
|
||||
zoom(val)
|
||||
elseif btnp(KEY_F3) then
|
||||
fullscreen(not fullscreen())
|
||||
end
|
||||
|
||||
if x>160 then x=-strlen(text)*4 end
|
||||
end
|
||||
|
||||
redefinekeys = {
|
||||
state = 0,
|
||||
init = function ()
|
||||
redefinekeys.state=0
|
||||
_update=redefinekeys.update
|
||||
end,
|
||||
update = function()
|
||||
cls(20)
|
||||
if redefinekeys.state == 0 then
|
||||
prnt("PULSA TECLA PER A DRETA...",0,0)
|
||||
local key = btnp();
|
||||
if key ~= 0 then
|
||||
redefinekeys.state = 1
|
||||
keyRight=key
|
||||
setconf("keyright", keyRight)
|
||||
end
|
||||
elseif redefinekeys.state == 1 then
|
||||
prnt("PULSA TECLA PER A ESQUERRA...",0,0)
|
||||
local key = btnp();
|
||||
if key ~= 0 then
|
||||
keyLeft=key
|
||||
setconf("keyleft", keyLeft)
|
||||
_update=normal_update
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
38
data/gbc.glsl
Normal file
38
data/gbc.glsl
Normal 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
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
9
data/ia/other.lua
Normal 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
3
data/ia/test.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
function test2()
|
||||
draw.text("THIS WORKS!",1,140,4)
|
||||
end
|
||||
41
data/lynx.glsl
Normal file
41
data/lynx.glsl
Normal file
@@ -0,0 +1,41 @@
|
||||
varying vec2 tex_coord;
|
||||
varying vec2 pix_coord;
|
||||
|
||||
#if defined(VERTEX)
|
||||
|
||||
void main()
|
||||
{
|
||||
pix_coord = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
|
||||
tex_coord = vec2((gl_Vertex.x+1.0)*0.5, (-gl_Vertex.y+1.0)*0.5);
|
||||
vec4 pos = vec4(gl_Vertex.x * 2.0, gl_Vertex.y * 2.0, gl_Vertex.z, gl_Vertex.w);
|
||||
gl_Position = gl_Vertex; //(gl_Vertex*2)-vec3(1.0, 1.0, 1.0);//gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2D Texture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float x = sign(pix_coord.x)*floor(abs(pix_coord.x)+0.5);
|
||||
float column = mod(x,4.0);
|
||||
vec4 color = texture2D(Texture, tex_coord);
|
||||
float xfade = abs((tex_coord.s * 2.0) - 1.0);
|
||||
xfade = xfade * xfade * xfade * xfade * xfade;
|
||||
float yfade = abs((tex_coord.t * 2.0) - 1.0);
|
||||
yfade = yfade * yfade * yfade * yfade * yfade;
|
||||
color = color + vec4(0.7, 0.7, 0.7, 0.0) * (1.0-tex_coord.t) * (1.0-xfade) * (1.0-yfade);
|
||||
vec4 newcolor;
|
||||
if (column == 0.0) {
|
||||
newcolor = color * vec4(1.0, 0.4, 0.6, 1.0);
|
||||
} else if (column == 1.0) {
|
||||
newcolor = color * vec4(0.4, 1.0, 0.4, 1.0);
|
||||
} else if (column == 2.0) {
|
||||
newcolor = color * vec4(0.6, 0.4, 1.0, 1.0);
|
||||
} else {
|
||||
newcolor = color * vec4(0.2, 0.2, 0.2, 1.0);
|
||||
}
|
||||
gl_FragColor = newcolor;
|
||||
}
|
||||
|
||||
#endif
|
||||
45
data/main.lua
Normal file
45
data/main.lua
Normal file
@@ -0,0 +1,45 @@
|
||||
require "ia.other"
|
||||
|
||||
x=0
|
||||
|
||||
function mini.init()
|
||||
s = surf.load("gfx/logo.gif")
|
||||
surf.source(s)
|
||||
p = pal.load("gfx/logo.gif")
|
||||
pal.set(p)
|
||||
pal.trans(255)
|
||||
--surf.save(s, "prova.gif", p)
|
||||
|
||||
print("=== PACKAGES LOADED ===")
|
||||
for name, value in pairs(package.loaded) do
|
||||
print(name, value)
|
||||
end
|
||||
print("========================")
|
||||
|
||||
end
|
||||
|
||||
function mini.update()
|
||||
surf.cls(0)
|
||||
draw.surf(0, 0, 160, 144, 0, 0)
|
||||
|
||||
draw.text("PRESS START", 60, 110, 28)
|
||||
if key.press(key.ESCAPE) then sys.quit() end
|
||||
draw.text(sys.fps(), 1, 1, 28)
|
||||
|
||||
if key.press(key.N1) then
|
||||
shader.init("lynx.glsl")
|
||||
shader.enable()
|
||||
end
|
||||
if key.press(key.N2) then
|
||||
shader.init("gbc.glsl")
|
||||
shader.enable()
|
||||
end
|
||||
if key.press(key.N3) then
|
||||
shader.disable()
|
||||
end
|
||||
|
||||
local mx, my = mouse.pos()
|
||||
draw.rectf(mx, my, 4, 4, 8)
|
||||
draw.text(mx .. " " .. my, 1, 8, 8)
|
||||
draw.text(other.peiv(),1,100,4)
|
||||
end
|
||||
BIN
data/tiles01.gif
Normal file
BIN
data/tiles01.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 764 B |
478
gif.c
478
gif.c
@@ -1,478 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define EXTENSION_INTRODUCER 0x21
|
||||
#define IMAGE_DESCRIPTOR 0x2C
|
||||
#define TRAILER 0x3B
|
||||
|
||||
#define GRAPHIC_CONTROL 0xF9
|
||||
#define APPLICATION_EXTENSION 0xFF
|
||||
#define COMMENT_EXTENSION 0xFE
|
||||
#define PLAINTEXT_EXTENSION 0x01
|
||||
|
||||
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned char fields;
|
||||
unsigned char background_color_index;
|
||||
unsigned char pixel_aspect_ratio;
|
||||
}
|
||||
screen_descriptor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
}
|
||||
rgb;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short image_left_position;
|
||||
unsigned short image_top_position;
|
||||
unsigned short image_width;
|
||||
unsigned short image_height;
|
||||
unsigned char fields;
|
||||
}
|
||||
image_descriptor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char byte;
|
||||
int prev;
|
||||
int len;
|
||||
}
|
||||
dictionary_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char extension_code;
|
||||
unsigned char block_size;
|
||||
}
|
||||
extension_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char fields;
|
||||
unsigned short delay_time;
|
||||
unsigned char transparent_color_index;
|
||||
}
|
||||
graphic_control_extension_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char application_id[ 8 ];
|
||||
unsigned char version[ 3 ];
|
||||
}
|
||||
application_extension_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short left;
|
||||
unsigned short top;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned char cell_width;
|
||||
unsigned char cell_height;
|
||||
unsigned char foreground_color;
|
||||
unsigned char background_color;
|
||||
}
|
||||
plaintext_extension_t;
|
||||
|
||||
//static unsigned short width = 0;
|
||||
//static unsigned short height = 0;
|
||||
//static unsigned char* uncompressed_data = NULL;
|
||||
|
||||
void uncompress( int code_length,
|
||||
const unsigned char *input,
|
||||
int input_length,
|
||||
unsigned char *out )
|
||||
{
|
||||
//int maxbits;
|
||||
int i, bit;
|
||||
int code, prev = -1;
|
||||
dictionary_entry_t *dictionary;
|
||||
int dictionary_ind;
|
||||
unsigned int mask = 0x01;
|
||||
int reset_code_length;
|
||||
int clear_code; // This varies depending on code_length
|
||||
int stop_code; // one more than clear code
|
||||
int match_len;
|
||||
|
||||
clear_code = 1 << ( code_length );
|
||||
stop_code = clear_code + 1;
|
||||
// To handle clear codes
|
||||
reset_code_length = code_length;
|
||||
|
||||
// Create a dictionary large enough to hold "code_length" entries.
|
||||
// Once the dictionary overflows, code_length increases
|
||||
dictionary = ( dictionary_entry_t * )
|
||||
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
// Initialize the first 2^code_len entries of the dictionary with their
|
||||
// indices. The rest of the entries will be built up dynamically.
|
||||
|
||||
// Technically, it shouldn't be necessary to initialize the
|
||||
// dictionary. The spec says that the encoder "should output a
|
||||
// clear code as the first code in the image data stream". It doesn't
|
||||
// say must, though...
|
||||
for ( dictionary_ind = 0;
|
||||
dictionary_ind < ( 1 << code_length );
|
||||
dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
// XXX this only works because prev is a 32-bit int (> 12 bits)
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
|
||||
// 2^code_len + 1 is the special "end" code; don't give it an entry here
|
||||
dictionary_ind++;
|
||||
dictionary_ind++;
|
||||
|
||||
// TODO verify that the very last byte is clear_code + 1
|
||||
while ( input_length )
|
||||
{
|
||||
code = 0x0;
|
||||
// Always read one more bit than the code length
|
||||
for ( i = 0; i < ( code_length + 1 ); i++ )
|
||||
{
|
||||
// This is different than in the file read example; that
|
||||
// was a call to "next_bit"
|
||||
bit = ( *input & mask ) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
|
||||
if ( mask == 0x100 )
|
||||
{
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
|
||||
code = code | ( bit << i );
|
||||
}
|
||||
|
||||
if ( code == clear_code )
|
||||
{
|
||||
code_length = reset_code_length;
|
||||
dictionary = ( dictionary_entry_t * ) realloc( dictionary,
|
||||
sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
for ( dictionary_ind = 0;
|
||||
dictionary_ind < ( 1 << code_length );
|
||||
dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
// XXX this only works because prev is a 32-bit int (> 12 bits)
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
dictionary_ind++;
|
||||
dictionary_ind++;
|
||||
prev = -1;
|
||||
continue;
|
||||
}
|
||||
else if ( code == stop_code )
|
||||
{
|
||||
/*if ( input_length > 1 )
|
||||
{
|
||||
fprintf( stderr, "Malformed GIF (early stop code)\n" );
|
||||
exit( 0 );
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the dictionary with this character plus the _entry_
|
||||
// (character or string) that came before it
|
||||
if ( ( prev > -1 ) && ( code_length < 12 ) )
|
||||
{
|
||||
if ( code > dictionary_ind )
|
||||
{
|
||||
fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n",
|
||||
code, dictionary_ind );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
// Special handling for KwKwK
|
||||
if ( code == dictionary_ind )
|
||||
{
|
||||
int ptr = prev;
|
||||
|
||||
while ( dictionary[ ptr ].prev != -1 )
|
||||
{
|
||||
ptr = dictionary[ ptr ].prev;
|
||||
}
|
||||
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
int ptr = code;
|
||||
while ( dictionary[ ptr ].prev != -1 )
|
||||
{
|
||||
ptr = dictionary[ ptr ].prev;
|
||||
}
|
||||
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
|
||||
}
|
||||
|
||||
dictionary[ dictionary_ind ].prev = prev;
|
||||
|
||||
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
|
||||
|
||||
dictionary_ind++;
|
||||
|
||||
// GIF89a mandates that this stops at 12 bits
|
||||
if ( ( dictionary_ind == ( 1 << ( code_length + 1 ) ) ) &&
|
||||
( code_length < 11 ) )
|
||||
{
|
||||
code_length++;
|
||||
|
||||
dictionary = ( dictionary_entry_t * ) realloc( dictionary,
|
||||
sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
prev = code;
|
||||
|
||||
// Now copy the dictionary entry backwards into "out"
|
||||
match_len = dictionary[ code ].len;
|
||||
while ( code != -1 )
|
||||
{
|
||||
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
|
||||
if ( dictionary[ code ].prev == code )
|
||||
{
|
||||
fprintf( stderr, "Internal error; self-reference." );
|
||||
exit( 0 );
|
||||
}
|
||||
code = dictionary[ code ].prev;
|
||||
}
|
||||
|
||||
out += match_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sub_blocks( unsigned char* buffer, unsigned char **data )
|
||||
{
|
||||
int data_length;
|
||||
int index;
|
||||
unsigned char block_size;
|
||||
|
||||
// Everything following are data sub-blocks, until a 0-sized block is
|
||||
// encountered.
|
||||
data_length = 0;
|
||||
*data = NULL;
|
||||
index = 0;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
READ(&block_size, 1);
|
||||
|
||||
if ( block_size == 0 ) // end of sub-blocks
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
data_length += block_size;
|
||||
*data = (unsigned char*)realloc( *data, data_length );
|
||||
|
||||
// TODO this could be split across block size boundaries
|
||||
READ(*data + index, block_size);
|
||||
|
||||
index += block_size;
|
||||
}
|
||||
|
||||
return data_length;
|
||||
}
|
||||
|
||||
unsigned char* process_image_descriptor( unsigned char* buffer,
|
||||
rgb *gct,
|
||||
int gct_size,
|
||||
int resolution_bits )
|
||||
{
|
||||
image_descriptor_t image_descriptor;
|
||||
int compressed_data_length;
|
||||
unsigned char *compressed_data = NULL;
|
||||
unsigned char lzw_code_size;
|
||||
int uncompressed_data_length = 0;
|
||||
unsigned char *uncompressed_data = NULL;
|
||||
|
||||
// TODO there could actually be lots of these
|
||||
READ(&image_descriptor, 9);
|
||||
|
||||
// TODO if LCT = true, read the LCT
|
||||
|
||||
READ(&lzw_code_size, 1);
|
||||
|
||||
compressed_data_length = read_sub_blocks( buffer, &compressed_data );
|
||||
|
||||
// width = image_descriptor.image_width;
|
||||
// height = image_descriptor.image_height;
|
||||
uncompressed_data_length = image_descriptor.image_width *
|
||||
image_descriptor.image_height;
|
||||
uncompressed_data = (unsigned char*)malloc( uncompressed_data_length );
|
||||
|
||||
uncompress( lzw_code_size, compressed_data, compressed_data_length,
|
||||
uncompressed_data );
|
||||
|
||||
if ( compressed_data ) free( compressed_data );
|
||||
|
||||
//if ( uncompressed_data )
|
||||
// free( uncompressed_data );
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param gif_file the file descriptor of a file containing a
|
||||
* GIF-encoded file. This should point to the first byte in
|
||||
* the file when invoked.
|
||||
*/
|
||||
#define rb (*(buffer++))
|
||||
|
||||
uint32_t* LoadPalette(unsigned char *buffer) {
|
||||
unsigned char header[7];
|
||||
screen_descriptor_t screen_descriptor;
|
||||
//int color_resolution_bits;
|
||||
|
||||
int global_color_table_size = 0; // number of entries in global_color_table
|
||||
uint32_t *global_color_table = NULL;
|
||||
|
||||
READ(header, 6);
|
||||
READ(&screen_descriptor, 7);
|
||||
|
||||
//color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
|
||||
global_color_table = (uint32_t *)calloc(1, 1024);
|
||||
|
||||
if (screen_descriptor.fields & 0x80) {
|
||||
global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
||||
|
||||
//global_color_table = (rgb *)malloc(3 * global_color_table_size);
|
||||
//READ(global_color_table, 3 * global_color_table_size);
|
||||
for (int i=0; i<global_color_table_size;++i) {
|
||||
global_color_table[i] = (buffer[0]<<16) + (buffer[1]<<8) + buffer[2];
|
||||
buffer+=3;
|
||||
}
|
||||
}
|
||||
return global_color_table;
|
||||
}
|
||||
|
||||
static unsigned char* process_gif_stream(unsigned char *buffer, unsigned short* w, unsigned short* h)
|
||||
{
|
||||
unsigned char header[ 7 ];
|
||||
screen_descriptor_t screen_descriptor;
|
||||
int color_resolution_bits;
|
||||
|
||||
int global_color_table_size =0; // number of entries in global_color_table
|
||||
rgb *global_color_table = NULL;
|
||||
|
||||
unsigned char block_type = 0x0;
|
||||
|
||||
// A GIF file starts with a Header (section 17)
|
||||
READ(header, 6);
|
||||
header[ 6 ] = 0x0;
|
||||
|
||||
// XXX there's another format, GIF87a, that you may still find
|
||||
// floating around.
|
||||
/*if ( strcmp( "GIF89a", (char*)header ) )
|
||||
{
|
||||
fprintf( stderr,
|
||||
"Invalid GIF file (header is '%s', should be 'GIF89a')\n",
|
||||
header );
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
// Followed by a logical screen descriptor
|
||||
// Note that this works because GIFs specify little-endian order; on a
|
||||
// big-endian machine, the height & width would need to be reversed.
|
||||
|
||||
// Can't use sizeof here since GCC does byte alignment;
|
||||
// sizeof( screen_descriptor_t ) = 8!
|
||||
READ(&screen_descriptor, 7);
|
||||
*w = screen_descriptor.width;
|
||||
*h = screen_descriptor.height;
|
||||
|
||||
color_resolution_bits = ( ( screen_descriptor.fields & 0x70 ) >> 4 ) + 1;
|
||||
|
||||
if ( screen_descriptor.fields & 0x80 )
|
||||
{
|
||||
//int i;
|
||||
// If bit 7 is set, the next block is a global color table; read it
|
||||
global_color_table_size = 1 <<
|
||||
( ( ( screen_descriptor.fields & 0x07 ) + 1 ) );
|
||||
|
||||
global_color_table = ( rgb * ) malloc( 3 * global_color_table_size );
|
||||
|
||||
// XXX this could conceivably return a short count...
|
||||
READ(global_color_table, 3 * global_color_table_size);
|
||||
}
|
||||
|
||||
while ( block_type != TRAILER )
|
||||
{
|
||||
READ(&block_type, 1);
|
||||
|
||||
unsigned char size;
|
||||
switch ( block_type )
|
||||
{
|
||||
case IMAGE_DESCRIPTOR:
|
||||
return process_image_descriptor(buffer,
|
||||
global_color_table,
|
||||
global_color_table_size,
|
||||
color_resolution_bits);
|
||||
break;
|
||||
case EXTENSION_INTRODUCER:
|
||||
buffer++;
|
||||
size = *(buffer++);
|
||||
buffer += size;
|
||||
do {
|
||||
size = *(buffer++);
|
||||
buffer += size;
|
||||
} while (size != 0);
|
||||
|
||||
/*if ( !process_extension( buffer ) )
|
||||
{
|
||||
return NULL;
|
||||
}*/
|
||||
break;
|
||||
case TRAILER:
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "Bailing on unrecognized block type %.02x\n",
|
||||
block_type );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
|
||||
return process_gif_stream(buffer, w, h);
|
||||
}
|
||||
|
||||
/*int main( int argc, char *argv[] )
|
||||
{
|
||||
FILE* gif_file;
|
||||
|
||||
if ( argc < 2 )
|
||||
{
|
||||
fprintf( stderr, "Usage: %s <path-to-gif-file>\n", argv[ 0 ] );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
gif_file = fopen( argv[ 1 ], "rb" );
|
||||
|
||||
if ( gif_file == NULL )
|
||||
{
|
||||
fprintf( stderr, "Unable to open file '%s'", argv[ 1 ] );
|
||||
perror( ": " );
|
||||
}
|
||||
|
||||
process_gif_stream( gif_file );
|
||||
|
||||
fclose( gif_file );
|
||||
}*/
|
||||
227
gif.h
Normal file
227
gif.h
Normal file
@@ -0,0 +1,227 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
|
||||
|
||||
struct rgb { uint8_t r, g, b; };
|
||||
|
||||
struct image_descriptor_t
|
||||
{
|
||||
uint16_t left, top, width, height;
|
||||
uint8_t fields;
|
||||
};
|
||||
|
||||
struct dictionary_entry_t
|
||||
{
|
||||
unsigned char byte;
|
||||
int prev, len;
|
||||
};
|
||||
|
||||
void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out )
|
||||
{
|
||||
dictionary_entry_t *dictionary;
|
||||
int dictionary_ind;
|
||||
|
||||
const int clear_code = 1 << ( code_length );
|
||||
const int stop_code = clear_code + 1;
|
||||
const int reset_code_length = code_length;
|
||||
|
||||
dictionary = ( dictionary_entry_t * )
|
||||
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
dictionary_ind+=2;
|
||||
|
||||
int prev = -1;
|
||||
uint32_t mask = 0x01;
|
||||
while ( input_length )
|
||||
{
|
||||
int code = 0x0;
|
||||
|
||||
for (int i=0; i<(code_length + 1); i++)
|
||||
{
|
||||
const int bit = ( *input & mask ) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
|
||||
if ( mask == 0x100 )
|
||||
{
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
|
||||
code = code | ( bit << i );
|
||||
}
|
||||
|
||||
if ( code == clear_code )
|
||||
{
|
||||
code_length = reset_code_length;
|
||||
dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
dictionary_ind+=2;
|
||||
prev = -1;
|
||||
continue;
|
||||
}
|
||||
else if ( code == stop_code ) break;
|
||||
|
||||
if ( (prev > -1) && (code_length < 12) )
|
||||
{
|
||||
if (code > dictionary_ind)
|
||||
{
|
||||
fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
int ptr = (code == dictionary_ind) ? prev : code;
|
||||
while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
|
||||
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
|
||||
|
||||
dictionary[ dictionary_ind ].prev = prev;
|
||||
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
|
||||
dictionary_ind++;
|
||||
|
||||
if ( (dictionary_ind == (1 << (code_length + 1))) && (code_length < 11) )
|
||||
{
|
||||
code_length++;
|
||||
dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
prev = code;
|
||||
|
||||
const int match_len = dictionary[ code ].len;
|
||||
while ( code != -1 )
|
||||
{
|
||||
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
|
||||
if ( dictionary[ code ].prev == code )
|
||||
{
|
||||
fprintf( stderr, "Internal error; self-reference." );
|
||||
exit( 0 );
|
||||
}
|
||||
code = dictionary[ code ].prev;
|
||||
}
|
||||
out += match_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sub_blocks( uint8_t* buffer, uint8_t **data )
|
||||
{
|
||||
int data_length = 0;
|
||||
*data = NULL;
|
||||
int index = 0;
|
||||
|
||||
while (1) {
|
||||
uint8_t block_size = *(buffer++);
|
||||
if ( block_size == 0 ) break;
|
||||
|
||||
data_length += block_size;
|
||||
*data = (uint8_t*)realloc( *data, data_length );
|
||||
READ(*data + index, block_size);
|
||||
index += block_size;
|
||||
}
|
||||
|
||||
return data_length;
|
||||
}
|
||||
|
||||
uint8_t* process_image_descriptor( uint8_t* buffer, rgb *gct, int gct_size, int resolution_bits )
|
||||
{
|
||||
image_descriptor_t image_descriptor;
|
||||
READ(&image_descriptor, 9);
|
||||
|
||||
uint8_t lzw_code_size;
|
||||
READ(&lzw_code_size, 1);
|
||||
|
||||
uint8_t *compressed_data = NULL;
|
||||
const int compressed_data_length = read_sub_blocks( buffer, &compressed_data );
|
||||
|
||||
const int uncompressed_data_length = image_descriptor.width * image_descriptor.height;
|
||||
uint8_t *uncompressed_data = (uint8_t*)malloc( uncompressed_data_length );
|
||||
|
||||
uncompress( lzw_code_size, compressed_data, compressed_data_length, uncompressed_data );
|
||||
|
||||
if ( compressed_data ) free( compressed_data );
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
uint32_t* LoadPalette(uint8_t *buffer, uint16_t *size = NULL )
|
||||
{
|
||||
buffer += 10;
|
||||
const uint8_t fields = *buffer;
|
||||
|
||||
uint32_t *global_color_table = (uint32_t *)calloc(1, 1024);;
|
||||
|
||||
if (size) *size = 0;
|
||||
if (fields & 0x80) {
|
||||
int global_color_table_size = 1 << (((fields & 0x07) + 1));
|
||||
if (size) *size = global_color_table_size;
|
||||
|
||||
for (int i=0; i<global_color_table_size;++i) {
|
||||
buffer+=3;
|
||||
global_color_table[i] = (buffer[0]<<16) + (buffer[1]<<8) + buffer[2];
|
||||
}
|
||||
}
|
||||
return global_color_table;
|
||||
}
|
||||
|
||||
static uint8_t* LoadGif(uint8_t *buffer, uint16_t* w, uint16_t* h)
|
||||
{
|
||||
int global_color_table_size = 0; // number of entries in global_color_table
|
||||
rgb *global_color_table = NULL;
|
||||
|
||||
buffer += 6; // Ignore header
|
||||
*w = *((uint16_t*)buffer); buffer+=2;
|
||||
*h = *((uint16_t*)buffer); buffer+=2;
|
||||
const uint8_t fields = *buffer; buffer+=3;
|
||||
|
||||
const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1;
|
||||
|
||||
if ( fields & 0x80 )
|
||||
{
|
||||
global_color_table_size = 1 << ( ( ( fields & 0x07 ) + 1 ) );
|
||||
global_color_table = (rgb*)malloc( 3 * global_color_table_size );
|
||||
READ(global_color_table, 3 * global_color_table_size);
|
||||
}
|
||||
|
||||
uint8_t block_type = 0x0;
|
||||
while ( block_type != 0x3B )
|
||||
{
|
||||
READ(&block_type, 1);
|
||||
|
||||
uint8_t size;
|
||||
switch ( block_type )
|
||||
{
|
||||
case 0x2C:
|
||||
return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits);
|
||||
case 0x21:
|
||||
buffer++; //size = *(buffer++); buffer += size;
|
||||
do { size = *(buffer++); buffer += size; } while (size != 0);
|
||||
break;
|
||||
case 0x3B:
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "Bailing on unrecognized block type %.02x\n", block_type );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
|
||||
return process_gif_stream(buffer, w, h);
|
||||
}*/
|
||||
174
gifenc.h
Normal file
174
gifenc.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DICT_SIZE 4096
|
||||
|
||||
namespace gif
|
||||
{
|
||||
typedef struct {
|
||||
int prefix;
|
||||
uint8_t character;
|
||||
} DictEntry;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
int bit_pos;
|
||||
uint32_t bit_buffer;
|
||||
} BitStream;
|
||||
|
||||
void bitstream_init(BitStream *bs) {
|
||||
bs->capacity = 256;
|
||||
bs->size = 0;
|
||||
bs->data = (uint8_t*)malloc(bs->capacity);
|
||||
bs->bit_pos = 0;
|
||||
bs->bit_buffer = 0;
|
||||
}
|
||||
|
||||
void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
|
||||
bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
|
||||
bs->bit_pos += code_size;
|
||||
|
||||
while (bs->bit_pos >= 8) {
|
||||
if (bs->size >= bs->capacity) {
|
||||
bs->capacity *= 2;
|
||||
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||
}
|
||||
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||
bs->bit_buffer >>= 8;
|
||||
bs->bit_pos -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstream_flush(BitStream *bs) {
|
||||
if (bs->bit_pos > 0) {
|
||||
if (bs->size >= bs->capacity) {
|
||||
bs->capacity *= 2;
|
||||
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||
}
|
||||
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lzw_compress(uint8_t *input, int width, int height, int min_code_size, size_t *out_size) {
|
||||
int clear_code = 1 << min_code_size;
|
||||
int end_code = clear_code + 1;
|
||||
int next_code = end_code + 1;
|
||||
int code_size = min_code_size + 1;
|
||||
|
||||
DictEntry dict[MAX_DICT_SIZE];
|
||||
int dict_len = next_code;
|
||||
|
||||
BitStream bs;
|
||||
bitstream_init(&bs);
|
||||
bitstream_write(&bs, clear_code, code_size);
|
||||
|
||||
int prefix = input[0];
|
||||
for (int i = 1; i < width * height; i++) {
|
||||
uint8_t c = input[i];
|
||||
|
||||
// Search for prefix + c in dictionary
|
||||
int found = -1;
|
||||
for (int j = end_code + 1; j < dict_len; j++) {
|
||||
if (dict[j].prefix == prefix && dict[j].character == c) {
|
||||
found = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != -1) {
|
||||
prefix = found; // Extend prefix
|
||||
} else {
|
||||
bitstream_write(&bs, prefix, code_size); // Emit current prefix
|
||||
if (dict_len < MAX_DICT_SIZE) {
|
||||
if (dict_len == (1 << code_size) && code_size < 12) code_size++;
|
||||
dict[dict_len].prefix = prefix;
|
||||
dict[dict_len].character = c;
|
||||
dict_len++;
|
||||
} else {
|
||||
bitstream_write(&bs, clear_code, code_size);
|
||||
dict_len = end_code + 1;
|
||||
code_size = min_code_size + 1;
|
||||
}
|
||||
prefix = c; // Start new prefix
|
||||
}
|
||||
}
|
||||
|
||||
// Emit final prefix and end code
|
||||
bitstream_write(&bs, prefix, code_size);
|
||||
bitstream_write(&bs, end_code, code_size);
|
||||
bitstream_flush(&bs);
|
||||
|
||||
*out_size = bs.size;
|
||||
return bs.data;
|
||||
}
|
||||
|
||||
void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror("Failed to open file");
|
||||
return;
|
||||
}
|
||||
|
||||
// Header
|
||||
fwrite("GIF89a", 1, 6, f);
|
||||
|
||||
// Determine min_code_size from palette_size
|
||||
int palette_depth = 0;
|
||||
while ((1 << palette_depth) < palette_size) palette_depth++;
|
||||
const int min_code_size = palette_depth < 2 ? 2 : palette_depth; // GIF spec requires at least 2
|
||||
|
||||
printf("min_code_size: %i\n", palette_depth);
|
||||
|
||||
// Logical Screen Descriptor
|
||||
uint8_t packed_field = palette ? (0x80 | ((palette_depth - 1) << 4) | (palette_depth - 1)) : 0x00;
|
||||
uint8_t screen_desc[] = {
|
||||
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
|
||||
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
|
||||
packed_field, // GCT flag + color resolution + size
|
||||
0x00, // Background color index
|
||||
0x00 // Pixel aspect ratio
|
||||
};
|
||||
fwrite(screen_desc, 1, sizeof(screen_desc), f);
|
||||
|
||||
// Global Color Table (if provided)
|
||||
if (palette) {
|
||||
int gct_size = 1 << palette_depth;
|
||||
fwrite(palette, 1, gct_size * 3, f);
|
||||
}
|
||||
|
||||
// Image Descriptor
|
||||
uint8_t image_desc[] = {
|
||||
0x2C, 0, 0, 0, 0,
|
||||
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
|
||||
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
|
||||
0x00 // No local color table
|
||||
};
|
||||
fwrite(image_desc, 1, sizeof(image_desc), f);
|
||||
|
||||
// LZW-compressed image data
|
||||
fwrite(&min_code_size, 1, 1, f);
|
||||
|
||||
size_t compressed_size;
|
||||
uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
|
||||
|
||||
// Write as sub-blocks
|
||||
size_t offset = 0;
|
||||
while (offset < compressed_size) {
|
||||
uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
|
||||
fwrite(&block_size, 1, 1, f);
|
||||
fwrite(compressed + offset, 1, block_size, f);
|
||||
offset += block_size;
|
||||
}
|
||||
fputc(0x00, f); // Block terminator
|
||||
|
||||
// Trailer
|
||||
fputc(0x3B, f);
|
||||
|
||||
free(compressed);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
507
jail_audio.cpp
Normal file
507
jail_audio.cpp
Normal file
@@ -0,0 +1,507 @@
|
||||
#ifndef JA_USESDLMIXER
|
||||
#include "jail_audio.h"
|
||||
#include "stb_vorbis.h"
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdio.h>
|
||||
#include "log.h"
|
||||
|
||||
#define JA_MAX_SIMULTANEOUS_CHANNELS 5
|
||||
|
||||
struct JA_Sound_t
|
||||
{
|
||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||
Uint32 length { 0 };
|
||||
Uint8 *buffer { NULL };
|
||||
};
|
||||
|
||||
struct JA_Channel_t
|
||||
{
|
||||
JA_Sound_t *sound { nullptr };
|
||||
int pos { 0 };
|
||||
int times { 0 };
|
||||
SDL_AudioStream *stream { nullptr };
|
||||
JA_Channel_state state { JA_CHANNEL_FREE };
|
||||
};
|
||||
|
||||
struct JA_Music_t
|
||||
{
|
||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||
Uint32 length { 0 };
|
||||
Uint8 *buffer { nullptr };
|
||||
|
||||
int pos { 0 };
|
||||
int times { 0 };
|
||||
SDL_AudioStream *stream { nullptr };
|
||||
JA_Music_state state { JA_MUSIC_INVALID };
|
||||
};
|
||||
|
||||
JA_Music_t *current_music { nullptr };
|
||||
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
|
||||
|
||||
SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 };
|
||||
float JA_musicVolume { 1.0f };
|
||||
float JA_soundVolume { 0.5f };
|
||||
bool JA_musicEnabled { true };
|
||||
bool JA_soundEnabled { true };
|
||||
SDL_AudioDeviceID sdlAudioDevice { 0 };
|
||||
SDL_TimerID JA_timerID { 0 };
|
||||
|
||||
bool fading = false;
|
||||
int fade_start_time;
|
||||
int fade_duration;
|
||||
int fade_initial_volume;
|
||||
|
||||
/*
|
||||
void audioCallback(void * userdata, uint8_t * stream, int len) {
|
||||
SDL_memset(stream, 0, len);
|
||||
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
|
||||
const int size = SDL_min(len, current_music->samples*2-current_music->pos);
|
||||
SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, JA_musicVolume);
|
||||
current_music->pos += size/2;
|
||||
if (size < len) {
|
||||
if (current_music->times != 0) {
|
||||
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, JA_musicVolume);
|
||||
current_music->pos = (len-size)/2;
|
||||
if (current_music->times > 0) current_music->times--;
|
||||
} else {
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mixar els channels mi amol
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING) {
|
||||
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
|
||||
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
|
||||
channels[i].pos += size;
|
||||
if (size < len) {
|
||||
if (channels[i].times != 0) {
|
||||
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
|
||||
channels[i].pos = len-size;
|
||||
if (channels[i].times > 0) channels[i].times--;
|
||||
} else {
|
||||
JA_StopChannel(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
|
||||
{
|
||||
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING)
|
||||
{
|
||||
if (fading) {
|
||||
int time = SDL_GetTicks();
|
||||
if (time > (fade_start_time+fade_duration)) {
|
||||
fading = false;
|
||||
JA_StopMusic();
|
||||
return 30;
|
||||
} else {
|
||||
const int time_passed = time - fade_start_time;
|
||||
const float percent = (float)time_passed / (float)fade_duration;
|
||||
SDL_SetAudioStreamGain(current_music->stream, 1.0 - percent);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_music->times != 0)
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(current_music->stream) < int(current_music->length/2)) {
|
||||
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
||||
}
|
||||
if (current_music->times>0) current_music->times--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic();
|
||||
}
|
||||
}
|
||||
|
||||
if (JA_soundEnabled)
|
||||
{
|
||||
for (int i=0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
||||
{
|
||||
if (channels[i].times != 0)
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(channels[i].stream) < int(channels[i].sound->length/2))
|
||||
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
|
||||
if (channels[i].times>0) channels[i].times--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 30;
|
||||
}
|
||||
|
||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
|
||||
#endif
|
||||
|
||||
JA_audioSpec = {format, channels, freq };
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
|
||||
if (!sdlAudioDevice) {
|
||||
log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError());
|
||||
} else {
|
||||
log_msg(LOG_OK, "Audio subsytem initialized\n");
|
||||
}
|
||||
//SDL_PauseAudioDevice(sdlAudioDevice);
|
||||
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
|
||||
}
|
||||
|
||||
void JA_Quit()
|
||||
{
|
||||
if (JA_timerID) SDL_RemoveTimer(JA_timerID);
|
||||
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = 0;
|
||||
}
|
||||
|
||||
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
|
||||
{
|
||||
JA_Music_t *music = new JA_Music_t();
|
||||
|
||||
int chan, samplerate;
|
||||
short *output;
|
||||
music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
||||
|
||||
music->spec.channels = chan;
|
||||
music->spec.freq = samplerate;
|
||||
music->spec.format = SDL_AUDIO_S16;
|
||||
music->buffer = (Uint8*)SDL_malloc(music->length);
|
||||
SDL_memcpy(music->buffer, output, music->length);
|
||||
free(output);
|
||||
music->pos = 0;
|
||||
music->state = JA_MUSIC_STOPPED;
|
||||
|
||||
return music;
|
||||
}
|
||||
|
||||
JA_Music_t *JA_LoadMusic(const char* filename)
|
||||
{
|
||||
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
|
||||
FILE *f = fopen(filename, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
|
||||
if (fread(buffer, fsize, 1, f)!=1) return NULL;
|
||||
fclose(f);
|
||||
|
||||
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
|
||||
|
||||
free(buffer);
|
||||
|
||||
return music;
|
||||
}
|
||||
|
||||
void JA_PlayMusic(JA_Music_t *music, const int loop)
|
||||
{
|
||||
if (!JA_musicEnabled) return;
|
||||
|
||||
JA_StopMusic();
|
||||
|
||||
current_music = music;
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_PLAYING;
|
||||
current_music->times = loop;
|
||||
|
||||
current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec);
|
||||
if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n");
|
||||
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
||||
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
|
||||
//SDL_ResumeAudioStreamDevice(current_music->stream);
|
||||
}
|
||||
|
||||
void JA_PauseMusic()
|
||||
{
|
||||
if (!JA_musicEnabled) return;
|
||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
||||
|
||||
current_music->state = JA_MUSIC_PAUSED;
|
||||
//SDL_PauseAudioStreamDevice(current_music->stream);
|
||||
SDL_UnbindAudioStream(current_music->stream);
|
||||
}
|
||||
|
||||
void JA_ResumeMusic()
|
||||
{
|
||||
if (!JA_musicEnabled) return;
|
||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
||||
|
||||
current_music->state = JA_MUSIC_PLAYING;
|
||||
//SDL_ResumeAudioStreamDevice(current_music->stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
|
||||
}
|
||||
|
||||
void JA_StopMusic()
|
||||
{
|
||||
if (!JA_musicEnabled) return;
|
||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
||||
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
//SDL_PauseAudioStreamDevice(current_music->stream);
|
||||
SDL_DestroyAudioStream(current_music->stream);
|
||||
current_music->stream = nullptr;
|
||||
}
|
||||
|
||||
void JA_FadeOutMusic(const int milliseconds)
|
||||
{
|
||||
if (!JA_musicEnabled) return;
|
||||
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
|
||||
|
||||
fading = true;
|
||||
fade_start_time = SDL_GetTicks();
|
||||
fade_duration = milliseconds;
|
||||
fade_initial_volume = JA_musicVolume;
|
||||
}
|
||||
|
||||
JA_Music_state JA_GetMusicState()
|
||||
{
|
||||
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
|
||||
if (!current_music) return JA_MUSIC_INVALID;
|
||||
|
||||
return current_music->state;
|
||||
}
|
||||
|
||||
void JA_DeleteMusic(JA_Music_t *music)
|
||||
{
|
||||
if (current_music == music) current_music = nullptr;
|
||||
SDL_free(music->buffer);
|
||||
if (music->stream) SDL_DestroyAudioStream(music->stream);
|
||||
delete music;
|
||||
}
|
||||
|
||||
float JA_SetMusicVolume(float volume)
|
||||
{
|
||||
JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f );
|
||||
if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
||||
return JA_musicVolume;
|
||||
}
|
||||
|
||||
void JA_SetMusicPosition(float value)
|
||||
{
|
||||
if (!current_music) return;
|
||||
current_music->pos = value * current_music->spec.freq;
|
||||
}
|
||||
|
||||
float JA_GetMusicPosition()
|
||||
{
|
||||
if (!current_music) return 0;
|
||||
return float(current_music->pos)/float(current_music->spec.freq);
|
||||
}
|
||||
|
||||
void JA_EnableMusic(const bool value)
|
||||
{
|
||||
if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic();
|
||||
|
||||
JA_musicEnabled = value;
|
||||
}
|
||||
|
||||
const bool JA_IsMusicEnabled()
|
||||
{
|
||||
return JA_musicEnabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
sound->buffer = buffer;
|
||||
sound->length = length;
|
||||
return sound;
|
||||
}
|
||||
|
||||
JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length);
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
JA_Sound_t *JA_LoadSound(const char* filename)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
int JA_PlaySound(JA_Sound_t *sound, const int loop)
|
||||
{
|
||||
if (!JA_soundEnabled) return -1;
|
||||
|
||||
int channel = 0;
|
||||
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
|
||||
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
|
||||
JA_StopChannel(channel);
|
||||
|
||||
channels[channel].sound = sound;
|
||||
channels[channel].times = loop;
|
||||
channels[channel].pos = 0;
|
||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
||||
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
|
||||
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
|
||||
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
|
||||
{
|
||||
if (!JA_soundEnabled) return -1;
|
||||
|
||||
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1;
|
||||
JA_StopChannel(channel);
|
||||
|
||||
channels[channel].sound = sound;
|
||||
channels[channel].times = loop;
|
||||
channels[channel].pos = 0;
|
||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
||||
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
|
||||
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
|
||||
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
void JA_DeleteSound(JA_Sound_t *sound)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].sound == sound) JA_StopChannel(i);
|
||||
}
|
||||
SDL_free(sound->buffer);
|
||||
delete sound;
|
||||
}
|
||||
|
||||
void JA_PauseChannel(const int channel)
|
||||
{
|
||||
if (!JA_soundEnabled) return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
||||
{
|
||||
channels[i].state = JA_CHANNEL_PAUSED;
|
||||
//SDL_PauseAudioStreamDevice(channels[i].stream);
|
||||
SDL_UnbindAudioStream(channels[i].stream);
|
||||
}
|
||||
}
|
||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
||||
{
|
||||
if (channels[channel].state == JA_CHANNEL_PLAYING)
|
||||
{
|
||||
channels[channel].state = JA_CHANNEL_PAUSED;
|
||||
//SDL_PauseAudioStreamDevice(channels[channel].stream);
|
||||
SDL_UnbindAudioStream(channels[channel].stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JA_ResumeChannel(const int channel)
|
||||
{
|
||||
if (!JA_soundEnabled) return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
if (channels[i].state == JA_CHANNEL_PAUSED)
|
||||
{
|
||||
channels[i].state = JA_CHANNEL_PLAYING;
|
||||
//SDL_ResumeAudioStreamDevice(channels[i].stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
|
||||
}
|
||||
}
|
||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
||||
{
|
||||
if (channels[channel].state == JA_CHANNEL_PAUSED)
|
||||
{
|
||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
||||
//SDL_ResumeAudioStreamDevice(channels[channel].stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JA_StopChannel(const int channel)
|
||||
{
|
||||
if (!JA_soundEnabled) return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[i].stream);
|
||||
channels[i].stream = nullptr;
|
||||
channels[i].state = JA_CHANNEL_FREE;
|
||||
channels[i].pos = 0;
|
||||
channels[i].sound = NULL;
|
||||
}
|
||||
}
|
||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
||||
{
|
||||
if (channels[channel].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[channel].stream);
|
||||
channels[channel].stream = nullptr;
|
||||
channels[channel].state = JA_CHANNEL_FREE;
|
||||
channels[channel].pos = 0;
|
||||
channels[channel].sound = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JA_Channel_state JA_GetChannelState(const int channel)
|
||||
{
|
||||
if (!JA_soundEnabled) return JA_SOUND_DISABLED;
|
||||
|
||||
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
|
||||
|
||||
return channels[channel].state;
|
||||
}
|
||||
|
||||
float JA_SetSoundVolume(float volume)
|
||||
{
|
||||
JA_soundVolume = SDL_clamp( volume, 0.0f, 1.0f );
|
||||
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
if ( (channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED) )
|
||||
SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume);
|
||||
|
||||
return JA_soundVolume;
|
||||
}
|
||||
|
||||
void JA_EnableSound(const bool value)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
|
||||
}
|
||||
JA_soundEnabled = value;
|
||||
}
|
||||
|
||||
const bool JA_IsSoundEnabled()
|
||||
{
|
||||
return JA_soundEnabled;
|
||||
}
|
||||
|
||||
float JA_SetVolume(float volume)
|
||||
{
|
||||
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
|
||||
|
||||
return JA_musicVolume;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
jail_audio.h
Normal file
42
jail_audio.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
|
||||
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
|
||||
|
||||
struct JA_Sound_t;
|
||||
struct JA_Music_t;
|
||||
|
||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
|
||||
void JA_Quit();
|
||||
|
||||
JA_Music_t *JA_LoadMusic(const char* filename);
|
||||
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length);
|
||||
void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
|
||||
void JA_PauseMusic();
|
||||
void JA_ResumeMusic();
|
||||
void JA_StopMusic();
|
||||
void JA_FadeOutMusic(const int milliseconds);
|
||||
JA_Music_state JA_GetMusicState();
|
||||
void JA_DeleteMusic(JA_Music_t *music);
|
||||
float JA_SetMusicVolume(float volume);
|
||||
void JA_SetMusicPosition(float value);
|
||||
float JA_GetMusicPosition();
|
||||
void JA_EnableMusic(const bool value);
|
||||
const bool JA_IsMusicEnabled();
|
||||
|
||||
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
|
||||
JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
|
||||
JA_Sound_t *JA_LoadSound(const char* filename);
|
||||
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
|
||||
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
|
||||
void JA_PauseChannel(const int channel);
|
||||
void JA_ResumeChannel(const int channel);
|
||||
void JA_StopChannel(const int channel);
|
||||
JA_Channel_state JA_GetChannelState(const int channel);
|
||||
void JA_DeleteSound(JA_Sound_t *sound);
|
||||
float JA_SetSoundVolume(float volume);
|
||||
void JA_EnableSound(const bool value);
|
||||
const bool JA_IsSoundEnabled();
|
||||
|
||||
float JA_SetVolume(float volume);
|
||||
235
jfile.cpp
235
jfile.cpp
@@ -5,40 +5,30 @@
|
||||
#include "jfile.h"
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <algorithm>
|
||||
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_FILENAME "data.jrf"
|
||||
#define DEFAULT_FILENAME "data.jf2"
|
||||
#define DEFAULT_FOLDER "data/"
|
||||
#define CONFIG_FILENAME "config.txt"
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct DATA_Header {
|
||||
char magic[4];
|
||||
uint32_t num_files;
|
||||
uint32_t index_offset;
|
||||
struct file_t
|
||||
{
|
||||
std::string path;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
struct DATA_Info {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
char name[13];
|
||||
};
|
||||
|
||||
struct DATA_Index {
|
||||
DATA_Info* file_info;
|
||||
};
|
||||
|
||||
struct DATA_File {
|
||||
DATA_Header header;
|
||||
DATA_Index index;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
std::vector<file_t> toc;
|
||||
|
||||
/* El std::map me fa coses rares, vaig a usar un good old std::vector amb una estructura key,value propia i au, que sempre funciona */
|
||||
struct keyvalue_t {
|
||||
@@ -47,7 +37,6 @@ struct keyvalue_t {
|
||||
|
||||
char *resource_filename = NULL;
|
||||
char *resource_folder = NULL;
|
||||
DATA_File *data_file = NULL;
|
||||
int file_source = SOURCE_FILE;
|
||||
char scratch[255];
|
||||
static std::string config_folder;
|
||||
@@ -72,18 +61,31 @@ void file_setsource(const int src) {
|
||||
|
||||
bool file_getdictionary() {
|
||||
if (resource_filename == NULL) file_setresourcefilename(DEFAULT_FILENAME);
|
||||
FILE* f = fopen(resource_filename, "rb");
|
||||
if (f) {
|
||||
data_file = (DATA_File*)malloc(sizeof(DATA_File));
|
||||
fread((char*)&data_file->header, sizeof(DATA_Header), 1, f);
|
||||
fseek(f, data_file->header.index_offset, SEEK_SET);
|
||||
data_file->index.file_info = (DATA_Info*)malloc(data_file->header.num_files * sizeof(DATA_Info));
|
||||
fread((char*)data_file->index.file_info, data_file->header.num_files * sizeof(DATA_Info), 1, f);
|
||||
fclose(f);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
std::ifstream fi (resource_filename, std::ios::binary);
|
||||
if (!fi.is_open()) return false;
|
||||
char header[4];
|
||||
fi.read(header, 4);
|
||||
uint32_t num_files, toc_offset;
|
||||
fi.read((char*)&num_files, 4);
|
||||
fi.read((char*)&toc_offset, 4);
|
||||
fi.seekg(toc_offset);
|
||||
|
||||
for (uint32_t i=0; i<num_files; ++i)
|
||||
{
|
||||
uint32_t file_offset, file_size;
|
||||
fi.read( (char*)&file_offset, 4 );
|
||||
fi.read( (char*)&file_size, 4 );
|
||||
uint8_t path_size;
|
||||
fi.read( (char*)&path_size, 1 );
|
||||
char file_name[path_size+1];
|
||||
fi.read( file_name, path_size );
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
toc.push_back({filename, file_size, file_offset});
|
||||
}
|
||||
fi.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
char *file_getfilenamewithfolder(const char* filename) {
|
||||
@@ -94,7 +96,7 @@ char *file_getfilenamewithfolder(const char* filename) {
|
||||
|
||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary) {
|
||||
|
||||
if (file_source==SOURCE_FILE and not data_file) {
|
||||
if (file_source==SOURCE_FILE and toc.size()==0) {
|
||||
if (not file_getdictionary()) file_setsource(SOURCE_FOLDER);
|
||||
}
|
||||
|
||||
@@ -103,8 +105,8 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
|
||||
if (file_source==SOURCE_FILE) {
|
||||
bool found = false;
|
||||
uint32_t count = 0;
|
||||
while( !found && count < data_file->header.num_files ) {
|
||||
found = ( strcmp( resourcename, data_file->index.file_info[count].name ) == 0 );
|
||||
while( !found && count < toc.size() ) {
|
||||
found = ( std::string(resourcename) == toc[count].path );
|
||||
if( !found ) count++;
|
||||
}
|
||||
|
||||
@@ -113,14 +115,14 @@ FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool bi
|
||||
exit(1);
|
||||
}
|
||||
|
||||
filesize = data_file->index.file_info[count].length;
|
||||
filesize = toc[count].size;
|
||||
|
||||
f = fopen(resource_filename, binary?"rb":"r");
|
||||
if (not f) {
|
||||
perror("No s'ha pogut obrir l'arxiu de recursos");
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, data_file->index.file_info[count].offset, SEEK_SET);
|
||||
fseek(f, toc[count].offset, SEEK_SET);
|
||||
} else {
|
||||
f = fopen(file_getfilenamewithfolder(resourcename), binary?"rb":"r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
@@ -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
10
jfile.h
@@ -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
250
jshader.cpp
Normal 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, ¶m);
|
||||
//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
48
jshader.h
Normal 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
5
lagueirtofile
Normal 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
27
log.h
Normal 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
|
||||
2
lua.h
2
lua.h
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
bool lua_is_playing();
|
||||
void lua_init(char* filenames);
|
||||
void lua_init(const char* main_lua_file = "main.lua");
|
||||
void lua_call_init();
|
||||
void lua_call_update();
|
||||
void lua_quit();
|
||||
|
||||
112
lua/loadlib.c
112
lua/loadlib.c
@@ -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] */
|
||||
|
||||
129
mini.h
129
mini.h
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#define MINI_VERSION "0.9.32d"
|
||||
#include "version.h"
|
||||
|
||||
#define KEY_UNKNOWN 0
|
||||
#define KEY_A 4
|
||||
@@ -112,34 +112,50 @@
|
||||
#define KEY_RALT 230
|
||||
#define KEY_RGUI 231
|
||||
|
||||
#define DRAWMODE_NORMAL 0
|
||||
#define DRAWMODE_PATTERN 1
|
||||
#define DRAWMODE_AND 2
|
||||
#define DRAWMODE_OR 3
|
||||
#define DRAWMODE_XOR 4
|
||||
#define DRAWMODE_NOT 5
|
||||
|
||||
void loop();
|
||||
|
||||
int scrw();
|
||||
int scrh();
|
||||
|
||||
uint8_t newsurf(int w, int h);
|
||||
uint8_t loadsurf(const char* filename);
|
||||
uint8_t loadsurf(const char* filename, const bool external = false);
|
||||
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
|
||||
void freesurf(uint8_t surface);
|
||||
int surfw(uint8_t surface);
|
||||
int surfh(uint8_t surface);
|
||||
|
||||
void setdest(uint8_t surface);
|
||||
void setsource(uint8_t surface);
|
||||
void setmap(uint8_t surface);
|
||||
uint8_t getdest();
|
||||
uint8_t getsource();
|
||||
uint8_t getmap();
|
||||
|
||||
void shader_init(const char* vshader, const char* fshader);
|
||||
void shader_enable();
|
||||
void shader_disable();
|
||||
|
||||
void cls(uint8_t color=0);
|
||||
void color(uint8_t color=6);
|
||||
void bcolor(uint8_t color=0);
|
||||
|
||||
uint32_t *loadpal(const char* filename);
|
||||
uint32_t *loadpal(const char* filename, uint16_t *palsize=NULL);
|
||||
void setpal(uint32_t *pal);
|
||||
void setcolor(uint8_t index, uint32_t color);
|
||||
uint32_t getcolor(uint8_t index);
|
||||
void settrans(uint8_t index);
|
||||
uint8_t gettrans();
|
||||
void subpal(uint8_t index, uint8_t color);
|
||||
void reset_subpal();
|
||||
|
||||
/*void pal();
|
||||
void pal(uint8_t c0, uint8_t c1, uint8_t p = 0);
|
||||
void palt();
|
||||
void palt(uint16_t bits);
|
||||
void palt(uint8_t col, bool t);*/
|
||||
|
||||
void set_draw_mode(uint8_t mode);
|
||||
void pset(int x, int y);
|
||||
void pset(int x, int y, uint8_t color);
|
||||
|
||||
@@ -154,11 +170,11 @@ void hline(int x0, int y, int x1, uint8_t color);
|
||||
void vline(int x, int y0, int y1);
|
||||
void vline(int x, int y0, int y1, uint8_t color);
|
||||
|
||||
void rect(int x0, int y0, int x1, int y1);
|
||||
void rect(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
void rect(int x, int y, int w, int h);
|
||||
void rect(int x, int y, int w, int h, uint8_t color);
|
||||
|
||||
void rectfill(int x0, int y0, int x1, int y1);
|
||||
void rectfill(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
void rectfill(int x, int y, int w, int h);
|
||||
void rectfill(int x, int y, int w, int h, uint8_t color);
|
||||
|
||||
void fillp(uint16_t pat, bool transparent = false);
|
||||
|
||||
@@ -167,9 +183,9 @@ void print(const char *str, int x, int y, uint8_t color);
|
||||
|
||||
void clip(int x, int y, int w, int h);
|
||||
void clip();
|
||||
void camera(int x, int y);
|
||||
void view(int x, int y, int w, int h);
|
||||
void view();
|
||||
void origin(int x, int y);
|
||||
int camx();
|
||||
int camy();
|
||||
|
||||
void circ(int x, int y, uint8_t r = 4);
|
||||
void circ(int x, int y, uint8_t r, uint8_t color);
|
||||
@@ -177,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);
|
||||
|
||||
@@ -188,19 +210,16 @@ void sset(int x, int y);
|
||||
void sset(int x, int y, uint8_t color);
|
||||
|
||||
void spr(uint8_t n, int x, int y, float w = 1.0f, float h = 1.0f, bool flip_x = false, bool flip_y = false);
|
||||
void sspr(int sx, int sy, int sw, int sh, int dx, int dy, int dw=0, int dh=0, bool flip_x = false, bool flip_y = false);
|
||||
void blit(int sx, int sy, int sw, int sh, int dx, int dy, int dw=0, int dh=0, bool flip_x = false, bool flip_y = false, bool invert = false);
|
||||
void blit_r(int sx, int sy, int sw, int sh, int x, int y, float a);
|
||||
|
||||
void tline(int x0, int y0, int x1, int y1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
|
||||
void thline(int x0, int y, int x1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
|
||||
void tvline(int x, int y0, int y1, float mx, float my, float mdx=0.0f, float mdy=0.125f);
|
||||
|
||||
void cline(int x0, int y0, int x1, int y1, uint8_t c0, uint8_t c1);
|
||||
void chline(int x0, int y, int x1, uint8_t c0, uint8_t c1);
|
||||
void cvline(int x, int y0, int y1, uint8_t c0, uint8_t c1);
|
||||
|
||||
uint8_t mget(int celx, int cely);
|
||||
void mset(int celx, int cely, uint8_t snum);
|
||||
void map(int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
|
||||
void map(); //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
|
||||
|
||||
bool btn(uint8_t i);
|
||||
int wbtnp();
|
||||
@@ -216,69 +235,35 @@ 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);
|
||||
|
||||
//float abs(float x);
|
||||
|
||||
float flr(float x);
|
||||
float sgn(float x);
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
float ceil(float x);
|
||||
float sin(float x);
|
||||
float cos(float x);
|
||||
float atan2(float dx, float dy);
|
||||
float sqrt(float x);
|
||||
#endif
|
||||
|
||||
float max(float x, float y);
|
||||
float mid(float x, float y, float z);
|
||||
float min(float x, float y);
|
||||
|
||||
int utfstrlen(const char *str);
|
||||
|
||||
int rnd(int x);
|
||||
//void srand(int x);
|
||||
|
||||
const char* tostr(int val);
|
||||
|
||||
//void debug(const char *str);
|
||||
#define debug printf
|
||||
|
||||
uint8_t ascii(const char *str, uint8_t index);
|
||||
|
||||
void fopen(const char *filename, uint8_t mode=0);
|
||||
void fopenres(const char *filename);
|
||||
void fclose();
|
||||
bool feof();
|
||||
|
||||
void fwritei(int value);
|
||||
void fwrited(float value);
|
||||
void fwrites(const char *value);
|
||||
void fwritew(const char *value);
|
||||
void fwriteb(bool value);
|
||||
void fwriteln();
|
||||
|
||||
int freadi();
|
||||
float freadd();
|
||||
const char *freads();
|
||||
const char *freadw();
|
||||
bool freadb();
|
||||
int getfps();
|
||||
|
||||
void playmusic(const char *filename, const int loop=-1);
|
||||
void pausemusic();
|
||||
void resumemusic();
|
||||
void stopmusic();
|
||||
void stopmusic(const int t=1000);
|
||||
void musicpos(float value);
|
||||
float musicpos();
|
||||
void enablemusic(const bool value);
|
||||
const bool ismusicenabled();
|
||||
|
||||
int loadsound(const char *filename);
|
||||
void freesound(int soundfile);
|
||||
int playsound(int soundfile, const int volume=-1);
|
||||
void stopsound(int soundchannel);
|
||||
void enablesound(const bool value);
|
||||
const bool issoundenabled();
|
||||
|
||||
int getzoom();
|
||||
void setzoom(const int value);
|
||||
void setres(const int w, const int h);
|
||||
bool getfullscreen();
|
||||
void setfullscreen(const bool value);
|
||||
bool getcursor();
|
||||
@@ -288,6 +273,10 @@ const char *getconfig(const char* key);
|
||||
void setconfig(const char* key, const char* value);
|
||||
const char *configfolder();
|
||||
|
||||
void setturbo(const bool value);
|
||||
#define UPDATE_ALWAYS 0
|
||||
#define UPDATE_WAIT 1
|
||||
#define UPDATE_TIMEOUT 2
|
||||
void setupdatemode(const int value, const int t=0);
|
||||
int getupdatemode();
|
||||
|
||||
void exit();
|
||||
|
||||
5584
stb_vorbis.h
Normal file
5584
stb_vorbis.h
Normal file
File diff suppressed because it is too large
Load Diff
5
tools/fonted/data/game.ini
Normal file
5
tools/fonted/data/game.ini
Normal file
@@ -0,0 +1,5 @@
|
||||
title=FONTED
|
||||
config=fonted
|
||||
width=320
|
||||
height=240
|
||||
zoom=2
|
||||
122
tools/fonted/data/main.lua
Normal file
122
tools/fonted/data/main.lua
Normal 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
|
||||
BIN
tools/fonted/data/subatomic.gif
Normal file
BIN
tools/fonted/data/subatomic.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
146
tools/fonted/data/ui.lua
Normal file
146
tools/fonted/data/ui.lua
Normal 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
|
||||
}
|
||||
}
|
||||
890
vscode/library.lua
Normal file
890
vscode/library.lua
Normal file
@@ -0,0 +1,890 @@
|
||||
---@meta
|
||||
|
||||
---@class mini
|
||||
mini = {}
|
||||
|
||||
---@class surf
|
||||
surf = {}
|
||||
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@return number surface
|
||||
---Create new surface specifying width and height
|
||||
function surf.new(w, h) end
|
||||
|
||||
---@param filename string
|
||||
---@return number surface
|
||||
---Load GIF file and return surface
|
||||
function surf.load(filename) end
|
||||
|
||||
---@param filename string
|
||||
---@return number surface
|
||||
---Load GIF from external file and return surface
|
||||
function surf.loadex(filename) end
|
||||
|
||||
---@param surface number
|
||||
---@param filename string
|
||||
---@optional palette table
|
||||
---Save surface as GIF file, with optional palette
|
||||
function surf.save(surface, filename, palette) end
|
||||
|
||||
---@param surface number
|
||||
---Free the specified surface
|
||||
function surf.free(surface) end
|
||||
|
||||
---@param surface number
|
||||
---@return number w, number h
|
||||
---Retrieve width and height of surface
|
||||
function surf.size(surface) end
|
||||
|
||||
---@return number surface
|
||||
---Get current target surface
|
||||
function surf.target() end
|
||||
|
||||
---@param surface number
|
||||
---Set surface as target
|
||||
function surf.target(surface) end
|
||||
|
||||
---@return number surface
|
||||
---Get current source surface
|
||||
function surf.source() end
|
||||
|
||||
---@param surface number
|
||||
---Set surface as source
|
||||
function surf.source(surface) end
|
||||
|
||||
---Erase the current target surface with color 0.
|
||||
function surf.cls() end
|
||||
|
||||
---@param color number
|
||||
---Erase the current target surface with 'color'
|
||||
function surf.cls(color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return number color
|
||||
---Get color of pixel (x,y) on the source surface.
|
||||
function surf.pixel(x, y) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param color number
|
||||
---Set the color for pixel (x,y) on the target surface.
|
||||
function surf.pixel(x, y, color) end
|
||||
|
||||
---@class map
|
||||
map = {}
|
||||
|
||||
---@return number surface
|
||||
---Get tilemaps current surface
|
||||
function map.surf() end
|
||||
|
||||
---@param surface number
|
||||
---Set surface as the current tilemap
|
||||
function map.surf(surface) end
|
||||
|
||||
---Draw the tilemap, using the source surface as tile graphics source
|
||||
function map.draw() end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return number tile
|
||||
---Get tile at the position (x,y) in the current tilemap
|
||||
function map.tile(x, y) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param tile number
|
||||
---Set the tile at the position (x,y) in the current tilemap
|
||||
function map.tile(x, y, tile) end
|
||||
|
||||
---@class pal
|
||||
pal = {}
|
||||
|
||||
---@param filename string
|
||||
---@return table pal
|
||||
---Load a palette from a GIF file and return it
|
||||
function pal.load(filename) end
|
||||
|
||||
---@param pal table
|
||||
---Set a specified palette as the current palette
|
||||
function pal.set(pal) end
|
||||
|
||||
---@param index number
|
||||
---@return number r, number g, number b
|
||||
---Retrieve (r,g,b) color for the index specified in the current palette
|
||||
function pal.color(index) end
|
||||
|
||||
---@param index number
|
||||
---@param r number
|
||||
---@param g number
|
||||
---@param b number
|
||||
---Set (r,g,b) color for the specified index in the current palette
|
||||
function pal.color(index, r, g, b) end
|
||||
|
||||
---@param index number
|
||||
---Set the index specified as transparent color
|
||||
function pal.trans(index) end
|
||||
|
||||
---Reset all the subpalette indices to their default palette index
|
||||
function pal.subpal() end
|
||||
|
||||
---@param index number
|
||||
---Reset the specified subpalette index to its default palette index
|
||||
function pal.subpal(index) end
|
||||
|
||||
---@param index number
|
||||
---@param color number
|
||||
---Set the specified subpalette index to the specified palette index
|
||||
function pal.subpal(index, color) end
|
||||
|
||||
---@param index1 number
|
||||
---@param index2 number
|
||||
---@param color number
|
||||
---Set the specified subpalette range to the specified palette index
|
||||
function pal.subpal(index1, index2, color) end
|
||||
|
||||
---@class view
|
||||
view = {}
|
||||
|
||||
---reset the current clipping region to the entire window
|
||||
function view.clip() end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---Set the current clipping region
|
||||
function view.clip(x, y, w, h) end
|
||||
|
||||
---@return number x, number y
|
||||
---Get the current origin position
|
||||
function view.origin() end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---Set the current origin position
|
||||
function view.origin(x, y) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return number x, number y
|
||||
---Convert screen position to viewport position
|
||||
function view.tolocal(x, y) end
|
||||
|
||||
|
||||
---@class draw
|
||||
---@field draw.NORMAL number
|
||||
---@field draw.PATTERN number
|
||||
---@field draw.AND number
|
||||
---@field draw.OR number
|
||||
---@field draw.XOR number
|
||||
---@field draw.NOT number
|
||||
|
||||
draw = {}
|
||||
|
||||
---@param x1 number
|
||||
---@param y1 number
|
||||
---@param x2 number
|
||||
---@param y2 number
|
||||
---@param color number
|
||||
---Draw a line from (x1,y1) to (x2,y2) with the given color
|
||||
function draw.line(x1, y1, x2, y2, color) end
|
||||
|
||||
---@param x1 number
|
||||
---@param y number
|
||||
---@param x2 number
|
||||
---@param color number
|
||||
---Draw an horizontal line from (x1,y) to (x2,y) with the given color
|
||||
function draw.hline(x1, y, x2, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y1 number
|
||||
---@param y2 number
|
||||
---@param color number
|
||||
---Draw a vertical line from (x,y1) to (x,y2) with the givencolor
|
||||
function draw.vline(x, y1, y2, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@param color number
|
||||
---Draw the ouline of a rectangle at (x,y) of size (w,h) with the given color
|
||||
function draw.rect(x, y, w, h, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@param color number
|
||||
---Draw a filled rectangle at (x,y) of size (w,h) with the given color
|
||||
function draw.rectf(x, y, w, h, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param r number
|
||||
---@param color number
|
||||
---Draw the outline of a cicle at position(x,y) with radius r and the given color
|
||||
function draw.circ(x, y, r, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param r number
|
||||
---@param color number
|
||||
---Draw a filled cicle at position(x,y) with radius r and the given color
|
||||
function draw.circf(x, y, r, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@param r number
|
||||
---@param color number
|
||||
---Draw the outline of a round rectangle at (x,y) of size (w,h) with border radius r and the given color
|
||||
function draw.rrect(x, y, w, h, r, color) end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@param r number
|
||||
---@param color number
|
||||
---Draw a filled round rectangle at (x,y) of size (w,h) with border radius r and the given color
|
||||
function draw.rrectf(x, y, w, h, r, color) end
|
||||
|
||||
---@param x1 number
|
||||
---@param y1 number
|
||||
---@param x2 number
|
||||
---@param y2 number
|
||||
---@param color number
|
||||
---Draw the outline of an oval enclosed in (x1,y1)-(x2,y2) and the given color
|
||||
function draw.oval(x1, y1, x2, y2, color) end
|
||||
|
||||
---@param x1 number
|
||||
---@param y1 number
|
||||
---@param x2 number
|
||||
---@param y2 number
|
||||
---@param color number
|
||||
---Draw a filled oval enclosed in (x1,y1)-(x2,y2) and the given color
|
||||
function draw.ovalf(x1, y1, x2, y2, color) end
|
||||
|
||||
---@param pattern number
|
||||
---Specify a pattern for the drawing functions
|
||||
function draw.pattern(pattern) end
|
||||
|
||||
---Reset to no pattern for drawing functions
|
||||
function draw.pattern() end
|
||||
|
||||
---@param sx number
|
||||
---@param sy number
|
||||
---@param sw number
|
||||
---@param sh number
|
||||
---@param dx number
|
||||
---@param dy number
|
||||
---@optional dw number
|
||||
---@optional dh number
|
||||
---@optional boolean flip_x
|
||||
---@optional boolean flip_y
|
||||
---@optional boolean invert
|
||||
---Blit the region starting at (sx,sy) and size (sw, sh) from the source surface
|
||||
---to the position (dx, dy) (and optionally of size (dw, dh)) to the target surface,
|
||||
---optionally flipping it horizontally or vertically, or inverting x and y axes
|
||||
function draw.surf(sx, sy, sw, sh, dx, dy, dw, dh, flip_x, flip_y, invert) end
|
||||
|
||||
---@param sx number
|
||||
---@param sy number
|
||||
---@param sw number
|
||||
---@param sh number
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param a number
|
||||
---Blit the region starting at (sx,sy) and size (sw, sh) from the source surface
|
||||
---to the position (dx, dy) of the target surface, rotating it by a degrees
|
||||
function draw.surfrot(sx, sy, sw, sh, x, y, a) end
|
||||
|
||||
---@param text string
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param color number
|
||||
---Draw text to (x,y) using the specified color
|
||||
function draw.text(text, x, y, color) end
|
||||
|
||||
---@param text number
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param color number
|
||||
---Draw text to (x,y) using the specified color
|
||||
function draw.text(text, x, y, color) end
|
||||
|
||||
---@param mode number
|
||||
---Specify the mode for the drawing functions
|
||||
function draw.mode(mode) end
|
||||
|
||||
draw.NORMAL = 0
|
||||
draw.PATTERN = 1
|
||||
draw.AND = 2
|
||||
draw.OR = 3
|
||||
draw.XOR = 4
|
||||
draw.NOT = 5
|
||||
|
||||
|
||||
---@class shader
|
||||
shader = {}
|
||||
|
||||
---Initialize shaders subsystem, still non functional without shaders
|
||||
function shader.init() end
|
||||
|
||||
---@param shader string
|
||||
---Initialize shaders subsystem, specifying a file that contains both vertex and fragment shader
|
||||
function shader.init(shader) end
|
||||
|
||||
---@param vshader string
|
||||
---@param fshader string
|
||||
---Initialize shaders subsystem, specifying both a vertex shader file and a fragment shader file
|
||||
function shader.init(vshader, fshader) end
|
||||
|
||||
---Enable previously loaded shader
|
||||
function shader.enable() end
|
||||
|
||||
---Disable shaders
|
||||
function shader.disable() end
|
||||
|
||||
---@class music
|
||||
music = {}
|
||||
|
||||
---@param filename string
|
||||
---Load and play the song in the specified OGG file
|
||||
function music.play(filename) end
|
||||
|
||||
---@param filename string
|
||||
---@param loop integer
|
||||
---Load and play the song in the specified OGG file, loop number of times
|
||||
function music.play(filename, loop) end
|
||||
|
||||
---Pause the currently playing song
|
||||
function music.pause() end
|
||||
|
||||
---Resume the currently paused song
|
||||
function music.resume() end
|
||||
|
||||
---Stop the currently playing song
|
||||
function music.stop() end
|
||||
|
||||
---@return number pos
|
||||
---Get the playing position of the currently loaded song
|
||||
function music.pos() end
|
||||
|
||||
---@param pos number
|
||||
---Set the playing position of the currently loaded song
|
||||
function music.pos(pos) end
|
||||
|
||||
---@return boolean value
|
||||
---Get if music is enabled
|
||||
function music.enabled() end
|
||||
|
||||
---@param value boolean
|
||||
---Set if music is enabled or not
|
||||
function music.enabled(value) end
|
||||
|
||||
|
||||
---@class sound
|
||||
sound = {}
|
||||
|
||||
---@param filename string
|
||||
---@return number snd
|
||||
---Load a sound in WAV format from the specified file and return it
|
||||
function sound.load(filename) end
|
||||
|
||||
---@param snd number
|
||||
---Free the sound specified
|
||||
function sound.free(snd) end
|
||||
|
||||
---@param snd number
|
||||
---@return number chl
|
||||
---Play the sound specified, returns the channel in which it's playing
|
||||
function sound.play(snd) end
|
||||
|
||||
---@param snd number
|
||||
---@param loop integer
|
||||
---@return number chl
|
||||
---Play the sound specified loop number of times, returns the channel in which it's playing
|
||||
function sound.play(snd, loop) end
|
||||
|
||||
---@param chl number
|
||||
---Stop the channel specified
|
||||
function sound.stop(chl) end
|
||||
|
||||
---@return boolean value
|
||||
---Get if sound is enabled
|
||||
function sound.enabled() end
|
||||
|
||||
---@param value boolean
|
||||
---Set if sound is enabled or not
|
||||
function sound.enabled(value) end
|
||||
|
||||
---@class sys
|
||||
sys = {}
|
||||
|
||||
---Get delta time from last update in seconds (with decimals)
|
||||
function sys.delta() end
|
||||
|
||||
---Get current system timer in seconds (with decimals)
|
||||
function sys.time() end
|
||||
|
||||
---@param offset number
|
||||
---Reset chrono time (with offset in seconds) (with decimals)
|
||||
function sys.chrono(offset) end
|
||||
|
||||
---@return number
|
||||
---@---Get chrono time since last chrono reset in seconds (with decimals)
|
||||
function sys.chrono() end
|
||||
|
||||
---@return boolean
|
||||
---Query if a beat has already passed
|
||||
function sys.beat() end
|
||||
|
||||
---@param bts number
|
||||
---Set number of frames between beats
|
||||
function sys.beat(bts) end
|
||||
|
||||
---@param mode number
|
||||
---@param ms number
|
||||
---Sets the update mode.
|
||||
---UPDATE_ALWAYS: The game will call mini.update as fast as possible
|
||||
---UPDATE_EVENTS: The game will call mini.update only when a keyboard, mouse or pad event fires
|
||||
---UPDATE_TIMEOUT: The game will call mini.update on events or after the milliseconds specified passed
|
||||
function sys.update(mode, ms) end
|
||||
|
||||
---@return table
|
||||
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
|
||||
---boolean specifying if it's a directory, for each file in the 'data' directory
|
||||
function sys.dir() end
|
||||
|
||||
---@param path string
|
||||
---@return table
|
||||
---Gets a table in which each entry has a field "name" with the name and a field "dir" with a
|
||||
---boolean specifying if it's a directory, for each file in the specified path
|
||||
function sys.dir(path) end
|
||||
|
||||
---Exit the game
|
||||
function sys.quit() end
|
||||
|
||||
---@return number
|
||||
---Gets the frames per second
|
||||
function sys.fps() end
|
||||
|
||||
---@return string
|
||||
---Gets the content of the clipboard
|
||||
function sys.clipboard() end
|
||||
|
||||
---@param value string
|
||||
---Sets the content of the clipboard
|
||||
function sys.clipboard(value) end
|
||||
|
||||
---@return boolean
|
||||
---Returns true if running on debug version of mini. False otherwise.
|
||||
function sys.debug() end
|
||||
|
||||
|
||||
---@class win
|
||||
win = {}
|
||||
|
||||
---@param value number
|
||||
---Set the window zoom
|
||||
function win.zoom(value) end
|
||||
|
||||
---@return number value
|
||||
---Get the window zoom
|
||||
function win.zoom() end
|
||||
|
||||
---@param value boolean
|
||||
---Specifies if the window must display at fullscreen or not
|
||||
function win.fullscreen(value) end
|
||||
|
||||
---@return boolean value
|
||||
---Returns if the window is at fullscreen or not
|
||||
function win.fullscreen() end
|
||||
|
||||
---@param value boolean
|
||||
---Specifies if the cursor must be visible or not
|
||||
function win.cursor(value) end
|
||||
|
||||
---@return number w, number h
|
||||
---Returns the current window size
|
||||
function win.res() end
|
||||
|
||||
---@param w number
|
||||
---@param h number
|
||||
---Sets the window size
|
||||
function win.res(w, h) end
|
||||
|
||||
|
||||
---@class config
|
||||
config = {}
|
||||
|
||||
---@param key string
|
||||
---@param value any
|
||||
---Sets the value of a key in the configuration file
|
||||
function config.key(key, value) end
|
||||
|
||||
---@param key string
|
||||
---@return string value
|
||||
---Gets the value of a key in the configuration file
|
||||
function config.key(key) end
|
||||
|
||||
---@return string value
|
||||
---Returns the folder in which the configuration file resides
|
||||
function config.folder() end
|
||||
|
||||
|
||||
---@class mouse
|
||||
---@field mouse.LEFT number
|
||||
---@field mouse.MIDDLE number
|
||||
---@field mouse.RIGHT number
|
||||
|
||||
mouse = {}
|
||||
|
||||
---@return number x, number y
|
||||
---Returns the current position of the mouse
|
||||
function mouse.pos() end
|
||||
|
||||
---@return number value
|
||||
---Returns the value of the mouse wheel
|
||||
function mouse.wheel() end
|
||||
|
||||
---@param btn number
|
||||
---@return boolean
|
||||
---Returns whether the specified mouse button is down
|
||||
function mouse.down(btn) end
|
||||
|
||||
---@param btn number
|
||||
---@return boolean
|
||||
---Returns whether the specified mouse button has just been pressed
|
||||
function mouse.press(btn) end
|
||||
|
||||
---@return boolean
|
||||
---Returns whether the user performed a double click
|
||||
function mouse.dblclick() end
|
||||
|
||||
---Ignores current down button, effectively not raising the next "press" event
|
||||
function mouse.discard() end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@return boolean
|
||||
---Returns whether the mouse is inside the rectangle specified
|
||||
function mouse.inside(x,y,w,h) end
|
||||
|
||||
|
||||
mouse.LEFT = 1
|
||||
mouse.MIDDLE = 2
|
||||
mouse.RIGHT = 3
|
||||
|
||||
---@class key
|
||||
key = {}
|
||||
|
||||
---@param key number
|
||||
---@return boolean
|
||||
---Returns whether the specified keyboard key is down
|
||||
function key.down(key) end
|
||||
|
||||
---@return number
|
||||
---Returns which keyboard key has just been pressed
|
||||
function key.press() end
|
||||
|
||||
---@param key number
|
||||
---@return boolean
|
||||
---Returns whether the specified keyboard key has just been pressed
|
||||
function key.press(key) end
|
||||
|
||||
---@return boolean
|
||||
---Returns whether any keyboard key has just been pressed
|
||||
function key.any() end
|
||||
|
||||
|
||||
---@class pad
|
||||
---@field pad.INVALID number
|
||||
---@field pad.A number
|
||||
---@field pad.B number
|
||||
---@field pad.X number
|
||||
---@field pad.Y number
|
||||
---@field pad.BACK number
|
||||
---@field pad.GUIDE number
|
||||
---@field pad.START number
|
||||
---@field pad.LEFTSTICK number
|
||||
---@field pad.RIGHTSTICK number
|
||||
---@field pad.LEFTSHOULDER number
|
||||
---@field pad.RIGHTSHOULDER number
|
||||
---@field pad.UP number
|
||||
---@field pad.DOWN number
|
||||
---@field pad.LEFT number
|
||||
---@field pad.RIGHT number
|
||||
---@field pad.MISC1 number
|
||||
---@field pad.PADDLE1 number
|
||||
---@field pad.PADDLE2 number
|
||||
---@field pad.PADDLE3 number
|
||||
---@field pad.PADDLE4 number
|
||||
---@field pad.TOUCHPAD number
|
||||
|
||||
pad = {}
|
||||
|
||||
---@param btn number
|
||||
---@return boolean
|
||||
---Returns whether the specified gamepad button is down
|
||||
function pad.down(btn) end
|
||||
|
||||
---@return number
|
||||
---Returns which gamepad button has just been pressed
|
||||
function pad.press() end
|
||||
|
||||
---@param btn number
|
||||
---@return boolean
|
||||
---Returns whether the specified gamepad button has just been pressed
|
||||
function pad.press(btn) end
|
||||
|
||||
---@return boolean
|
||||
---Returns whether any gamepad button has just been pressed
|
||||
function pad.any() end
|
||||
|
||||
pad.INVALID = -1
|
||||
pad.A = 0
|
||||
pad.B = 1
|
||||
pad.X = 2
|
||||
pad.Y = 3
|
||||
pad.BACK = 4
|
||||
pad.GUIDE = 5
|
||||
pad.START = 6
|
||||
pad.LEFTSTICK = 7
|
||||
pad.RIGHTSTICK = 8
|
||||
pad.LEFTSHOULDER = 9
|
||||
pad.RIGHTSHOULDER = 10
|
||||
pad.UP = 11
|
||||
pad.DOWN = 12
|
||||
pad.LEFT = 13
|
||||
pad.RIGHT = 14
|
||||
pad.MISC1 = 15
|
||||
pad.PADDLE1 = 16
|
||||
pad.PADDLE2 = 17
|
||||
pad.PADDLE3 = 18
|
||||
pad.PADDLE4 = 19
|
||||
pad.TOUCHPAD = 20
|
||||
|
||||
---@class key
|
||||
---@field key.UNKNOWN number
|
||||
---@field key.A number
|
||||
---@field key.B number
|
||||
---@field key.C number
|
||||
---@field key.D number
|
||||
---@field key.E number
|
||||
---@field key.F number
|
||||
---@field key.G number
|
||||
---@field key.H number
|
||||
---@field key.I number
|
||||
---@field key.J number
|
||||
---@field key.K number
|
||||
---@field key.L number
|
||||
---@field key.M number
|
||||
---@field key.N number
|
||||
---@field key.O number
|
||||
---@field key.P number
|
||||
---@field key.Q number
|
||||
---@field key.R number
|
||||
---@field key.S number
|
||||
---@field key.T number
|
||||
---@field key.U number
|
||||
---@field key.V number
|
||||
---@field key.W number
|
||||
---@field key.X number
|
||||
---@field key.Y number
|
||||
---@field key.Z number
|
||||
---@field key.N1 number
|
||||
---@field key.N2 number
|
||||
---@field key.N3 number
|
||||
---@field key.N4 number
|
||||
---@field key.N5 number
|
||||
---@field key.N6 number
|
||||
---@field key.N7 number
|
||||
---@field key.N8 number
|
||||
---@field key.N9 number
|
||||
---@field key.N0 number
|
||||
---@field key.RETURN number
|
||||
---@field key.ESCAPE number
|
||||
---@field key.BACKSPACE number
|
||||
---@field key.TAB number
|
||||
---@field key.SPACE number
|
||||
---@field key.MINUS number
|
||||
---@field key.EQUALS number
|
||||
---@field key.LEFTBRACKET number
|
||||
---@field key.RIGHTBRACKET number
|
||||
---@field key.BACKSLASH number
|
||||
---@field key.NONUSHASH number
|
||||
---@field key.SEMICOLON number
|
||||
---@field key.APOSTROPHE number
|
||||
---@field key.GRAVE number
|
||||
---@field key.COMMA number
|
||||
---@field key.PERIOD number
|
||||
---@field key.SLASH number
|
||||
---@field key.CAPSLOCK number
|
||||
---@field key.F1 number
|
||||
---@field key.F2 number
|
||||
---@field key.F3 number
|
||||
---@field key.F4 number
|
||||
---@field key.F5 number
|
||||
---@field key.F6 number
|
||||
---@field key.F7 number
|
||||
---@field key.F8 number
|
||||
---@field key.F9 number
|
||||
---@field key.F10 number
|
||||
---@field key.F11 number
|
||||
---@field key.F12 number
|
||||
---@field key.PRINTSCREEN number
|
||||
---@field key.SCROLLLOCK number
|
||||
---@field key.PAUSE number
|
||||
---@field key.INSERT number
|
||||
---@field key.HOME number
|
||||
---@field key.PAGEUP number
|
||||
---@field key.DELETE number
|
||||
---@field key.END number
|
||||
---@field key.PAGEDOWN number
|
||||
---@field key.RIGHT number
|
||||
---@field key.LEFT number
|
||||
---@field key.DOWN number
|
||||
---@field key.UP number
|
||||
---@field key.NUMLOCKCLEAR number
|
||||
---@field key.KP_DIVIDE number
|
||||
---@field key.KP_MULTIPLY number
|
||||
---@field key.KP_MINUS number
|
||||
---@field key.KP_PLUS number
|
||||
---@field key.KP_ENTER number
|
||||
---@field key.KP_1 number
|
||||
---@field key.KP_2 number
|
||||
---@field key.KP_3 number
|
||||
---@field key.KP_4 number
|
||||
---@field key.KP_5 number
|
||||
---@field key.KP_6 number
|
||||
---@field key.KP_7 number
|
||||
---@field key.KP_8 number
|
||||
---@field key.KP_9 number
|
||||
---@field key.KP_0 number
|
||||
---@field key.KP_PERIOD number
|
||||
---@field key.NONUSBACKSLASH number
|
||||
---@field key.APPLICATION number
|
||||
---@field key.LCTRL number
|
||||
---@field key.LSHIFT number
|
||||
---@field key.LALT number
|
||||
---@field key.LGUI number
|
||||
---@field key.RCTRL number
|
||||
---@field key.RSHIFT number
|
||||
---@field key.RALT number
|
||||
---@field key.RGUI number
|
||||
|
||||
key.UNKNOWN = 0
|
||||
key.A = 4
|
||||
key.B = 5
|
||||
key.C = 6
|
||||
key.D = 7
|
||||
key.E = 8
|
||||
key.F = 9
|
||||
key.G = 10
|
||||
key.H = 11
|
||||
key.I = 12
|
||||
key.J = 13
|
||||
key.K = 14
|
||||
key.L = 15
|
||||
key.M = 16
|
||||
key.N = 17
|
||||
key.O = 18
|
||||
key.P = 19
|
||||
key.Q = 20
|
||||
key.R = 21
|
||||
key.S = 22
|
||||
key.T = 23
|
||||
key.U = 24
|
||||
key.V = 25
|
||||
key.W = 26
|
||||
key.X = 27
|
||||
key.Y = 28
|
||||
key.Z = 29
|
||||
key.N1 = 30
|
||||
key.N2 = 31
|
||||
key.N3 = 32
|
||||
key.N4 = 33
|
||||
key.N5 = 34
|
||||
key.N6 = 35
|
||||
key.N7 = 36
|
||||
key.N8 = 37
|
||||
key.N9 = 38
|
||||
key.N0 = 39
|
||||
key.RETURN = 40
|
||||
key.ESCAPE = 41
|
||||
key.BACKSPACE = 42
|
||||
key.TAB = 43
|
||||
key.SPACE = 44
|
||||
key.MINUS = 45
|
||||
key.EQUALS = 46
|
||||
key.LEFTBRACKET = 47
|
||||
key.RIGHTBRACKET = 48
|
||||
key.BACKSLASH = 49
|
||||
key.NONUSHASH = 50
|
||||
key.SEMICOLON = 51
|
||||
key.APOSTROPHE = 52
|
||||
key.GRAVE = 53
|
||||
key.COMMA = 54
|
||||
key.PERIOD = 55
|
||||
key.SLASH = 56
|
||||
key.CAPSLOCK = 57
|
||||
key.F1 = 58
|
||||
key.F2 = 59
|
||||
key.F3 = 60
|
||||
key.F4 = 61
|
||||
key.F5 = 62
|
||||
key.F6 = 63
|
||||
key.F7 = 64
|
||||
key.F8 = 65
|
||||
key.F9 = 66
|
||||
key.F10 = 67
|
||||
key.F11 = 68
|
||||
key.F12 = 69
|
||||
key.PRINTSCREEN = 70
|
||||
key.SCROLLLOCK = 71
|
||||
key.PAUSE = 72
|
||||
key.INSERT = 73
|
||||
key.HOME = 74
|
||||
key.PAGEUP = 75
|
||||
key.DELETE = 76
|
||||
key.END = 77
|
||||
key.PAGEDOWN = 78
|
||||
key.RIGHT = 79
|
||||
key.LEFT = 80
|
||||
key.DOWN = 81
|
||||
key.UP = 82
|
||||
key.NUMLOCKCLEAR = 83
|
||||
key.KP_DIVIDE = 84
|
||||
key.KP_MULTIPLY = 85
|
||||
key.KP_MINUS = 86
|
||||
key.KP_PLUS = 87
|
||||
key.KP_ENTER = 88
|
||||
key.KP_1 = 89
|
||||
key.KP_2 = 90
|
||||
key.KP_3 = 91
|
||||
key.KP_4 = 92
|
||||
key.KP_5 = 93
|
||||
key.KP_6 = 94
|
||||
key.KP_7 = 95
|
||||
key.KP_8 = 96
|
||||
key.KP_9 = 97
|
||||
key.KP_0 = 98
|
||||
key.KP_PERIOD = 99
|
||||
key.NONUSBACKSLASH = 100
|
||||
key.APPLICATION = 101
|
||||
key.LCTRL = 224
|
||||
key.LSHIFT = 225
|
||||
key.LALT = 226
|
||||
key.LGUI = 227
|
||||
key.RCTRL = 228
|
||||
key.RSHIFT = 229
|
||||
key.RALT = 230
|
||||
key.RGUI = 231
|
||||
Reference in New Issue
Block a user