- [NEW] Passat a SDL3
- [NEW] Ara usa JailAudio - [NEW] Usant última versió de Respak - [NEW] Afegit lagueirtofile
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ arounders_debug
|
||||
release/*
|
||||
respak2
|
||||
*.dSYM/*
|
||||
build/*
|
||||
|
||||
5
lagueirtofile
Normal file
5
lagueirtofile
Normal file
@@ -0,0 +1,5 @@
|
||||
libs = -lSDL3 -lGL
|
||||
cppflags = -D DEBUG -D VERBOSE -g -Wall
|
||||
executable = arounders
|
||||
sourcepath = source
|
||||
buildpath = build
|
||||
@@ -22,7 +22,7 @@ namespace textfile
|
||||
|
||||
const bool open(std::string filename)
|
||||
{
|
||||
buffer = file::getFileBuffer(filename.c_str(), &fsize);
|
||||
buffer = file_getfilebuffer(filename.c_str(), fsize);
|
||||
p = 0;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -25,9 +25,7 @@ namespace gamestate
|
||||
menu::fondo = draw::loadSurface("menuprin.gif", true);
|
||||
menu::cursor = draw::loadSurface("cursor.gif");
|
||||
|
||||
if (audio::getMusicState() != audio::music_state::MUSIC_PLAYING || audio::whichMusic() != "mus3.ogg") {
|
||||
audio::playMusic(audio::loadMusic("mus3.ogg"));
|
||||
}
|
||||
JA_LoadAndPlayMusic("mus3.ogg");
|
||||
|
||||
font::selectFont(font::type::colored);
|
||||
font::setColor(font::color::white);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace gamestate
|
||||
fondo = draw::loadSurface("mort.gif", true);
|
||||
cursor = draw::loadSurface("cursor.gif");
|
||||
|
||||
audio::playMusic(audio::loadMusic("mus5.ogg"));
|
||||
JA_LoadAndPlayMusic("mus5.ogg");
|
||||
|
||||
draw::fadein();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include "aux_font.h"
|
||||
#include "proc_mapa.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace gamestate
|
||||
{
|
||||
@@ -120,7 +120,7 @@ namespace gamestate
|
||||
{
|
||||
password[10] = 0;
|
||||
int filesize = 0;
|
||||
const char *buffer = file::getFileBuffer("offsets.bal", &filesize);
|
||||
const char *buffer = file_getfilebuffer("offsets.bal", filesize);
|
||||
|
||||
int punter = 0;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "gamestates.h"
|
||||
#include "jgame.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <string>
|
||||
#include "aux_font.h"
|
||||
#include "proc_mapa.h"
|
||||
@@ -72,8 +72,7 @@ namespace gamestate
|
||||
// arounder_seleccionat = primerArounders
|
||||
|
||||
// Enxufa el arradio
|
||||
audio::loadMusic((game::getConfig("fase")+1) % 5 == 0 ? "mus6.ogg" : "mus4.ogg");
|
||||
audio::playMusic();
|
||||
JA_LoadAndPlayMusic((game::getConfig("fase")+1) % 5 == 0 ? "mus6.ogg" : "mus4.ogg");
|
||||
|
||||
// Fiquem a contar el cronómetre de arounders
|
||||
play::arounderCount = play::startTicks = game::getTicks();
|
||||
@@ -225,11 +224,11 @@ namespace gamestate
|
||||
if (mapa::arounders::arrivats >= mapa::arounders::necessaris) {
|
||||
game::setConfig("fase", game::getConfig("fase")+1);
|
||||
draw::fadeout();
|
||||
audio::fadeoutMusic();
|
||||
JA_FadeOutMusic(250);
|
||||
play::exit = 1;
|
||||
} else {
|
||||
draw::fadeout();
|
||||
audio::fadeoutMusic();
|
||||
JA_FadeOutMusic(250);
|
||||
play::exit = 2;
|
||||
}
|
||||
}
|
||||
@@ -287,13 +286,13 @@ namespace gamestate
|
||||
if (input::mouseY() >= 71 && input::mouseY() <= 76) {
|
||||
free(play::original_palette);
|
||||
draw::fadeout();
|
||||
audio::fadeoutMusic();
|
||||
JA_FadeOutMusic(250);
|
||||
play::exit = 1;
|
||||
}
|
||||
if (input::mouseY() >= 82 && input::mouseY() <= 87) {
|
||||
free(play::original_palette);
|
||||
draw::fadeout();
|
||||
audio::fadeoutMusic();
|
||||
JA_FadeOutMusic(250);
|
||||
play::exit = 2;
|
||||
}
|
||||
if (input::mouseY() >= 93 && input::mouseY() <= 98) {
|
||||
|
||||
@@ -31,8 +31,7 @@ namespace gamestate
|
||||
gamestate::sequence::init();
|
||||
return;
|
||||
} else {
|
||||
audio::loadMusic("mus3.ogg");
|
||||
audio::playMusic();
|
||||
JA_LoadAndPlayMusic("mus3.ogg");
|
||||
}
|
||||
|
||||
if (game::getConfig("fase") % 5 == 0) {
|
||||
@@ -104,7 +103,8 @@ namespace gamestate
|
||||
|
||||
std::string getPassword()
|
||||
{
|
||||
char *buffer = file::getFileBuffer("offsets.bal");
|
||||
int size;
|
||||
char *buffer = file_getfilebuffer("offsets.bal", size);
|
||||
|
||||
int punter = (game::getConfig("fase")-1)*10;
|
||||
char passFile[11];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "gamestates.h"
|
||||
#include "jgame.h"
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "aux_font.h"
|
||||
|
||||
namespace gamestate
|
||||
@@ -33,7 +33,8 @@ namespace gamestate
|
||||
default: gamestate::prefase::init(); return; break;
|
||||
}
|
||||
|
||||
sequence_file = file::getFilePointer(filename);
|
||||
int size;
|
||||
sequence_file = file_getfilepointer(filename.c_str(), size);
|
||||
|
||||
game::setState(&gamestate::sequence::loop);
|
||||
}
|
||||
@@ -98,15 +99,14 @@ namespace gamestate
|
||||
|
||||
} else if (command=="PLAYMUSIC") {
|
||||
fscanf(sequence_file, " '%[^']'", text);
|
||||
audio::loadMusic(text);
|
||||
audio::playMusic();
|
||||
JA_LoadAndPlayMusic(text);
|
||||
|
||||
} else if (command=="FADEOUT") {
|
||||
draw::fadeout();
|
||||
|
||||
} else if (command=="FADEOUTMUSIC") {
|
||||
draw::fadeout();
|
||||
audio::fadeoutMusic();
|
||||
JA_FadeOutMusic(250);
|
||||
|
||||
} else if (command=="END") {
|
||||
fclose(sequence_file);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define EXTENSION_INTRODUCER 0x21
|
||||
#define IMAGE_DESCRIPTOR 0x2C
|
||||
509
source/jail_audio.cpp
Normal file
509
source/jail_audio.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
#ifndef JA_USESDLMIXER
|
||||
#include "jail_audio.h"
|
||||
#include "jfile.h"
|
||||
#include "stb_vorbis.h"
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdio.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 };
|
||||
char *filename { 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, JA_musicVolume*(1.0 - percent));
|
||||
}
|
||||
}
|
||||
|
||||
if (current_music->times != 0)
|
||||
{
|
||||
if (SDL_GetAudioStreamAvailable(current_music->stream) < (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) < (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 num_channels)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
|
||||
#endif
|
||||
|
||||
SDL_Log("Iniciant JailAudio...");
|
||||
JA_audioSpec = {format, num_channels, freq };
|
||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
|
||||
SDL_Log( (sdlAudioDevice==0) ? "Failed to initialize SDL audio!\n" : "OK!\n");
|
||||
for (int i=0;i<JA_MAX_SIMULTANEOUS_CHANNELS;++i) channels[i].state = JA_CHANNEL_FREE;
|
||||
//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)
|
||||
{
|
||||
int size;
|
||||
char *buffer = file_getfilebuffer(filename, size);
|
||||
JA_Music_t *music = JA_LoadMusic((Uint8*)buffer, size);
|
||||
|
||||
music->filename = (char*)malloc(strlen(filename)+1);
|
||||
strcpy(music->filename, filename);
|
||||
|
||||
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)) printf("[ERROR] SDL_PutAudioStreamData failed!\n");
|
||||
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
||||
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) printf("[ERROR] SDL_BindAudioStream failed!\n");
|
||||
//SDL_ResumeAudioStreamDevice(current_music->stream);
|
||||
}
|
||||
|
||||
void JA_LoadAndPlayMusic(const char* filename, const bool force_reinit)
|
||||
{
|
||||
if ( (JA_GetMusicState() != JA_MUSIC_PLAYING) || (strcmp(JA_GetMusicFilename(), filename)!=0) || force_reinit ) {
|
||||
JA_PlayMusic(JA_LoadMusic(filename));
|
||||
}
|
||||
}
|
||||
|
||||
char *JA_GetMusicFilename(JA_Music_t *music)
|
||||
{
|
||||
if (!music) music = current_music;
|
||||
return music->filename;
|
||||
}
|
||||
|
||||
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;
|
||||
free(current_music->filename);
|
||||
current_music->filename = 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float JA_SetVolume(float volume)
|
||||
{
|
||||
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
|
||||
|
||||
return JA_musicVolume;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
source/jail_audio.h
Normal file
42
source/jail_audio.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
|
||||
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
|
||||
|
||||
struct JA_Sound_t;
|
||||
struct JA_Music_t;
|
||||
|
||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int num_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_LoadAndPlayMusic(const char* filename, const bool force_reinit=false);
|
||||
char *JA_GetMusicFilename(JA_Music_t *music = nullptr);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
float JA_SetVolume(float volume);
|
||||
@@ -1,168 +0,0 @@
|
||||
#include "jaudio.h"
|
||||
#include "jfile.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_mixer.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace audio
|
||||
{
|
||||
// Açò son estructures de mentires, per a usar estructures de SDL_Mixer de forma opaca.
|
||||
// Al final es un punter, així que és irrelevant el tipus del punter,
|
||||
// però si amague que son estructures de SDL_Mixer, no fa falta ficar el include a SDL_mixer fora de este arxiu
|
||||
struct sound
|
||||
{
|
||||
}; // Dummy structs
|
||||
|
||||
static char *buffer = nullptr;
|
||||
static Mix_Music *music = nullptr;
|
||||
static std::string music_filename = "";
|
||||
|
||||
// Inicialitza el sistema de só
|
||||
void init()
|
||||
{
|
||||
// Al final he ficat la configuració automàtica i au. Si en el futur necesitem canviar-ho pos se canvia
|
||||
if (Mix_Init(MIX_INIT_OGG)==0) {
|
||||
printf("Failed Mix_Init()\n");
|
||||
}
|
||||
if (Mix_OpenAudio(48000, AUDIO_S16, 2, 1024)!=0) {
|
||||
printf("Failed Mix_OpenAudio()\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Tanca el sistema de só (no shit, sherlock)
|
||||
void quit()
|
||||
{
|
||||
Mix_CloseAudio();
|
||||
}
|
||||
|
||||
// Carrega un arxiu de música en format OGG
|
||||
const bool loadMusic(const std::string filename)
|
||||
{
|
||||
if (music != nullptr) {
|
||||
Mix_FreeMusic(music);
|
||||
free(buffer);
|
||||
}
|
||||
int filesize=0;
|
||||
buffer = file::getFileBuffer(filename, &filesize);
|
||||
music = Mix_LoadMUS_RW(SDL_RWFromMem(buffer, filesize), 1);
|
||||
|
||||
if (music==nullptr) return false;
|
||||
|
||||
music_filename = filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Comença a reproduïr la música en questió
|
||||
void playMusic(const int loop)
|
||||
{
|
||||
if (Mix_PlayMusic(music, loop) == -1) {
|
||||
printf("Failed Mix_PlayMusic()\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Pausa la música que està sonant ara
|
||||
void pauseMusic()
|
||||
{
|
||||
Mix_PauseMusic();
|
||||
}
|
||||
|
||||
// Continua la música pausada
|
||||
void resumeMusic()
|
||||
{
|
||||
Mix_ResumeMusic();
|
||||
}
|
||||
|
||||
// Para la música que estava sonant
|
||||
void stopMusic()
|
||||
{
|
||||
Mix_HaltMusic();
|
||||
}
|
||||
|
||||
// Para la música que estava sonant fent un fade
|
||||
void fadeoutMusic()
|
||||
{
|
||||
Mix_FadeOutMusic(500);
|
||||
}
|
||||
|
||||
// Obté el estat actual de la música
|
||||
const music_state getMusicState()
|
||||
{
|
||||
if (Mix_PausedMusic())
|
||||
{
|
||||
return MUSIC_PAUSED;
|
||||
}
|
||||
else if (Mix_PlayingMusic())
|
||||
{
|
||||
return MUSIC_PLAYING;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MUSIC_STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
// Obté el nom de l'arxiu de música actual
|
||||
std::string whichMusic()
|
||||
{
|
||||
return music_filename;
|
||||
}
|
||||
|
||||
// Carrega un só des d'un arxiu WAV
|
||||
const sound *loadSound(const std::string filename)
|
||||
{
|
||||
return (sound *)Mix_LoadWAV(filename.c_str());
|
||||
}
|
||||
|
||||
// Comença a reproduïr el só especificat
|
||||
const int playSound(sound *snd, const int loop)
|
||||
{
|
||||
return Mix_PlayChannel(-1, (Mix_Chunk *)snd, loop);
|
||||
}
|
||||
|
||||
// Allibera un só
|
||||
void deleteSound(sound *snd)
|
||||
{
|
||||
Mix_FreeChunk((Mix_Chunk *)snd);
|
||||
}
|
||||
|
||||
// Pausa un canal en el que s'estava reproduïnt un só
|
||||
void pauseChannel(const int channel)
|
||||
{
|
||||
Mix_Pause(channel);
|
||||
}
|
||||
|
||||
// Continua un canal pausat
|
||||
void resumeChannel(const int channel)
|
||||
{
|
||||
Mix_Resume(channel);
|
||||
}
|
||||
|
||||
// Para un canal que estava reproduïnt un só
|
||||
void stopChannel(const int channel)
|
||||
{
|
||||
Mix_HaltChannel(channel);
|
||||
}
|
||||
|
||||
// Obté l'estat d'un canal
|
||||
const channel_state getChannelState(const int channel)
|
||||
{
|
||||
if (Mix_Paused(channel))
|
||||
{
|
||||
return CHANNEL_PAUSED;
|
||||
}
|
||||
else if (Mix_Playing(channel))
|
||||
{
|
||||
return CHANNEL_PLAYING;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CHANNEL_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
// Estableix el volum general
|
||||
const int setVolume(int volume)
|
||||
{
|
||||
return Mix_Volume(-1, volume);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace audio
|
||||
{
|
||||
// Enumeració per a representar el estat de un canal de sò
|
||||
enum channel_state
|
||||
{
|
||||
CHANNEL_INVALID,
|
||||
CHANNEL_FREE,
|
||||
CHANNEL_PLAYING,
|
||||
CHANNEL_PAUSED
|
||||
};
|
||||
|
||||
// Enumeració per a representar el estat de la música
|
||||
enum music_state
|
||||
{
|
||||
MUSIC_INVALID,
|
||||
MUSIC_PLAYING,
|
||||
MUSIC_PAUSED,
|
||||
MUSIC_STOPPED
|
||||
};
|
||||
|
||||
// Estructures per a gestionar música i só
|
||||
struct sound;
|
||||
|
||||
/// @brief Inicialitza el sistema de só
|
||||
void init();
|
||||
|
||||
/// @brief Tanca el sistema de só
|
||||
void quit();
|
||||
|
||||
/// @brief Carrega un arxiu de música en format OGG
|
||||
/// @param filename nom de l'arxiu
|
||||
/// @return true si tot be, false si ha fallat
|
||||
const bool loadMusic(const std::string filename);
|
||||
|
||||
/// @brief Comença a reproduïr la música en questió
|
||||
/// @param loop quants bucles farà (-1=infinit, 0=no repeteix, 1=repeteix 1 vegada...)
|
||||
void playMusic(const int loop = -1);
|
||||
|
||||
/// @brief Pausa la música que està sonant ara
|
||||
void pauseMusic();
|
||||
|
||||
/// @brief Continua la música pausada
|
||||
void resumeMusic();
|
||||
|
||||
/// @brief Para la música que estava sonant
|
||||
void stopMusic();
|
||||
|
||||
/// @brief Para la música que estava sonant fent un fade
|
||||
void fadeoutMusic();
|
||||
|
||||
/// @brief Obté el estat actual de la música
|
||||
/// @return estat actual de la música (MUSIC_INVALID, MUSIC_PLAYING, MUSIC_PAUSED o MUSIC_STOPPED)
|
||||
const music_state getMusicState();
|
||||
|
||||
/// @brief Obté el nom de l'arxiu de música actual
|
||||
/// @return el nom de l'arxiu
|
||||
std::string whichMusic();
|
||||
|
||||
/// @brief Carrega un só des d'un arxiu WAV
|
||||
/// @param filename nom de l'arxiu
|
||||
/// @return un punter al só
|
||||
const sound *loadSound(const std::string filename);
|
||||
|
||||
/// @brief Comença a reproduïr el só especificat
|
||||
/// @param snd punter al só a reproduïr
|
||||
/// @param loop si es fa bucle (-1=infinit, 0=no repeteix, 1=repeteix 1 vegada...)
|
||||
/// @return número del canal en que està sonant el só
|
||||
const int playSound(sound *snd, const int loop = 0);
|
||||
|
||||
/// @brief Pausa un canal en el que s'estava reproduïnt un só
|
||||
/// @param channel número del canal a pausar
|
||||
void pauseChannel(const int channel);
|
||||
|
||||
/// @brief Continua un canal pausat
|
||||
/// @param channel número del canal pausat
|
||||
void resumeChannel(const int channel);
|
||||
|
||||
/// @brief Para un canal que estava reproduïnt un só
|
||||
/// @param channel número del canal a parar
|
||||
void stopChannel(const int channel);
|
||||
|
||||
/// @brief Obté l'estat d'un canal
|
||||
/// @param channel canal del que es vol obtindre l'estat
|
||||
/// @return estat del canal (CHANNEL_INVALID, CHANNEL_FREE, CHANNEL_PLAYING o CHANNEL_PAUSED)
|
||||
const channel_state getChannelState(const int channel);
|
||||
|
||||
/// @brief Allibera un só
|
||||
/// @param snd punter al só
|
||||
void deleteSound(sound *snd);
|
||||
|
||||
/// @brief Estableix el volum general
|
||||
/// @param volume valor a establir com a volum (128 màxim)
|
||||
/// @return el volum anterior
|
||||
const int setVolume(int volume);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "jdraw.h"
|
||||
#include "SDL2/SDL.h"
|
||||
#include "gif.c"
|
||||
#include "SDL3/SDL.h"
|
||||
#include "gif.h"
|
||||
#include "jfile.h"
|
||||
|
||||
namespace draw
|
||||
@@ -42,12 +42,16 @@ namespace draw
|
||||
// [TODO] Incloure gestió de pantalla completa
|
||||
|
||||
// Inicialització de les estructures de SDL
|
||||
sdl_window = SDL_CreateWindow(titol.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width * zoom, height * zoom, SDL_WINDOW_SHOWN);
|
||||
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
|
||||
sdl_window = SDL_CreateWindow(titol.c_str(), width * zoom, height * zoom, 0);
|
||||
if (!sdl_window) { SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR: Failed to initialize window!\n"); exit(1); }
|
||||
sdl_renderer = SDL_CreateRenderer(sdl_window, NULL);
|
||||
if (!sdl_renderer) { SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR: Failed to initialize renderer!\n"); exit(1); }
|
||||
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
SDL_SetTextureScaleMode(sdl_texture, SDL_SCALEMODE_NEAREST);
|
||||
if (!sdl_texture) { SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "ERROR: Failed to initialize texture!\n"); exit(1); }
|
||||
|
||||
// Establim el tamany "logic", indepndent del tamany de finestra
|
||||
SDL_RenderSetLogicalSize(sdl_renderer, width, height);
|
||||
//SDL_SetRenderLogicalPresentation(sdl_renderer, width, height,);
|
||||
|
||||
// Creem la superficie "screen" i la establim com a superficie destinació
|
||||
screen = createSurface(width, height);
|
||||
@@ -58,7 +62,7 @@ namespace draw
|
||||
sel_color = transparent = 0;
|
||||
for (int i=0;i<256;++i) color_indices[i] = i;
|
||||
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
SDL_HideCursor();
|
||||
//textsurf = loadSurface("font.gif");
|
||||
}
|
||||
|
||||
@@ -114,7 +118,7 @@ namespace draw
|
||||
// Agafem un buffer de bytes de l'arxiu especificat
|
||||
// getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char
|
||||
int size;
|
||||
uint8_t *buffer = (uint8_t *)file::getFileBuffer(filename, &size);
|
||||
uint8_t *buffer = (uint8_t *)file_getfilebuffer(filename.c_str(), size);
|
||||
|
||||
// Si ens ha tornat nullptr, es que no l'ha trobat, tornem nosaltres també nullptr ja que no s'ha pogut crear la superficie
|
||||
if (buffer == nullptr)
|
||||
@@ -230,7 +234,7 @@ namespace draw
|
||||
// Agafem un buffer de bytes de l'arxiu especificat
|
||||
// getFileBuffer() simplement ens torna el arxiu sencer dins de un array de char
|
||||
int size;
|
||||
uint8_t *buffer = (uint8_t *)file::getFileBuffer(filename, &size);
|
||||
uint8_t *buffer = (uint8_t *)file_getfilebuffer(filename.c_str(), size);
|
||||
|
||||
// Li passem el array del arxiu a LoadPalette. Ell ens torna un array de uint32_t amb la paleta
|
||||
// Van a ser 256 entrades de 32 bits, cada entrada es un color, amb el format 0xAARRGGBB
|
||||
@@ -497,14 +501,14 @@ namespace draw
|
||||
// i el enviem a la textura SDL
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
{
|
||||
sdl_pixels[i] = palette[screen->pixels[i]];
|
||||
sdl_pixels[i] = palette[screen->pixels[i]] | 0xff000000;
|
||||
}
|
||||
|
||||
// Desbloquejem la textura
|
||||
SDL_UnlockTexture(sdl_texture);
|
||||
|
||||
// Pintem la textura a pantalla
|
||||
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
|
||||
SDL_RenderTexture(sdl_renderer, sdl_texture, NULL, NULL);
|
||||
|
||||
// I ho presentem
|
||||
SDL_RenderPresent(sdl_renderer);
|
||||
|
||||
647
source/jfile.cpp
647
source/jfile.cpp
@@ -15,486 +15,215 @@
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_FILENAME "data.jf2"
|
||||
#define DEFAULT_FOLDER "data/"
|
||||
#define CONFIG_FILENAME "config.txt"
|
||||
#define DEFAULT_FILENAME "data.jf2"
|
||||
#define DEFAULT_FOLDER "data/"
|
||||
#define CONFIG_FILENAME "config.txt"
|
||||
|
||||
/* FORMAT DEL ARXIU .JF2
|
||||
|
||||
4 bytes header capçalera "PK2" (caracter 0 de final de cadena al final) (en realitat passe de ella, pero be...)
|
||||
4 bytes num_files nombre d'arxius inclosos
|
||||
4 bytes toc_offset en quina posició de l'arxiu està la taula de continguts
|
||||
|
||||
... Ara venen tots els arxius inclosos, uno darrere de l'altre.
|
||||
... Quan acaben ve la taula de continguts. La taula te tantes entrades com arxius inclosos. Cada entrada te el següent format:
|
||||
|
||||
(per cert, toc_offset apunta ací)
|
||||
4 bytes offset en quina posició del arxiu de recursos comença este arxiu
|
||||
4 bytes size tamany d'este arxiu
|
||||
1 byte path_size tamany de la cadena amb la ruta de l'arxiu
|
||||
path_size bytes path ruta de l'arxiu original. La usem per a trobar el arxiu que ens demanen.
|
||||
|
||||
EXEMPLE SIMPLE:
|
||||
|
||||
- Imaginem que volem incloure un arxiu "data/hola.txt" amb el contingut "HOLA", i un arxiu "data/adios.txt" amb el contingut "ADIOS":
|
||||
|
||||
OFFSET CONTINGUT TAMANY DESCRIPCIÓ
|
||||
0 "PK2"+0 4 La capçalera
|
||||
4 2 4 nombre d'arxius
|
||||
8 21 4 offset a la taula de continguts
|
||||
|
||||
--- COMENCEN ELS ARXIUS INCLOSOS ---
|
||||
|
||||
12 HOLA 4 el contingut del primer arxiu
|
||||
16 ADIOS 5 el contingut del segon arxiu
|
||||
|
||||
--- COMENÇA LA TAULA DE CONTINGUTS ---
|
||||
|
||||
21 12 4 offset al primer arxiu
|
||||
25 4 4 tamany del primer axiu
|
||||
29 13 1 tamany de la ruta al primer arxiu
|
||||
30 "data/hola.txt" 13 la ruta al primer arxiu
|
||||
43 16 4 offset al primer arxiu
|
||||
47 4 4 tamany del primer axiu
|
||||
51 13 1 tamany de la ruta al primer arxiu
|
||||
52 "data/adios.txt" 14 la ruta al primer arxiu
|
||||
|
||||
|
||||
- Es un exemple raro, perque ocupa mes la ruta al arxiu que l'arxiu en si, pero espere que la idea quede clara!
|
||||
|
||||
Al principi se carrega la tabla de continguts en memòria, així el acces als arxius es ràpid.
|
||||
|
||||
|
||||
|
||||
Y com funciona tot açò? pos per defecte va a intentar llegir tots els arxius de "data.jf2". Si no troba e l'arxiu, automaticament passa a
|
||||
buscar-ho tot en la carpeta "data" en arxius independents. En principi, si no se tenen requeriments diferents, no fa falta configurar res.
|
||||
|
||||
|
||||
|
||||
Respecte al tema de l'arxiu de configuració, està montat de forma que se pot escriure i llegir valors asociats a una clau sense calfar-se el cap.
|
||||
En l'arxiu de configuració els valor se guarden de la forma:
|
||||
|
||||
CLAU=VALOR
|
||||
|
||||
Cada un en una linea. Si llegim i no existeix, torna cadena buida. Si escrivim i ja exisita, se reemplaça.
|
||||
Tot son valors de cadena. Si en realitat son números, tindràs que encarregar-te tu de la caonversió de cadena a numero o al reves.
|
||||
|
||||
*/
|
||||
|
||||
namespace file
|
||||
struct file_t
|
||||
{
|
||||
// Estructures
|
||||
// ===============================================================================================================================
|
||||
std::string path;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
// Estructura que representa un arxiu en la tabla de continguts del arxiu de recursos
|
||||
struct file_t
|
||||
{
|
||||
std::string path; // Ruta relativa de l'arxiu
|
||||
uint32_t size; // Tamany de l'arxiu
|
||||
uint32_t offset; // Offset a l'arxiu dins de l'arxiu de recursos
|
||||
};
|
||||
std::vector<file_t> toc;
|
||||
|
||||
std::vector<file_t> toc; // vector que conté la taula de continguts de l'arxiu de recursos
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
// Variables
|
||||
// ===============================================================================================================================
|
||||
static std::string resource_filename = DEFAULT_FILENAME; // Nom de l'arxiu de recursos
|
||||
static std::string resource_folder = DEFAULT_FOLDER; // Nom de la carpeta de recursos
|
||||
static int file_source = SOURCE_FILE; // D'on anem a pillar els recursos, arxiu o carpeta
|
||||
static std::string config_folder; // Nom de la carpeta on guardar la configuració
|
||||
std::vector<keyvalue_t> config; // Vector amb els valors guardats a l'arxiu de configuració
|
||||
void file_setresourcefilename(const char *str) {
|
||||
if (resource_filename != NULL) free(resource_filename);
|
||||
resource_filename = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_filename, str);
|
||||
}
|
||||
|
||||
// Funcions
|
||||
// ===============================================================================================================================
|
||||
void file_setresourcefolder(const char *str) {
|
||||
if (resource_folder != NULL) free(resource_folder);
|
||||
resource_folder = (char*)malloc(strlen(str)+1);
|
||||
strcpy(resource_folder, str);
|
||||
}
|
||||
|
||||
// Estableix el nom de l'arxiu on estàn guardats els recursos (es "data.jf2" per defecte)
|
||||
void setResourceFilename(const std::string str)
|
||||
{
|
||||
resource_filename = 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 (int i=0; i<num_files; ++i)
|
||||
{
|
||||
uint32_t file_offset, file_size;
|
||||
fi.read( (char*)&file_offset, 4 );
|
||||
fi.read( (char*)&file_size, 4 );
|
||||
uint8_t path_size;
|
||||
fi.read( (char*)&path_size, 1 );
|
||||
char file_name[path_size+1];
|
||||
fi.read( file_name, path_size );
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
toc.push_back({filename, file_size, file_offset});
|
||||
}
|
||||
fi.close();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Estableix el nom de la carpeta on estàn guardats els recursos (es "data" per defecte)
|
||||
void setResourceFolder(const std::string str)
|
||||
{
|
||||
resource_folder = str;
|
||||
}
|
||||
char *file_getfilebuffer(const char *resourcename, int& filesize) {
|
||||
FILE *f = file_getfilepointer(resourcename, filesize, true);
|
||||
char* buffer = (char*)malloc(filesize);
|
||||
fread(buffer, filesize, 1, f);
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Estableix d'on s'han de obtenir els recursos (arxius individuals dins d'una carpeta o arxiu de recursos)
|
||||
void setSource(const int src)
|
||||
{
|
||||
file_source = src % 2; // mod 2 de forma que sempre es un valor vàlid, 0 (arxiu) o 1 (carpeta)
|
||||
|
||||
// Si volem que busque en carpeta i encara no haviem especificat una carpeta, usem la per defecte
|
||||
if (/*src == SOURCE_FOLDER && */resource_folder == "")
|
||||
{
|
||||
setResourceFolder(DEFAULT_FOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
// Carreguem la taula de continguts de l'arxiu de recursos
|
||||
bool getTableOfContents()
|
||||
{
|
||||
// Si encara no haviem especificat un arxiu de recursos, usem el arxiu de recursos per defecte
|
||||
if (resource_filename == "")
|
||||
{
|
||||
setResourceFilename(DEFAULT_FILENAME);
|
||||
}
|
||||
|
||||
// Si l'arxiu de recursos existeix...
|
||||
std::ifstream fi(resource_filename, std::ios::binary);
|
||||
if (fi.is_open())
|
||||
{
|
||||
// Llegim la capçalera (controlar que siga correcta?)
|
||||
char header[4];
|
||||
fi.read(header, 4);
|
||||
|
||||
// LLegim el nombre d'arxius i la posició de la taula de continguts
|
||||
uint32_t num_files, toc_offset;
|
||||
fi.read((char *)&num_files, 4);
|
||||
fi.read((char *)&toc_offset, 4);
|
||||
|
||||
// Anem a la taula de continguts
|
||||
fi.seekg(toc_offset);
|
||||
|
||||
// Per a cada arxiu inclos en l'arxiu de recursos...
|
||||
for (unsigned int i = 0; i < num_files; ++i)
|
||||
{
|
||||
// Llegim en quina posició està i quant ocupa
|
||||
uint32_t file_offset, file_size;
|
||||
fi.read((char *)&file_offset, 4);
|
||||
fi.read((char *)&file_size, 4);
|
||||
|
||||
// Llegim la seua ruta
|
||||
uint8_t path_size;
|
||||
fi.read((char *)&path_size, 1);
|
||||
char file_name[path_size + 1];
|
||||
fi.read(file_name, path_size);
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
|
||||
// Y afegim les dades a la taula de continguts en memòria
|
||||
toc.push_back({filename, file_size, file_offset});
|
||||
}
|
||||
|
||||
// Tanquem la paradeta i tornem true
|
||||
fi.close();
|
||||
return true;
|
||||
}
|
||||
else // Si no s'ha pogut llegir el arxiu de recursos, tornem false
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obté un "std::ifstream" al arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos)
|
||||
std::ifstream getFileStream(const std::string resourcename, int *filesize, const bool binary)
|
||||
{
|
||||
// Si tenim configurat agafar els recursos de arxiu, pero encara no tenim la taula de continguts carregada...
|
||||
if (file_source == SOURCE_FILE and toc.size() == 0)
|
||||
{
|
||||
// Si fallem al intentar carregar la taula de continguts de l'arxiu de recursos, canviem a pillar els recursos de carpeta
|
||||
if (not getTableOfContents())
|
||||
{
|
||||
setSource(SOURCE_FOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
std::ifstream f;
|
||||
|
||||
// Si estem pillant els recursos de un arxiu de recursos...
|
||||
if (file_source == SOURCE_FILE)
|
||||
{
|
||||
// Busquem el recurs en la taula de continguts usant la ruta
|
||||
bool found = false;
|
||||
uint32_t count = 0;
|
||||
while (!found && count < toc.size())
|
||||
{
|
||||
found = (resource_folder + resourcename == toc[count].path);
|
||||
if (!found)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Si no trobem el recurs, petem el mame
|
||||
if (!found)
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha trobat el recurs '%s' a l'arxiu de recursos '%s'\n", resourcename.c_str(), resource_filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Agafem el tamany del recurs de la taula de continguts
|
||||
if (filesize) *filesize = toc[count].size;
|
||||
|
||||
// obrim l'arxiu de recursos
|
||||
f.open(resource_filename.c_str(), binary ? std::ios::binary : std::ios::in);
|
||||
if (!f.is_open()) // En el raruno cas de que a este altures pete al obrir el arxiu de recursos, petem el mame
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha pogut obrir l'arxiu de recursos '%s'\n", resource_filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Anem a la posició on està el recurs que volem. Amb açò "f" ja està preparat per a ser tornar.
|
||||
// Ojo, realment estic tornant un FILE* al arxiu de recursos, pero ja apuntant al moment en que comença el recurs que volem.
|
||||
// Ho dic perque si fem fseek(f, 0, SEEK_SET) tornarà al principi de l'arxiu de recursos, no del recurs. Tindre-ho en compte.
|
||||
f.seekg(toc[count].offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Si estem pillant els recursos de carpeta, simplement obrim el arxiu en questió i tornem el FILE* associat.
|
||||
f.open((resource_folder + resourcename), binary ? std::ios::binary : std::ios::in);
|
||||
if (f.rdstate() & std::ios_base::failbit)
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha pogut obrir l'arxiu '%s/%s'\n", resource_folder.c_str(), resourcename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
f.seekg(0, std::ios_base::end);
|
||||
if (filesize) *filesize = f.tellg();
|
||||
f.seekg(0, std::ios_base::beg);
|
||||
}
|
||||
|
||||
// Tornar el punter FILE* al arxiu. OJO! Tenim que tancar-lo quan acabem amb ell
|
||||
return f;
|
||||
}
|
||||
|
||||
// Obté un "FILE*" al arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos)
|
||||
FILE *getFilePointer(const std::string resourcename, int *filesize, const bool binary)
|
||||
{
|
||||
// Si tenim configurat agafar els recursos de arxiu, pero encara no tenim la taula de continguts carregada...
|
||||
if (file_source == SOURCE_FILE and toc.size() == 0)
|
||||
{
|
||||
// Si fallem al intentar carregar la taula de continguts de l'arxiu de recursos, canviem a pillar els recursos de carpeta
|
||||
if (not getTableOfContents())
|
||||
{
|
||||
setSource(SOURCE_FOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
// Si estem pillant els recursos de un arxiu de recursos...
|
||||
if (file_source == SOURCE_FILE)
|
||||
{
|
||||
// Busquem el recurs en la taula de continguts usant la ruta
|
||||
bool found = false;
|
||||
uint32_t count = 0;
|
||||
while (!found && count < toc.size())
|
||||
{
|
||||
found = (resource_folder + resourcename == toc[count].path);
|
||||
if (!found)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Si no trobem el recurs, petem el mame
|
||||
if (!found)
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha trobat el recurs '%s' a l'arxiu de recursos '%s'\n", resourcename.c_str(), resource_filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Agafem el tamany del recurs de la taula de continguts
|
||||
if (filesize) *filesize = toc[count].size;
|
||||
|
||||
// obrim l'arxiu de recursos
|
||||
f = fopen(resource_filename.c_str(), binary ? "rb" : "r");
|
||||
if (!f) // En el raruno cas de que a este altures pete al obrir el arxiu de recursos, petem el mame
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha pogut obrir l'arxiu de recursos '%s'\n", resource_filename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Anem a la posició on està el recurs que volem. Amb açò "f" ja està preparat per a ser tornar.
|
||||
// Ojo, realment estic tornant un FILE* al arxiu de recursos, pero ja apuntant al moment en que comença el recurs que volem.
|
||||
// Ho dic perque si fem fseek(f, 0, SEEK_SET) tornarà al principi de l'arxiu de recursos, no del recurs. Tindre-ho en compte.
|
||||
fseek(f, toc[count].offset, SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Si estem pillant els recursos de carpeta, simplement obrim el arxiu en questió i tornem el FILE* associat.
|
||||
f = fopen((resource_folder + resourcename).c_str(), binary ? "rb" : "r");
|
||||
if(!f)
|
||||
{
|
||||
printf("ERROR FATAL: No s'ha pogut obrir l'arxiu '%s/%s'\n", resource_folder.c_str(), resourcename.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
if (filesize) *filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
// Tornar el punter FILE* al arxiu. OJO! Tenim que tancar-lo quan acabem amb ell
|
||||
return f;
|
||||
}
|
||||
|
||||
// Obté un buffer de memòria en format "char*" del arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos)
|
||||
char *getFileBuffer(const std::string resourcename, int *filesize)
|
||||
{
|
||||
int size;
|
||||
// Usem la funció anterior per a obtinde un FILE*, independentment de on pillem els recursos
|
||||
FILE *f = getFilePointer(resourcename, &size, true);
|
||||
|
||||
// Reservem memòria per al buffer
|
||||
char *buffer = (char *)malloc(size);
|
||||
|
||||
// llegim el contingut del arxiu i el fiquem en el buffer
|
||||
fread(buffer, size, 1, f);
|
||||
|
||||
// Tanquem l'arxiu
|
||||
fclose(f);
|
||||
|
||||
if (filesize) *filesize = size;
|
||||
|
||||
// Tornem el buffer. OJO! recordar alliberar-lo amb free(buffer) quan acabem amb ell.
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Estableix el nom de la carpeta on es guardarà la configuració
|
||||
// Adaptat del codi que va escriure JailDesigner en el JailDoctor's Dilemma
|
||||
// Vull revisar-la tranquilament algun dia
|
||||
void setConfigFolder(const std::string foldername)
|
||||
{
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void file_setconfigfolder(const char *foldername)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
|
||||
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;
|
||||
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;
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
config_folder = std::string(homedir) + "/." + foldername;
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(config_folder.c_str(), &st) == -1)
|
||||
{
|
||||
struct stat st = {0};
|
||||
if (stat(config_folder.c_str(), &st) == -1)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(config_folder.c_str());
|
||||
int ret = mkdir(config_folder.c_str());
|
||||
#else
|
||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Obté el nom de la carpeta on es guardarà la configuració
|
||||
const std::string getConfigFolder()
|
||||
{
|
||||
return config_folder + "/";
|
||||
}
|
||||
|
||||
// Carrega tots els valors guardats a l'arxiu de recursos
|
||||
void loadConfigValues()
|
||||
{
|
||||
// Buidem la taula de claus-valors en memòria
|
||||
config.clear();
|
||||
|
||||
// Obrim l'arxiu de configuració
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "r");
|
||||
if (f)
|
||||
if (ret == -1)
|
||||
{
|
||||
// Agafem linea a linea
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
// Separem la clau del valor
|
||||
char *value = strchr(line, '=');
|
||||
if (value)
|
||||
{
|
||||
*value = '\0';
|
||||
value++;
|
||||
value[strlen(value) - 1] = '\0';
|
||||
|
||||
// i els afegim a la taula de claus-valors en memòria
|
||||
config.push_back({line, value});
|
||||
}
|
||||
}
|
||||
|
||||
// tanquem la paradeta
|
||||
fclose(f);
|
||||
printf("ERROR CREATING CONFIG FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Guardem tots els valors en la taula de claus-valors a l'arxiu de configuració
|
||||
void saveConfigValues()
|
||||
{
|
||||
// Obrim l'arxiu de configuració
|
||||
std::string config_file = config_folder + "/config.txt";
|
||||
FILE *f = fopen(config_file.c_str(), "w");
|
||||
if (f)
|
||||
{
|
||||
// Guardem cada parella clau/valor de la taula en memòria en una linea en format "clau=valor\n" en l'arxiu de configuració
|
||||
for (auto pair : config)
|
||||
{
|
||||
fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
|
||||
}
|
||||
|
||||
// tanquem la paradeta
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
// Obté un valor de l'arxiu de configuració per a la clau donada (o cadena buida si no existeix)
|
||||
const std::string getConfigValue(const std::string key)
|
||||
{
|
||||
// Si la taula de claus-valors esta buida, la carreguem de l'arxiu de configuració
|
||||
if (config.empty())
|
||||
{
|
||||
loadConfigValues();
|
||||
}
|
||||
|
||||
// busquem la clau en la taula
|
||||
for (auto pair : config)
|
||||
{
|
||||
if (pair.key == std::string(key))
|
||||
{
|
||||
// Si la trobem, tornem el seu valor
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Si no la trobem, tornem cadena buida
|
||||
return "";
|
||||
}
|
||||
|
||||
// Estableix un valor en l'arxiu de configuració per a la clau donada
|
||||
void setConfigValue(const std::string key, const std::string value)
|
||||
{
|
||||
// Si la taula de claus-valors esta buida, la carreguem de l'arxiu de configuració
|
||||
if (config.empty())
|
||||
{
|
||||
loadConfigValues();
|
||||
}
|
||||
|
||||
// busquem la clau en la taula
|
||||
for (auto &pair : config)
|
||||
{
|
||||
if (pair.key == std::string(key))
|
||||
{
|
||||
// Si la trobem, actualitzem el seu valor i guardem els canvis a l'arxiu de configuració
|
||||
pair.value = value;
|
||||
saveConfigValues();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Si NO la trobem, afegim la nova clau i el seu valor, i guardem els canvis a l'arxiu de configuració
|
||||
config.push_back({key, value});
|
||||
saveConfigValues();
|
||||
}
|
||||
}
|
||||
|
||||
const char *file_getconfigfolder() {
|
||||
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;
|
||||
}
|
||||
@@ -1,68 +1,18 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#define SOURCE_FILE 0
|
||||
#define SOURCE_FOLDER 1
|
||||
#define SOURCE_FILE 0
|
||||
#define SOURCE_FOLDER 1
|
||||
|
||||
// Unitat per a la gestió de l'acces a arxius
|
||||
namespace file
|
||||
{
|
||||
// Funcions d'acces als recursos (gràfics, musiques...)
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
void file_setconfigfolder(const char *foldername);
|
||||
const char *file_getconfigfolder();
|
||||
|
||||
/// @brief Estableix el nom de l'arxiu on estàn guardats els recursos (es "data.jf2" per defecte)
|
||||
/// @param str nom de l'arxiu de recursos
|
||||
void setResourceFilename(const std::string str);
|
||||
void file_setresourcefilename(const char *str);
|
||||
void file_setresourcefolder(const char *str);
|
||||
void file_setsource(const int src);
|
||||
|
||||
/// @brief Estableix el nom de la carpeta on estàn guardats els recursos (es "data" per defecte)
|
||||
/// @param str nom de la carpeta de recursos
|
||||
void setResourceFolder(const std::string str);
|
||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false);
|
||||
char *file_getfilebuffer(const char *resourcename, int& filesize);
|
||||
|
||||
/// @brief Estableix d'on s'han de obtenir els recursos (arxius individuals dins d'una carpeta o arxiu de recursos)
|
||||
/// @param src SOURCE_FILE o SOURCE_FOLDER, si es vol que se pillen recursos de arxiu o de carpeta
|
||||
void setSource(const int src);
|
||||
|
||||
/// @brief Obté un "std::ifstream" al arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos). Recordar tancar-lo al acabar amb ell.
|
||||
/// @param resourcename el nom de l'arxiu que volem obrir
|
||||
/// @param filesize paràmetre de retorn. Ací es torna el tamany de l'arxiu
|
||||
/// @param binary si volem obrir el arxiu en format binary
|
||||
/// @return un std::ifstream al arxiu
|
||||
std::ifstream getFileStream(const std::string resourcename, int *filesize = nullptr, const bool binary = false);
|
||||
|
||||
/// @brief Obté un "FILE*" al arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos). Recordar tancar-lo al acabar amb ell.
|
||||
/// @param resourcename el nom de l'arxiu que volem obrir
|
||||
/// @param filesize paràmetre de retorn. Ací es torna el tamany de l'arxiu
|
||||
/// @param binary si volem obrir el arxiu en format binary
|
||||
/// @return un punter FILE* al arxiu
|
||||
FILE *getFilePointer(const std::string resourcename, int *filesize = nullptr, const bool binary = false);
|
||||
|
||||
/// @brief Obté un buffer de memòria en format "char*" del arxiu que se li demana, independentment de la font (arxius individual en carpeta, o arxiu de recursos).
|
||||
/// @brief Recordar alliberar la memoria del buffer amb free(buffer) al acabar amb ell.
|
||||
/// @param resourcename el nom de l'arxiu del que volem obrindre el buffer
|
||||
/// @param filesize paràmetre de retorn. Ací es torna el tamany de l'arxiu
|
||||
/// @return un array de "filesize" bytes amb el contingut del arxiu
|
||||
char *getFileBuffer(const std::string resourcename, int *filesize = nullptr);
|
||||
|
||||
// Funcions d'access a la configuració (clau = valor)
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
/// @brief Estableix el nom de la carpeta on es guardarà la configuració
|
||||
/// @param foldername nom de la carpeta
|
||||
void setConfigFolder(const std::string foldername);
|
||||
|
||||
/// @brief Obté el nom de la carpeta on es guardarà la configuració
|
||||
/// @return nom de la carpeta
|
||||
const std::string getConfigFolder();
|
||||
|
||||
/// @brief Obté un valor de l'arxiu de configuració per a la clau donada (o cadena buida si no existeix)
|
||||
/// @param key clau de la que obtindre el valor
|
||||
/// @return el valor de la clau especificada
|
||||
const std::string getConfigValue(const std::string key);
|
||||
|
||||
/// @brief Estableix un valor en l'arxiu de configuració per a la clau donada
|
||||
/// @param key clau a la que establir un valor
|
||||
/// @param value valor a establir per a la clau
|
||||
void setConfigValue(const std::string key, const std::string value);
|
||||
}
|
||||
const char* file_getconfigvalue(const char *key);
|
||||
void file_setconfigvalue(const char* key, const char* value);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "jgame.h"
|
||||
#include "jdraw.h"
|
||||
#include "jinput.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <map>
|
||||
|
||||
#ifdef MACOS_BUNDLE
|
||||
@@ -49,9 +49,11 @@ int main(int argc, char *argv[])
|
||||
char res_file[255] = "";
|
||||
strcpy(res_file, dirname(argv[0]));
|
||||
strcat(res_file, "/../Resources/data.jf2");
|
||||
file::setResourceFilename(res_file);
|
||||
file_setresourcefilename(res_file);
|
||||
#endif
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
||||
|
||||
game::windowHasFocus = true;
|
||||
game::init();
|
||||
input::init(draw::getZoom());
|
||||
@@ -64,26 +66,34 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
while(SDL_PollEvent(&e))
|
||||
{
|
||||
if (e.type==SDL_QUIT) { should_exit = true; break; }
|
||||
if (e.type==SDL_KEYDOWN)
|
||||
if (e.type==SDL_EVENT_QUIT)
|
||||
{
|
||||
input::updateKey(e.key.keysym.scancode);
|
||||
should_exit = true;
|
||||
break;
|
||||
}
|
||||
if (e.type==SDL_KEYUP)
|
||||
if (e.type==SDL_EVENT_KEY_DOWN)
|
||||
{
|
||||
input::updateKeypressed(e.key.keysym.scancode);
|
||||
input::updateKey(e.key.scancode);
|
||||
}
|
||||
if (e.type==SDL_MOUSEBUTTONUP)
|
||||
if (e.type==SDL_EVENT_KEY_UP)
|
||||
{
|
||||
input::updateKeypressed(e.key.scancode);
|
||||
}
|
||||
if (e.type==SDL_EVENT_MOUSE_BUTTON_UP)
|
||||
{
|
||||
input::updateClk(e.button.button);
|
||||
}
|
||||
if (e.type==SDL_MOUSEWHEEL)
|
||||
if (e.type==SDL_EVENT_MOUSE_WHEEL)
|
||||
{
|
||||
input::updateWheel(e.wheel.y);
|
||||
}
|
||||
if ( e.type == SDL_WINDOWEVENT ) {
|
||||
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) game::windowHasFocus = true;
|
||||
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) game::windowHasFocus = false;
|
||||
if ( e.type == SDL_EVENT_WINDOW_FOCUS_GAINED )
|
||||
{
|
||||
game::windowHasFocus = true;
|
||||
}
|
||||
if ( e.type == SDL_EVENT_WINDOW_FOCUS_LOST )
|
||||
{
|
||||
game::windowHasFocus = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "jdraw.h"
|
||||
#include "jinput.h"
|
||||
#include "jaudio.h"
|
||||
#include "jail_audio.h"
|
||||
#include "jfile.h"
|
||||
namespace game
|
||||
{
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "jinput.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include "jdraw.h"
|
||||
|
||||
namespace input
|
||||
{
|
||||
static const uint8_t *keys = nullptr;
|
||||
static const bool *keys = nullptr;
|
||||
static uint8_t keypressed = 0;
|
||||
static uint8_t keydown = 0;
|
||||
static uint8_t btnClicked = 0;
|
||||
@@ -79,7 +79,7 @@ namespace input
|
||||
// Torna la posició X actual del ratolí
|
||||
const int mouseX()
|
||||
{
|
||||
int x;
|
||||
float x;
|
||||
SDL_GetMouseState(&x, NULL);
|
||||
return x/screen_zoom;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace input
|
||||
// Torna la posició Y actual del ratolí
|
||||
const int mouseY()
|
||||
{
|
||||
int y;
|
||||
float y;
|
||||
SDL_GetMouseState(NULL, &y);
|
||||
return y/screen_zoom;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace input
|
||||
// Determina si el botó del ratolí especificat està sent polsada ara mateix
|
||||
const bool mouseBtn(const int btn)
|
||||
{
|
||||
return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(btn));
|
||||
return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MASK(btn));
|
||||
}
|
||||
|
||||
// Determina si el botó especificat ha sigut polsat, pero no tornarà a ser true fins
|
||||
|
||||
@@ -8,7 +8,7 @@ void game::init()
|
||||
draw::setTrans(0);
|
||||
|
||||
input::init(3);
|
||||
audio::init();
|
||||
JA_Init(48000, SDL_AUDIO_S16, 2);
|
||||
|
||||
font::init();
|
||||
|
||||
|
||||
5584
source/stb_vorbis.h
Normal file
5584
source/stb_vorbis.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user