Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1e8425b09 | |||
| 770971142f | |||
| 90f057fc5e | |||
| 948870215d | |||
| a125e799ad | |||
| e6d4833e8b | |||
| 9c4c94093c | |||
| 52d2fcf0d3 | |||
| 884df104bd | |||
| c0d1b1fecf | |||
| 380295aed0 | |||
| 0142d79d91 | |||
| 14a7fda8b7 | |||
| 6cfddadf43 | |||
| bc006b8f72 | |||
| 569221d047 | |||
| 4a1627835f | |||
| f4eac55989 | |||
| 5c0b046ad8 | |||
| 7739b563f3 | |||
| 6e5f9fb1a8 | |||
| 6f5bdd274a | |||
| 6a24086556 | |||
| b78fbe4378 | |||
| 9f8533f62b | |||
| 8a4110e821 | |||
| 0547378331 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
mini.exe
|
||||
mini
|
||||
/mini.exe
|
||||
/mini
|
||||
mini_debug.exe
|
||||
mini_debug
|
||||
.vscode/*
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -9,10 +9,12 @@ IF "%1"=="" (
|
||||
set PARAM=%1
|
||||
|
||||
echo Compilando windows...
|
||||
make windows || exit /b 1
|
||||
rmdir /S /Q build || exit /b 1
|
||||
lagueirto windows || exit /b 1
|
||||
|
||||
echo Compilando windows_debug...
|
||||
make windows_debug || exit /b 1
|
||||
rmdir /S /Q build || exit /b 1
|
||||
lagueirto windows_debug || exit /b 1
|
||||
|
||||
echo Creando paquetes...
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@ echo "Versión detectada: $VERSION"
|
||||
|
||||
# Datos Windows
|
||||
WIN_USER="raimon"
|
||||
WIN_HOST="tonlab19"
|
||||
WIN_HOST="192.168.1.53"
|
||||
WIN_PATH_SSH="C:\Users\raimon\dev\mini"
|
||||
WIN_PATH_SCP="C:/Users/Raimon/dev/mini"
|
||||
|
||||
echo "=== Compilando Linux ==="
|
||||
make linux
|
||||
make linux_debug
|
||||
rm -rf build
|
||||
lagueirto linux
|
||||
rm -rf build
|
||||
lagueirto linux_debug
|
||||
|
||||
echo "=== Empaquetando Linux ==="
|
||||
tar -czf mini_v${VERSION}_linux_release.tar.gz mini
|
||||
@@ -30,12 +32,12 @@ echo "=== Ejecutando build remoto Windows ==="
|
||||
ssh ${WIN_USER}@${WIN_HOST} "cd ${WIN_PATH_SSH} && do_release.bat v${VERSION}"
|
||||
|
||||
echo "=== Copiando ZIPs desde Windows ==="
|
||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_windows_release.zip" .
|
||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_windows_debug.zip" .
|
||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_win32-x64_release.zip" .
|
||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_win32-x64_debug.zip" .
|
||||
|
||||
echo "=== Build completado correctamente ==="
|
||||
echo "Generados:"
|
||||
echo " mini_v${VERSION}_linux_release.tar.gz"
|
||||
echo " mini_v${VERSION}_linux_debug.tar.gz"
|
||||
echo " mini_v${VERSION}_windows_release.zip"
|
||||
echo " mini_v${VERSION}_windows_debug.zip"
|
||||
echo " mini_v${VERSION}_win32-x64_release.zip"
|
||||
echo " mini_v${VERSION}_win32-x64_debug.zip"
|
||||
|
||||
507
jail_audio.cpp
507
jail_audio.cpp
@@ -1,507 +0,0 @@
|
||||
#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
42
jail_audio.h
@@ -1,42 +0,0 @@
|
||||
#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);
|
||||
384
jfile.cpp
384
jfile.cpp
@@ -1,384 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "jfile.h"
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_FILENAME "data.jf2"
|
||||
#define DEFAULT_FOLDER "data/"
|
||||
#define CONFIG_FILENAME "config.txt"
|
||||
|
||||
struct file_t
|
||||
{
|
||||
std::string path;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
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 {
|
||||
std::string key, value;
|
||||
};
|
||||
|
||||
char *resource_filename = NULL;
|
||||
char *resource_folder = NULL;
|
||||
int file_source = SOURCE_FILE;
|
||||
char scratch[255];
|
||||
static std::string config_folder;
|
||||
std::vector<keyvalue_t> config;
|
||||
|
||||
void file_setresourcefilename(const char *str) {
|
||||
if (resource_filename != NULL) free(resource_filename);
|
||||
resource_filename = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_filename, str);
|
||||
}
|
||||
|
||||
void file_setresourcefolder(const char *str) {
|
||||
if (resource_folder != NULL) free(resource_folder);
|
||||
resource_folder = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_folder, str);
|
||||
}
|
||||
|
||||
void file_setsource(const int src) {
|
||||
file_source = src%2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder)
|
||||
if (src==SOURCE_FOLDER && resource_folder==NULL) file_setresourcefolder(DEFAULT_FOLDER);
|
||||
}
|
||||
|
||||
bool file_getdictionary() {
|
||||
if (resource_filename == NULL) file_setresourcefilename(DEFAULT_FILENAME);
|
||||
|
||||
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 = (char*)malloc(path_size+1);
|
||||
fi.read( file_name, path_size );
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
free(file_name);
|
||||
toc.push_back({filename, file_size, file_offset});
|
||||
}
|
||||
fi.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
char *file_getfilenamewithfolder(const char* filename) {
|
||||
strcpy(scratch, resource_folder);
|
||||
strcat(scratch, filename);
|
||||
return scratch;
|
||||
}
|
||||
|
||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary) {
|
||||
|
||||
if (file_source==SOURCE_FILE and toc.size()==0) {
|
||||
if (not file_getdictionary()) file_setsource(SOURCE_FOLDER);
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
if (file_source==SOURCE_FILE) {
|
||||
bool found = false;
|
||||
uint32_t count = 0;
|
||||
while( !found && count < toc.size() ) {
|
||||
found = ( std::string(resourcename) == toc[count].path );
|
||||
if( !found ) count++;
|
||||
}
|
||||
|
||||
if( !found ) {
|
||||
perror("El recurs no s'ha trobat en l'arxiu de recursos");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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, toc[count].offset, SEEK_SET);
|
||||
} else {
|
||||
f = fopen(file_getfilenamewithfolder(resourcename), binary?"rb":"r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
|
||||
FILE *f = file_getfilepointer(resourcename, 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;
|
||||
}
|
||||
|
||||
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary) {
|
||||
|
||||
FILE *f;
|
||||
f = fopen(filename, binary?"rb":"r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
return f;
|
||||
}
|
||||
|
||||
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
|
||||
FILE *f = file_getfilepointerex(filename, filesize, true);
|
||||
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
|
||||
fread(buffer, filesize, 1, f);
|
||||
if (zero_terminate) buffer[filesize]=0;
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void file_setconfigfolder(const char *foldername)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
|
||||
#elif __APPLE__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/Library/Application Support/" + foldername;
|
||||
#elif __linux__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/." + foldername;
|
||||
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
|
||||
|
||||
{
|
||||
// Intenta crear ".config", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Intenta crear ".config/jailgames", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(config_folder.c_str(), &st) == -1)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(config_folder.c_str());
|
||||
#else
|
||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *file_getconfigfolder() {
|
||||
static std::string folder = config_folder + "/";
|
||||
return folder.c_str();
|
||||
}
|
||||
|
||||
void file_loadconfigvalues() {
|
||||
config.clear();
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "r");
|
||||
if (!f) return;
|
||||
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *value = strchr(line, '=');
|
||||
if (value) {
|
||||
*value='\0'; value++;
|
||||
value[strlen(value)-1] = '\0';
|
||||
config.push_back({line, value});
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void file_saveconfigvalues() {
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "w");
|
||||
if (f) {
|
||||
for (auto pair : config) {
|
||||
fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
const char* file_getconfigvalue(const char *key) {
|
||||
if (config.empty()) file_loadconfigvalues();
|
||||
for (auto pair : config) {
|
||||
if (pair.key == std::string(key)) {
|
||||
strcpy(scratch, pair.value.c_str());
|
||||
return scratch;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void file_setconfigvalue(const char* key, const char* value) {
|
||||
if (config.empty()) file_loadconfigvalues();
|
||||
for (auto &pair : config) {
|
||||
if (pair.key == std::string(key)) {
|
||||
pair.value = value;
|
||||
file_saveconfigvalues();
|
||||
return;
|
||||
}
|
||||
}
|
||||
config.push_back({key, value});
|
||||
file_saveconfigvalues();
|
||||
return;
|
||||
}
|
||||
|
||||
bool file_createFolder(const char* name) {
|
||||
char tmp[256];
|
||||
strcpy(tmp, "./");
|
||||
strcat(tmp, name);
|
||||
#ifdef _WIN32
|
||||
return mkdir(tmp)==0;
|
||||
#else
|
||||
return mkdir(tmp, 0755)==0;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
26
jfile.h
26
jfile.h
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define SOURCE_FILE 0
|
||||
#define SOURCE_FOLDER 1
|
||||
|
||||
void file_setconfigfolder(const char *foldername);
|
||||
const char *file_getconfigfolder();
|
||||
|
||||
void file_setresourcefilename(const char *str);
|
||||
void file_setresourcefolder(const char *str);
|
||||
void file_setsource(const int src);
|
||||
|
||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false);
|
||||
char *file_getfilebuffer(const char *resourcename, int& filesize, 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);
|
||||
253
jshader.cpp
253
jshader.cpp
@@ -1,253 +0,0 @@
|
||||
#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;
|
||||
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
||||
|
||||
|
||||
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");
|
||||
glActiveTexture = (PFNGLACTIVETEXTUREPROC)SDL_GL_GetProcAddress("glActiveTexture");
|
||||
|
||||
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
48
jshader.h
@@ -1,48 +0,0 @@
|
||||
#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();
|
||||
}
|
||||
@@ -1,5 +1,27 @@
|
||||
libs = -lSDL3 -lGL
|
||||
cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall
|
||||
executable = mini_debug
|
||||
sourcepath = . lua
|
||||
[linux]
|
||||
cppflags = -D LUA_USE_LINUX -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource
|
||||
libs = -Wl,--gc-sections -lSDL3 -lGL
|
||||
executable = mini
|
||||
sourcepath = source+
|
||||
buildpath = build
|
||||
|
||||
[linux_debug] default
|
||||
cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall -std=c++20 -Isource
|
||||
libs = -lSDL3 -lGL
|
||||
executable = mini_debug
|
||||
sourcepath = source+
|
||||
buildpath = build
|
||||
|
||||
[windows]
|
||||
cppflags = -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource
|
||||
libs = icon.res -Wl,--gc-sections -lmingw32 -lSDL3 -lopengl32 -static-libstdc++ -static-libgcc -lpthread -mwindows
|
||||
executable = mini.exe
|
||||
sourcepath = source+
|
||||
buildpath = build
|
||||
|
||||
[windows_debug]
|
||||
cppflags = -D DEBUG -g -Wall -std=c++20 -Isource
|
||||
libs = -lmingw32 -lSDL3 -lopengl32
|
||||
executable = mini_debug.exe
|
||||
sourcepath = source+
|
||||
buildpath = build
|
||||
|
||||
7
lua.h
7
lua.h
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
bool lua_is_playing();
|
||||
void lua_init(const char* main_lua_file = "main.lua");
|
||||
void lua_call_init();
|
||||
void lua_call_update();
|
||||
void lua_quit();
|
||||
9
main.cpp
9
main.cpp
@@ -1,9 +0,0 @@
|
||||
#include "mini.h"
|
||||
|
||||
void loop() {
|
||||
settrans(255);
|
||||
setcolor(0,0xff0000);
|
||||
const int w=scrw();
|
||||
const int h=scrh();
|
||||
rect(0,0,w-1,h-1,0);
|
||||
}
|
||||
294
mini.h
294
mini.h
@@ -1,294 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#define KEY_UNKNOWN 0
|
||||
#define KEY_A 4
|
||||
#define KEY_B 5
|
||||
#define KEY_C 6
|
||||
#define KEY_D 7
|
||||
#define KEY_E 8
|
||||
#define KEY_F 9
|
||||
#define KEY_G 10
|
||||
#define KEY_H 11
|
||||
#define KEY_I 12
|
||||
#define KEY_J 13
|
||||
#define KEY_K 14
|
||||
#define KEY_L 15
|
||||
#define KEY_M 16
|
||||
#define KEY_N 17
|
||||
#define KEY_O 18
|
||||
#define KEY_P 19
|
||||
#define KEY_Q 20
|
||||
#define KEY_R 21
|
||||
#define KEY_S 22
|
||||
#define KEY_T 23
|
||||
#define KEY_U 24
|
||||
#define KEY_V 25
|
||||
#define KEY_W 26
|
||||
#define KEY_X 27
|
||||
#define KEY_Y 28
|
||||
#define KEY_Z 29
|
||||
#define KEY_1 30
|
||||
#define KEY_2 31
|
||||
#define KEY_3 32
|
||||
#define KEY_4 33
|
||||
#define KEY_5 34
|
||||
#define KEY_6 35
|
||||
#define KEY_7 36
|
||||
#define KEY_8 37
|
||||
#define KEY_9 38
|
||||
#define KEY_0 39
|
||||
#define KEY_RETURN 40
|
||||
#define KEY_ESCAPE 41
|
||||
#define KEY_BACKSPACE 42
|
||||
#define KEY_TAB 43
|
||||
#define KEY_SPACE 44
|
||||
#define KEY_MINUS 45
|
||||
#define KEY_EQUALS 46
|
||||
#define KEY_LEFTBRACKET 47
|
||||
#define KEY_RIGHTBRACKET 48
|
||||
#define KEY_BACKSLASH 49
|
||||
#define KEY_NONUSHASH 50
|
||||
#define KEY_SEMICOLON 51
|
||||
#define KEY_APOSTROPHE 52
|
||||
#define KEY_GRAVE 53
|
||||
#define KEY_COMMA 54
|
||||
#define KEY_PERIOD 55
|
||||
#define KEY_SLASH 56
|
||||
#define KEY_CAPSLOCK 57
|
||||
#define KEY_F1 58
|
||||
#define KEY_F2 59
|
||||
#define KEY_F3 60
|
||||
#define KEY_F4 61
|
||||
#define KEY_F5 62
|
||||
#define KEY_F6 63
|
||||
#define KEY_F7 64
|
||||
#define KEY_F8 65
|
||||
#define KEY_F9 66
|
||||
#define KEY_F10 67
|
||||
#define KEY_F11 68
|
||||
#define KEY_F12 69
|
||||
#define KEY_PRINTSCREEN 70
|
||||
#define KEY_SCROLLLOCK 71
|
||||
#define KEY_PAUSE 72
|
||||
#define KEY_INSERT 73
|
||||
#define KEY_HOME 74
|
||||
#define KEY_PAGEUP 75
|
||||
#define KEY_DELETE 76
|
||||
#define KEY_END 77
|
||||
#define KEY_PAGEDOWN 78
|
||||
#define KEY_RIGHT 79
|
||||
#define KEY_LEFT 80
|
||||
#define KEY_DOWN 81
|
||||
#define KEY_UP 82
|
||||
#define KEY_NUMLOCKCLEAR 83
|
||||
#define KEY_KP_DIVIDE 84
|
||||
#define KEY_KP_MULTIPLY 85
|
||||
#define KEY_KP_MINUS 86
|
||||
#define KEY_KP_PLUS 87
|
||||
#define KEY_KP_ENTER 88
|
||||
#define KEY_KP_1 89
|
||||
#define KEY_KP_2 90
|
||||
#define KEY_KP_3 91
|
||||
#define KEY_KP_4 92
|
||||
#define KEY_KP_5 93
|
||||
#define KEY_KP_6 94
|
||||
#define KEY_KP_7 95
|
||||
#define KEY_KP_8 96
|
||||
#define KEY_KP_9 97
|
||||
#define KEY_KP_0 98
|
||||
#define KEY_KP_PERIOD 99
|
||||
#define KEY_NONUSBACKSLASH 100
|
||||
#define KEY_APPLICATION 101
|
||||
#define KEY_LCTRL 224
|
||||
#define KEY_LSHIFT 225
|
||||
#define KEY_LALT 226
|
||||
#define KEY_LGUI 227
|
||||
#define KEY_RCTRL 228
|
||||
#define KEY_RSHIFT 229
|
||||
#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, 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();
|
||||
|
||||
uint8_t loadfont(const char *filename);
|
||||
uint8_t getfont();
|
||||
void setfont(uint8_t font);
|
||||
uint8_t getfontspacing();
|
||||
void setfontspacing(uint8_t spacing);
|
||||
|
||||
void cls(uint8_t color=0);
|
||||
void color(uint8_t color=6);
|
||||
void bcolor(uint8_t color=0);
|
||||
|
||||
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();
|
||||
uint8_t subpal(uint8_t index, uint8_t color);
|
||||
void reset_subpal();
|
||||
|
||||
void set_draw_mode(uint8_t mode);
|
||||
void pset(int x, int y);
|
||||
void pset(int x, int y, uint8_t color);
|
||||
|
||||
uint8_t pget(int x, int y);
|
||||
|
||||
void line(int x0, int y0, int x1, int y1);
|
||||
void line(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
|
||||
void hline(int x0, int y, int x1);
|
||||
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 x, int y, int w, int h);
|
||||
void rect(int x, int y, int w, int h, 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);
|
||||
|
||||
void print(const char *str, int x, int y);
|
||||
void print(const char *str, int x, int y, uint8_t color);
|
||||
|
||||
void clip(int x, int y, int w, int h);
|
||||
void clip();
|
||||
void origin(int x, int y);
|
||||
int camx();
|
||||
int camy();
|
||||
|
||||
void circ(int x, int y, uint8_t r = 4);
|
||||
void circ(int x, int y, uint8_t r, uint8_t color);
|
||||
|
||||
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);
|
||||
|
||||
void ovalfill(int x0, int y0, int x1, int y1);
|
||||
void ovalfill(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
|
||||
uint8_t sget(int x, int y);
|
||||
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 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 blit_r(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg);
|
||||
|
||||
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);
|
||||
|
||||
uint8_t mget(int celx, int cely);
|
||||
void mset(int celx, int cely, uint8_t snum);
|
||||
uint8_t gettilew();
|
||||
uint8_t gettileh();
|
||||
void settilesize(int w, int h);
|
||||
void map(); //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
|
||||
|
||||
bool btn(uint8_t i);
|
||||
int wbtnp();
|
||||
bool btnp(uint8_t i);
|
||||
bool anykey();
|
||||
void textenable(const bool enable);
|
||||
const char *textinput();
|
||||
|
||||
bool pad(int8_t i);
|
||||
bool padp(int8_t i);
|
||||
int wpad();
|
||||
|
||||
int mousex();
|
||||
int mousey();
|
||||
int mwheel();
|
||||
bool mbtn(uint8_t i);
|
||||
bool mbtnp(uint8_t i);
|
||||
bool doubleclick();
|
||||
void mdiscard();
|
||||
bool minside(int x, int y, int w, int h);
|
||||
|
||||
float time();
|
||||
bool beat(int16_t i);
|
||||
|
||||
int rnd(int x);
|
||||
int getfps();
|
||||
|
||||
void playmusic(const char *filename, const int loop=-1);
|
||||
void pausemusic();
|
||||
void resumemusic();
|
||||
void stopmusic(const int t=1000);
|
||||
void musicpos(float value);
|
||||
float musicpos();
|
||||
void enablemusic(const bool value);
|
||||
const bool ismusicenabled();
|
||||
|
||||
int loadsound(const char *filename);
|
||||
void freesound(int soundfile);
|
||||
int playsound(int soundfile, const int volume=-1);
|
||||
void stopsound(int soundchannel);
|
||||
void enablesound(const bool value);
|
||||
const bool issoundenabled();
|
||||
|
||||
int getzoom();
|
||||
void setzoom(const int value);
|
||||
void setres(const int w, const int h);
|
||||
bool getfullscreen();
|
||||
void setfullscreen(const bool value);
|
||||
bool getcursor();
|
||||
void setcursor(const bool value);
|
||||
|
||||
const char *getconfig(const char* key);
|
||||
void setconfig(const char* key, const char* value);
|
||||
const char *configfolder();
|
||||
|
||||
#define UPDATE_ALWAYS 0
|
||||
#define UPDATE_WAIT 1
|
||||
#define UPDATE_TIMEOUT 2
|
||||
void setupdatemode(const int value, const int t=0);
|
||||
int getupdatemode();
|
||||
|
||||
void exit();
|
||||
@@ -6,7 +6,7 @@ set -e
|
||||
# exit 1
|
||||
#fi
|
||||
|
||||
GITEA_TOKEN="eb44d9c0142f5038c61c5afd17f5a41177bfaedc"
|
||||
#GITEA_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
if [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "ERROR: Debes exportar GITEA_TOKEN"
|
||||
|
||||
96
source/backends/SDL3/base.cpp
Normal file
96
source/backends/SDL3/base.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#if BACKEND == SDL3
|
||||
|
||||
#include "backends/backend.h"
|
||||
#include "state.h"
|
||||
#include "mini/win/win.h"
|
||||
#include "mini/surf/surf.h"
|
||||
|
||||
namespace backend
|
||||
{
|
||||
state_t current_state = running;
|
||||
|
||||
void init() {
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD);
|
||||
//video::init();
|
||||
}
|
||||
|
||||
void quit() {
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void poll_events() {
|
||||
//[TODO]
|
||||
//if (update_mode==UPDATE_WAIT)
|
||||
// SDL_WaitEvent(NULL);
|
||||
//else if (update_mode==UPDATE_TIMEOUT)
|
||||
// SDL_WaitEventTimeout(NULL, timeout);
|
||||
|
||||
SDL_Event e;
|
||||
while(SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_EVENT_QUIT) {
|
||||
current_state=quitting;
|
||||
break;
|
||||
}
|
||||
else if (e.type == SDL_EVENT_TEXT_INPUT) {
|
||||
SDL_strlcpy(input::key::text_input_buffer, e.text.text, sizeof(input::key::text_input_buffer));
|
||||
input::key::has_text_input = true;
|
||||
}
|
||||
else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||
#ifdef DEBUG
|
||||
if (e.key.scancode == SDL_SCANCODE_F12) {
|
||||
mini::surf::reloadsurfs();
|
||||
//} else if (e.key.scancode == SDL_SCANCODE_F11) {
|
||||
// mini::lua::debug::toggle();
|
||||
} else if (e.key.scancode == SDL_SCANCODE_F5) {
|
||||
current_state=exiting;
|
||||
} else {
|
||||
input::key::just_pressed = e.key.scancode;
|
||||
}
|
||||
#else
|
||||
input::key::just_pressed = e.key.scancode;
|
||||
#endif
|
||||
}
|
||||
else if (e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||
if (input::mouse::discard_buttons)
|
||||
input::mouse::discard_buttons = false;
|
||||
else
|
||||
if (e.button.clicks==2 && e.button.button==SDL_BUTTON_LEFT) {
|
||||
input::mouse::double_click = true;
|
||||
} else {
|
||||
input::mouse::just_pressed = e.button.button;
|
||||
}
|
||||
}
|
||||
else if (e.type == SDL_EVENT_MOUSE_WHEEL) {
|
||||
input::mouse::w = e.wheel.y;
|
||||
}
|
||||
else if (e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
|
||||
input::pad::just_pressed = e.gbutton.button;
|
||||
}
|
||||
}
|
||||
|
||||
input::key::keys = SDL_GetKeyboardState(NULL);
|
||||
|
||||
// Update mouse
|
||||
float real_mouse_x, real_mouse_y;
|
||||
input::mouse::buttons = SDL_GetMouseState(&real_mouse_x, &real_mouse_y);
|
||||
float mx, my;
|
||||
SDL_RenderCoordinatesFromWindow(video::renderer, real_mouse_x, real_mouse_y, &mx, &my);
|
||||
input::mouse::x = int(mx/mini::win::state.zoom);
|
||||
input::mouse::y = int(my/mini::win::state.zoom);
|
||||
}
|
||||
|
||||
const state_t& state() {
|
||||
return current_state;
|
||||
}
|
||||
|
||||
char *clipboard() {
|
||||
return SDL_GetClipboardText();
|
||||
}
|
||||
|
||||
void clipboard(const char* value) {
|
||||
SDL_SetClipboardText(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
153
source/backends/SDL3/input.cpp
Normal file
153
source/backends/SDL3/input.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#if BACKEND == SDL3
|
||||
|
||||
#include "backends/backend.h"
|
||||
#include "state.h"
|
||||
#include "mini/view/view.h"
|
||||
|
||||
namespace backend
|
||||
{
|
||||
namespace input
|
||||
{
|
||||
void reset() {
|
||||
key::just_pressed = 0;
|
||||
key::has_text_input = false;
|
||||
key::text_input_buffer[0] = '\0';
|
||||
mouse::just_pressed = 0;
|
||||
mouse::double_click = false;
|
||||
mouse::w = 0;
|
||||
pad::just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
|
||||
}
|
||||
|
||||
namespace key
|
||||
{
|
||||
const bool *keys;
|
||||
uint8_t just_pressed = 0;
|
||||
char text_input_buffer[10];
|
||||
bool has_text_input = false;
|
||||
|
||||
bool down(uint8_t i) {
|
||||
return keys[i];
|
||||
}
|
||||
|
||||
bool press(uint8_t i) {
|
||||
if (just_pressed == i) {
|
||||
just_pressed=0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int press() {
|
||||
return just_pressed;
|
||||
}
|
||||
|
||||
bool any() {
|
||||
const bool something_pressed = (just_pressed != 0) || (pad::just_pressed != -1);
|
||||
just_pressed=0;
|
||||
pad::just_pressed=-1;
|
||||
return something_pressed;
|
||||
}
|
||||
|
||||
void text(const bool enable) {
|
||||
if (enable)
|
||||
SDL_StartTextInput(backend::video::window);
|
||||
else
|
||||
SDL_StopTextInput(backend::video::window);
|
||||
}
|
||||
|
||||
const char *utf8char() {
|
||||
return has_text_input ? text_input_buffer : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mouse
|
||||
{
|
||||
int x, y, w;
|
||||
uint32_t buttons;
|
||||
uint8_t just_pressed = 0;
|
||||
bool double_click = false;
|
||||
bool discard_buttons = false;
|
||||
|
||||
int posx() {
|
||||
return x - mini::view::state.origin[0];
|
||||
}
|
||||
|
||||
int posy() {
|
||||
return y - mini::view::state.origin[1];
|
||||
}
|
||||
|
||||
int wheel() {
|
||||
return w;
|
||||
}
|
||||
|
||||
bool down(uint8_t i) {
|
||||
if (discard_buttons) return false;
|
||||
return buttons & SDL_BUTTON_MASK(i);
|
||||
}
|
||||
|
||||
bool press(uint8_t i) {
|
||||
return just_pressed == i;
|
||||
}
|
||||
|
||||
bool dblclick() {
|
||||
return double_click;
|
||||
}
|
||||
|
||||
void discard() {
|
||||
discard_buttons = true;
|
||||
}
|
||||
|
||||
bool inside(int x, int y, int w, int h) {
|
||||
const int mx = x - mini::view::state.origin[0];
|
||||
const int my = y - mini::view::state.origin[1];
|
||||
return (mx>=x) && (my>=y) && (mx<x+w) && (my<y+h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace pad
|
||||
{
|
||||
SDL_Gamepad *gamepad = nullptr;
|
||||
int8_t just_pressed = -1;
|
||||
|
||||
void init() {
|
||||
int num_joysticks;
|
||||
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
|
||||
if (joysticks) {
|
||||
for (int i=0; i<num_joysticks; ++i) {
|
||||
if (SDL_IsGamepad(joysticks[i])) {
|
||||
gamepad = SDL_OpenGamepad(joysticks[i]);
|
||||
if (SDL_GamepadConnected(gamepad)) {
|
||||
SDL_SetGamepadEventsEnabled(true);
|
||||
// [TODO]
|
||||
//log_msg(LOG_OK, "Gamepad found and initialized");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool down(int8_t i) {
|
||||
if (!gamepad) return false;
|
||||
return SDL_GetGamepadButton(gamepad, SDL_GamepadButton(i)) == 1;
|
||||
}
|
||||
|
||||
bool press(int8_t i) {
|
||||
if (just_pressed == i) {
|
||||
just_pressed = -1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int press() {
|
||||
return just_pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
43
source/backends/SDL3/state.h
Normal file
43
source/backends/SDL3/state.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#if BACKEND == SDL3
|
||||
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace backend
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
extern SDL_Window *window;
|
||||
extern SDL_Renderer *renderer;
|
||||
extern SDL_Texture *tex_back;
|
||||
extern SDL_Texture *tex_shader;
|
||||
}
|
||||
|
||||
namespace input
|
||||
{
|
||||
namespace key
|
||||
{
|
||||
extern const bool *keys;
|
||||
extern uint8_t just_pressed;
|
||||
extern char text_input_buffer[10];
|
||||
extern bool has_text_input;
|
||||
}
|
||||
|
||||
namespace mouse
|
||||
{
|
||||
extern int x, y, w;
|
||||
extern uint32_t buttons;
|
||||
extern uint8_t just_pressed;
|
||||
extern bool double_click;
|
||||
extern bool discard_buttons;
|
||||
}
|
||||
|
||||
namespace pad
|
||||
{
|
||||
extern SDL_Gamepad *gamepad;
|
||||
extern int8_t just_pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
90
source/backends/SDL3/video.cpp
Normal file
90
source/backends/SDL3/video.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#if BACKEND == SDL3
|
||||
|
||||
#include "backends/backend.h"
|
||||
#include "state.h"
|
||||
#include "mini/win/win.h"
|
||||
#include "mini/surf/surf.h"
|
||||
#include "mini/pal/pal.h"
|
||||
#include "mini/shader/shader.h"
|
||||
|
||||
namespace backend
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
SDL_Window *window { nullptr };
|
||||
SDL_Renderer *renderer { nullptr };
|
||||
SDL_Texture *tex_back { nullptr };
|
||||
SDL_Texture *tex_shader { nullptr };
|
||||
|
||||
void init() {
|
||||
const auto &title = mini::win::state.title;
|
||||
const auto &width = mini::win::state.width;
|
||||
const auto &height = mini::win::state.height;
|
||||
auto &zoom = mini::win::state.zoom;
|
||||
|
||||
// Ajustar el zoom a un valor vàlid
|
||||
if (zoom <= 0) zoom = 1;
|
||||
const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
|
||||
while ( width * zoom > dm->w || height * zoom > dm->h) zoom--;
|
||||
|
||||
// Crear SDL_Window i SDL_Renderer
|
||||
window = SDL_CreateWindow(title, width*zoom, height*zoom, SDL_WINDOW_OPENGL|(mini::win::state.fullscreen?SDL_WINDOW_FULLSCREEN:0));
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
||||
renderer = SDL_CreateRenderer(window, NULL);
|
||||
|
||||
// Mostrar o ocultar el cursor
|
||||
if (mini::win::state.cursor) SDL_ShowCursor(); else SDL_HideCursor();
|
||||
|
||||
// Crear textura backbuffer
|
||||
tex_back = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
SDL_SetTextureScaleMode(tex_back, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
// Crear textura shaders i inicialitzar shaders
|
||||
tex_shader = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width*zoom, height*zoom);
|
||||
SDL_SetTextureScaleMode(tex_shader, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
mini::shader::init(window, tex_shader, nullptr);
|
||||
|
||||
// [TODO]
|
||||
//log_msg(LOG_OK, "Graphics subsystem initialized\n");
|
||||
}
|
||||
|
||||
void quit() {
|
||||
SDL_DestroyTexture(tex_shader);
|
||||
SDL_DestroyTexture(tex_back);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
|
||||
void render() {
|
||||
// Render frame
|
||||
SDL_SetRenderTarget(renderer, tex_shader);
|
||||
//SDL_SetRenderDrawColor(win::state.renderer, 0, 0, 0, 255);
|
||||
//SDL_RenderClear(win::state.renderer);
|
||||
|
||||
uint32_t *pixels;
|
||||
int pitch;
|
||||
SDL_LockTexture(tex_back, NULL, (void**)&pixels, &pitch);
|
||||
auto &s = mini::surf::state.surfaces[SCREEN];
|
||||
uint8_t *p = s.p;
|
||||
for (uint32_t i=0;i<s.size;++i) pixels[i] = mini::pal::palette[p[i]];
|
||||
SDL_UnlockTexture(tex_back);
|
||||
SDL_RenderTexture(renderer, tex_back, NULL, NULL); //NEW
|
||||
|
||||
mini::shader::render();
|
||||
|
||||
//SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL);
|
||||
//SDL_RenderPresent(mini_ren);
|
||||
}
|
||||
|
||||
void raise_window() {
|
||||
SDL_RaiseWindow(window);
|
||||
}
|
||||
|
||||
void cursor(const bool value) {
|
||||
if (value) SDL_ShowCursor(); else SDL_HideCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
16
source/backends/backend.cpp
Normal file
16
source/backends/backend.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "backend.h"
|
||||
#include <chrono>
|
||||
|
||||
namespace backend
|
||||
{
|
||||
uint64_t get_time_ms() {
|
||||
using namespace std::chrono;
|
||||
return duration_cast<milliseconds>(
|
||||
steady_clock::now().time_since_epoch()
|
||||
).count();
|
||||
}
|
||||
|
||||
void exit() {
|
||||
current_state = quitting;
|
||||
}
|
||||
}
|
||||
77
source/backends/backend.h
Normal file
77
source/backends/backend.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#define SDL3 1
|
||||
#define SFML 2
|
||||
#define EMSCRIPTEN 3
|
||||
|
||||
#ifndef BACKEND
|
||||
#define BACKEND SDL3
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace backend
|
||||
{
|
||||
enum state_t { running=0, exiting=1, quitting=2 };
|
||||
extern state_t current_state;
|
||||
|
||||
void init();
|
||||
void quit();
|
||||
void poll_events();
|
||||
const state_t& state();
|
||||
void exit();
|
||||
uint64_t get_time_ms();
|
||||
char* clipboard();
|
||||
void clipboard(const char* value);
|
||||
|
||||
namespace video
|
||||
{
|
||||
void init();
|
||||
void quit();
|
||||
void render();
|
||||
void raise_window();
|
||||
void cursor(const bool value);
|
||||
}
|
||||
|
||||
namespace audio
|
||||
{
|
||||
void init();
|
||||
void quit();
|
||||
void render();
|
||||
}
|
||||
|
||||
namespace input
|
||||
{
|
||||
void reset();
|
||||
|
||||
namespace key
|
||||
{
|
||||
bool down(uint8_t i);
|
||||
bool press(uint8_t i);
|
||||
int press();
|
||||
bool any();
|
||||
void text(const bool enable);
|
||||
const char *utf8char();
|
||||
}
|
||||
|
||||
namespace mouse
|
||||
{
|
||||
int posx();
|
||||
int posy();
|
||||
int wheel();
|
||||
bool down(uint8_t i);
|
||||
bool press(uint8_t i);
|
||||
bool dblclick();
|
||||
void discard();
|
||||
bool inside(int x, int y, int w, int h);
|
||||
}
|
||||
|
||||
namespace pad
|
||||
{
|
||||
void init();
|
||||
bool down(int8_t i);
|
||||
bool press(int8_t i);
|
||||
int press();
|
||||
}
|
||||
}
|
||||
}
|
||||
0
lua/lapi.c → source/external/lua/lapi.c
vendored
0
lua/lapi.c → source/external/lua/lapi.c
vendored
0
lua/lapi.h → source/external/lua/lapi.h
vendored
0
lua/lapi.h → source/external/lua/lapi.h
vendored
0
lua/ldo.c → source/external/lua/ldo.c
vendored
0
lua/ldo.c → source/external/lua/ldo.c
vendored
0
lua/ldo.h → source/external/lua/ldo.h
vendored
0
lua/ldo.h → source/external/lua/ldo.h
vendored
0
lua/lgc.c → source/external/lua/lgc.c
vendored
0
lua/lgc.c → source/external/lua/lgc.c
vendored
0
lua/lgc.h → source/external/lua/lgc.h
vendored
0
lua/lgc.h → source/external/lua/lgc.h
vendored
0
lua/llex.c → source/external/lua/llex.c
vendored
0
lua/llex.c → source/external/lua/llex.c
vendored
0
lua/llex.h → source/external/lua/llex.h
vendored
0
lua/llex.h → source/external/lua/llex.h
vendored
0
lua/lmem.c → source/external/lua/lmem.c
vendored
0
lua/lmem.c → source/external/lua/lmem.c
vendored
0
lua/lmem.h → source/external/lua/lmem.h
vendored
0
lua/lmem.h → source/external/lua/lmem.h
vendored
0
lua/ltm.c → source/external/lua/ltm.c
vendored
0
lua/ltm.c → source/external/lua/ltm.c
vendored
0
lua/ltm.h → source/external/lua/ltm.h
vendored
0
lua/ltm.h → source/external/lua/ltm.h
vendored
0
lua/lua.h → source/external/lua/lua.h
vendored
0
lua/lua.h → source/external/lua/lua.h
vendored
0
lua/lvm.c → source/external/lua/lvm.c
vendored
0
lua/lvm.c → source/external/lua/lvm.c
vendored
0
lua/lvm.h → source/external/lua/lvm.h
vendored
0
lua/lvm.h → source/external/lua/lvm.h
vendored
0
lua/lzio.c → source/external/lua/lzio.c
vendored
0
lua/lzio.c → source/external/lua/lzio.c
vendored
0
lua/lzio.h → source/external/lua/lzio.h
vendored
0
lua/lzio.h → source/external/lua/lzio.h
vendored
107
source/mini/audio/audio.cpp
Normal file
107
source/mini/audio/audio.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "audio.h"
|
||||
#include "jail_audio.h"
|
||||
#include "mini/file/file.h"
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
int current_music = -1;
|
||||
//#define MAX_SOUNDS 50
|
||||
//JA_Sound_t *sounds[MAX_SOUNDS];
|
||||
|
||||
void init() {
|
||||
jail::audio::init();
|
||||
//for (int i=0;i<MAX_SOUNDS;++i) sounds[i] = NULL;
|
||||
}
|
||||
|
||||
void quit() {
|
||||
//if (current_music != NULL) JA_DeleteMusic(current_music);
|
||||
//for (int i=0;i<MAX_SOUNDS;++i) if (sounds[i]!=NULL) JA_DeleteSound(sounds[i]);
|
||||
jail::audio::quit();
|
||||
}
|
||||
|
||||
namespace music
|
||||
{
|
||||
void play(const char *filename, const int loop) {
|
||||
int size;
|
||||
char *buffer = file::getfilebuffer(filename, size);
|
||||
if (current_music != -1) jail::audio::music::destroy(current_music);
|
||||
current_music = jail::audio::music::load((uint8_t*)buffer, size);
|
||||
jail::audio::music::play(current_music, loop);
|
||||
}
|
||||
|
||||
void pause() {
|
||||
jail::audio::music::pause();
|
||||
}
|
||||
|
||||
void resume() {
|
||||
jail::audio::music::resume();
|
||||
}
|
||||
|
||||
void stop(const int t) {
|
||||
jail::audio::music::stop();
|
||||
}
|
||||
|
||||
namespace pos {
|
||||
void set(float value)
|
||||
{
|
||||
jail::audio::music::setPosition(value);
|
||||
}
|
||||
|
||||
float get()
|
||||
{
|
||||
return jail::audio::music::getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
namespace enable {
|
||||
void set(const bool value)
|
||||
{
|
||||
jail::audio::music::enable(value);
|
||||
file::setconfigvalue("music", value?"true":"false");
|
||||
}
|
||||
|
||||
const bool get()
|
||||
{
|
||||
return jail::audio::music::isEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace sound
|
||||
{
|
||||
int load(const char *filename) {
|
||||
int size;
|
||||
char *buffer = file::getfilebuffer(filename, size);
|
||||
return jail::audio::sound::load((uint8_t*)buffer, size);
|
||||
}
|
||||
|
||||
void free(int soundfile) {
|
||||
return jail::audio::sound::destroy(soundfile);
|
||||
}
|
||||
|
||||
int play(int soundfile, const int volume) {
|
||||
// [TODO] Ficar el volumen
|
||||
return jail::audio::sound::play(soundfile, 0);
|
||||
}
|
||||
|
||||
void stop(int soundchannel) {
|
||||
return jail::audio::sound::channel::stop(soundchannel);
|
||||
}
|
||||
|
||||
namespace enable {
|
||||
void set(const bool value)
|
||||
{
|
||||
return jail::audio::sound::enable(value);
|
||||
file::setconfigvalue("sound", value?"true":"false");
|
||||
}
|
||||
|
||||
const bool get()
|
||||
{
|
||||
return jail::audio::sound::isEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
source/mini/audio/audio.h
Normal file
38
source/mini/audio/audio.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
void init();
|
||||
void quit();
|
||||
|
||||
namespace music
|
||||
{
|
||||
void play(const char *filename, const int loop=-1);
|
||||
void pause();
|
||||
void resume();
|
||||
void stop(const int t=1000);
|
||||
namespace pos {
|
||||
void set(float value);
|
||||
float get();
|
||||
}
|
||||
namespace enable {
|
||||
void set(const bool value);
|
||||
const bool get();
|
||||
}
|
||||
}
|
||||
|
||||
namespace sound
|
||||
{
|
||||
int load(const char *filename);
|
||||
void free(int soundfile);
|
||||
int play(int soundfile, const int volume=-1);
|
||||
void stop(int soundchannel);
|
||||
namespace enable {
|
||||
void set(const bool value);
|
||||
const bool get();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
642
source/mini/audio/jail_audio.cpp
Normal file
642
source/mini/audio/jail_audio.cpp
Normal file
@@ -0,0 +1,642 @@
|
||||
#ifndef JA_USESDLMIXER
|
||||
#include "jail_audio.h"
|
||||
#include "external/stb_vorbis.h"
|
||||
#include "other/log.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
// structs i variables
|
||||
// =============================
|
||||
namespace jail
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
static SDL_AudioSpec audioSpec { SDL_AUDIO_S16, 2, 48000 };
|
||||
SDL_AudioDeviceID sdlAudioDevice { 0 };
|
||||
SDL_TimerID timerID { 0 };
|
||||
|
||||
namespace music
|
||||
{
|
||||
struct 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 };
|
||||
music::state state { music::state::invalid };
|
||||
};
|
||||
|
||||
static int current { -1 };
|
||||
static std::vector<music_t> musics;
|
||||
static float volume { 1.0f };
|
||||
static bool enabled { true };
|
||||
|
||||
namespace fade
|
||||
{
|
||||
static bool fading = false;
|
||||
static int start_time;
|
||||
static int duration;
|
||||
static int initial_volume;
|
||||
}
|
||||
}
|
||||
|
||||
namespace sound
|
||||
{
|
||||
struct sound_t
|
||||
{
|
||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||
Uint32 length { 0 };
|
||||
Uint8 *buffer { NULL };
|
||||
};
|
||||
|
||||
static std::vector<sound_t> sounds;
|
||||
static float volume { 0.5f };
|
||||
static bool enabled { true };
|
||||
|
||||
namespace channel
|
||||
{
|
||||
struct channel_t
|
||||
{
|
||||
int sound { -1 };
|
||||
int pos { 0 };
|
||||
int times { 0 };
|
||||
SDL_AudioStream *stream { nullptr };
|
||||
channel::state state { channel::state::free };
|
||||
};
|
||||
|
||||
static std::vector<channel_t> channels;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funcions
|
||||
// ==================
|
||||
namespace jail
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
static void updateMusic()
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (music::current < 0 || music::current > music::musics.size()) return;
|
||||
auto &m = music::musics[music::current];
|
||||
if (m.state != music::state::playing) return;
|
||||
|
||||
if (music::fade::fading) {
|
||||
int time = SDL_GetTicks();
|
||||
if (time > (music::fade::start_time + music::fade::duration)) {
|
||||
music::fade::fading = false;
|
||||
music::stop();
|
||||
return;
|
||||
} else {
|
||||
const int time_passed = time - music::fade::start_time;
|
||||
const float percent = (float)time_passed / (float)music::fade::duration;
|
||||
SDL_SetAudioStreamGain(m.stream, 1.0 - percent);
|
||||
}
|
||||
}
|
||||
|
||||
if (m.times != 0)
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(m.stream) < int(m.length/2)) {
|
||||
SDL_PutAudioStreamData(m.stream, m.buffer, m.length);
|
||||
}
|
||||
if (m.times>0) m.times--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(m.stream) == 0) music::stop();
|
||||
}
|
||||
}
|
||||
|
||||
static void updateSound()
|
||||
{
|
||||
if (sound::enabled)
|
||||
{
|
||||
for (int i=0; i < sound::channel::channels.size(); ++i) {
|
||||
auto &c = sound::channel::channels[i];
|
||||
if (c.state == sound::channel::state::playing)
|
||||
{
|
||||
if (c.times != 0)
|
||||
{
|
||||
auto &s = sound::sounds[c.sound];
|
||||
if (SDL_GetAudioStreamAvailable(c.stream) < int(s.length/2))
|
||||
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||
if (c.times>0) c.times--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(c.stream) == 0) sound::channel::stop(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 updateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
|
||||
{
|
||||
updateMusic();
|
||||
updateSound();
|
||||
return 30;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
|
||||
#endif
|
||||
|
||||
audioSpec = {SDL_AUDIO_S16, 1, 48000 };
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &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);
|
||||
timerID = SDL_AddTimer(30, updateCallback, nullptr);
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
if (timerID) SDL_RemoveTimer(timerID);
|
||||
|
||||
for (int i=0; i<music::musics.size();++i) music::destroy(i);
|
||||
music::musics.clear();
|
||||
|
||||
for (int i=0; i<sound::channel::channels.size();++i) sound::channel::stop(i);
|
||||
sound::channel::channels.clear();
|
||||
|
||||
for (int i=0; i<sound::sounds.size();++i) sound::destroy(i);
|
||||
sound::sounds.clear();
|
||||
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = 0;
|
||||
}
|
||||
|
||||
float setVolume(float vol)
|
||||
{
|
||||
sound::setVolume(music::setVolume(vol) / 2.0f);
|
||||
return music::volume;
|
||||
}
|
||||
|
||||
|
||||
namespace music
|
||||
{
|
||||
int load(const uint8_t* buffer, uint32_t length)
|
||||
{
|
||||
int music = 0;
|
||||
while (music < musics.size() && musics[music].state != state::invalid) { music++; }
|
||||
if (music == musics.size()) musics.emplace_back();
|
||||
|
||||
auto &m = musics[music];
|
||||
|
||||
int chan, samplerate;
|
||||
short *output;
|
||||
m.length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
||||
|
||||
m.spec.channels = chan;
|
||||
m.spec.freq = samplerate;
|
||||
m.spec.format = SDL_AUDIO_S16;
|
||||
m.buffer = (uint8_t*)SDL_malloc(m.length);
|
||||
SDL_memcpy(m.buffer, output, m.length);
|
||||
free(output);
|
||||
m.pos = 0;
|
||||
m.state = state::stopped;
|
||||
|
||||
return music;
|
||||
}
|
||||
|
||||
int load(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);
|
||||
|
||||
int music = load(buffer, fsize);
|
||||
|
||||
free(buffer);
|
||||
|
||||
return music;
|
||||
}
|
||||
|
||||
void play(int mus, int loop)
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
stop();
|
||||
if (mus < 0 || mus >= musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::play: Illegal music handle: %i\n", mus);
|
||||
return;
|
||||
}
|
||||
|
||||
current = mus;
|
||||
auto &m = musics[current];
|
||||
m.pos = 0;
|
||||
m.state = state::playing;
|
||||
m.times = loop;
|
||||
m.stream = SDL_CreateAudioStream(&m.spec, &audioSpec);
|
||||
if (!SDL_PutAudioStreamData(m.stream, m.buffer, m.length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n");
|
||||
SDL_SetAudioStreamGain(m.stream, volume);
|
||||
if (!SDL_BindAudioStream(sdlAudioDevice, m.stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
|
||||
//SDL_ResumeAudioStreamDevice(current->stream);
|
||||
}
|
||||
|
||||
void pause()
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::pause: Illegal music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::pause: Invalidated music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
|
||||
m.state = state::paused;
|
||||
//SDL_PauseAudioStreamDevice(current->stream);
|
||||
SDL_UnbindAudioStream(m.stream);
|
||||
}
|
||||
|
||||
void resume()
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::resume: Illegal music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::resume: Invalidated music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
|
||||
m.state = state::playing;
|
||||
//SDL_ResumeAudioStreamDevice(current->stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, m.stream);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::stop: Illegal music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::stop: Invalidated music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
|
||||
m.pos = 0;
|
||||
m.state = state::stopped;
|
||||
//SDL_PauseAudioStreamDevice(current->stream);
|
||||
SDL_DestroyAudioStream(m.stream);
|
||||
m.stream = nullptr;
|
||||
}
|
||||
|
||||
void fadeOut(int milliseconds)
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::fadeOut: Illegal music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::fadeOut: Invalidated music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
|
||||
fade::fading = true;
|
||||
fade::start_time = SDL_GetTicks();
|
||||
fade::duration = milliseconds;
|
||||
fade::initial_volume = volume;
|
||||
}
|
||||
|
||||
music::state getState()
|
||||
{
|
||||
if (!music::enabled) return music::state::disabled;
|
||||
if (current<0 || current>musics.size()) return state::invalid;
|
||||
return musics[current].state;
|
||||
}
|
||||
|
||||
void destroy(int mus)
|
||||
{
|
||||
if (current == mus) current = -1;
|
||||
if (mus<0 || mus>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::destroy: Illegal music handle: %i\n", mus);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[mus];
|
||||
SDL_free(m.buffer);
|
||||
m.buffer = nullptr;
|
||||
if (m.stream) SDL_DestroyAudioStream(m.stream);
|
||||
m.stream = nullptr;
|
||||
m.state = state::invalid;
|
||||
}
|
||||
|
||||
float setVolume(float vol)
|
||||
{
|
||||
volume = SDL_clamp( vol, 0.0f, 1.0f );
|
||||
|
||||
if (current<0 || current>musics.size()) return vol;
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) return vol;
|
||||
|
||||
SDL_SetAudioStreamGain(m.stream, volume);
|
||||
return volume;
|
||||
}
|
||||
|
||||
void setPosition(float value)
|
||||
{
|
||||
if (!music::enabled) return;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::setPosition: Illegal music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::setPosition: Invalidated music handle: %i\n", current);
|
||||
return;
|
||||
}
|
||||
|
||||
m.pos = value * m.spec.freq;
|
||||
}
|
||||
|
||||
float getPosition()
|
||||
{
|
||||
if (!music::enabled) return 0;
|
||||
if (current<0 || current>musics.size()) {
|
||||
log_msg(LOG_FAIL, "music::getPosition: Illegal music handle: %i\n", current);
|
||||
return 0;
|
||||
}
|
||||
auto &m = musics[current];
|
||||
if (m.state == state::invalid) {
|
||||
log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return float(m.pos)/float(m.spec.freq);
|
||||
}
|
||||
|
||||
void enable(bool value)
|
||||
{
|
||||
if (!value && music::enabled && current>=0 && current<musics.size() && musics[current].state==state::playing) stop();
|
||||
music::enabled = value;
|
||||
}
|
||||
|
||||
bool isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace sound
|
||||
{
|
||||
int create(uint8_t* buffer, uint32_t length)
|
||||
{
|
||||
int snd = 0;
|
||||
while (snd < sounds.size() && sounds[snd].buffer) { snd++; }
|
||||
if (snd == sounds.size()) sounds.emplace_back();
|
||||
|
||||
auto &s = sounds[snd];
|
||||
s.buffer = buffer;
|
||||
s.length = length;
|
||||
return snd;
|
||||
}
|
||||
|
||||
int load(uint8_t* buffer, uint32_t size)
|
||||
{
|
||||
int snd = 0;
|
||||
while (snd < sounds.size() && sounds[snd].buffer) { snd++; }
|
||||
if (snd == sounds.size()) sounds.emplace_back();
|
||||
|
||||
auto &s = sounds[snd];
|
||||
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &s.spec, &s.buffer, &s.length);
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
int load(const char* filename)
|
||||
{
|
||||
int snd = 0;
|
||||
while (snd < sounds.size() && sounds[snd].buffer) { snd++; }
|
||||
if (snd == sounds.size()) sounds.emplace_back();
|
||||
|
||||
auto &s = sounds[snd];
|
||||
SDL_LoadWAV(filename, &s.spec, &s.buffer, &s.length);
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
int play(int snd, int loop)
|
||||
{
|
||||
if (!sound::enabled) return -1;
|
||||
|
||||
if (snd<0 || snd>sounds.size()) {
|
||||
log_msg(LOG_FAIL, "sound::play: Illegal sound handle: %i\n", snd);
|
||||
return -1;
|
||||
}
|
||||
auto &s = sounds[snd];
|
||||
if (!s.buffer) {
|
||||
log_msg(LOG_FAIL, "sound::play: Invalid sound: %i\n", snd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int chan = 0;
|
||||
while (chan < channel::channels.size() && channel::channels[chan].state != channel::state::free) { chan++; }
|
||||
if (chan == channel::channels.size()) channel::channels.emplace_back();
|
||||
channel::stop(chan);
|
||||
auto &c = channel::channels[chan];
|
||||
c.sound = snd;
|
||||
c.times = loop;
|
||||
c.pos = 0;
|
||||
c.state = channel::state::playing;
|
||||
c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec);
|
||||
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||
SDL_SetAudioStreamGain(c.stream, volume);
|
||||
SDL_BindAudioStream(sdlAudioDevice, c.stream);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
int playOnChannel(int snd, int chan, int loop)
|
||||
{
|
||||
if (!sound::enabled) return -1;
|
||||
|
||||
if (snd<0 || snd>sounds.size()) {
|
||||
log_msg(LOG_FAIL, "sound::playOnChannel: Illegal sound handle: %i\n", snd);
|
||||
return -1;
|
||||
}
|
||||
auto &s = sounds[snd];
|
||||
if (!s.buffer) {
|
||||
log_msg(LOG_FAIL, "sound::playOnChannel: Invalid sound: %i\n", snd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chan<0 || chan>channel::channels.size()) {
|
||||
log_msg(LOG_FAIL, "sound::playOnChannel: Illegal channel handle: %i\n", chan);
|
||||
return -1;
|
||||
}
|
||||
|
||||
channel::stop(chan);
|
||||
|
||||
auto &c = channel::channels[chan];
|
||||
c.sound = snd;
|
||||
c.times = loop;
|
||||
c.pos = 0;
|
||||
c.state = channel::state::playing;
|
||||
c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec);
|
||||
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||
SDL_SetAudioStreamGain(c.stream, volume);
|
||||
SDL_BindAudioStream(sdlAudioDevice, c.stream);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
void destroy(int snd)
|
||||
{
|
||||
for (int i = 0; i < channel::channels.size(); i++) {
|
||||
if (channel::channels[i].sound == snd) channel::stop(i);
|
||||
}
|
||||
|
||||
if (snd<0 || snd>sounds.size()) {
|
||||
log_msg(LOG_FAIL, "sound::destroy: Illegal sound handle: %i\n", snd);
|
||||
return;
|
||||
}
|
||||
auto &s = sounds[snd];
|
||||
SDL_free(s.buffer);
|
||||
}
|
||||
|
||||
float setVolume(float vol)
|
||||
{
|
||||
volume = SDL_clamp( vol, 0.0f, 1.0f );
|
||||
|
||||
for (int i = 0; i < channel::channels.size(); i++) {
|
||||
auto &c = channel::channels[i];
|
||||
if ( (c.state == channel::state::playing) || (c.state == channel::state::paused) )
|
||||
SDL_SetAudioStreamGain(c.stream, volume);
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
void enable(bool value)
|
||||
{
|
||||
if (!value && sound::enabled) {
|
||||
for (int i = 0; i < channel::channels.size(); i++) {
|
||||
if (channel::channels[i].state == channel::state::playing) channel::stop(i);
|
||||
}
|
||||
}
|
||||
enabled = value;
|
||||
}
|
||||
|
||||
bool isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
namespace channel
|
||||
{
|
||||
void pause(const int chan)
|
||||
{
|
||||
if (!sound::enabled) return;
|
||||
|
||||
if (chan == -1)
|
||||
{
|
||||
for (int i = 0; i < channels.size(); i++)
|
||||
if (channels[i].state == state::playing)
|
||||
{
|
||||
channels[i].state = state::paused;
|
||||
//SDL_PauseAudioStreamDevice(channels[i].stream);
|
||||
SDL_UnbindAudioStream(channels[i].stream);
|
||||
}
|
||||
}
|
||||
else if (chan >= 0 && chan < channels.size())
|
||||
{
|
||||
if (channels[chan].state == state::playing)
|
||||
{
|
||||
channels[chan].state = state::paused;
|
||||
//SDL_PauseAudioStreamDevice(channels[channel].stream);
|
||||
SDL_UnbindAudioStream(channels[chan].stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resume(int chan)
|
||||
{
|
||||
if (!sound::enabled) return;
|
||||
|
||||
if (chan == -1)
|
||||
{
|
||||
for (int i = 0; i < channels.size(); i++)
|
||||
if (channels[i].state == state::paused)
|
||||
{
|
||||
channels[i].state = state::playing;
|
||||
//SDL_ResumeAudioStreamDevice(channels[i].stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
|
||||
}
|
||||
}
|
||||
else if (chan >= 0 && chan < channels.size())
|
||||
{
|
||||
if (channels[chan].state == state::paused)
|
||||
{
|
||||
channels[chan].state = state::playing;
|
||||
//SDL_ResumeAudioStreamDevice(channels[channel].stream);
|
||||
SDL_BindAudioStream(sdlAudioDevice, channels[chan].stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop(int chan)
|
||||
{
|
||||
if (!sound::enabled) return;
|
||||
|
||||
if (chan == -1)
|
||||
{
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
if (channels[i].state != state::free) SDL_DestroyAudioStream(channels[i].stream);
|
||||
channels[i].stream = nullptr;
|
||||
channels[i].state = state::free;
|
||||
channels[i].pos = 0;
|
||||
channels[i].sound = -1;
|
||||
}
|
||||
}
|
||||
else if (chan >= 0 && chan < channels.size())
|
||||
{
|
||||
if (channels[chan].state != state::free) SDL_DestroyAudioStream(channels[chan].stream);
|
||||
channels[chan].stream = nullptr;
|
||||
channels[chan].state = state::free;
|
||||
channels[chan].pos = 0;
|
||||
channels[chan].sound = -1;
|
||||
}
|
||||
}
|
||||
|
||||
channel::state getState(int chan)
|
||||
{
|
||||
if (!sound::enabled) return state::disabled;
|
||||
if (chan < 0 || chan >= channels.size()) return state::invalid;
|
||||
return channels[chan].state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
57
source/mini/audio/jail_audio.h
Normal file
57
source/mini/audio/jail_audio.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace jail
|
||||
{
|
||||
namespace audio
|
||||
{
|
||||
void init(/*const int freq, const SDL_AudioFormat format, const int channels*/);
|
||||
void quit();
|
||||
|
||||
namespace music
|
||||
{
|
||||
//struct JA_Music_t;
|
||||
enum state { invalid, playing, paused, stopped, disabled };
|
||||
|
||||
int load(const char* filename);
|
||||
int load(const uint8_t* buffer, uint32_t length);
|
||||
void play(int mus, int loop = -1);
|
||||
void pause();
|
||||
void resume();
|
||||
void stop();
|
||||
void fadeOut(int milliseconds);
|
||||
state getState();
|
||||
void destroy(int mus);
|
||||
float setVolume(float vol);
|
||||
void setPosition(float value);
|
||||
float getPosition();
|
||||
void enable(bool value);
|
||||
bool isEnabled();
|
||||
}
|
||||
|
||||
namespace sound
|
||||
{
|
||||
//struct JA_Sound_t;
|
||||
int create(uint8_t* buffer, uint32_t length);
|
||||
int load(uint8_t* buffer, uint32_t length);
|
||||
int load(const char* filename);
|
||||
int play(int snd, int loop = 0);
|
||||
int playOnChannel(int snd, int chan, int loop = 0);
|
||||
void destroy(int snd);
|
||||
float setVolume(float vol);
|
||||
void enable(bool value);
|
||||
bool isEnabled();
|
||||
|
||||
namespace channel
|
||||
{
|
||||
enum state { invalid, free, playing, paused, disabled };
|
||||
void pause(int chan);
|
||||
void resume(int chan);
|
||||
void stop(int chan);
|
||||
state getState(int chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
source/mini/config/config.cpp
Normal file
21
source/mini/config/config.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "config.h"
|
||||
#include "mini/file/file.h"
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace config
|
||||
{
|
||||
namespace key {
|
||||
void set(const char* key, const char* value) {
|
||||
file::setconfigvalue(key, value);
|
||||
}
|
||||
const char* get(const char* key) {
|
||||
return file::getconfigvalue(key);
|
||||
}
|
||||
}
|
||||
|
||||
const char *folder() {
|
||||
return file::getconfigfolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
source/mini/config/config.h
Normal file
15
source/mini/config/config.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace config
|
||||
{
|
||||
namespace key {
|
||||
void set(const char* key, const char* value);
|
||||
const char *get(const char* key);
|
||||
}
|
||||
|
||||
const char *folder();
|
||||
}
|
||||
}
|
||||
488
source/mini/draw/draw.cpp
Normal file
488
source/mini/draw/draw.cpp
Normal file
@@ -0,0 +1,488 @@
|
||||
#include "draw.h"
|
||||
#include "mini/surf/surf.h"
|
||||
#include "mini/view/view.h"
|
||||
#include "mini/font/font.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace draw
|
||||
{
|
||||
state_t state;
|
||||
|
||||
void init() {
|
||||
state.mode = DRAWMODE_NORMAL;
|
||||
state.fill_pattern = 0b1111111111111111;
|
||||
}
|
||||
|
||||
void quit() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace pixel {
|
||||
static inline void pset_fast(int x, int y, uint8_t color) {
|
||||
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||
uint8_t *p = s.p;
|
||||
if (state.trans != color) p[x+y*s.w] = color;
|
||||
}
|
||||
|
||||
static inline void pset_bool(int x, int y, uint8_t color) {
|
||||
if (state.trans != color) {
|
||||
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||
uint8_t *p = s.p;
|
||||
switch (state.mode) {
|
||||
case DRAWMODE_AND:
|
||||
p[x+y*s.w] &= color;
|
||||
break;
|
||||
case DRAWMODE_OR:
|
||||
p[x+y*s.w] |= color;
|
||||
break;
|
||||
case DRAWMODE_XOR:
|
||||
p[x+y*s.w] ^= color;
|
||||
break;
|
||||
case DRAWMODE_NOT:
|
||||
p[x+y*s.w] = ~p[x+y*s.w];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pset_pattern(int x, int y, uint8_t color) {
|
||||
int pbx = x % 4, pby = y % 4;
|
||||
int pb = pbx+pby*4;
|
||||
if (state.fill_pattern & (1 << pb))
|
||||
if (state.trans != color) {
|
||||
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||
uint8_t *p = s.p;
|
||||
p[x+y*s.w] = color;
|
||||
}
|
||||
}
|
||||
|
||||
// Per a les funcions que pinten tot del mateix color
|
||||
static inline void direct_pset(int x, int y, uint8_t color) {
|
||||
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||
x += view::state.origin[0]; y += view::state.origin[1];
|
||||
if (x < s.clip[0] || x > s.clip[2] || y < s.clip[1] || y > s.clip[3]) return;
|
||||
switch (state.mode) {
|
||||
case DRAWMODE_NORMAL: pset_fast(x,y,color); break;
|
||||
case DRAWMODE_PATTERN: pset_pattern(x,y,color); break;
|
||||
default: pset_bool(x,y,color); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Per a les funcions que van canviant de color (surf.pixel i draw.surf, bàsicament)
|
||||
static inline void subst_pset(int x, int y, uint8_t color) {
|
||||
direct_pset(x, y, state.draw_palette[color]);
|
||||
}
|
||||
|
||||
void set(int x, int y, uint8_t color) {
|
||||
subst_pset(x,y,color);
|
||||
}
|
||||
|
||||
uint8_t get(int x, int y) {
|
||||
if (surf::state.source_surface==-1) return 0;
|
||||
auto &s = surf::state.surfaces[surf::state.source_surface];
|
||||
if (x < 0 || x > (s.w-1) || y < 0 || y > (s.h-1)) return 0;
|
||||
return s.p[x+y*s.w];
|
||||
}
|
||||
}
|
||||
|
||||
// Bresenham Line Algorithm
|
||||
void line(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||
int x, y;
|
||||
int dx, dy;
|
||||
int incx, incy;
|
||||
int balance;
|
||||
color = state.draw_palette[color];
|
||||
|
||||
if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; }
|
||||
if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; }
|
||||
|
||||
x = x0; y = y0;
|
||||
|
||||
if (dx >= dy) {
|
||||
dy <<= 1;
|
||||
balance = dy - dx;
|
||||
dx <<= 1;
|
||||
|
||||
while (x != x1) {
|
||||
pixel::direct_pset(x, y, color);
|
||||
if (balance >= 0) { y += incy; balance -= dx; }
|
||||
balance += dy;
|
||||
x += incx;
|
||||
}
|
||||
pixel::direct_pset(x, y, color);
|
||||
} else {
|
||||
dx <<= 1;
|
||||
balance = dx - dy;
|
||||
dy <<= 1;
|
||||
|
||||
while (y != y1) {
|
||||
pixel::direct_pset(x, y, color);
|
||||
if (balance >= 0) { x += incx; balance -= dy; }
|
||||
balance += dx;
|
||||
y += incy;
|
||||
}
|
||||
pixel::direct_pset(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
void hline(int x0, int y, int x1, uint8_t color) {
|
||||
color = state.draw_palette[color];
|
||||
if (x0>x1) { const int tmp=x0;x0=x1;x1=tmp; }
|
||||
for (int x=x0; x<=x1; ++x) pixel::direct_pset(x, y, color);
|
||||
}
|
||||
|
||||
void vline(int x, int y0, int y1, uint8_t color) {
|
||||
color = state.draw_palette[color];
|
||||
if (y0>y1) { const int tmp=y0;y0=y1;y1=tmp; }
|
||||
for (int y=y0; y<=y1; ++y) pixel::direct_pset(x, y, color);
|
||||
}
|
||||
|
||||
void rect(int x, int y, int w, int h, uint8_t color) {
|
||||
int x1 = w+x-1;
|
||||
int y1 = h+y-1;
|
||||
hline(x, y, x1, color);
|
||||
hline(x, y1, x1, color);
|
||||
vline(x, y, y1, color);
|
||||
vline(x1, y, y1, color);
|
||||
}
|
||||
|
||||
void rectf(int x, int y, int w, int h, uint8_t color) {
|
||||
int x1 = w+x-1;
|
||||
int y1 = h+y-1;
|
||||
for (int i=y; i<=y1; ++i) hline(x, i, x1, color);
|
||||
}
|
||||
|
||||
static inline void circ_scanline(int xc, int yc, int x, int y, uint8_t color) {
|
||||
pixel::direct_pset(xc+x, yc+y, color);
|
||||
pixel::direct_pset(xc-x, yc+y, color);
|
||||
pixel::direct_pset(xc+x, yc-y, color);
|
||||
pixel::direct_pset(xc-x, yc-y, color);
|
||||
pixel::direct_pset(xc+y, yc+x, color);
|
||||
pixel::direct_pset(xc-y, yc+x, color);
|
||||
pixel::direct_pset(xc+y, yc-x, color);
|
||||
pixel::direct_pset(xc-y, yc-x, color);
|
||||
}
|
||||
|
||||
void circ(int x, int y, uint8_t r, uint8_t color) {
|
||||
color = state.draw_palette[color];
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
circ_scanline(x, y, xi, yi, color);
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
circ_scanline(x, y, xi, yi, color);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void circf_scanline(int xc, int yc, int x, int y, uint8_t color) {
|
||||
hline(xc-x, yc+y, xc+x, color);
|
||||
hline(xc-x, yc-y, xc+x, color);
|
||||
hline(xc-y, yc+x, xc+y, color);
|
||||
hline(xc-y, yc-x, xc+y, color);
|
||||
}
|
||||
|
||||
void circf(int x, int y, uint8_t r, uint8_t color) {
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
circf_scanline(x, y, xi, yi, color);
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
circf_scanline(x, y, xi, yi, color);
|
||||
}
|
||||
}
|
||||
|
||||
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) {
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
|
||||
int xf = w+x-1;
|
||||
int yf = h+y-1;
|
||||
int x1 = x+r, y1 = y+r;
|
||||
int x2 = xf-r, y2 = yf-r;
|
||||
hline(x1, y, x2, color);
|
||||
hline(x1, yf, x2, color);
|
||||
vline(x, y1, y2, color);
|
||||
vline(xf, y1, y2, color);
|
||||
|
||||
color = state.draw_palette[color];
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
pixel::direct_pset(x2+xi, y2+yi, color);
|
||||
pixel::direct_pset(x1-xi, y2+yi, color);
|
||||
pixel::direct_pset(x2+xi, y1-yi, color);
|
||||
pixel::direct_pset(x1-xi, y1-yi, color);
|
||||
pixel::direct_pset(x2+yi, y2+xi, color);
|
||||
pixel::direct_pset(x1-yi, y2+xi, color);
|
||||
pixel::direct_pset(x2+yi, y1-xi, color);
|
||||
pixel::direct_pset(x1-yi, y1-xi, color);
|
||||
}
|
||||
}
|
||||
|
||||
void roundrectf(int x, int y, int w, int h, uint8_t r, uint8_t color) {
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
|
||||
int xf = w+x-1;
|
||||
int yf = h+y-1;
|
||||
int x1 = x+r, y1 = y+r;
|
||||
int x2 = xf-r, y2 = yf-r;
|
||||
for (int i=y1; i<=y2; ++i) hline(x, i, xf, color);
|
||||
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
hline(x1-xi, y2+yi, x2+xi, color);
|
||||
hline(x1-xi, y1-yi, x2+xi, color);
|
||||
hline(x1-yi, y2+xi, x2+yi, color);
|
||||
hline(x1-yi, y1-xi, x2+yi, color);
|
||||
}
|
||||
}
|
||||
|
||||
void oval_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) {
|
||||
pixel::direct_pset((xc+x)*xf, (yc+y)*yf, color);
|
||||
pixel::direct_pset((xc-x)*xf, (yc+y)*yf, color);
|
||||
pixel::direct_pset((xc+x)*xf, (yc-y)*yf, color);
|
||||
pixel::direct_pset((xc-x)*xf, (yc-y)*yf, color);
|
||||
pixel::direct_pset((xc+y)*xf, (yc+x)*yf, color);
|
||||
pixel::direct_pset((xc-y)*xf, (yc+x)*yf, color);
|
||||
pixel::direct_pset((xc+y)*xf, (yc-x)*yf, color);
|
||||
pixel::direct_pset((xc-y)*xf, (yc-x)*yf, color);
|
||||
}
|
||||
|
||||
void oval(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||
color = state.draw_palette[color];
|
||||
int rx = (x1-x0)/2;
|
||||
int ry = (y1-y0)/2;
|
||||
int r = rx;
|
||||
int x = x0 + rx;
|
||||
int y = y0 + ry;
|
||||
float xf = 1.0f, yf = 1.0f;
|
||||
if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);}
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
oval_scanline(x, y, xi, yi, xf, yf, color);
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
oval_scanline(x, y, xi, yi, xf, yf, color);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ovalf_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) {
|
||||
hline((xc-x)*xf, (yc+y)*yf, (xc+x)*xf, color);
|
||||
hline((xc-x)*xf, (yc-y)*yf, (xc+x)*xf, color);
|
||||
hline((xc-y)*xf, (yc+x)*yf, (xc+y)*xf, color);
|
||||
hline((xc-y)*xf, (yc-x)*yf, (xc+y)*xf, color);
|
||||
}
|
||||
|
||||
void ovalf(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||
int rx = (x1-x0)/2;
|
||||
int ry = (y1-y0)/2;
|
||||
int r = rx;
|
||||
int x = x0 + rx;
|
||||
int y = y0 + ry;
|
||||
float xf = 1.0f, yf = 1.0f;
|
||||
if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);}
|
||||
int xi=0, yi=r;
|
||||
int d=3-2*r;
|
||||
ovalf_scanline(x, y, xi, yi, xf, yf, color);
|
||||
while (yi>=xi++) {
|
||||
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||
ovalf_scanline(x, y, xi, yi, xf, yf, color);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pattern {
|
||||
void set(uint16_t pat, bool transparent) {
|
||||
state.fill_pattern = pat;
|
||||
}
|
||||
}
|
||||
|
||||
void surf(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, bool invert) {
|
||||
if (dw == 0) dw = sw;
|
||||
if (dh == 0) dh = sh;
|
||||
|
||||
// 16.16 fixed point
|
||||
int sdx = (sw << 16) / dw;
|
||||
int sdy = (sh << 16) / dh;
|
||||
|
||||
if (flip_x) sdx = -sdx;
|
||||
if (flip_y) sdy = -sdy;
|
||||
|
||||
int ssx = flip_x ? ((sx + sw - 1) << 16) : (sx << 16);
|
||||
int ssy = flip_y ? ((sy + sh - 1) << 16) : (sy << 16);
|
||||
|
||||
int csy = ssy;
|
||||
|
||||
if (!invert) {
|
||||
for (int y = dy; y < dy + dh; ++y) {
|
||||
int csx = ssx;
|
||||
for (int x = dx; x < dx + dw; ++x) {
|
||||
uint8_t color = pixel::get(csx >> 16, csy >> 16);
|
||||
pixel::subst_pset(x, y, color);
|
||||
csx += sdx;
|
||||
}
|
||||
csy += sdy;
|
||||
}
|
||||
} else {
|
||||
for (int y = dy; y < dy + dh; ++y) {
|
||||
int csx = ssx;
|
||||
for (int x = dx; x < dx + dw; ++x) {
|
||||
uint8_t color = pixel::get(csy >> 16, csx >> 16);
|
||||
pixel::subst_pset(x, y, color);
|
||||
csx += sdx;
|
||||
}
|
||||
csy += sdy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void surfrot(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg) {
|
||||
if (dw == 0) dw = sw;
|
||||
if (dh == 0) dh = sh;
|
||||
|
||||
// Centro del destino (rectángulo sin rotar)
|
||||
float dcx = dx + dw * 0.5f;
|
||||
float dcy = dy + dh * 0.5f;
|
||||
|
||||
// Centro del subrectángulo origen
|
||||
float scx = sx + sw * 0.5f;
|
||||
float scy = sy + sh * 0.5f;
|
||||
|
||||
// Escalado destino -> origen
|
||||
float inv_scale_x = float(sw) / float(dw);
|
||||
float inv_scale_y = float(sh) / float(dh);
|
||||
|
||||
// Flips integrados en la escala
|
||||
if (flip_x) inv_scale_x = -inv_scale_x;
|
||||
if (flip_y) inv_scale_y = -inv_scale_y;
|
||||
|
||||
// Ángulo en radianes
|
||||
float a = angle_deg * 3.14159265f / 180.0f;
|
||||
float ca = cosf(a);
|
||||
float sa = sinf(a);
|
||||
|
||||
// --- 1. Bounding box rotado del rectángulo destino ---
|
||||
|
||||
float hx = dw * 0.5f;
|
||||
float hy = dh * 0.5f;
|
||||
|
||||
float vx[4] = { -hx, hx, -hx, hx };
|
||||
float vy[4] = { -hy, -hy, hy, hy };
|
||||
|
||||
float min_x = 1e9f, max_x = -1e9f;
|
||||
float min_y = 1e9f, max_y = -1e9f;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float rr_x = vx[i] * ca - vy[i] * sa;
|
||||
float rr_y = vx[i] * sa + vy[i] * ca;
|
||||
|
||||
float dxp = dcx + rr_x;
|
||||
float dyp = dcy + rr_y;
|
||||
|
||||
if (dxp < min_x) min_x = dxp;
|
||||
if (dxp > max_x) max_x = dxp;
|
||||
if (dyp < min_y) min_y = dyp;
|
||||
if (dyp > max_y) max_y = dyp;
|
||||
}
|
||||
|
||||
int bb_x0 = (int)floorf(min_x);
|
||||
int bb_x1 = (int)ceilf (max_x);
|
||||
int bb_y0 = (int)floorf(min_y);
|
||||
int bb_y1 = (int)ceilf (max_y);
|
||||
|
||||
// --- 2. Rotación inversa + escalado + clipping estricto ---
|
||||
|
||||
for (int y = bb_y0; y <= bb_y1; ++y) {
|
||||
for (int x = bb_x0; x <= bb_x1; ++x) {
|
||||
|
||||
// Coordenadas relativas al centro destino
|
||||
float rx = x - dcx;
|
||||
float ry = y - dcy;
|
||||
|
||||
// Rotación inversa
|
||||
float ux = rx * ca + ry * sa;
|
||||
float uy = -rx * sa + ry * ca;
|
||||
|
||||
// Escalado destino -> origen (con flips)
|
||||
float sxp = scx + ux * inv_scale_x;
|
||||
float syp = scy + uy * inv_scale_y;
|
||||
|
||||
// Clipping estricto al subrectángulo origen
|
||||
if (sxp < sx || sxp >= sx + sw ||
|
||||
syp < sy || syp >= sy + sh)
|
||||
continue; // no pintamos nada
|
||||
|
||||
uint8_t color = pixel::get((int)sxp, (int)syp);
|
||||
pixel::subst_pset(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tileblit(uint8_t n, int x, int y, int tw, int th) {
|
||||
//const int tw = tile_width;
|
||||
//const int th = tile_height;
|
||||
|
||||
const int tiles_per_row = mini::surf::state.surfaces[mini::surf::state.source_surface].w / tw;
|
||||
|
||||
// Coordenadas del tile dentro del spritesheet
|
||||
int tx = (n % tiles_per_row) * tw;
|
||||
int ty = (n / tiles_per_row) * th;
|
||||
|
||||
int src_y = ty;
|
||||
|
||||
for (int yi = 0; yi < th; ++yi) {
|
||||
int src_x = tx;
|
||||
|
||||
for (int xi = 0; xi < tw; ++xi) {
|
||||
uint8_t c = mini::draw::pixel::get(src_x, src_y);
|
||||
mini::draw::pixel::subst_pset(x + xi, y + yi, c);
|
||||
src_x++;
|
||||
}
|
||||
|
||||
src_y++;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t printchar(uint8_t c, int x, int y) {
|
||||
font::char_t &chr = font::current_font->chars[c];
|
||||
draw::surf(chr.x, chr.y, chr.w, chr.h, x, y-chr.base);
|
||||
return chr.w;
|
||||
}
|
||||
|
||||
void text(const char* str, int x, int y, uint8_t color) {
|
||||
|
||||
const unsigned char* p = (const unsigned char*)str;
|
||||
uint8_t cp;
|
||||
uint8_t xpos = x;
|
||||
|
||||
uint8_t old_source = surf::source::get();
|
||||
surf::source::set(font::current_font->surface);
|
||||
uint8_t old_color = state.draw_palette[1];
|
||||
state.draw_palette[1] = color;
|
||||
uint8_t old_trans = state.trans;
|
||||
state.trans = 0;
|
||||
while (p[0]!=0) {
|
||||
if (p[0] < 0x80) {
|
||||
cp = p[0];
|
||||
p+=1;
|
||||
} else if ((p[0] & 0xE0) == 0xC0) {
|
||||
cp = (p[0] << 6) | (p[1] & 0x3F);
|
||||
p+=2;
|
||||
}
|
||||
xpos += printchar(cp, xpos, y) + font::current_font->spacing;
|
||||
}
|
||||
state.trans = old_trans;
|
||||
state.draw_palette[1] = old_color;
|
||||
surf::source::set(old_source);
|
||||
}
|
||||
|
||||
namespace mode {
|
||||
void set(uint8_t mode) {
|
||||
state.mode = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
source/mini/draw/draw.h
Normal file
62
source/mini/draw/draw.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DRAWMODE_NORMAL 0
|
||||
#define DRAWMODE_PATTERN 1
|
||||
#define DRAWMODE_AND 2
|
||||
#define DRAWMODE_OR 3
|
||||
#define DRAWMODE_XOR 4
|
||||
#define DRAWMODE_NOT 5
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace draw
|
||||
{
|
||||
struct state_t {
|
||||
uint8_t trans = 0;
|
||||
uint16_t fill_pattern = 0b1111111111111111;
|
||||
uint8_t draw_palette[256];
|
||||
uint8_t mode = DRAWMODE_NORMAL;
|
||||
};
|
||||
extern state_t state;
|
||||
|
||||
void init();
|
||||
void quit();
|
||||
|
||||
namespace pixel {
|
||||
void set(int x, int y, uint8_t color);
|
||||
uint8_t get(int x, int y);
|
||||
}
|
||||
|
||||
void line(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
void hline(int x0, int y, int x1, uint8_t color);
|
||||
void vline(int x, int y0, int y1, uint8_t color);
|
||||
|
||||
void rect(int x, int y, int w, int h, uint8_t color);
|
||||
void rectf(int x, int y, int w, int h, uint8_t color);
|
||||
|
||||
void circ(int x, int y, uint8_t r, uint8_t color);
|
||||
void circf(int x, int y, uint8_t r, uint8_t color);
|
||||
|
||||
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color);
|
||||
void roundrectf(int x, int y, int w, int h, uint8_t r, uint8_t color);
|
||||
void oval(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
void ovalf(int x0, int y0, int x1, int y1, uint8_t color);
|
||||
|
||||
namespace pattern {
|
||||
void set(uint16_t pat, bool transparent = false);
|
||||
}
|
||||
|
||||
void surf(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 surfrot(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg);
|
||||
void tileblit(uint8_t n, int x, int y, int tw, int th);
|
||||
|
||||
void text(const char *str, int x, int y, uint8_t color);
|
||||
|
||||
namespace mode
|
||||
{
|
||||
void set(uint8_t mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
390
source/mini/file/file.cpp
Normal file
390
source/mini/file/file.cpp
Normal file
@@ -0,0 +1,390 @@
|
||||
#include "file.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_FILENAME "data.jf2"
|
||||
#define DEFAULT_FOLDER "data/"
|
||||
#define CONFIG_FILENAME "config.txt"
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace file
|
||||
{
|
||||
struct file_t
|
||||
{
|
||||
std::string path;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
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 {
|
||||
std::string key, value;
|
||||
};
|
||||
|
||||
char *resource_filename = NULL;
|
||||
char *resource_folder = NULL;
|
||||
int file_source = SOURCE_FILE;
|
||||
char scratch[255];
|
||||
static std::string config_folder;
|
||||
std::vector<keyvalue_t> config;
|
||||
|
||||
void setresourcefilename(const char *str) {
|
||||
if (resource_filename != NULL) free(resource_filename);
|
||||
resource_filename = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_filename, str);
|
||||
}
|
||||
|
||||
void setresourcefolder(const char *str) {
|
||||
if (resource_folder != NULL) free(resource_folder);
|
||||
resource_folder = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_folder, str);
|
||||
}
|
||||
|
||||
void setsource(const int src) {
|
||||
file_source = src%2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder)
|
||||
if (src==SOURCE_FOLDER && resource_folder==NULL) setresourcefolder(DEFAULT_FOLDER);
|
||||
}
|
||||
|
||||
bool getdictionary() {
|
||||
if (resource_filename == NULL) setresourcefilename(DEFAULT_FILENAME);
|
||||
|
||||
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 = (char*)malloc(path_size+1);
|
||||
fi.read( file_name, path_size );
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
free(file_name);
|
||||
toc.push_back({filename, file_size, file_offset});
|
||||
}
|
||||
fi.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
char *getfilenamewithfolder(const char* filename) {
|
||||
strcpy(scratch, resource_folder);
|
||||
strcat(scratch, filename);
|
||||
return scratch;
|
||||
}
|
||||
|
||||
FILE *getfilepointer(const char *resourcename, int& filesize, const bool binary) {
|
||||
|
||||
if (file_source==SOURCE_FILE and toc.size()==0) {
|
||||
if (not getdictionary()) setsource(SOURCE_FOLDER);
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
if (file_source==SOURCE_FILE) {
|
||||
bool found = false;
|
||||
uint32_t count = 0;
|
||||
while( !found && count < toc.size() ) {
|
||||
found = ( std::string(resourcename) == toc[count].path );
|
||||
if( !found ) count++;
|
||||
}
|
||||
|
||||
if( !found ) {
|
||||
perror("El recurs no s'ha trobat en l'arxiu de recursos");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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, toc[count].offset, SEEK_SET);
|
||||
} else {
|
||||
f = fopen(getfilenamewithfolder(resourcename), binary?"rb":"r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
char *getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
|
||||
FILE *f = getfilepointer(resourcename, 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;
|
||||
}
|
||||
|
||||
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 *getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
|
||||
FILE *f = getfilepointerex(filename, filesize, true);
|
||||
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
|
||||
fread(buffer, filesize, 1, f);
|
||||
if (zero_terminate) buffer[filesize]=0;
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void setconfigfolder(const char *foldername)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
|
||||
#elif __APPLE__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/Library/Application Support/" + foldername;
|
||||
#elif __linux__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/." + foldername;
|
||||
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
|
||||
|
||||
{
|
||||
// Intenta crear ".config", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Intenta crear ".config/jailgames", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(config_folder.c_str(), &st) == -1)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(config_folder.c_str());
|
||||
#else
|
||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *getconfigfolder() {
|
||||
static std::string folder = config_folder + "/";
|
||||
return folder.c_str();
|
||||
}
|
||||
|
||||
void loadconfigvalues() {
|
||||
config.clear();
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "r");
|
||||
if (!f) return;
|
||||
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *value = strchr(line, '=');
|
||||
if (value) {
|
||||
*value='\0'; value++;
|
||||
value[strlen(value)-1] = '\0';
|
||||
config.push_back({line, value});
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void saveconfigvalues() {
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "w");
|
||||
if (f) {
|
||||
for (auto pair : config) {
|
||||
fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
const char* getconfigvalue(const char *key) {
|
||||
if (config.empty()) loadconfigvalues();
|
||||
for (auto pair : config) {
|
||||
if (pair.key == std::string(key)) {
|
||||
strcpy(scratch, pair.value.c_str());
|
||||
return scratch;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void setconfigvalue(const char* key, const char* value) {
|
||||
if (config.empty()) loadconfigvalues();
|
||||
for (auto &pair : config) {
|
||||
if (pair.key == std::string(key)) {
|
||||
pair.value = value;
|
||||
saveconfigvalues();
|
||||
return;
|
||||
}
|
||||
}
|
||||
config.push_back({key, value});
|
||||
saveconfigvalues();
|
||||
return;
|
||||
}
|
||||
|
||||
bool createFolder(const char* name) {
|
||||
char tmp[256];
|
||||
strcpy(tmp, "./");
|
||||
strcat(tmp, name);
|
||||
#ifdef _WIN32
|
||||
return mkdir(tmp)==0;
|
||||
#else
|
||||
return mkdir(tmp, 0755)==0;
|
||||
#endif
|
||||
}
|
||||
|
||||
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> listresourcesdir(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
source/mini/file/file.h
Normal file
32
source/mini/file/file.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define SOURCE_FILE 0
|
||||
#define SOURCE_FOLDER 1
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace file
|
||||
{
|
||||
void setconfigfolder(const char *foldername);
|
||||
const char *getconfigfolder();
|
||||
|
||||
void setresourcefilename(const char *str);
|
||||
void setresourcefolder(const char *str);
|
||||
void setsource(const int src);
|
||||
|
||||
FILE *getfilepointer(const char *resourcename, int& filesize, const bool binary=false);
|
||||
char *getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate=false);
|
||||
|
||||
FILE *getfilepointerex(const char *filename, int& filesize, const bool binary=false);
|
||||
char *getfilebufferex(const char *filename, int& filesize, const bool zero_terminate=false);
|
||||
|
||||
const char* getconfigvalue(const char *key);
|
||||
void setconfigvalue(const char* key, const char* value);
|
||||
|
||||
bool createFolder(const char* name);
|
||||
std::vector<std::string> listresourcesdir(const char *folder, const char *extension=NULL);
|
||||
}
|
||||
}
|
||||
139
source/mini/font/font.cpp
Normal file
139
source/mini/font/font.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "font.h"
|
||||
#include "default_font_gif.h"
|
||||
#include "default_font_fnt.h"
|
||||
|
||||
#include "mini/surf/surf.h"
|
||||
#include "mini/file/file.h"
|
||||
#include "other/log.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_FONTS 5
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace font
|
||||
{
|
||||
font_t fonts[MAX_FONTS];
|
||||
font_t *current_font;
|
||||
|
||||
uint8_t load_from_buffer(const char* buffer, uint8_t index, const char* name) {
|
||||
if (!buffer) return false;
|
||||
|
||||
const char* ptr = buffer;
|
||||
char line[256];
|
||||
|
||||
// --- Read first line ---
|
||||
{
|
||||
// Extract line
|
||||
int len = 0;
|
||||
while (ptr[len] && ptr[len] != '\n' && len < 255) len++;
|
||||
|
||||
memcpy(line, ptr, len);
|
||||
line[len] = '\0';
|
||||
ptr += (ptr[len] == '\n') ? len + 1 : len; // Advance pointer
|
||||
if (len > 0 && line[len - 1] == '\r') line[len - 1] = '\0';
|
||||
|
||||
if (strncmp(line, "bitmap=", 7) != 0) return false; // Parse first line
|
||||
|
||||
fonts[index].surface = surf::load(line + 7);
|
||||
|
||||
fonts[index].name = (char*)malloc(strlen(name)+1);
|
||||
strcpy(fonts[index].name, name);
|
||||
}
|
||||
|
||||
// --- Read character lines ---
|
||||
while (*ptr) {
|
||||
// Extract next line
|
||||
int len = 0;
|
||||
while (ptr[len] && ptr[len] != '\n' && len < 255) len++;
|
||||
|
||||
memcpy(line, ptr, len);
|
||||
line[len] = '\0';
|
||||
ptr += (ptr[len] == '\n') ? len + 1 : len; // Advance pointer
|
||||
if (len > 0 && line[len - 1] == '\r') line[len - 1] = '\0';
|
||||
|
||||
// Remove comments
|
||||
char* hash = strchr(line, '#');
|
||||
if (hash) *hash = '\0';
|
||||
|
||||
// Parse
|
||||
int code, x, y, w, h, base;
|
||||
if (sscanf(line, "%d: %d %d %d %d %d", &code, &x, &y, &w, &h, &base) == 6) {
|
||||
if (code >= 0 && code < 256) {
|
||||
fonts[index].chars[code] = { (uint8_t)x, (uint8_t)y, (uint8_t)w, (uint8_t)h, (uint8_t)base };
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t load(const char *filename) {
|
||||
// Si la font ja s'ha carregat, tornem eixa font
|
||||
for (unsigned int i=0; i<MAX_FONTS; ++i)
|
||||
if (fonts[i].name && strcmp(fonts[i].name, filename)==0) {
|
||||
log_msg(LOG_INFO, "Carrega de '%s' abortada: Reusant: %i.\n", filename, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
// Agafar la pròxima font lliure
|
||||
unsigned int i = 0;
|
||||
while (i<MAX_FONTS && fonts[i].name != NULL) ++i;
|
||||
if (i==MAX_FONTS) return 255;
|
||||
|
||||
// Carregar l'arxiu de disc
|
||||
int size;
|
||||
char *buffer;
|
||||
buffer = file::getfilebuffer(filename, size);
|
||||
|
||||
// Si no s'ha pogut, petar
|
||||
if (!buffer) {
|
||||
log_msg(LOG_FAIL, "Error al intentar obrir l'arxiu '%s'\n", filename);
|
||||
exit(-1);
|
||||
return 255;
|
||||
}
|
||||
|
||||
load_from_buffer(buffer, i, filename);
|
||||
free(buffer);
|
||||
|
||||
log_msg(LOG_INFO, "Arxiu '%s' carregat en font: %i.\n", filename, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
void init() {
|
||||
//uint8_t font_surf =
|
||||
surf::load(default_font_gif, "default_font");
|
||||
//surfaces[font_surf].flags |= SURF_GENERATED;
|
||||
font::load_from_buffer((const char*)default_font_fnt, 0, "default_font");
|
||||
current_font = &fonts[0];
|
||||
}
|
||||
|
||||
void quit() {
|
||||
for (int i=0;i<MAX_FONTS;++i) {
|
||||
if (fonts[i].name != NULL) free(fonts[i].name);
|
||||
fonts[i].name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
namespace current {
|
||||
void set(uint8_t font) {
|
||||
current_font = &fonts[font];
|
||||
}
|
||||
uint8_t get() {
|
||||
for (unsigned int i=0; i<MAX_FONTS; ++i) if (current_font == &fonts[i]) return i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace spacing {
|
||||
void set(uint8_t spacing) {
|
||||
current_font->spacing = spacing;
|
||||
}
|
||||
uint8_t get() {
|
||||
return current_font->spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
source/mini/font/font.h
Normal file
36
source/mini/font/font.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace font
|
||||
{
|
||||
struct char_t {
|
||||
uint8_t x,y,w,h,base;
|
||||
};
|
||||
|
||||
struct font_t {
|
||||
char *name {nullptr};
|
||||
uint8_t surface {0};
|
||||
uint8_t spacing {1};
|
||||
char_t chars[256];
|
||||
};
|
||||
extern font_t *current_font;
|
||||
|
||||
void init();
|
||||
void quit();
|
||||
|
||||
uint8_t load(const char *filename);
|
||||
|
||||
namespace current {
|
||||
void set(uint8_t font);
|
||||
uint8_t get();
|
||||
}
|
||||
|
||||
namespace spacing {
|
||||
void set(uint8_t spacing);
|
||||
uint8_t get();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
source/mini/key/key.cpp
Normal file
36
source/mini/key/key.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "key.h"
|
||||
#include "mini/pad/pad.h"
|
||||
#include "mini/win/win.h"
|
||||
|
||||
#include "backends/backend.h"
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace key
|
||||
{
|
||||
bool down(uint8_t i) {
|
||||
return backend::input::key::down(i);
|
||||
}
|
||||
|
||||
bool press(uint8_t i) {
|
||||
return backend::input::key::press(i);
|
||||
}
|
||||
|
||||
int press() {
|
||||
return backend::input::key::press();
|
||||
}
|
||||
|
||||
bool any() {
|
||||
return backend::input::key::any();
|
||||
}
|
||||
|
||||
void text(const bool enable) {
|
||||
backend::input::key::text(enable);
|
||||
}
|
||||
|
||||
const char* utf8char() {
|
||||
return backend::input::key::utf8char();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
source/mini/key/key.h
Normal file
15
source/mini/key/key.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mini
|
||||
{
|
||||
namespace key
|
||||
{
|
||||
bool down(uint8_t i);
|
||||
bool press(uint8_t i);
|
||||
int press();
|
||||
bool any();
|
||||
void text(const bool enable);
|
||||
const char *utf8char();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user