diff options
Diffstat (limited to 'src')
78 files changed, 4473 insertions, 3947 deletions
diff --git a/src/3rdparty/buildvm/buildvm.exe b/src/3rdparty/buildvm/buildvm.exe Binary files differindex 731fbfb..ed23035 100644 --- a/src/3rdparty/buildvm/buildvm.exe +++ b/src/3rdparty/buildvm/buildvm.exe diff --git a/src/3rdparty/minilua/minilua.exe b/src/3rdparty/minilua/minilua.exe Binary files differindex 1567a0c..8e7c938 100644 --- a/src/3rdparty/minilua/minilua.exe +++ b/src/3rdparty/minilua/minilua.exe diff --git a/src/libjin/Audio/SDL/je_sdl_audio.cpp b/src/libjin/Audio/SDL/je_sdl_audio.cpp index 4ce02f7..c21d077 100644 --- a/src/libjin/Audio/SDL/je_sdl_audio.cpp +++ b/src/libjin/Audio/SDL/je_sdl_audio.cpp @@ -9,135 +9,137 @@ #include "je_sdl_audio.h" #include "je_sdl_source.h" +using namespace JinEngine::Math; + namespace JinEngine { namespace Audio { - - using namespace JinEngine::Math; - - /* עcallbackƵ̵߳ */ - static void defaultCallback(void *userdata, Uint8 *stream, int size) - { - static SDLAudio* audio = static_cast<SDLAudio*>(userdata); - if (!audio->goOnProcess()) - return; - audio->lock(); - audio->processCommands(); - audio->processSources(stream, size); - audio->processBuffer(stream, size); - audio->unlock(); - } - - /*call only once*/ bool SDLAudio::initSystem(const SettingBase* s) - { - #if defined(jin_debug) - Loghelper::log(Loglevel::LV_INFO, "Init AudioManager System"); - #endif - - if (SDL_Init(SDL_INIT_AUDIO) < 0) - return false; - - SDL_AudioSpec spec; - Setting* setting = (Setting*)s; - if (setting == nullptr) - return false; - - unsigned int samplerate = setting->samplerate; - unsigned int samples = clamp<int>(setting->samples, 1, setting->samplerate); - - spec.freq = samplerate; // ÿsample,õ 11025, 22050, 44100 and 48000 Hz. - spec.format = AUDIO_S16SYS; // signed 16-bit samples in native byte order - spec.channels = SDLAUDIO_CHANNELS; // - spec.samples = samples; // ÿβʱһã=setting->samplerateÿֻ1 - spec.userdata = this; - spec.callback = defaultCallback; - - audioDevice = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0); - if (audioDevice == 0) - return false; - /* start audio */ - SDL_PauseAudioDevice(audioDevice, 0); - return true; - } - - /*call only once*/ void SDLAudio::quitSystem() - { - SDL_CloseAudio(); - } - - void SDLAudio::lock() - { - SDL_LockAudioDevice(audioDevice); - } - - void SDLAudio::unlock() - { - SDL_UnlockAudioDevice(audioDevice); - } - - bool SDLAudio::goOnProcess() - { - if (state == SDLAudio::State::STOP) - { - SDLSourceManager::get()->removeAllSource(); - pause(); - return false; - } - else if (state == SDLAudio::State::PAUSE) - return false; - else - return true; - } - - void SDLAudio::processCommands() - { - SDLSourceManager::get()->processCommands(); - } - - void SDLAudio::processSources(void* buffer, size_t len) - { - SDLSourceManager::get()->processSources(buffer, len); - } - - void SDLAudio::processBuffer(void* buff, size_t len) - { - short* buffer = (short*)buff; - int samples = (len / SDLAUDIO_BYTEDEPTH) >> 1; // ˫ - const char L = 0, R = 1; - for (int i = 0; i < samples; ++i) - { - short* clip = buffer + (i << 1); - clip[L] *= volume; - clip[R] *= volume; - } - } - - void SDLAudio::play() - { - state = State::PLAY; - } - - void SDLAudio::stop() - { - state = State::STOP; - } - - void SDLAudio::pause() - { - state = State::PAUSE; - } - - void SDLAudio::resume() - { - state = State::PLAY; - } - - void SDLAudio::setVolume(float volume) - { - this->volume = clamp(volume, 0.0f, 1.0f); - } - + namespace SDL + { + + /* עcallbackƵ̵߳ */ + static void defaultCallback(void *userdata, Uint8 *stream, int size) + { + static SDLAudio* audio = static_cast<SDLAudio*>(userdata); + if (!audio->goOnProcess()) + return; + audio->lock(); + audio->processCommands(); + audio->processSources(stream, size); + audio->processBuffer(stream, size); + audio->unlock(); + } + + /*call only once*/ bool SDLAudio::initSystem(const SettingBase* s) + { + jin_log_info("Initialize audio system."); + + if (SDL_Init(SDL_INIT_AUDIO) < 0) + return false; + + SDL_AudioSpec spec; + Setting* setting = (Setting*)s; + if (setting == nullptr) + return false; + + unsigned int samplerate = setting->samplerate; + unsigned int samples = clamp<int>(setting->samples, 1, setting->samplerate); + + spec.freq = samplerate; // ÿsample,õ 11025, 22050, 44100 and 48000 Hz. + spec.format = AUDIO_S16SYS; // signed 16-bit samples in native byte order + spec.channels = SDLAUDIO_CHANNELS; // + spec.samples = samples; // ÿβʱһã=setting->samplerateÿֻ1 + spec.userdata = this; + spec.callback = defaultCallback; + + audioDevice = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0); + if (audioDevice == 0) + return false; + /* start audio */ + SDL_PauseAudioDevice(audioDevice, 0); + return true; + } + + /*call only once*/ void SDLAudio::quitSystem() + { + jin_log_info("Quit audio system."); + SDL_CloseAudio(); + } + + void SDLAudio::lock() + { + SDL_LockAudioDevice(audioDevice); + } + + void SDLAudio::unlock() + { + SDL_UnlockAudioDevice(audioDevice); + } + + bool SDLAudio::goOnProcess() + { + if (state == SDLAudio::State::STOP) + { + SDLSourceManager::get()->removeAllSource(); + pause(); + return false; + } + else if (state == SDLAudio::State::PAUSE) + return false; + else + return true; + } + + void SDLAudio::processCommands() + { + SDLSourceManager::get()->processCommands(); + } + + void SDLAudio::processSources(void* buffer, size_t len) + { + SDLSourceManager::get()->processSources(buffer, len); + } + + void SDLAudio::processBuffer(void* buff, size_t len) + { + short* buffer = (short*)buff; + int samples = (len / SDLAUDIO_BYTEDEPTH) >> 1; // ˫ + const char L = 0, R = 1; + for (int i = 0; i < samples; ++i) + { + short* clip = buffer + (i << 1); + clip[L] *= volume; + clip[R] *= volume; + } + } + + void SDLAudio::play() + { + state = State::PLAY; + } + + void SDLAudio::stop() + { + state = State::STOP; + } + + void SDLAudio::pause() + { + state = State::PAUSE; + } + + void SDLAudio::resume() + { + state = State::PLAY; + } + + void SDLAudio::setVolume(float volume) + { + this->volume = clamp(volume, 0.0f, 1.0f); + } + + } // namespace SDL } // namespace Audio } // namespace JinEngine diff --git a/src/libjin/Audio/SDL/je_sdl_audio.h b/src/libjin/Audio/SDL/je_sdl_audio.h index 57fee5b..1b12ac1 100644 --- a/src/libjin/Audio/SDL/je_sdl_audio.h +++ b/src/libjin/Audio/SDL/je_sdl_audio.h @@ -13,120 +13,123 @@ namespace JinEngine { namespace Audio { - - #define SDLAUDIO_BITDEPTH 16 - #define SDLAUDIO_BYTEDEPTH (SDLAUDIO_BITDEPTH >> 3) - #define SDLAUDIO_CHANNELS 2 - - /// - /// Audio system SDL implementation. - /// - class SDLAudio : public AudioManager<SDLAudio> - { - public: - /// - /// SDL audio setting. - /// - struct Setting : SettingBase - { - public: - int samplerate; // Ƶ - int samples; // sample<=samplerate - }; - - /// - /// Play all sources whose state is playing. - /// - void play() override; - - /// - /// Stop and remove all sources from the queue. - /// - void stop() override; - - /// - /// Pause audio. - /// - void pause() override; - - /// - /// Resume audio. - /// - void resume() override; - - /// - /// Set global audio volume. - /// - void setVolume(float volume) override; - - /// - /// Process all commands in the queue. - /// - void processCommands(); - - /// - /// Process all sources. - /// - /// @param buffer Source buffer. - /// @param len Source length. - /// - void processSources(void* buffer, size_t len); - - /// - /// Process audio buffer. - /// - /// @param buffer Audio stream buffer. - /// @param len Length of stream buffer. - /// - void processBuffer(void* buffer, size_t len); - - /// - /// Goon process. - /// - /// @return True if sucessful, otherwise return false. - /// - bool goOnProcess(); - - /// - /// Lock audio device. - /// - void lock(); - - /// - /// Unlock audio device. - /// - void unlock(); - - private: - singleton(SDLAudio); - - /// - /// SDL audio constructor. - /// - SDLAudio() {}; - - /// - /// SDL audio destructor. - /// - ~SDLAudio() {}; - - /// - /// Initialize audio system. - /// - /// @param setting Audio setting. - /// - bool initSystem(const SettingBase* setting) override; - - /// - /// Quit audio system. - /// - void quitSystem() override; - - // Audio device id. - unsigned int audioDevice; - - }; - + namespace SDL + { + +#define SDLAUDIO_BITDEPTH 16 +#define SDLAUDIO_BYTEDEPTH (SDLAUDIO_BITDEPTH >> 3) +#define SDLAUDIO_CHANNELS 2 + + /// + /// Audio system SDL implementation. + /// + class SDLAudio : public AudioManager<SDLAudio> + { + public: + /// + /// SDL audio setting. + /// + struct Setting : SettingBase + { + public: + int samplerate; // Ƶ + int samples; // sample<=samplerate + }; + + /// + /// Play all sources whose state is playing. + /// + void play() override; + + /// + /// Stop and remove all sources from the queue. + /// + void stop() override; + + /// + /// Pause audio. + /// + void pause() override; + + /// + /// Resume audio. + /// + void resume() override; + + /// + /// Set global audio volume. + /// + void setVolume(float volume) override; + + /// + /// Process all commands in the queue. + /// + void processCommands(); + + /// + /// Process all sources. + /// + /// @param buffer Source buffer. + /// @param len Source length. + /// + void processSources(void* buffer, size_t len); + + /// + /// Process audio buffer. + /// + /// @param buffer Audio stream buffer. + /// @param len Length of stream buffer. + /// + void processBuffer(void* buffer, size_t len); + + /// + /// Goon process. + /// + /// @return True if sucessful, otherwise return false. + /// + bool goOnProcess(); + + /// + /// Lock audio device. + /// + void lock(); + + /// + /// Unlock audio device. + /// + void unlock(); + + private: + singleton(SDLAudio); + + /// + /// SDL audio constructor. + /// + SDLAudio() {}; + + /// + /// SDL audio destructor. + /// + ~SDLAudio() {}; + + /// + /// Initialize audio system. + /// + /// @param setting Audio setting. + /// + bool initSystem(const SettingBase* setting) override; + + /// + /// Quit audio system. + /// + void quitSystem() override; + + // Audio device id. + unsigned int audioDevice; + + }; + + } // namespace SDL } // namespace Audio } // namespace JinEngine diff --git a/src/libjin/Audio/SDL/je_sdl_source.cpp b/src/libjin/Audio/SDL/je_sdl_source.cpp index 9e09e61..207aa86 100644 --- a/src/libjin/Audio/SDL/je_sdl_source.cpp +++ b/src/libjin/Audio/SDL/je_sdl_source.cpp @@ -15,160 +15,163 @@ #include "je_sdl_audio.h" #include "je_sdl_source.h" +using namespace JinEngine::Math; + namespace JinEngine { namespace Audio { - - using namespace JinEngine::Math; - - #define BITS 8 - - typedef struct SDLSourceCommand - { - typedef enum Action - { - Nothing = 0, - Play, - Stop, - Pause, - Resume, - Rewind, - SetVolume, - SetLoop, - SetRate, - }; - Action action; - union { - int _integer; - float _float; - bool _boolean; - const char* _string; - } parameter; - - SDLSource* source; - }; - - typedef enum CHANNEL - { - MONO = 1, // - STEREO = 2, // - }; - - typedef /*mask*/ enum STATUS - { - PLAYING = 1, - PAUSED = 2, - STOPPED = 4 - }; - - #define Command SDLSourceCommand - #define Action Command::Action - #define Manager SDLSourceManager - - ///*class member*/ std::queue<Command*> Manager::commands; - ///*class member*/ std::stack<Command*> Manager::commandsPool; - ///*class member*/ std::vector<SDLSource*> Manager::sources; - /*class member*/ Manager* Manager::manager = nullptr; - - SDLSource* SDLSource::createSource(const char* file) - { - std::ifstream fs; - fs.open(file, std::ios::binary); - if (!fs.is_open()) - { - fs.close(); - return nullptr; - } - fs.seekg(0,std::ios::end); - int size = fs.tellg(); - fs.seekg(0, std::ios::beg); - char* buffer = (char*)malloc(size); - memset(buffer, 0, size); - fs.read(buffer, size); - fs.close(); - SDLSource* source = createSource(buffer, size); - free(buffer); - return source; - } - - SDLSource* SDLSource::createSource(void* mem, size_t size) - { - if (mem == nullptr) - return nullptr; - SDLSource* source = new SDLSource(); - try - { - SourceType format = getType(mem, size); - switch (format) - { - case OGG: source->decode_ogg(mem, size); break; - case WAV: source->decode_wav(mem, size); break; - } - } - catch (SourceException& exp) - { - delete source; - return nullptr; - }; - return source; - } - - SDLSource::SDLSource() - { - memset(&status, 0, sizeof(status)); - memset(&raw, 0, sizeof(raw)); - status.volume = 1; - } - - SDLSource::~SDLSource() - { - delete raw.data; - raw.end = 0; - raw.data = 0; - } - - void SDLSource::decode_wav(void* mem, int size) - { - wav_t wav; - if (wav_read(&wav, mem, size) == 0) - { - raw.data = wav.data; - raw.length = wav.length * wav.channels * wav.bitdepth / 8; - raw.channels = clamp<int>(wav.channels, CHANNEL::MONO, CHANNEL::STEREO); - raw.end = (char*)raw.data + raw.length; - raw.samplerate = wav.samplerate; - raw.bitdepth = wav.bitdepth; - raw.samples = wav.length; - } - else - throw SourceException(); - } - - void SDLSource::decode_ogg(void* _mem, int size) - { - unsigned char* mem = (unsigned char*)_mem; - int channels; - int samplerate; - short* data = (short*)raw.data; - int samples = stb_vorbis_decode_memory( - mem, - size, - &channels, - &samplerate, - &data - ); - const int bitdepth = sizeof(short) * BITS; - raw.channels = channels; - raw.samplerate = samplerate; - raw.data = data; - raw.samples = samples; // һsample - raw.length = samples * channels * sizeof(short); // һsample - raw.bitdepth = bitdepth; - raw.end = (char*)data + raw.length; - } - - #define ActionNone(T)\ + namespace SDL + { + + +#define BITS 8 + + typedef struct SDLSourceCommand + { + typedef enum Action + { + Nothing = 0, + Play, + Stop, + Pause, + Resume, + Rewind, + SetVolume, + SetLoop, + SetRate, + }; + Action action; + union { + int _integer; + float _float; + bool _boolean; + const char* _string; + } parameter; + + SDLSource* source; + }; + + typedef enum CHANNEL + { + MONO = 1, // + STEREO = 2, // + }; + + typedef /*mask*/ enum STATUS + { + PLAYING = 1, + PAUSED = 2, + STOPPED = 4 + }; + +#define Command SDLSourceCommand +#define Action Command::Action +#define Manager SDLSourceManager + + ///*class member*/ std::queue<Command*> Manager::commands; + ///*class member*/ std::stack<Command*> Manager::commandsPool; + ///*class member*/ std::vector<SDLSource*> Manager::sources; + /*class member*/ Manager* Manager::manager = nullptr; + + SDLSource* SDLSource::createSource(const char* file) + { + std::ifstream fs; + fs.open(file, std::ios::binary); + if (!fs.is_open()) + { + fs.close(); + return nullptr; + } + fs.seekg(0, std::ios::end); + int size = fs.tellg(); + fs.seekg(0, std::ios::beg); + char* buffer = (char*)malloc(size); + memset(buffer, 0, size); + fs.read(buffer, size); + fs.close(); + SDLSource* source = createSource(buffer, size); + free(buffer); + return source; + } + + SDLSource* SDLSource::createSource(void* mem, size_t size) + { + if (mem == nullptr) + return nullptr; + SDLSource* source = new SDLSource(); + try + { + SourceType format = getType(mem, size); + switch (format) + { + case OGG: source->decode_ogg(mem, size); break; + case WAV: source->decode_wav(mem, size); break; + } + } + catch (SourceException& exp) + { + delete source; + return nullptr; + }; + return source; + } + + SDLSource::SDLSource() + { + memset(&status, 0, sizeof(status)); + memset(&raw, 0, sizeof(raw)); + status.volume = 1; + } + + SDLSource::~SDLSource() + { + delete raw.data; + raw.end = 0; + raw.data = 0; + } + + void SDLSource::decode_wav(void* mem, int size) + { + wav_t wav; + if (wav_read(&wav, mem, size) == 0) + { + raw.data = wav.data; + raw.length = wav.length * wav.channels * wav.bitdepth / 8; + raw.channels = clamp<int>(wav.channels, CHANNEL::MONO, CHANNEL::STEREO); + raw.end = (char*)raw.data + raw.length; + raw.samplerate = wav.samplerate; + raw.bitdepth = wav.bitdepth; + raw.samples = wav.length; + } + else + throw SourceException(); + } + + void SDLSource::decode_ogg(void* _mem, int size) + { + unsigned char* mem = (unsigned char*)_mem; + int channels; + int samplerate; + short* data = (short*)raw.data; + int samples = stb_vorbis_decode_memory( + mem, + size, + &channels, + &samplerate, + &data + ); + const int bitdepth = sizeof(short) * BITS; + raw.channels = channels; + raw.samplerate = samplerate; + raw.data = data; + raw.samples = samples; // һsample + raw.length = samples * channels * sizeof(short); // һsample + raw.bitdepth = bitdepth; + raw.end = (char*)data + raw.length; + } + +#define ActionNone(T)\ do{\ Command* cmd = Manager::get()->getCommand();\ cmd->action = Action::T; \ @@ -176,7 +179,7 @@ namespace JinEngine Manager::get()->pushCommand(cmd); \ } while (0) - #define ActionArg(T, ARGT, ARG)\ +#define ActionArg(T, ARGT, ARG)\ do{\ Command* cmd = Manager::get()->getCommand();\ cmd->action = Action::T; \ @@ -185,217 +188,217 @@ namespace JinEngine Manager::get()->pushCommand(cmd); \ }while(0) - #define ActionInt(T, INT) ActionArg(T, _integer, INT) - #define ActionFloat(T, FLT) ActionArg(T, _float, FLT) - #define ActionString(T, STR) ActionArg(T, _string, STR) - #define ActionBool(T, BOL) ActionArg(T, _boolean, BOL) - - void SDLSource::play() - { - ActionNone(Play); - } - - void SDLSource::stop() - { - ActionNone(Stop); - } - - void SDLSource::pause() - { - ActionNone(Pause); - } - - void SDLSource::resume() - { - ActionNone(Resume); - } - - void SDLSource::rewind() - { - ActionNone(Rewind); - } - - inline bool SDLSource::isStopped() const - { - return is(STOPPED); - } - - bool SDLSource::isPaused() const - { - return is(PAUSED); - } - - void SDLSource::setPitch(float pitch) - { - } - - void SDLSource::setVolume(float volume) - { - ActionFloat(SetVolume, clamp(volume, 0.0f, 1.0f)); - } - - void SDLSource::setLoop(bool loop) - { - ActionBool(SetLoop, loop); - } - - void SDLSource::setRate(float rate) - { - ActionFloat(SetRate, rate); - } - - inline void SDLSource::handle( - SDLSourceManager* manager, - SDLSourceCommand* cmd - ) - { - switch (cmd->action) - { - case Command::Action::Play: - manager->removeSource(this); - manager->pushSource(this); - status.state = PLAYING; - status.pos = 0; // rewind - break; - case Command::Action::Stop: - manager->removeSource(this); - status.state = STOPPED; - status.pos = 0; // rewind - break; - case Command::Action::Pause: - manager->removeSource(this); - status.state = PAUSED; - break; - case Command::Action::Resume: - manager->removeSource(this); - manager->pushSource(this); - status.state = PLAYING; - break; - case Command::Action::Rewind: - status.state = PLAYING; - status.pos = 0; - break; - case Command::Action::SetVolume: - status.volume = cmd->parameter._float; - break; - case Command::Action::SetLoop: - status.loop = cmd->parameter._boolean; - break; - } - } - - inline void SDLSource::process(void* buf, size_t size) - { - short* buffer = (short*)buf; // AUDIO_S16SYS - int samples = (size / SDLAUDIO_BYTEDEPTH) >> 1; // ˫ - const char L = 0, R = 1; - for (int i = 0; i < samples; ++i) - { - char* source = (char*)raw.data + status.pos * (raw.bitdepth / 8) * raw.channels; - short l = 0; - short r = 0; - if (raw.bitdepth == 16) - { - l = ((short*)source)[L] * status.volume; - r = ((short*)source)[L + raw.channels - 1] * status.volume; - } - else if (raw.bitdepth == 8) - { - l = source[L] << 8; // << 8 Ŵ16bits - r = source[L + raw.channels - 1] << 8; - } - short* sample = buffer + (i << 1); - sample[L] = clamp(sample[L] + l, SHRT_MIN, SHRT_MAX); // - sample[R] = clamp(sample[R] + r, SHRT_MIN, SHRT_MAX); // - ++status.pos; - if (status.pos > raw.samples && status.loop) - status.pos = 0; // rewind - else if (status.pos > raw.samples && !status.loop) - break; - } - } - - Manager* Manager::get() - { - return (manager == nullptr ? manager = new Manager() : manager); - } - - void Manager::processCommands() - { - Command* cmd = nullptr; - SDLSource* source = nullptr; - while (!commands.empty()) - { - cmd = commands.front(); - if (cmd != nullptr) - { - source = cmd->source; - if (source != nullptr) - source->handle(manager, cmd); - } - commands.pop(); - } - } - - /* AUDIO_S16SYS[size>>1] buffer */ - void Manager::processSources(void* buf, size_t size) - { - /* clear render buffer */ - memset(buf, 0, size); - SDLSource* src = nullptr; - std::vector<SDLSource*>::iterator it = sources.begin(); - for (; it != sources.end();) - { - src = *it; - if (src != nullptr) - src->process(buf, size); - ++it; - } - } - - void Manager::removeSource(SDLSource* source) - { - std::vector<SDLSource*>::iterator it = sources.begin(); - for (it = sources.begin(); it != sources.end(); ) - { - if (*it == source) - { - it = sources.erase(it); - return; - } - ++it; - } - } - - void Manager::removeAllSource() - { - sources.clear(); - } - - void Manager::pushSource(SDLSource* source) - { - if(source != nullptr) - sources.push_back(source); - } - - void Manager::pushCommand(SDLSourceCommand* cmd) - { - commands.push(cmd); - } - - Command* Manager::getCommand() - { - if (!commandsPool.empty()) - { - Command* cmd = commandsPool.top(); - commandsPool.pop(); - return cmd; - } - return new Command(); - } - - +#define ActionInt(T, INT) ActionArg(T, _integer, INT) +#define ActionFloat(T, FLT) ActionArg(T, _float, FLT) +#define ActionString(T, STR) ActionArg(T, _string, STR) +#define ActionBool(T, BOL) ActionArg(T, _boolean, BOL) + + void SDLSource::play() + { + ActionNone(Play); + } + + void SDLSource::stop() + { + ActionNone(Stop); + } + + void SDLSource::pause() + { + ActionNone(Pause); + } + + void SDLSource::resume() + { + ActionNone(Resume); + } + + void SDLSource::rewind() + { + ActionNone(Rewind); + } + + inline bool SDLSource::isStopped() const + { + return is(STOPPED); + } + + bool SDLSource::isPaused() const + { + return is(PAUSED); + } + + void SDLSource::setPitch(float pitch) + { + } + + void SDLSource::setVolume(float volume) + { + ActionFloat(SetVolume, clamp(volume, 0.0f, 1.0f)); + } + + void SDLSource::setLoop(bool loop) + { + ActionBool(SetLoop, loop); + } + + void SDLSource::setRate(float rate) + { + ActionFloat(SetRate, rate); + } + + inline void SDLSource::handle( + SDLSourceManager* manager, + SDLSourceCommand* cmd + ) + { + switch (cmd->action) + { + case Command::Action::Play: + manager->removeSource(this); + manager->pushSource(this); + status.state = PLAYING; + status.pos = 0; // rewind + break; + case Command::Action::Stop: + manager->removeSource(this); + status.state = STOPPED; + status.pos = 0; // rewind + break; + case Command::Action::Pause: + manager->removeSource(this); + status.state = PAUSED; + break; + case Command::Action::Resume: + manager->removeSource(this); + manager->pushSource(this); + status.state = PLAYING; + break; + case Command::Action::Rewind: + status.state = PLAYING; + status.pos = 0; + break; + case Command::Action::SetVolume: + status.volume = cmd->parameter._float; + break; + case Command::Action::SetLoop: + status.loop = cmd->parameter._boolean; + break; + } + } + + inline void SDLSource::process(void* buf, size_t size) + { + short* buffer = (short*)buf; // AUDIO_S16SYS + int samples = (size / SDLAUDIO_BYTEDEPTH) >> 1; // ˫ + const char L = 0, R = 1; + for (int i = 0; i < samples; ++i) + { + char* source = (char*)raw.data + status.pos * (raw.bitdepth / 8) * raw.channels; + short l = 0; + short r = 0; + if (raw.bitdepth == 16) + { + l = ((short*)source)[L] * status.volume; + r = ((short*)source)[L + raw.channels - 1] * status.volume; + } + else if (raw.bitdepth == 8) + { + l = source[L] << 8; // << 8 Ŵ16bits + r = source[L + raw.channels - 1] << 8; + } + short* sample = buffer + (i << 1); + sample[L] = clamp(sample[L] + l, SHRT_MIN, SHRT_MAX); // + sample[R] = clamp(sample[R] + r, SHRT_MIN, SHRT_MAX); // + ++status.pos; + if (status.pos > raw.samples && status.loop) + status.pos = 0; // rewind + else if (status.pos > raw.samples && !status.loop) + break; + } + } + + Manager* Manager::get() + { + return (manager == nullptr ? manager = new Manager() : manager); + } + + void Manager::processCommands() + { + Command* cmd = nullptr; + SDLSource* source = nullptr; + while (!commands.empty()) + { + cmd = commands.front(); + if (cmd != nullptr) + { + source = cmd->source; + if (source != nullptr) + source->handle(manager, cmd); + } + commands.pop(); + } + } + + /* AUDIO_S16SYS[size>>1] buffer */ + void Manager::processSources(void* buf, size_t size) + { + /* clear render buffer */ + memset(buf, 0, size); + SDLSource* src = nullptr; + std::vector<SDLSource*>::iterator it = sources.begin(); + for (; it != sources.end();) + { + src = *it; + if (src != nullptr) + src->process(buf, size); + ++it; + } + } + + void Manager::removeSource(SDLSource* source) + { + std::vector<SDLSource*>::iterator it = sources.begin(); + for (it = sources.begin(); it != sources.end(); ) + { + if (*it == source) + { + it = sources.erase(it); + return; + } + ++it; + } + } + + void Manager::removeAllSource() + { + sources.clear(); + } + + void Manager::pushSource(SDLSource* source) + { + if (source != nullptr) + sources.push_back(source); + } + + void Manager::pushCommand(SDLSourceCommand* cmd) + { + commands.push(cmd); + } + + Command* Manager::getCommand() + { + if (!commandsPool.empty()) + { + Command* cmd = commandsPool.top(); + commandsPool.pop(); + return cmd; + } + return new Command(); + } + + } // namespace SDL } // namespace Audio } // namespace JinEngine -#endif // (jin_audio) && (jin_audio == jin_audio_sdl) +#endif // (jin_audio) && (jin_audio == jin_audio_sdl)
\ No newline at end of file diff --git a/src/libjin/Audio/SDL/je_sdl_source.h b/src/libjin/Audio/SDL/je_sdl_source.h index 78cae80..42ac255 100644 --- a/src/libjin/Audio/SDL/je_sdl_source.h +++ b/src/libjin/Audio/SDL/je_sdl_source.h @@ -14,253 +14,256 @@ namespace JinEngine { namespace Audio { + namespace SDL + { - typedef struct SDLSourceCommand; + typedef struct SDLSourceCommand; - class SDLSourceManager; + class SDLSourceManager; - /// - /// Audio source SDL implementation. - /// - class SDLSource : public Source - { - public: /// - /// Create source from raw source data file. + /// Audio source SDL implementation. /// - /// @param file Audio source file. - /// @return Return source if create successful, otherwise return null. - /// - static SDLSource* createSource(const char* file); - - /// - /// Create source from raw source data. - /// - /// @param mem Source data. - /// @param size Source data size. - /// @return Return source if create successful, otherwise return null. - /// - static SDLSource* createSource(void* mem, size_t size); - - /// - /// Source destructor. - /// - ~SDLSource(); - - /// - /// Play source. - /// - void play() override; - - /// - /// Stop source. - /// - void stop() override; - - /// - /// Pause source. - /// - void pause() override; - - /// - /// Resume source. - /// - void resume() override; - - /// - /// Rewind source. - /// - void rewind() override; - - /// - /// Return if the source is stopped. - /// - /// @return True if the source is stopped, otherwise return false. - /// - bool isStopped() const override; - - /// - /// Return if the source is paused. - /// - /// @return True if the source is paused(, otherwise return false. - /// - bool isPaused() const override; - - /// - /// Set pitch. - /// - /// @param pitch Pitch of source. - /// - void setPitch(float pitch) override; - - /// - /// Set volume. - /// - /// @param volume Volume of source. - /// - void setVolume(float volume) override; - - /// - /// Set source loop. - /// - /// @param loop Looping or not. - /// - void setLoop(bool loop) override; - - /// - /// Set source rate. - /// - /// @param rate Rate of source. - /// - void setRate(float rate) override; - - /// - /// Handle a specific command. - /// - /// @param manager Audio manager. - /// @param cmd Source commad. - /// - inline void handle(SDLSourceManager* manager, SDLSourceCommand* cmd); - - /// - /// Process decoded source data. - /// - /// @param buffer Source data. - /// @param size Data size. - /// - inline void process(void* buffer, size_t size); - - protected: - /// - /// Source constructor. - /// - SDLSource(); - - /// - /// Decode wav file. - /// - /// @param mem Wav file data. - /// @param size Wav data size. - /// - void decode_wav(void* mem, int size); + class SDLSource : public Source + { + public: + /// + /// Create source from raw source data file. + /// + /// @param file Audio source file. + /// @return Return source if create successful, otherwise return null. + /// + static SDLSource* createSource(const char* file); + + /// + /// Create source from raw source data. + /// + /// @param mem Source data. + /// @param size Source data size. + /// @return Return source if create successful, otherwise return null. + /// + static SDLSource* createSource(void* mem, size_t size); + + /// + /// Source destructor. + /// + ~SDLSource(); + + /// + /// Play source. + /// + void play() override; + + /// + /// Stop source. + /// + void stop() override; + + /// + /// Pause source. + /// + void pause() override; + + /// + /// Resume source. + /// + void resume() override; + + /// + /// Rewind source. + /// + void rewind() override; + + /// + /// Return if the source is stopped. + /// + /// @return True if the source is stopped, otherwise return false. + /// + bool isStopped() const override; + + /// + /// Return if the source is paused. + /// + /// @return True if the source is paused(, otherwise return false. + /// + bool isPaused() const override; + + /// + /// Set pitch. + /// + /// @param pitch Pitch of source. + /// + void setPitch(float pitch) override; + + /// + /// Set volume. + /// + /// @param volume Volume of source. + /// + void setVolume(float volume) override; + + /// + /// Set source loop. + /// + /// @param loop Looping or not. + /// + void setLoop(bool loop) override; + + /// + /// Set source rate. + /// + /// @param rate Rate of source. + /// + void setRate(float rate) override; + + /// + /// Handle a specific command. + /// + /// @param manager Audio manager. + /// @param cmd Source commad. + /// + inline void handle(SDLSourceManager* manager, SDLSourceCommand* cmd); + + /// + /// Process decoded source data. + /// + /// @param buffer Source data. + /// @param size Data size. + /// + inline void process(void* buffer, size_t size); + + protected: + /// + /// Source constructor. + /// + SDLSource(); + + /// + /// Decode wav file. + /// + /// @param mem Wav file data. + /// @param size Wav data size. + /// + void decode_wav(void* mem, int size); + + /// + /// Decode ogg file. + /// + /// @param mem ogg file data. + /// @param size ogg data size. + /// + void decode_ogg(void* mem, int size); + + /// + /// Check source state. + /// + /// @param state State to be checked. + /// @return True if state is given state, otherwise return false. + /// + inline bool is(int state) const + { + return (status.state & state) == state; + } + + // Source data. + struct { + const void* data; // Ƶ + int length; // dataֽڳ + const void* end; // dataβ = (unsigned char*)data + size + int samplerate; // Ƶ + unsigned char bitdepth; // ÿsampleıس + int samples; // sample = size / (bitdepth / 8) + unsigned char channels; // channel1(mono)2(stereo) + } raw; + // Procedure controller variable. + struct { + int pos; // ǰŵsample + int pitch; // pitch + int state; // ǰ״̬ + bool loop; // loop or not + float volume; // + } status; + + }; /// - /// Decode ogg file. - /// - /// @param mem ogg file data. - /// @param size ogg data size. + /// Source manager. /// - void decode_ogg(void* mem, int size); - - /// - /// Check source state. - /// - /// @param state State to be checked. - /// @return True if state is given state, otherwise return false. - /// - inline bool is(int state) const - { - return (status.state & state) == state; - } - - // Source data. - struct{ - const void* data; // Ƶ - int length; // dataֽڳ - const void* end; // dataβ = (unsigned char*)data + size - int samplerate; // Ƶ - unsigned char bitdepth; // ÿsampleıس - int samples; // sample = size / (bitdepth / 8) - unsigned char channels; // channel1(mono)2(stereo) - } raw; - // Procedure controller variable. - struct{ - int pos; // ǰŵsample - int pitch; // pitch - int state; // ǰ״̬ - bool loop; // loop or not - float volume; // - } status; - - }; - - /// - /// Source manager. - /// - class SDLSourceManager - { - public: - /// - /// Get manager singleton. - /// - /// @return Singleton of SDL source manager. - /// - static SDLSourceManager* get(); - - /// - /// Process commands. - /// - void processCommands(); - - /// - /// Process sources. - /// - /// @param buffer Source data. - /// @param size Size of source data. - /// - void processSources(void* buffer, size_t size); - - /// - /// Clear source queue. - /// - /// This function will stop all sources. - /// - void removeAllSource(); - - /// - /// Remove specific source. - /// - /// @param source SDL audio source. - /// - void removeSource(SDLSource* source); - - /// - /// Push specific source into queue. - /// - /// @param source SDL audio source. - /// - void pushSource(SDLSource* source); - - /// - /// Get command from queue. - /// - /// @return Command at first place. - /// - SDLSourceCommand* getCommand(); - - /// - /// Push command. - /// - /// @param cmd Spcific command. - /// - void pushCommand(SDLSourceCommand* cmd); - - private: - std::queue<SDLSourceCommand*> commands; - std::stack<SDLSourceCommand*> commandsPool; - std::vector<SDLSource*> sources; // processing sources - static SDLSourceManager* manager; - - }; - - class SourceException : public std::exception - { - const char* what() const throw () - { - return "Load Source Exception"; - } - }; - + class SDLSourceManager + { + public: + /// + /// Get manager singleton. + /// + /// @return Singleton of SDL source manager. + /// + static SDLSourceManager* get(); + + /// + /// Process commands. + /// + void processCommands(); + + /// + /// Process sources. + /// + /// @param buffer Source data. + /// @param size Size of source data. + /// + void processSources(void* buffer, size_t size); + + /// + /// Clear source queue. + /// + /// This function will stop all sources. + /// + void removeAllSource(); + + /// + /// Remove specific source. + /// + /// @param source SDL audio source. + /// + void removeSource(SDLSource* source); + + /// + /// Push specific source into queue. + /// + /// @param source SDL audio source. + /// + void pushSource(SDLSource* source); + + /// + /// Get command from queue. + /// + /// @return Command at first place. + /// + SDLSourceCommand* getCommand(); + + /// + /// Push command. + /// + /// @param cmd Spcific command. + /// + void pushCommand(SDLSourceCommand* cmd); + + private: + std::queue<SDLSourceCommand*> commands; + std::stack<SDLSourceCommand*> commandsPool; + std::vector<SDLSource*> sources; // processing sources + static SDLSourceManager* manager; + + }; + + class SourceException : public std::exception + { + const char* what() const throw () + { + return "Load Source Exception"; + } + }; + + } // namespace SDL } // namespace Audio } // namespace JinEngine diff --git a/src/libjin/Core/je_configuration.h b/src/libjin/Core/je_configuration.h index d96d5b9..065fbae 100644 --- a/src/libjin/Core/je_configuration.h +++ b/src/libjin/Core/je_configuration.h @@ -6,7 +6,7 @@ /// /// Debug output /// -//#define jin_debug +#define jin_debug #define jin_os_windows 0x01 #define jin_os_mac 0x02 diff --git a/src/libjin/Graphics/Font/je_decoder.cpp b/src/libjin/Graphics/Font/je_decoder.cpp deleted file mode 100644 index 01e1990..0000000 --- a/src/libjin/Graphics/Font/je_decoder.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include "je_decoder.h" - -namespace JinEngine -{ - namespace Graphics - { - - /* utf8 byte string to unicode codepoint */ - static const char *utf8toCodepoint(const char *p, unsigned *res) { - return nullptr; - - } - - ///////////////////////////////////////////////////////////////////////////// - // decoders - ///////////////////////////////////////////////////////////////////////////// - - const void* Utf8::decode(const void* data, Codepoint* res) const - { - const char* p = (char*)data; - unsigned x, mask, shift; - switch (*p & 0xf0) { - case 0xf0: mask = 0x07; shift = 18; break; - case 0xe0: mask = 0x0f; shift = 12; break; - case 0xc0: - case 0xd0: mask = 0x1f; shift = 6; break; - default: - *res = *p; - return p + 1; - } - x = (*p & mask) << shift; - do { - if (*(++p) == '\0') { - *res = x; - return p; - } - shift -= 6; - x |= (*p & 0x3f) << shift; - } while (shift); - *res = x; - return p + 1; - } - - const void* Utf8::next(const void* data) const - { - const char* p = (char*)data; - unsigned x, mask, shift; - switch (*p & 0xf0) { - case 0xf0: mask = 0x07; shift = 18; break; - case 0xe0: mask = 0x0f; shift = 12; break; - case 0xc0: - case 0xd0: mask = 0x1f; shift = 6; break; - default: - return p + 1; - } - x = (*p & mask) << shift; - do { - if (*(++p) == '\0') { - return p; - } - shift -= 6; - x |= (*p & 0x3f) << shift; - } while (shift); - return p + 1; - } - /* - const void* Utf16::decode(const void* data, Codepoint* res) const - { - return nullptr; - } - - const void* Utf16::next(const void* data) const - { - return nullptr; - } - */ - const void* Ascii::decode(const void* data, Codepoint* res) const - { - const char* p = (char*)data; - *res = *p; - return p + 1; - } - - const void* Ascii::next(const void* data) const - { - const char* p = (char*)data; - return p + 1; - } - - } // namespace Graphics -} // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_decoder.h b/src/libjin/Graphics/Font/je_decoder.h deleted file mode 100644 index 36cbda7..0000000 --- a/src/libjin/Graphics/Font/je_decoder.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef __JE_UTF8_H -#define __JE_UTF8_H - -#include <vector> - -#include "je_text.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Text decoder. - /// - class Decoder - { - public: - - /// - /// Decode a code unit. - /// - /// @param data Code units. - /// @param codepoint Value of code point. - /// @return Next code unit location. - /// - virtual const void* decode(const void* data, Codepoint* codepoint) const = 0 ; - - /// - /// Get next code unit location. - /// - /// @param data Code units. - /// @return Next code unit location. - /// - virtual const void* next(const void* data) const = 0; - - }; - - /// - /// Utf-8 decoder. - /// - class Utf8 : public Decoder - { - public: - - /// - /// Decode a code unit. - /// - /// @param data Code units. - /// @param codepoint Value of code point. - /// @return Next code unit location. - /// - const void* decode(const void* data, Codepoint* codepoint) const override; - - /// - /// Get next code unit location. - /// - /// @param data Code units. - /// @return Next code unit location. - /// - const void* next(const void* data) const override; - - }; - - /// - /// Ascii decoder. - /// - class Ascii : public Decoder - { - public: - - /// - /// Decode a code unit. - /// - /// @param data Code units. - /// @param codepoint Value of code point. - /// @return Next code unit location. - /// - const void* decode(const void* data, Codepoint* codepoint) const override; - - /// - /// Get next code unit location. - /// - /// @param data Code units. - /// @return Next code unit location. - /// - const void* next(const void* data) const override; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_font.h b/src/libjin/Graphics/Font/je_font.h deleted file mode 100644 index 42f83b6..0000000 --- a/src/libjin/Graphics/Font/je_font.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef __JE_FONT_H -#define __JE_FONT_H - -#include <vector> -#include "je_text.h" - -namespace JinEngine -{ - namespace Graphics - { - - struct Page; - - // - // Font - // |- TTF - // |- TextureFont - // - - /// - /// Base Font class. - /// - class Font - { - public: - /// - /// Font constructor. - /// - Font(unsigned fontsize) - : mFontSize(fontsize) - { - } - - /// - /// Font destructor. - /// - virtual ~Font() {}; - - /// - /// Create page with given text. - /// - /// @param text Text to be typesetted. - /// @param lineheight Line height of text. - /// @param spacing Spacing between characters. 0 by default. - /// @return Page if created successfully, otherwise return null. - /// - virtual Page* typeset(const Text& text, int lineheight, int spacing = 0) = 0; - - /// - /// Create page with given unicode codepoints. - /// - /// @param content Unicode codepoints to be typesetted. - /// @param lineheight Line height of text. - /// @param spacing Spacing between characters. 0 by default. - /// @return Page if created successfully, otherwise return null. - /// - virtual Page* typeset(const Content& content, int lineheight, int spacing = 0) = 0; - - /// - /// Render page to given position. - /// - /// @param page Page to be rendered. - /// @param x X value of the position. - /// @param y Y value of the position. - /// - virtual void render(const Page* page, int x, int y) = 0; - - /// - /// Render unicode codepoints to given position. - /// - /// @param content Unicode codepoints to be typesetted. - /// @param x X value of the position. - /// @param y Y value of the position. - /// @param lineheight Line height of the content. - /// @param spacing Spacing between characters. - /// - virtual void render(const Content& content, int x, int y, int lineheight, int spacing = 0) = 0; - - /// - /// Render text to given position. - /// - /// @param text Text to be rendered. - /// @param x X value of the position. - /// @param y Y value of the position. - /// @param lineheight Line height of the text. - /// @param spacing Spacing between characters. - /// - virtual void render(const Text& text, int x, int y, int lineheight, int spacing = 0) = 0; - - /// - /// Get font size. - /// - /// @return Font size. - /// - inline unsigned getFontSize() { return mFontSize; }; - - protected: - - unsigned mFontSize; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif // __JE_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_page.h b/src/libjin/Graphics/Font/je_page.h deleted file mode 100644 index fbc297e..0000000 --- a/src/libjin/Graphics/Font/je_page.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __JE_PAGE_H -#define __JE_PAGE_H - -#include "../../math/je_vector2.hpp" - -#include "je_font.h" - -namespace JinEngine -{ - namespace Graphics - { - - class Font; - - /// - /// Glyphs data to be rendered. - /// - struct GlyphVertex - { - int x, y; ///< screen coordinates - float u, v; ///< normalized texture uv - }; - - /// - /// Glyphs info for reducing draw call. - /// - struct GlyphArrayDrawInfo - { - GLuint texture; ///< atlas - unsigned int start; ///< glyph vertex indecies - unsigned int count; ///< glyph vertex count - }; - - /// - /// Page to be rendered. - /// - /// A page is a pre-rendered text struct for reducing draw call. Each page - /// keeps a font pointer which should not be changed. - /// - struct Page - { - Font* font; - std::vector<GlyphArrayDrawInfo> glyphinfolist; - std::vector<GlyphVertex> glyphvertices; - Math::Vector2<int> size; - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif // __JE_PAGE_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_text.cpp b/src/libjin/Graphics/Font/je_text.cpp deleted file mode 100644 index 75dfc7b..0000000 --- a/src/libjin/Graphics/Font/je_text.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include <cstring> - -#include "je_text.h" -#include "je_decoder.h" - -namespace JinEngine -{ - namespace Graphics - { - - ///////////////////////////////////////////////////////////////////////////// - // iterator - ///////////////////////////////////////////////////////////////////////////// - - Text::Iterator::Iterator(const Iterator& itor) - : data(itor.data) - , p(itor.p) - , encode(itor.encode) - , length(itor.length) - { - switch (encode) - { - case Encode::UTF8: decoder = new Utf8(); break; - case Encode::ASCII: decoder = new Ascii(); break; - } - } - - Text::Iterator::Iterator(const Encode& _encode, const void* _data, unsigned int _length) - : data(_data) - , p(_data) - , encode(_encode) - , length(_length) - { - switch (encode) - { - case Encode::UTF8: decoder = new Utf8(); break; - case Encode::ASCII: decoder = new Ascii(); break; - } - } - - Text::Iterator::~Iterator() - { - delete decoder; - } - - Codepoint Text::Iterator::get() - { - Codepoint codepoint; - decoder->decode(p, &codepoint); - return codepoint; - } - - Codepoint Text::Iterator::operator*() - { - return get(); - } - /* - Text::Iterator Text::Iterator::begin() - { - Iterator itor(encode, data, length); - itor.toBegin(); - return itor; - } - - Text::Iterator Text::Iterator::end() - { - Iterator itor(encode, data, length); - itor.toEnd(); - return itor; - } - */ - void Text::Iterator::toBegin() - { - p = (const unsigned char*)data; - } - - void Text::Iterator::toEnd() - { - p = (const unsigned char*)data + length; - } - - Text::Iterator& Text::Iterator::operator ++() - { - p = decoder->next(p); - return *this; - } - - Text::Iterator Text::Iterator::operator ++(int) - { - p = decoder->next(p); - Iterator itor(encode, data, length); - itor.p = p; - return itor; - } - - bool Text::Iterator::operator !=(const Iterator& itor) - { - return !(data == itor.data - && p == itor.p - && length == itor.length - && encode == itor.encode); - } - - bool Text::Iterator::operator ==(const Iterator& itor) - { - return data == itor.data - && p == itor.p - && length == itor.length - && encode == itor.encode; - } - - ///////////////////////////////////////////////////////////////////////////// - // text - ///////////////////////////////////////////////////////////////////////////// - - Text::Text(Encode encode, const void* data) - { - unsigned length = strlen((const char*)data); - Iterator end = Iterator(encode, data, length); - end.toEnd(); - Iterator it = Iterator(encode, data, length); - for (; it != end; ++it) - { - content.push_back(*it); - } - } - - Text::Text(Encode encode, const void* data, unsigned length) - { - Iterator end = Iterator(encode, data, length); - end.toEnd(); - Iterator it = Iterator(encode, data, length); - for (; it != end; ++it) - { - content.push_back(*it); - } - } - - Text::~Text() - { - } - - const Content& Text::getContent() const - { - return content; - } - - const Content& Text::operator*() const - { - return content; - } - - } // namespace Graphics -} // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_text.h b/src/libjin/Graphics/Font/je_text.h deleted file mode 100644 index 7436875..0000000 --- a/src/libjin/Graphics/Font/je_text.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef __JE_TEXT_H -#define __JE_TEXT_H - -#include <vector> - -namespace JinEngine -{ - namespace Graphics - { - - typedef unsigned int Codepoint; - - typedef std::vector<Codepoint> Content; - - class Text; - - class Decoder; - - /// - /// Supported text encoding. - /// - enum Encode - { - UTF8, ///< utf-8 - ASCII, ///< ASCII - }; - - /// - /// Decoded text. Saved as unicode codepoints. - /// - class Text - { - public: - /// - /// - /// - Text(Encode encode, const void* data); - - /// - /// - /// - Text(Encode encode, const void* data, unsigned int length); - - /// - /// - /// - ~Text(); - - /// - /// - /// - const Content& getContent() const; - - /// - /// - /// - const Content& operator*() const; - - private: - /// - /// - /// - class Iterator - { - public: - - /// - /// - /// - Iterator(const Iterator& itor); - - /// - /// - /// - Iterator(const Encode& encode, const void* data, unsigned int length); - - /// - /// - /// - ~Iterator(); - - /// - /// - /// - Codepoint get(); - - //Iterator begin(); - //Iterator end(); - - /// - /// - /// - void toBegin(); - - /// - /// - /// - void toEnd(); - - /// - /// - /// - Codepoint operator *(); - - /// - /// - /// - Iterator& operator ++(); - - /// - /// - /// - Iterator operator ++(int); - - /// - /// - /// - bool operator !=(const Iterator& itor); - - /// - /// - /// - bool operator ==(const Iterator& itor); - - private: - - /// - /// - /// - void operator = (const Iterator&); - - /// - /// - /// - const Encode encode; - - /// - /// - /// - const Decoder* decoder; - - /// - /// - /// - const void* p; - - /// - /// - /// - const void* const data; - - /// - /// - /// - unsigned int length; - - }; - - /// - /// - /// - Content content; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_texture_font.cpp b/src/libjin/Graphics/Font/je_texture_font.cpp deleted file mode 100644 index dcebdb2..0000000 --- a/src/libjin/Graphics/Font/je_texture_font.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include <vector> - -#include "../../math/je_vector2.hpp" - -#include "../shader/je_shader.h" - -#include "je_texture_font.h" - -using namespace std; -using namespace JinEngine::Math; - -namespace JinEngine -{ - namespace Graphics - { - - TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) - { - TextureFont* tf = new TextureFont(bitmap, codepoints, cellw, cellh); - return tf; - } - - TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, int cellw, int cellh) - { - TextureFont* tf = new TextureFont(bitmap, *codepoints, cellw, cellh); - return tf; - } - - TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) - { - TextureFont* tf = new TextureFont(bitmap, codepoints, mask, cellh); - return tf; - } - - TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, Color mask, int cellh) - { - TextureFont* tf = new TextureFont(bitmap, *codepoints, mask, cellh); - return tf; - } - - TextureFont::~TextureFont() - { - } - - const TextureFont::TextureGlyph* TextureFont::findGlyph(Codepoint codepoint) const - { - auto it = glyphs.find(codepoint); - if (it != glyphs.end()) - { - return &it->second; - } - else - return nullptr; - } - - Page* TextureFont::typeset(const Content& text, int lineheight, int spacing) - { - Page* page = new Page(); - page->font = this; - vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - vector<GlyphVertex>& glyphvertices = page->glyphvertices; - int texture = -1; - const TextureGlyph* glyph = nullptr; - GlyphVertex vertex; - Vector2<int> p(0, 0); - int i = 0; - - #define glyphvertices_push(_x, _y, _u, _v) \ - vertex.x = _x; vertex.y = _y;\ - vertex.u = _u; vertex.v = _v;\ - glyphvertices.push_back(vertex);\ - - for (Codepoint c : text) - { - // return - if (c == 0x0D) continue; - // newline - if (c == 0x0A) - { - p.y += lineheight; - p.x = 0; - continue; - } - if (c == 0x09) - { - // tab = 4*space - unsigned cw = getCharWidth(0x20); - p.x += cw * 4; - continue; - } - glyph = findGlyph(c); - if (glyph == nullptr) continue; - if (texture != getGLTexture()) - { - texture = getGLTexture(); - GlyphArrayDrawInfo info; - info.start = i; - info.count = 0; - info.texture = texture; - glyphinfolist.push_back(info); - } - glyphinfolist[glyphinfolist.size() - 1].count += 4; - // normalized - float w = getWidth(), h = getHeight(); - float nx = glyph->x / w, ny = glyph->y / h; - float nw = glyph->w / w, nh = glyph->h / h; - glyphvertices_push(p.x, p.y, nx, ny); - glyphvertices_push(p.x, p.y + glyph->h, nx, ny + nh); - glyphvertices_push(p.x + glyph->w, p.y + glyph->h, nx + nw, ny + nh); - glyphvertices_push(p.x + glyph->w, p.y, nx + nw, ny); - p.x += glyph->w + spacing; - i += 4; - } - getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); - return page; - } - - int TextureFont::getCharWidth(int c) - { - auto it = glyphs.find(c); - if (it != glyphs.end()) - { - return it->second.w; - } - return 0; - } - - int TextureFont::getCharHeight(int c) - { - auto it = glyphs.find(c); - if (it != glyphs.end()) - { - return it->second.h; - } - return 0; - } - - int TextureFont::getTextWidth(const Content& t, int spacing) - { - int res = 0; - int tmp = 0; - for (Codepoint c : t) - { - if (c == 0x0D) - continue; - if (c == 0x0A) - { - tmp = 0; - continue; - } - if (c == 0x09) - { - // tab = 4*space - unsigned cw = getCharWidth(0x20); - tmp += cw * 4; - if (tmp > res) res = tmp; - continue; - } - tmp += getCharWidth(c) + spacing; - if (tmp > res) res = tmp; - } - return res; - } - - int TextureFont::getTextHeight(const Content& t, int lineheight) - { - int res = 0; - bool newline = true; - for (Codepoint c : t) - { - if (c == 0x0A) - newline = true; - else if (c == 0x0D); - else if (newline) - { - newline = false; - res += lineheight; - } - } - return res; - } - - void TextureFont::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) - { - *w = 0; - *h = 0; - int tmp = 0; - bool newline = true; - for (Codepoint c : text) - { - if (c == 0x0D) - continue; - if (c == 0x0A) - { - tmp = 0; - newline = true; - continue; - } - else if (newline) - { - newline = false; - *h += lineheight; - } - tmp += getCharWidth(c) + spacing; - if (tmp > *w) - *w = tmp; - } - } - - Page* TextureFont::typeset(const Text& text, int lineheight, int spacing) - { - return typeset(*text, lineheight, spacing); - } - - void TextureFont::render(const Page* page, int x, int y) - { - Shader* shader = Shader::getCurrentShader(); - const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - const vector<GlyphVertex>& glyphvertices = page->glyphvertices; - gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); - shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); - shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); - for (int i = 0; i < glyphinfolist.size(); ++i) - { - const GlyphArrayDrawInfo& info = glyphinfolist[i]; - shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); - shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); - gl.bindTexture(info.texture); - gl.drawArrays(GL_QUADS, 0, info.count); - gl.bindTexture(0); - } - } - - void TextureFont::render(const Content& text, int x, int y, int lineheight, int spacing) - { - Page* page = typeset(text, lineheight, spacing); - render(page, x, y); - delete page; - } - - void TextureFont::render(const Text& text, int x, int y, int lineheight, int spacing) - { - Page* page = typeset(text, lineheight, spacing); - render(page, x, y); - delete page; - } - - TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) - : Graphic(bitmap) - , Font(cellh) - { - TextureGlyph glyph; - Vector2<int> count(bitmap->getWidth() / cellw, bitmap->getHeight() / cellh); - glyph.w = cellw; - glyph.h = cellh; - for (int y = 0; y < count.row; ++y) - { - glyph.y = y * cellh; - for (int x = 0; x < count.colum; ++x) - { - glyph.x = x * cellw; - if (x + y * count.colum >= codepoints.size()) - return; - glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[x + y * count.colum], glyph)); - } - } - } - - TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) - : Graphic(bitmap) - , Font(cellh) - { - TextureGlyph glyph; - glyph.h = cellh; - int w = bitmap->getWidth(); - int h = bitmap->getHeight(); - int i = 0; - for (int y = 0; y < h; y += cellh) - { - glyph.y = y; - bool newc = false; - for (int x = 0; x <= w; ++x) - { - if (x == w && newc) - { - glyph.w = x - glyph.x; - if (i >= codepoints.size()) - return; - glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); - ++i; - newc = false; - break; - } - Color c = bitmap->getPixels()[x + y * w]; - if (!newc && c != mask) - { - glyph.x = x; - newc = true; - } - else if (newc && c == mask) - { - glyph.w = x - glyph.x; - if (i >= codepoints.size()) - return; - glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); - if (codepoints[i] == 't') - { - int a = 10; - } - ++i; - newc = false; - } - } - } - } - - } -}
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_texture_font.h b/src/libjin/Graphics/Font/je_texture_font.h deleted file mode 100644 index fb74eca..0000000 --- a/src/libjin/Graphics/Font/je_texture_font.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef __JE_TEXTURE_FONT_H -#define __JE_TEXTURE_FONT_H - -#include <map> -#include <vector> - -#include "../../math/je_vector4.hpp" - -#include "../je_graphic.h" -#include "../je_bitmap.h" - -#include "je_page.h" -#include "je_font.h" -#include "je_text.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// - /// - class TextureFont : public Font , public Graphic - { - public: - - /// - /// - /// - static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); - - /// - /// - /// - static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, int cellw, int cellh); - - /// - /// - /// - static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); - - /// - /// - /// - static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, Color mask, int cellh); - - /// - /// - /// - ~TextureFont(); - - /// - /// - /// - Page* typeset(const Text& text, int lineheight, int spacing = 0) override; - - /// - /// - /// - Page* typeset(const Content& text, int lineheight, int spacing = 0) override ; - - /// - /// - /// - void render(const Page* page, int x, int y) override; - - /// - /// - /// - void render(const Content& text, int x, int y, int linehgiht, int spacing = 0) override; - - /// - /// - /// - void render(const Text& text, int x, int y, int lineheight, int spacing = 0)override; - - private: - - /// - /// - /// - struct TextureGlyph - { - float x, y, w, h; - }; - - /// - /// - /// - TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); - - /// - /// - /// - TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); - - /// - /// - /// - int getCharWidth(int c); - - /// - /// - /// - int getCharHeight(int c); - - /// - /// - /// - int getTextWidth(const Content& text, int spacing = 0); - - /// - /// - /// - int getTextHeight(const Content& text, int lineheight); - - /// - /// - /// - void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); - - /// - /// - /// - const TextureGlyph* findGlyph(Codepoint codepoint) const; - - - /// - /// - /// - std::map<Codepoint, TextureGlyph> glyphs; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_ttf.cpp b/src/libjin/Graphics/Font/je_ttf.cpp deleted file mode 100644 index 52547c9..0000000 --- a/src/libjin/Graphics/Font/je_ttf.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include "../../core/je_configuration.h" -#if defined(jin_graphics) - -#include <stdio.h> - -#include "../../common/je_array.hpp" - -#include "../je_gl.h" -#include "../je_color.h" -#include "../shader/je_shader.h" - -#include "je_ttf.h" -#include "je_page.h" - -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb/stb_truetype.h" - -namespace JinEngine -{ - namespace Graphics - { - - ///////////////////////////////////////////////////////////////////////////// - // TTFData - ///////////////////////////////////////////////////////////////////////////// - - TTFData* TTFData::createTTFData(const unsigned char* data, unsigned int size) - { - TTFData* ttf = nullptr; - try - { - ttf = new TTFData(data, size); - return ttf; - } - catch (...) - { - return nullptr; - } - } - - TTFData::TTFData(const unsigned char* d, unsigned int s) - { - raw.size = s; - raw.data = (unsigned char*)malloc(s); - memcpy(raw.data, d, s); - if (!stbtt_InitFont(&info, (const unsigned char*)raw.data, 0)) - { - delete raw.data; - throw 0; - } - /* push default fontsize */ - pushTTFsize(FONT_SIZE); - } - - TTFData::~TTFData() - { - free(raw.data); - } - - TTF* TTFData::createTTF(unsigned fontSize) - { - TTF* ttf; - try - { - ttf = new TTF(this, fontSize); - } - catch (...) - { - return nullptr; - } - return ttf; - } - - /* - * (0, 0) - * +--------------+ ascent - * | +--------+ | - * | | | | - * | | bitmap | | - * +--|--------|--+ baseline - * | +--------+ | - * +--|-----------+ decent - * | | - * leftSideBearing | - * advanceWidth - */ - void TTFData::getVMetrics(int* baseline, int* descent) - { - float scale = scales.back(); - int ascent; - stbtt_GetFontVMetrics(&info, &ascent, descent, 0); - *baseline = (int)(ascent*scale) + 1; // slight adjustment - *descent = *baseline - (int)(*descent*scale) + 1; - } - - void TTFData::getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing) - { - float scale = scales.back(); - int adw, lsb; - stbtt_GetCodepointHMetrics(&info, codepoint, &adw, &lsb); - *advanceWidth = (int)(adw*scale); - *leftSideBearing = (int)(lsb*scale); - } - - void TTFData::pushTTFsize(unsigned int fs) - { - float sc = stbtt_ScaleForPixelHeight(&info, fs); - scales.push_back(sc); - } - - void TTFData::popTTFsize() - { - /* always keep default ttf size on the bottom of stack */ - if (scales.size() > 1) - scales.pop_back(); - } - - Channel* TTFData::getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const - { - float scale = scales.back(); - Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); - return bitmap; - } - - Color* TTFData::getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const - { - float scale = scales.back(); - Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); - int w = *width, h = *height; - //int xo = *xoff, yo = *yoff; - Color* bitmap32 = new Color[w*h]; - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - bitmap32[x + y * w].set(0xff, 0xff, 0xff, bitmap[x + y * w]); - } - } - free(bitmap); - return bitmap32; - } - - ///////////////////////////////////////////////////////////////////////////// - // TTF - ///////////////////////////////////////////////////////////////////////////// - - #include "../shader/shaders/je_font.shader.h" - - using namespace std; - using namespace JinEngine::Math; - - const int TTF::TEXTURE_WIDTHS[] = { 128, 256, 256, 512, 512, 1024, 1024 }; - const int TTF::TEXTURE_HEIGHTS[] = { 128, 128, 256, 256, 512, 512, 1024 }; - - /* little endian unicode */ - static const char* unicodeLittleEndian(const char* p, unsigned* res) - { - } - - ///*static*/ TTF* TTF::createTTF(TTFData* fontData, unsigned int fontSzie) - //{ - // TTF* ttf; - // try - // { - // ttf = new TTF(fontData, fontSzie); - // } - // catch (...) - // { - // return nullptr; - // } - // return ttf; - //} - - TTF::TTF(TTFData* f, unsigned int fontSize) - : Font(fontSize) - , cursor(0, 0) - , ttf(f) - { - ttf->pushTTFsize(fontSize); - ttf->getVMetrics(&baseline, &descent); - estimateSize(); - ttf->popTTFsize(); - /* create a default texture */ - createAtlas(); - } - - /* estimate the size of atlas texture */ - void TTF::estimateSize() - { - for (int level = 0; level <= TEXTURE_SIZE_LEVEL_MAX; ++level) - { - if (descent * (descent*0.8) * 96 <= TEXTURE_WIDTHS[level] * TEXTURE_HEIGHTS[level]) - { - textureWidth = TEXTURE_WIDTHS[level]; - textureHeight = TEXTURE_HEIGHTS[level]; - break; - } - } - } - - TTF::~TTF() - { - } - - GLuint TTF::createAtlas() - { - GLuint t; - gl.flushError(); - t = gl.genTexture(); - gl.bindTexture(t); - gl.setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl.setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl.texImage(GL_RGBA8, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE); - if (glGetError() != GL_NO_ERROR) - { - glDeleteTextures(1, &t); - gl.bindTexture(0); - return 0; - } - atlases.push_back(t); - gl.bindTexture(0); - return t; - } - - void TTF::render(const Content& t, int x, int y, int lineheight, int spacing) - { - Page* page = typeset(t, lineheight, spacing); - render(page, x, y); - delete page; - } - - Page* TTF::typeset(const Content& text, int lineheight, int spacing) - { - Page* page = new Page(); - page->font = this; - vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - vector<GlyphVertex>& glyphvertices = page->glyphvertices; - int texture = -1; - TTFGlyph* glyph = nullptr; - GlyphVertex vertex; - Vector2<int> p(0, 0); - int i = 0; - - #define glyphvertices_push(_x, _y, _u, _v) \ - vertex.x = _x; vertex.y = _y;\ - vertex.u = _u; vertex.v = _v;\ - glyphvertices.push_back(vertex); - - #define glyphlize(c)\ - do{\ - glyph = &findGlyph(c); \ - if (texture != glyph->atlas) \ - { \ - GlyphArrayDrawInfo info; \ - info.start = i; \ - info.count = 0; \ - info.texture = glyph->atlas; \ - texture = glyph->atlas; \ - glyphinfolist.push_back(info); \ - } \ - glyphinfolist[glyphinfolist.size() - 1].count += 4; \ - TTFGlyph::Bbox& bbox = glyph->bbox; \ - glyphvertices_push(p.x, p.y, bbox.x, bbox.y); \ - glyphvertices_push(p.x, p.y + glyph->height, bbox.x, bbox.y + bbox.h); \ - glyphvertices_push(p.x + glyph->width, p.y + glyph->height, bbox.x + bbox.w, bbox.y + bbox.h); \ - glyphvertices_push(p.x + glyph->width, p.y, bbox.x + bbox.w, bbox.y); \ - }while(0) - - for (Codepoint c : text) - { - if (c == 0x0D) - continue; - if (c == 0x0A) - { - /* new line */ - p.y += lineheight; - p.x = 0; - continue; - } - if (c == 0x09) - { - // tab = 4*space - unsigned cw = getCharWidth(0x20); - p.x += cw * 4; - continue; - } - glyphlize(c); - p.x += glyph->width + spacing; - i += 4; - } - getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); - return page; - } - - Page* TTF::typeset(const Text& text, int lineheight, int spacing) - { - return typeset(*text, lineheight, spacing); - } - - void TTF::render(const Page* page, int x, int y) - { - Shader* shader = Shader::getCurrentShader(); - const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; - const vector<GlyphVertex>& glyphvertices = page->glyphvertices; - gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); - shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); - shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); - for (int i = 0; i < glyphinfolist.size(); ++i) - { - const GlyphArrayDrawInfo& info = glyphinfolist[i]; - shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); - shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); - gl.bindTexture(info.texture); - gl.drawArrays(GL_QUADS, 0, info.count); - gl.bindTexture(0); - } - } - - void TTF::render(const Text& text, int x, int y, int lineheight, int spacing /* = 0 */) - { - render(*text, x, y, lineheight, spacing); - } - - int TTF::getCharWidth(int c) - { - int adw, lsb; - ttf->pushTTFsize(mFontSize); - ttf->getHMetrics(c, &adw, &lsb); - ttf->popTTFsize(); - return adw; - } - - int TTF::getCharHeight(int c) - { - return descent; - } - - int TTF::getTextWidth(const Content& t, int spacing) - { - ttf->pushTTFsize(mFontSize); - int res = 0; - int tmp = 0; - for (Codepoint c : t) - { - if (c == 0x0D) - continue; - if (c == 0x0A) - { - tmp = 0; - continue; - } - tmp += getCharWidth(c) + spacing; - if (tmp > res) - res = tmp; - } - ttf->popTTFsize(); - return res; - } - - int TTF::getTextHeight(const Content& t, int lineheight) - { - ttf->pushTTFsize(mFontSize); - int res = 0; - bool newline = true; - for (Codepoint c : t) - { - if (c == 0x0A) - newline = true; - else if (c == 0x0D); - else if (newline) - { - newline = false; - res += lineheight; - } - } - ttf->popTTFsize(); - return res; - } - - void TTF::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) - { - ttf->pushTTFsize(mFontSize); - *w = 0; - *h = 0; - int tmp = 0; - bool newline = true; - for (Codepoint c : text) - { - if (c == 0x0D) - continue; - if (c == 0x0A) - { - tmp = 0; - newline = true; - continue; - } - else if (newline) - { - newline = false; - *h += lineheight; - } - tmp += getCharWidth(c) + spacing; - if (tmp > *w) - *w = tmp; - } - ttf->popTTFsize(); - } - - TTF::TTFGlyph& TTF::bakeGlyph(unsigned int character) - { - int w, h, xoff, yoff; - ttf->pushTTFsize(mFontSize); - GLuint atlas = atlases.back(); - const Color* bitmap = ttf->getCodepointBitmap(character, &w, &h, &xoff, &yoff); - int adw, lsb; - { - /* bake glyph */ - ttf->getHMetrics(character, &adw, &lsb); - ttf->popTTFsize(); - if (cursor.x + adw > textureWidth ) - { - cursor.x = 0; - cursor.y += descent; - if (cursor.y + descent * 2 > textureHeight) - { - /* create new atlas */ - atlas = createAtlas(); - cursor.y = 0; - } - } - gl.bindTexture(atlas); - gl.texSubImage(cursor.x + xoff, cursor.y + yoff + baseline, w, h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap); - gl.bindTexture(); - delete[] bitmap; - } - TTFGlyph glyph; - glyph.atlas = atlas; - glyph.bbox.x = cursor.x / (float)textureWidth; - glyph.bbox.y = cursor.y / (float)textureHeight; - glyph.bbox.w = adw / (float)textureWidth; - glyph.bbox.h = descent / (float)textureHeight; - glyph.width = adw; - glyph.height = descent; - glyphs.insert(std::pair<unsigned int, TTFGlyph>(character, glyph)); - cursor.x += adw; - return glyphs[character]; - } - - TTF::TTFGlyph& TTF::findGlyph(unsigned int character) - { - map<unsigned int, TTFGlyph>::iterator it = glyphs.find(character); - if (it != glyphs.end()) - return it->second; - else - return bakeGlyph(character); - } - - } // namespace Graphics -} // namespace JinEngine - -#endif // defined(jin_graphics)
\ No newline at end of file diff --git a/src/libjin/Graphics/Font/je_ttf.h b/src/libjin/Graphics/Font/je_ttf.h deleted file mode 100644 index b2c1802..0000000 --- a/src/libjin/Graphics/Font/je_ttf.h +++ /dev/null @@ -1,289 +0,0 @@ -#ifndef __JETTF_H -#define __JE_TTF_H -#include "../../core/je_configuration.h" -#if defined(jin_graphics) - -#include <vector> -#include <map> - -#include "stb/stb_truetype.h" - -#include "../../math/je_quad.h" - -#include "../je_color.h" -#include "../je_graphic.h" - -#include "je_page.h" -#include "je_font.h" -#include "je_text.h" - -namespace JinEngine -{ - namespace Graphics - { - - class TTF; - - // - // TTFData - // |- TTF(14px) - // |- TTF(15px) - // . - // . - // . - // - class TTFData - { - public: - - /// - /// - /// - static TTFData* createTTFData(const unsigned char* data, unsigned int size); - - /// - /// - /// - ~TTFData(); - - /// - /// - /// - TTF* createTTF(unsigned ttfsize); - - /// - /// - /// - void pushTTFsize(unsigned ttfsize); - - /// - /// - /// - void popTTFsize(); - - /// - /// - /// - Channel* getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; - - /// - /// - /// - Color* getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; - - /// - /// - /// - void getVMetrics(int* baseline, int* descent); - - /// - /// - /// - void getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing); - - private: - - /// - /// - /// - static const unsigned int FONT_SIZE = 12; - - /// - /// - /// - TTFData(const unsigned char* data, unsigned int size); - - /// - /// - /// - stbtt_fontinfo info; - - /// - /// - /// - struct - { - unsigned char* data; - unsigned int size; - } raw; - - /// - /// - /// - std::vector<float> scales; - - }; - - class TTF : public Font - { - public: - //static TTF* createTTF(TTFData* ttfData, unsigned ttfSzie); - - /// - /// - /// - Page* typeset(const Text& text, int lineheight, int spacing = 0) override; - - /// - /// - /// - Page* typeset(const Content& text, int lineheight, int spacing = 0) override; - - /// - /// - /// - void render(const Text& text, int x, int y, int lineheight, int spacing = 0) override; - - /// - /// - /// - void render(const Content& text, int x, int y, int lineheight, int spacing = 0) override; - - /// - /// - /// - void render(const Page* page, int x, int y) override; - - /// - /// - /// - ~TTF(); - - private: - - friend class TTFData; - - /// - /// - /// - struct TTFGlyph - { - GLuint atlas; - // normalized coordinates - struct Bbox - { - float x, y; - float w, h; - } bbox; - // glyph size in pixel - unsigned int width, height; - }; - - /// - /// - /// - static const int TEXTURE_SIZE_LEVELS_COUNT = 7; - - /// - /// - /// - static const int TEXTURE_SIZE_LEVEL_MAX = TEXTURE_SIZE_LEVELS_COUNT - 1; - - /// - /// - /// - static const int TEXTURE_WIDTHS[TEXTURE_SIZE_LEVELS_COUNT]; - - /// - /// - /// - static const int TEXTURE_HEIGHTS[TEXTURE_SIZE_LEVELS_COUNT]; - - /// - /// - /// - TTF(TTFData* ttf, Codepoint ttfSize); - - /// - /// - /// - void estimateSize(); - - /// - /// - /// - GLuint createAtlas(); - - /// - /// - /// - TTFGlyph& bakeGlyph(Codepoint character); - - /// - /// - /// - TTFGlyph& findGlyph(Codepoint character); - - /// - /// - /// - int getCharWidth(int c); - - /// - /// - /// - int getCharHeight(int c); - - /// - /// - /// - int getTextWidth(const Content& text, int spacing = 0); - - /// - /// - /// - int getTextHeight(const Content& text, int lineheight); - - /// - /// - /// - void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); - - /// - /// - /// - int textureWidth; - - /// - /// - /// - int textureHeight; - - /// - /// - /// - std::vector<GLuint> atlases; - - /// - /// - /// - std::map<Codepoint, TTFGlyph> glyphs; - - /// - /// - /// - TTFData* ttf; - - /// - /// - /// - int baseline; - - /// - /// - /// - int descent; - - /// - /// - /// - Math::Vector2<float> cursor; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif // defined(jin_graphics) - -#endif // __JE_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Shader/je_jsl_compiler.cpp b/src/libjin/Graphics/Shader/je_jsl_compiler.cpp deleted file mode 100644 index 81b14e8..0000000 --- a/src/libjin/Graphics/Shader/je_jsl_compiler.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "../../core/je_configuration.h" -#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) - -#include "../../Filesystem/je_buffer.h" - -#include "je_jsl_compiler.h" - -using namespace std; -using namespace JinEngine::Filesystem; - -namespace JinEngine -{ - namespace Graphics - { - -#include "je_base.shader.h" - - bool JSLCompiler::compile(const string& jsl, string* vertex_shader, string* fragment_shader) - { - // parse shader source, need some optimizations - int loc_VERTEX_SHADER = jsl.find("#VERTEX_SHADER"); - int loc_END_VERTEX_SHADER = jsl.find("#END_VERTEX_SHADER"); - int loc_FRAGMENT_SHADER = jsl.find("#FRAGMENT_SHADER"); - int loc_END_FRAGMENT_SHADER = jsl.find("#END_FRAGMENT_SHADER"); - if (loc_VERTEX_SHADER == string::npos - || loc_END_VERTEX_SHADER == string::npos - || loc_FRAGMENT_SHADER == string::npos - || loc_END_FRAGMENT_SHADER == string::npos - ) - return false; - // Load vertex and fragment shader source into buffers. - { - // Compile JSL vertex program. - int start = loc_VERTEX_SHADER + strlen("#VERTEX_SHADER"); - *vertex_shader = jsl.substr(start, loc_END_VERTEX_SHADER - start); - Buffer vbuffer = Buffer(vertex_shader->length() + BASE_VERTEX_SHADER_SIZE); - formatVertexShader((char*)&vbuffer, vertex_shader->c_str()); - vertex_shader->assign((char*)&vbuffer); - } - { - // Compile JSL fragment program. - int start = loc_FRAGMENT_SHADER + strlen("#FRAGMENT_SHADER"); - *fragment_shader = jsl.substr(start, loc_END_FRAGMENT_SHADER - start); - Buffer fbuffer = Buffer(fragment_shader->length() + BASE_FRAGMENT_SHADER_SIZE); - formatFragmentShader((char*)&fbuffer, fragment_shader->c_str()); - fragment_shader->assign((char*)&fbuffer); - } - return true; - } - - } // namespace Graphics -} // namespace JinEngine - -#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/Graphics/Shader/je_jsl_compiler.h b/src/libjin/Graphics/Shader/je_jsl_compiler.h deleted file mode 100644 index 29129e1..0000000 --- a/src/libjin/Graphics/Shader/je_jsl_compiler.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __JE_JSL_COMPILER_H -#define __JE_JSL_COMPILER_H - -#include "../../core/je_configuration.h" -#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) - -#include <string> - -#include "../../common/je_singleton.hpp" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Compile JSL into GLSL. - /// - class JSLCompiler : public Singleton<JSLCompiler> - { - public: - /// - /// Compile JSL shader source into GLSL. - /// - /// @param jsl JSL shader source. - /// @param glsl_vertex Output of vertex glsl shader source. - /// @param glsl_fragment Output of fragment glsl shader source. - /// @return True if compile successful, otherwise return false. - /// - bool compile(const std::string& jsl, std::string* glsl_vertex, std::string* glsl_fragment); - - private: - singleton(JSLCompiler); - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) - -#endif // __JE_JSL_COMPILER_H
\ No newline at end of file diff --git a/src/libjin/Graphics/Shader/je_shader.cpp b/src/libjin/Graphics/Shader/je_shader.cpp deleted file mode 100644 index 8e909d8..0000000 --- a/src/libjin/Graphics/Shader/je_shader.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "../../core/je_configuration.h" -#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) - -#include <iostream> - -#include "../../filesystem/je_buffer.h" -#include "../../utils/je_macros.h" - -#include "je_jsl_compiler.h" -#include "je_shader.h" - -namespace JinEngine -{ - namespace Graphics - { - - using namespace std; - using namespace JinEngine::Filesystem; - - // - // default_texture - // base_shader - // SHADER_FORMAT_SIZE - // formatShader - // - #include "shaders/je_default.shader.h" - - // - // https://stackoverflow.com/questions/27941496/use-sampler-without-passing-through-value - // The default value of a sampler variable is 0. From the GLSL 3.30 spec, - // section "4.3.5 Uniforms": - // - // The link time initial value is either the value of the variable's - // initializer, if present, or 0 if no initializer is present.Sampler - // types cannot have initializers. - // - // Since a value of 0 means that it's sampling from texture unit 0, it will - // work without ever setting the value as long as you bind your textures to - // unit 0. This is well defined behavior. - // - // Since texture unit 0 is also the default until you call glActiveTexture() - // with a value other than GL_TEXTURE0, it's very common to always use unit - // 0 as long as shaders do not need more than one texture.Which means that - // often times, setting the sampler uniforms is redundant for simple - // applications. - // - // I would still prefer to always set the values.If nothing else, it makes - // it clear to anybody reading your code that you really mean to sample from - // texture unit 0, and did not just forget to set the value. - // - const int DEFAULT_TEXTURE_UNIT = 0; - - /*static*/ Shader* Shader::CurrentShader = nullptr; - - Shader* Shader::createShader(const string& program) - { - Shader* shader = nullptr; - try - { - shader = new Shader(program); - } - catch(...) - { - return nullptr; - } - return shader; - } - - Shader::Shader(const string& program) - : mCurrentTextureUnit(DEFAULT_TEXTURE_UNIT) - { - if (!compile(program)) - throw 0; - } - - Shader::~Shader() - { - if (CurrentShader == this) - unuse(); - // delete shader program - glDeleteShader(mPID); - } - - bool Shader::compile(const string& program) - { - string vertex_shader, fragment_shader; - // Compile JSL shader source into GLSL shader source. - JSLCompiler* compiler = JSLCompiler::get(); - if (!compiler->compile(program, &vertex_shader, &fragment_shader)) - { - return false; - } -#define glsl(SHADER_MODE, SHADER, SRC) \ -do{ \ -const GLchar* src = SRC.c_str(); \ -glShaderSource(SHADER, 1, &src, NULL); \ -glCompileShader(SHADER); \ -GLint success; \ -glGetShaderiv(SHADER, GL_COMPILE_STATUS, &success); \ -if (success == GL_FALSE) \ - return false; \ -}while(0) - // Compile vertex shader. - GLuint vid = glCreateShader(GL_VERTEX_SHADER); - glsl(GL_VERTEX_SHADER, vid, vertex_shader); - // Compile fragment shader. - GLuint fid = glCreateShader(GL_FRAGMENT_SHADER); - glsl(GL_FRAGMENT_SHADER, fid, fragment_shader); -#undef glsl - // Create OpenGL shader program. - mPID = glCreateProgram(); - glAttachShader(mPID, vid); - glAttachShader(mPID, fid); - glLinkProgram(mPID); - GLint success; - glGetProgramiv(mPID, GL_LINK_STATUS, &success); - if (success == GL_FALSE) - return false; - } - - static inline GLint getMaxTextureUnits() - { - GLint maxTextureUnits = 0; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - return maxTextureUnits; - } - - void Shader::use() - { - glUseProgram(mPID); - CurrentShader = this; - sendInt(SHADER_MAIN_TEXTURE, DEFAULT_TEXTURE_UNIT); - } - - /*static*/ void Shader::unuse() - { - glUseProgram(0); - CurrentShader = nullptr; - } - - GLint Shader::claimTextureUnit(const std::string& name) - { - std::map<std::string, GLint>::iterator unit = mTextureUnits.find(name); - if (unit != mTextureUnits.end()) - return unit->second; - static GLint MAX_TEXTURE_UNITS = getMaxTextureUnits(); - if (++mCurrentTextureUnit >= MAX_TEXTURE_UNITS) - return 0; - mTextureUnits[name] = mCurrentTextureUnit; - return mCurrentTextureUnit; - } - - #define checkJSL() \ - if (CurrentShader != this) \ - return - - void Shader::sendInt(const char* name, int value) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, name); - glUniform1i(loc, value); - } - - void Shader::sendFloat(const char* variable, float number) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, variable); - glUniform1f(loc, number); - } - - // - // https://www.douban.com/note/627332677/ - // struct TextureUnit - // { - // GLuint targetTexture1D; - // GLuint targetTexture2D; - // GLuint targetTexture3D; - // GLuint targetTextureCube; - // ... - // }; - // - // TextureUnit mTextureUnits[GL_MAX_TEXTURE_IMAGE_UNITS] - // GLuint mCurrentTextureUnit = 0; - // - void Shader::sendTexture(const char* variable, const Texture* tex) - { - checkJSL(); - GLint location = glGetUniformLocation(mPID, variable); - if (location == -1) - return; - GLint unit = claimTextureUnit(variable); - if (unit == 0) - { - // TODO: 쳣 - return; - } - gl.activeTexUnit(unit); - glUniform1i(location, unit); - gl.bindTexture(tex->getGLTexture()); - gl.activeTexUnit(0); - } - - void Shader::sendCanvas(const char* variable, const Canvas* canvas) - { - checkJSL(); - GLint location = glGetUniformLocation(mPID, variable); - if (location == -1) - return; - GLint unit = claimTextureUnit(variable); - if (unit == 0) - { - // TODO: 쳣 - return; - } - glUniform1i(location, unit); - glActiveTexture(GL_TEXTURE0 + unit); - gl.bindTexture(canvas->getGLTexture()); - - glActiveTexture(GL_TEXTURE0); - } - - void Shader::sendVec2(const char* name, float x, float y) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, name); - glUniform2f(loc, x, y); - } - - void Shader::sendVec3(const char* name, float x, float y, float z) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, name); - glUniform3f(loc, x, y, z); - } - - void Shader::sendVec4(const char* name, float x, float y, float z, float w) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, name); - glUniform4f(loc, x, y, z, w); - } - - void Shader::sendColor(const char* name, const Color* col) - { - checkJSL(); - int loc = glGetUniformLocation(mPID, name); - glUniform4f(loc, - col->r / 255.f, - col->g / 255.f, - col->b / 255.f, - col->a / 255.f - ); - } - - void Shader::sendMatrix4(const char* name, const Math::Matrix* mat4) - { - int loc = glGetUniformLocation(mPID, name); - glUniformMatrix4fv(loc, 1, GL_FALSE, mat4->getElements()); - } - - void Shader::bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) - { - GLint loc = glGetAttribLocation(mPID, SHADER_VERTEX_COORDS); - glEnableVertexAttribArray(0); - glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); - } - - void Shader::bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) - { - GLint loc = glGetAttribLocation(mPID, SHADER_TEXTURE_COORDS); - glEnableVertexAttribArray(1); - glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); - } - - } // namespace Graphics -} // namespace JinEngine - -#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/Graphics/Shader/je_shader.h b/src/libjin/Graphics/Shader/je_shader.h deleted file mode 100644 index 039efb5..0000000 --- a/src/libjin/Graphics/Shader/je_shader.h +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef __JE_SHADER_H -#define __JE_SHADER_H - -#include "../../core/je_configuration.h" -#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) - -#include <string> -#include <map> - -#include "GLee/GLee.h" - -#include "../je_color.h" -#include "../je_texture.h" -#include "../je_canvas.h" - -#include "je_base.shader.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Built in shader program. - /// - /// Built in shader program written with custom shading language called JSL (jin shading language). A JSL - /// program is compiled into glsl, so most glsl built in functions and structs are available in JSL. - /// - class Shader - { - public: - /// - /// Create shader program from source code. - /// - /// @param source The shader source code. - /// - static Shader* createShader(const std::string& source); - - /// - /// Get current shader. - /// - /// @return Current used shader program. - /// - static inline Shader* getCurrentShader() { return CurrentShader; } - - /// - /// Unuse current shader. - /// - static void unuse(); - - /// - /// Destructor of shader. - /// - virtual ~Shader(); - - /// - /// Use specific shader. - /// - void use(); - - /// - /// Send float value to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param number Value of uniform variable to be sent. - /// - void sendFloat(const char* name, float number); - - /// - /// Send texture to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param texture Texture to be sent. - /// - void sendTexture(const char* name, const Texture* texture); - - /// - /// Send integer value to shader - /// - /// @param name Name of the uniform variable to be assigned. - /// @param value Value to be sent. - /// - void sendInt(const char* name, int value); - - /// - /// Send 2D vector to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param x X value of the vector to be sent. - /// @param y Y value of the vector to be sent. - /// - void sendVec2(const char* name, float x, float y); - - /// - /// Send 3D vector to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param x X value of the vector to be sent. - /// @param y Y value of the vector to be sent. - /// @param z Z value of the vector to be sent. - /// - void sendVec3(const char* name, float x, float y, float z); - - /// - /// Send 4D vector to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param x X value of the vector to be sent. - /// @param y Y value of the vector to be sent. - /// @param z Z value of the vector to be sent. - /// @param w W value of the vector to be sent. - /// - void sendVec4(const char* name, float x, float y, float z, float w); - - /// - /// Send canvas to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param canvas Canvas to be sent. - /// - void sendCanvas(const char* name, const Canvas* canvas); - - /// - /// Send color to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param color Color to be sent. - /// - void sendColor(const char* name, const Color* color); - - /// - /// Send 4 by 4 matrix to shader. - /// - /// @param name Name of the uniform variable to be assigned. - /// @param mat4 Matrix to be sent. - /// - void sendMatrix4(const char* name, const Math::Matrix* mat4); - - /// - /// Set vertices value. - /// - /// @param n Number of vertices. - /// @param type Data type of each component in the array. - /// @param stride Byte offset between consecutive generic vertex attributes. - /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. - /// - void bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); - - /// - /// Set texture UV coordinates. - /// - /// @param n Number of vertices. - /// @param type Data type of each component in the array. - /// @param stride Byte offset between consecutive generic vertex attributes. - /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. - /// - void bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); - - protected: - /// - /// Reference of current used shader. - /// - static Shader* CurrentShader; - - /// - /// Get texture unit of the uniform texture. If not, assign one. - /// - /// @param name Name of the texture uniform variable. - /// @return Texture unit which texture variable be assigned. - /// - GLint claimTextureUnit(const std::string& name); - - /// - /// Shader constructor. - /// - Shader(const std::string& program); - - /// - /// Compile JSL program into GLSL source. - /// - /// @param program JSL source code. - /// @return Return true if compile successed, otherwise return false. - /// - bool compile(const std::string& program); - - GLuint mPID; - GLint mCurrentTextureUnit; - std::map<std::string, GLint> mTextureUnits; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) - -#endif // __JE_SHADER_H
\ No newline at end of file diff --git a/src/libjin/Graphics/animation/je_animation.h b/src/libjin/Graphics/animation/je_animation.h deleted file mode 100644 index aa4c93f..0000000 --- a/src/libjin/Graphics/animation/je_animation.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __JE_ANIMATION_H -#define __JE_ANIMATION_H - -#include <vector> -#include <string> - -#include "../je_sprite.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Animation clip with key. - /// - class Animation - { - public: - void onUpdate(float dt); - - void start(); - void pause(); - void stop(); - void rewind(); - void setSpeed(float speed); - - /// - /// Get current frame index. - /// - uint getCurrentFrame(); - - /// - /// Set current frame index. - /// - /// @param frame Current frame to play. - /// - void setCurrentFrame(uint frame); - - private: - /// - /// Key frames. - /// - std::vector<Sprite*> mFrames; - - /// - /// Animation playing speed. - /// - float mSpeed; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/animation/je_animator.h b/src/libjin/Graphics/animation/je_animator.h deleted file mode 100644 index 973ff58..0000000 --- a/src/libjin/Graphics/animation/je_animator.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __JE_ANIMATOR_H -#define __JE_ANIMATOR_H - -#include <map> -#include <vector> -#include <string> - -#include "je_animation.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// - /// - class Animator - { - public: - void addAnimation(const std::string& key, Animation* clip); - bool hasKey(const std::string& key); - - void play(); - void switchAnimationByKey(const std::string& key); - void switchAnimation(const Animation* clip); - - /// - /// Control clips. - /// - void stopAnimation(); - void pauseAnimation(); - void rewindAnimation(); - void startAnimation(); - - private: - /// - /// Map a key to clips. - /// - std::map<std::string, Animation*> mAnimations; - Animation* mCurrentAnimation; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/animation/je_animation.cpp b/src/libjin/Graphics/animations/je_animation.cpp index e69de29..e69de29 100644 --- a/src/libjin/Graphics/animation/je_animation.cpp +++ b/src/libjin/Graphics/animations/je_animation.cpp diff --git a/src/libjin/Graphics/animations/je_animation.h b/src/libjin/Graphics/animations/je_animation.h new file mode 100644 index 0000000..f694455 --- /dev/null +++ b/src/libjin/Graphics/animations/je_animation.h @@ -0,0 +1,59 @@ +#ifndef __JE_ANIMATION_H +#define __JE_ANIMATION_H + +#include <vector> +#include <string> + +#include "../je_sprite.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Animations + { + + /// + /// Animation clip with key. + /// + class Animation + { + public: + void onUpdate(float dt); + + void start(); + void pause(); + void stop(); + void rewind(); + void setSpeed(float speed); + + /// + /// Get current frame index. + /// + uint getCurrentFrame(); + + /// + /// Set current frame index. + /// + /// @param frame Current frame to play. + /// + void setCurrentFrame(uint frame); + + private: + /// + /// Key frames. + /// + std::vector<Sprite*> mFrames; + + /// + /// Animation playing speed. + /// + float mSpeed; + + }; + + } // namespace Animations + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/animation/je_animator.cpp b/src/libjin/Graphics/animations/je_animator.cpp index e69de29..e69de29 100644 --- a/src/libjin/Graphics/animation/je_animator.cpp +++ b/src/libjin/Graphics/animations/je_animator.cpp diff --git a/src/libjin/Graphics/animations/je_animator.h b/src/libjin/Graphics/animations/je_animator.h new file mode 100644 index 0000000..9273ff8 --- /dev/null +++ b/src/libjin/Graphics/animations/je_animator.h @@ -0,0 +1,51 @@ +#ifndef __JE_ANIMATOR_H +#define __JE_ANIMATOR_H + +#include <map> +#include <vector> +#include <string> + +#include "je_animation.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Animations + { + + /// + /// + /// + class Animator + { + public: + void addAnimation(const std::string& key, Animation* clip); + bool hasKey(const std::string& key); + + void play(); + void switchAnimationByKey(const std::string& key); + void switchAnimation(const Animation* clip); + + /// + /// Control clips. + /// + void stopAnimation(); + void pauseAnimation(); + void rewindAnimation(); + void startAnimation(); + + private: + /// + /// Map a key to clips. + /// + std::map<std::string, Animation*> mAnimations; + Animation* mCurrentAnimation; + + }; + + } + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_decoder.cpp b/src/libjin/Graphics/fonts/je_decoder.cpp new file mode 100644 index 0000000..02112a0 --- /dev/null +++ b/src/libjin/Graphics/fonts/je_decoder.cpp @@ -0,0 +1,96 @@ +#include <stdlib.h> +#include <string.h> +#include "je_decoder.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + /* utf8 byte string to unicode codepoint */ + static const char *utf8toCodepoint(const char *p, unsigned *res) { + return nullptr; + + } + + ///////////////////////////////////////////////////////////////////////////// + // decoders + ///////////////////////////////////////////////////////////////////////////// + + const void* Utf8::decode(const void* data, Codepoint* res) const + { + const char* p = (char*)data; + unsigned x, mask, shift; + switch (*p & 0xf0) { + case 0xf0: mask = 0x07; shift = 18; break; + case 0xe0: mask = 0x0f; shift = 12; break; + case 0xc0: + case 0xd0: mask = 0x1f; shift = 6; break; + default: + *res = *p; + return p + 1; + } + x = (*p & mask) << shift; + do { + if (*(++p) == '\0') { + *res = x; + return p; + } + shift -= 6; + x |= (*p & 0x3f) << shift; + } while (shift); + *res = x; + return p + 1; + } + + const void* Utf8::next(const void* data) const + { + const char* p = (char*)data; + unsigned x, mask, shift; + switch (*p & 0xf0) { + case 0xf0: mask = 0x07; shift = 18; break; + case 0xe0: mask = 0x0f; shift = 12; break; + case 0xc0: + case 0xd0: mask = 0x1f; shift = 6; break; + default: + return p + 1; + } + x = (*p & mask) << shift; + do { + if (*(++p) == '\0') { + return p; + } + shift -= 6; + x |= (*p & 0x3f) << shift; + } while (shift); + return p + 1; + } + /* + const void* Utf16::decode(const void* data, Codepoint* res) const + { + return nullptr; + } + + const void* Utf16::next(const void* data) const + { + return nullptr; + } + */ + const void* Ascii::decode(const void* data, Codepoint* res) const + { + const char* p = (char*)data; + *res = *p; + return p + 1; + } + + const void* Ascii::next(const void* data) const + { + const char* p = (char*)data; + return p + 1; + } + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_decoder.h b/src/libjin/Graphics/fonts/je_decoder.h new file mode 100644 index 0000000..cacbad8 --- /dev/null +++ b/src/libjin/Graphics/fonts/je_decoder.h @@ -0,0 +1,97 @@ +#ifndef __JE_UTF8_H +#define __JE_UTF8_H + +#include <vector> + +#include "je_text.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + /// + /// Text decoder. + /// + class Decoder + { + public: + + /// + /// Decode a code unit. + /// + /// @param data Code units. + /// @param codepoint Value of code point. + /// @return Next code unit location. + /// + virtual const void* decode(const void* data, Codepoint* codepoint) const = 0; + + /// + /// Get next code unit location. + /// + /// @param data Code units. + /// @return Next code unit location. + /// + virtual const void* next(const void* data) const = 0; + + }; + + /// + /// Utf-8 decoder. + /// + class Utf8 : public Decoder + { + public: + + /// + /// Decode a code unit. + /// + /// @param data Code units. + /// @param codepoint Value of code point. + /// @return Next code unit location. + /// + const void* decode(const void* data, Codepoint* codepoint) const override; + + /// + /// Get next code unit location. + /// + /// @param data Code units. + /// @return Next code unit location. + /// + const void* next(const void* data) const override; + + }; + + /// + /// Ascii decoder. + /// + class Ascii : public Decoder + { + public: + + /// + /// Decode a code unit. + /// + /// @param data Code units. + /// @param codepoint Value of code point. + /// @return Next code unit location. + /// + const void* decode(const void* data, Codepoint* codepoint) const override; + + /// + /// Get next code unit location. + /// + /// @param data Code units. + /// @return Next code unit location. + /// + const void* next(const void* data) const override; + + }; + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_font.h b/src/libjin/Graphics/fonts/je_font.h new file mode 100644 index 0000000..ae151dc --- /dev/null +++ b/src/libjin/Graphics/fonts/je_font.h @@ -0,0 +1,109 @@ +#ifndef __JE_FONT_H +#define __JE_FONT_H + +#include <vector> +#include "je_text.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + struct Page; + + // + // Font + // |- TTF + // |- TextureFont + // + + /// + /// Base Font class. + /// + class Font + { + public: + /// + /// Font constructor. + /// + Font(unsigned fontsize) + : mFontSize(fontsize) + { + } + + /// + /// Font destructor. + /// + virtual ~Font() {}; + + /// + /// Create page with given text. + /// + /// @param text Text to be typesetted. + /// @param lineheight Line height of text. + /// @param spacing Spacing between characters. 0 by default. + /// @return Page if created successfully, otherwise return null. + /// + virtual Page* typeset(const Text& text, int lineheight, int spacing = 0) = 0; + + /// + /// Create page with given unicode codepoints. + /// + /// @param content Unicode codepoints to be typesetted. + /// @param lineheight Line height of text. + /// @param spacing Spacing between characters. 0 by default. + /// @return Page if created successfully, otherwise return null. + /// + virtual Page* typeset(const Content& content, int lineheight, int spacing = 0) = 0; + + /// + /// Render page to given position. + /// + /// @param page Page to be rendered. + /// @param x X value of the position. + /// @param y Y value of the position. + /// + virtual void render(const Page* page, int x, int y) = 0; + + /// + /// Render unicode codepoints to given position. + /// + /// @param content Unicode codepoints to be typesetted. + /// @param x X value of the position. + /// @param y Y value of the position. + /// @param lineheight Line height of the content. + /// @param spacing Spacing between characters. + /// + virtual void render(const Content& content, int x, int y, int lineheight, int spacing = 0) = 0; + + /// + /// Render text to given position. + /// + /// @param text Text to be rendered. + /// @param x X value of the position. + /// @param y Y value of the position. + /// @param lineheight Line height of the text. + /// @param spacing Spacing between characters. + /// + virtual void render(const Text& text, int x, int y, int lineheight, int spacing = 0) = 0; + + /// + /// Get font size. + /// + /// @return Font size. + /// + inline unsigned getFontSize() { return mFontSize; }; + + protected: + + unsigned mFontSize; + + }; + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif // __JE_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_page.h b/src/libjin/Graphics/fonts/je_page.h new file mode 100644 index 0000000..cc61ac2 --- /dev/null +++ b/src/libjin/Graphics/fonts/je_page.h @@ -0,0 +1,54 @@ +#ifndef __JE_PAGE_H +#define __JE_PAGE_H + +#include "../../math/je_vector2.hpp" + +#include "je_font.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + class Font; + + /// + /// Glyphs data to be rendered. + /// + struct GlyphVertex + { + int x, y; ///< screen coordinates + float u, v; ///< normalized texture uv + }; + + /// + /// Glyphs info for reducing draw call. + /// + struct GlyphArrayDrawInfo + { + GLuint texture; ///< atlas + unsigned int start; ///< glyph vertex indecies + unsigned int count; ///< glyph vertex count + }; + + /// + /// Page to be rendered. + /// + /// A page is a pre-rendered text struct for reducing draw call. Each page + /// keeps a font pointer which should not be changed. + /// + struct Page + { + Font* font; + std::vector<GlyphArrayDrawInfo> glyphinfolist; + std::vector<GlyphVertex> glyphvertices; + Math::Vector2<int> size; + }; + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif // __JE_PAGE_H
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_text.cpp b/src/libjin/Graphics/fonts/je_text.cpp new file mode 100644 index 0000000..80aaa6a --- /dev/null +++ b/src/libjin/Graphics/fonts/je_text.cpp @@ -0,0 +1,157 @@ +#include <cstring> + +#include "je_text.h" +#include "je_decoder.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + ///////////////////////////////////////////////////////////////////////////// + // iterator + ///////////////////////////////////////////////////////////////////////////// + + Text::Iterator::Iterator(const Iterator& itor) + : data(itor.data) + , p(itor.p) + , encode(itor.encode) + , length(itor.length) + { + switch (encode) + { + case Encode::UTF8: decoder = new Utf8(); break; + case Encode::ASCII: decoder = new Ascii(); break; + } + } + + Text::Iterator::Iterator(const Encode& _encode, const void* _data, unsigned int _length) + : data(_data) + , p(_data) + , encode(_encode) + , length(_length) + { + switch (encode) + { + case Encode::UTF8: decoder = new Utf8(); break; + case Encode::ASCII: decoder = new Ascii(); break; + } + } + + Text::Iterator::~Iterator() + { + delete decoder; + } + + Codepoint Text::Iterator::get() + { + Codepoint codepoint; + decoder->decode(p, &codepoint); + return codepoint; + } + + Codepoint Text::Iterator::operator*() + { + return get(); + } + /* + Text::Iterator Text::Iterator::begin() + { + Iterator itor(encode, data, length); + itor.toBegin(); + return itor; + } + + Text::Iterator Text::Iterator::end() + { + Iterator itor(encode, data, length); + itor.toEnd(); + return itor; + } + */ + void Text::Iterator::toBegin() + { + p = (const unsigned char*)data; + } + + void Text::Iterator::toEnd() + { + p = (const unsigned char*)data + length; + } + + Text::Iterator& Text::Iterator::operator ++() + { + p = decoder->next(p); + return *this; + } + + Text::Iterator Text::Iterator::operator ++(int) + { + p = decoder->next(p); + Iterator itor(encode, data, length); + itor.p = p; + return itor; + } + + bool Text::Iterator::operator !=(const Iterator& itor) + { + return !(data == itor.data + && p == itor.p + && length == itor.length + && encode == itor.encode); + } + + bool Text::Iterator::operator ==(const Iterator& itor) + { + return data == itor.data + && p == itor.p + && length == itor.length + && encode == itor.encode; + } + + ///////////////////////////////////////////////////////////////////////////// + // text + ///////////////////////////////////////////////////////////////////////////// + + Text::Text(Encode encode, const void* data) + { + unsigned length = strlen((const char*)data); + Iterator end = Iterator(encode, data, length); + end.toEnd(); + Iterator it = Iterator(encode, data, length); + for (; it != end; ++it) + { + content.push_back(*it); + } + } + + Text::Text(Encode encode, const void* data, unsigned length) + { + Iterator end = Iterator(encode, data, length); + end.toEnd(); + Iterator it = Iterator(encode, data, length); + for (; it != end; ++it) + { + content.push_back(*it); + } + } + + Text::~Text() + { + } + + const Content& Text::getContent() const + { + return content; + } + + const Content& Text::operator*() const + { + return content; + } + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_text.h b/src/libjin/Graphics/fonts/je_text.h new file mode 100644 index 0000000..261f112 --- /dev/null +++ b/src/libjin/Graphics/fonts/je_text.h @@ -0,0 +1,172 @@ +#ifndef __JE_TEXT_H +#define __JE_TEXT_H + +#include <vector> + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + typedef unsigned int Codepoint; + + typedef std::vector<Codepoint> Content; + + class Text; + + class Decoder; + + /// + /// Supported text encoding. + /// + enum Encode + { + UTF8, ///< utf-8 + ASCII, ///< ASCII + }; + + /// + /// Decoded text. Saved as unicode codepoints. + /// + class Text + { + public: + /// + /// + /// + Text(Encode encode, const void* data); + + /// + /// + /// + Text(Encode encode, const void* data, unsigned int length); + + /// + /// + /// + ~Text(); + + /// + /// + /// + const Content& getContent() const; + + /// + /// + /// + const Content& operator*() const; + + private: + /// + /// + /// + class Iterator + { + public: + + /// + /// + /// + Iterator(const Iterator& itor); + + /// + /// + /// + Iterator(const Encode& encode, const void* data, unsigned int length); + + /// + /// + /// + ~Iterator(); + + /// + /// + /// + Codepoint get(); + + //Iterator begin(); + //Iterator end(); + + /// + /// + /// + void toBegin(); + + /// + /// + /// + void toEnd(); + + /// + /// + /// + Codepoint operator *(); + + /// + /// + /// + Iterator& operator ++(); + + /// + /// + /// + Iterator operator ++(int); + + /// + /// + /// + bool operator !=(const Iterator& itor); + + /// + /// + /// + bool operator ==(const Iterator& itor); + + private: + + /// + /// + /// + void operator = (const Iterator&); + + /// + /// + /// + const Encode encode; + + /// + /// + /// + const Decoder* decoder; + + /// + /// + /// + const void* p; + + /// + /// + /// + const void* const data; + + /// + /// + /// + unsigned int length; + + }; + + /// + /// + /// + Content content; + + }; + + } + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_texture_font.cpp b/src/libjin/Graphics/fonts/je_texture_font.cpp new file mode 100644 index 0000000..6404b16 --- /dev/null +++ b/src/libjin/Graphics/fonts/je_texture_font.cpp @@ -0,0 +1,322 @@ +#include <vector> + +#include "../../math/je_vector2.hpp" + +#include "../shaders/je_shader.h" + +#include "je_texture_font.h" + +using namespace std; +using namespace JinEngine::Math; +using namespace JinEngine::Graphics::Shaders; + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, codepoints, cellw, cellh); + return tf; + } + + TextureFont * TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, int cellw, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, *codepoints, cellw, cellh); + return tf; + } + + TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, codepoints, mask, cellh); + return tf; + } + + TextureFont* TextureFont::createTextureFont(const Bitmap* bitmap, const Text& codepoints, Color mask, int cellh) + { + TextureFont* tf = new TextureFont(bitmap, *codepoints, mask, cellh); + return tf; + } + + TextureFont::~TextureFont() + { + } + + const TextureFont::TextureGlyph* TextureFont::findGlyph(Codepoint codepoint) const + { + auto it = glyphs.find(codepoint); + if (it != glyphs.end()) + { + return &it->second; + } + else + return nullptr; + } + + Page* TextureFont::typeset(const Content& text, int lineheight, int spacing) + { + Page* page = new Page(); + page->font = this; + vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + vector<GlyphVertex>& glyphvertices = page->glyphvertices; + int texture = -1; + const TextureGlyph* glyph = nullptr; + GlyphVertex vertex; + Vector2<int> p(0, 0); + int i = 0; + +#define glyphvertices_push(_x, _y, _u, _v) \ + vertex.x = _x; vertex.y = _y;\ + vertex.u = _u; vertex.v = _v;\ + glyphvertices.push_back(vertex);\ + + for (Codepoint c : text) + { + // return + if (c == 0x0D) continue; + // newline + if (c == 0x0A) + { + p.y += lineheight; + p.x = 0; + continue; + } + if (c == 0x09) + { + // tab = 4*space + unsigned cw = getCharWidth(0x20); + p.x += cw * 4; + continue; + } + glyph = findGlyph(c); + if (glyph == nullptr) continue; + if (texture != getGLTexture()) + { + texture = getGLTexture(); + GlyphArrayDrawInfo info; + info.start = i; + info.count = 0; + info.texture = texture; + glyphinfolist.push_back(info); + } + glyphinfolist[glyphinfolist.size() - 1].count += 4; + // normalized + float w = getWidth(), h = getHeight(); + float nx = glyph->x / w, ny = glyph->y / h; + float nw = glyph->w / w, nh = glyph->h / h; + glyphvertices_push(p.x, p.y, nx, ny); + glyphvertices_push(p.x, p.y + glyph->h, nx, ny + nh); + glyphvertices_push(p.x + glyph->w, p.y + glyph->h, nx + nw, ny + nh); + glyphvertices_push(p.x + glyph->w, p.y, nx + nw, ny); + p.x += glyph->w + spacing; + i += 4; + } + getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); + return page; + } + + int TextureFont::getCharWidth(int c) + { + auto it = glyphs.find(c); + if (it != glyphs.end()) + { + return it->second.w; + } + return 0; + } + + int TextureFont::getCharHeight(int c) + { + auto it = glyphs.find(c); + if (it != glyphs.end()) + { + return it->second.h; + } + return 0; + } + + int TextureFont::getTextWidth(const Content& t, int spacing) + { + int res = 0; + int tmp = 0; + for (Codepoint c : t) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + continue; + } + if (c == 0x09) + { + // tab = 4*space + unsigned cw = getCharWidth(0x20); + tmp += cw * 4; + if (tmp > res) res = tmp; + continue; + } + tmp += getCharWidth(c) + spacing; + if (tmp > res) res = tmp; + } + return res; + } + + int TextureFont::getTextHeight(const Content& t, int lineheight) + { + int res = 0; + bool newline = true; + for (Codepoint c : t) + { + if (c == 0x0A) + newline = true; + else if (c == 0x0D); + else if (newline) + { + newline = false; + res += lineheight; + } + } + return res; + } + + void TextureFont::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) + { + *w = 0; + *h = 0; + int tmp = 0; + bool newline = true; + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + newline = true; + continue; + } + else if (newline) + { + newline = false; + *h += lineheight; + } + tmp += getCharWidth(c) + spacing; + if (tmp > *w) + *w = tmp; + } + } + + Page* TextureFont::typeset(const Text& text, int lineheight, int spacing) + { + return typeset(*text, lineheight, spacing); + } + + void TextureFont::render(const Page* page, int x, int y) + { + Shader* shader = Shader::getCurrentShader(); + const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + const vector<GlyphVertex>& glyphvertices = page->glyphvertices; + gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); + shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); + shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); + for (int i = 0; i < glyphinfolist.size(); ++i) + { + const GlyphArrayDrawInfo& info = glyphinfolist[i]; + shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); + shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); + gl.bindTexture(info.texture); + gl.drawArrays(GL_QUADS, 0, info.count); + gl.bindTexture(0); + } + } + + void TextureFont::render(const Content& text, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(text, lineheight, spacing); + render(page, x, y); + delete page; + } + + void TextureFont::render(const Text& text, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(text, lineheight, spacing); + render(page, x, y); + delete page; + } + + TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh) + : Graphic(bitmap) + , Font(cellh) + { + TextureGlyph glyph; + Vector2<int> count(bitmap->getWidth() / cellw, bitmap->getHeight() / cellh); + glyph.w = cellw; + glyph.h = cellh; + for (int y = 0; y < count.row; ++y) + { + glyph.y = y * cellh; + for (int x = 0; x < count.colum; ++x) + { + glyph.x = x * cellw; + if (x + y * count.colum >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[x + y * count.colum], glyph)); + } + } + } + + TextureFont::TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh) + : Graphic(bitmap) + , Font(cellh) + { + TextureGlyph glyph; + glyph.h = cellh; + int w = bitmap->getWidth(); + int h = bitmap->getHeight(); + int i = 0; + for (int y = 0; y < h; y += cellh) + { + glyph.y = y; + bool newc = false; + for (int x = 0; x <= w; ++x) + { + if (x == w && newc) + { + glyph.w = x - glyph.x; + if (i >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); + ++i; + newc = false; + break; + } + Color c = bitmap->getPixels()[x + y * w]; + if (!newc && c != mask) + { + glyph.x = x; + newc = true; + } + else if (newc && c == mask) + { + glyph.w = x - glyph.x; + if (i >= codepoints.size()) + return; + glyphs.insert(std::pair<Codepoint, TextureGlyph>(codepoints[i], glyph)); + if (codepoints[i] == 't') + { + int a = 10; + } + ++i; + newc = false; + } + } + } + } + + } + } +}
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_texture_font.h b/src/libjin/Graphics/fonts/je_texture_font.h new file mode 100644 index 0000000..13abbae --- /dev/null +++ b/src/libjin/Graphics/fonts/je_texture_font.h @@ -0,0 +1,142 @@ +#ifndef __JE_TEXTURE_FONT_H +#define __JE_TEXTURE_FONT_H + +#include <map> +#include <vector> + +#include "../../math/je_vector4.hpp" + +#include "../je_graphic.h" +#include "../je_bitmap.h" + +#include "je_page.h" +#include "je_font.h" +#include "je_text.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + /// + /// + /// + class TextureFont : public Font, public Graphic + { + public: + + /// + /// + /// + static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); + + /// + /// + /// + static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, int cellw, int cellh); + + /// + /// + /// + static TextureFont* createTextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); + + /// + /// + /// + static TextureFont* createTextureFont(const Bitmap* bitmap, const Text& text, Color mask, int cellh); + + /// + /// + /// + ~TextureFont(); + + /// + /// + /// + Page* typeset(const Text& text, int lineheight, int spacing = 0) override; + + /// + /// + /// + Page* typeset(const Content& text, int lineheight, int spacing = 0) override; + + /// + /// + /// + void render(const Page* page, int x, int y) override; + + /// + /// + /// + void render(const Content& text, int x, int y, int linehgiht, int spacing = 0) override; + + /// + /// + /// + void render(const Text& text, int x, int y, int lineheight, int spacing = 0)override; + + private: + + /// + /// + /// + struct TextureGlyph + { + float x, y, w, h; + }; + + /// + /// + /// + TextureFont(const Bitmap* bitmap, const Content& codepoints, int cellw, int cellh); + + /// + /// + /// + TextureFont(const Bitmap* bitmap, const Content& codepoints, Color mask, int cellh); + + /// + /// + /// + int getCharWidth(int c); + + /// + /// + /// + int getCharHeight(int c); + + /// + /// + /// + int getTextWidth(const Content& text, int spacing = 0); + + /// + /// + /// + int getTextHeight(const Content& text, int lineheight); + + /// + /// + /// + void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); + + /// + /// + /// + const TextureGlyph* findGlyph(Codepoint codepoint) const; + + + /// + /// + /// + std::map<Codepoint, TextureGlyph> glyphs; + + }; + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_ttf.cpp b/src/libjin/Graphics/fonts/je_ttf.cpp new file mode 100644 index 0000000..3d0a02f --- /dev/null +++ b/src/libjin/Graphics/fonts/je_ttf.cpp @@ -0,0 +1,468 @@ +#include "../../core/je_configuration.h" +#if defined(jin_graphics) + +#include <stdio.h> + +#include "../../common/je_array.hpp" + +#include "../je_gl.h" +#include "../je_color.h" +#include "../shaders/je_shader.h" + +#include "je_ttf.h" +#include "je_page.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb/stb_truetype.h" + +using namespace JinEngine::Graphics::Shaders; + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + ///////////////////////////////////////////////////////////////////////////// + // TTFData + ///////////////////////////////////////////////////////////////////////////// + + TTFData* TTFData::createTTFData(const unsigned char* data, unsigned int size) + { + TTFData* ttf = nullptr; + try + { + ttf = new TTFData(data, size); + return ttf; + } + catch (...) + { + return nullptr; + } + } + + TTFData::TTFData(const unsigned char* d, unsigned int s) + { + raw.size = s; + raw.data = (unsigned char*)malloc(s); + memcpy(raw.data, d, s); + if (!stbtt_InitFont(&info, (const unsigned char*)raw.data, 0)) + { + delete raw.data; + throw 0; + } + /* push default fontsize */ + pushTTFsize(FONT_SIZE); + } + + TTFData::~TTFData() + { + free(raw.data); + } + + TTF* TTFData::createTTF(unsigned fontSize) + { + TTF* ttf; + try + { + ttf = new TTF(this, fontSize); + } + catch (...) + { + return nullptr; + } + return ttf; + } + + /* + * (0, 0) + * +--------------+ ascent + * | +--------+ | + * | | | | + * | | bitmap | | + * +--|--------|--+ baseline + * | +--------+ | + * +--|-----------+ decent + * | | + * leftSideBearing | + * advanceWidth + */ + void TTFData::getVMetrics(int* baseline, int* descent) + { + float scale = scales.back(); + int ascent; + stbtt_GetFontVMetrics(&info, &ascent, descent, 0); + *baseline = (int)(ascent*scale) + 1; // slight adjustment + *descent = *baseline - (int)(*descent*scale) + 1; + } + + void TTFData::getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing) + { + float scale = scales.back(); + int adw, lsb; + stbtt_GetCodepointHMetrics(&info, codepoint, &adw, &lsb); + *advanceWidth = (int)(adw*scale); + *leftSideBearing = (int)(lsb*scale); + } + + void TTFData::pushTTFsize(unsigned int fs) + { + float sc = stbtt_ScaleForPixelHeight(&info, fs); + scales.push_back(sc); + } + + void TTFData::popTTFsize() + { + /* always keep default ttf size on the bottom of stack */ + if (scales.size() > 1) + scales.pop_back(); + } + + Channel* TTFData::getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const + { + float scale = scales.back(); + Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); + return bitmap; + } + + Color* TTFData::getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const + { + float scale = scales.back(); + Channel* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, codepoint, width, height, xoff, yoff); + int w = *width, h = *height; + //int xo = *xoff, yo = *yoff; + Color* bitmap32 = new Color[w*h]; + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + bitmap32[x + y * w].set(0xff, 0xff, 0xff, bitmap[x + y * w]); + } + } + free(bitmap); + return bitmap32; + } + + ///////////////////////////////////////////////////////////////////////////// + // TTF + ///////////////////////////////////////////////////////////////////////////// + +#include "../shaders/built-in/je_font.shader.h" + + using namespace std; + using namespace JinEngine::Math; + + const int TTF::TEXTURE_WIDTHS[] = { 128, 256, 256, 512, 512, 1024, 1024 }; + const int TTF::TEXTURE_HEIGHTS[] = { 128, 128, 256, 256, 512, 512, 1024 }; + + /* little endian unicode */ + static const char* unicodeLittleEndian(const char* p, unsigned* res) + { + } + + ///*static*/ TTF* TTF::createTTF(TTFData* fontData, unsigned int fontSzie) + //{ + // TTF* ttf; + // try + // { + // ttf = new TTF(fontData, fontSzie); + // } + // catch (...) + // { + // return nullptr; + // } + // return ttf; + //} + + TTF::TTF(TTFData* f, unsigned int fontSize) + : Font(fontSize) + , cursor(0, 0) + , ttf(f) + { + ttf->pushTTFsize(fontSize); + ttf->getVMetrics(&baseline, &descent); + estimateSize(); + ttf->popTTFsize(); + /* create a default texture */ + createAtlas(); + } + + /* estimate the size of atlas texture */ + void TTF::estimateSize() + { + for (int level = 0; level <= TEXTURE_SIZE_LEVEL_MAX; ++level) + { + if (descent * (descent*0.8) * 96 <= TEXTURE_WIDTHS[level] * TEXTURE_HEIGHTS[level]) + { + textureWidth = TEXTURE_WIDTHS[level]; + textureHeight = TEXTURE_HEIGHTS[level]; + break; + } + } + } + + TTF::~TTF() + { + } + + GLuint TTF::createAtlas() + { + GLuint t; + gl.flushError(); + t = gl.genTexture(); + gl.bindTexture(t); + gl.setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl.setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl.setTexParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.texImage(GL_RGBA8, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE); + if (glGetError() != GL_NO_ERROR) + { + glDeleteTextures(1, &t); + gl.bindTexture(0); + return 0; + } + atlases.push_back(t); + gl.bindTexture(0); + return t; + } + + void TTF::render(const Content& t, int x, int y, int lineheight, int spacing) + { + Page* page = typeset(t, lineheight, spacing); + render(page, x, y); + delete page; + } + + Page* TTF::typeset(const Content& text, int lineheight, int spacing) + { + Page* page = new Page(); + page->font = this; + vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + vector<GlyphVertex>& glyphvertices = page->glyphvertices; + int texture = -1; + TTFGlyph* glyph = nullptr; + GlyphVertex vertex; + Vector2<int> p(0, 0); + int i = 0; + +#define glyphvertices_push(_x, _y, _u, _v) \ + vertex.x = _x; vertex.y = _y;\ + vertex.u = _u; vertex.v = _v;\ + glyphvertices.push_back(vertex); + +#define glyphlize(c)\ + do{\ + glyph = &findGlyph(c); \ + if (texture != glyph->atlas) \ + { \ + GlyphArrayDrawInfo info; \ + info.start = i; \ + info.count = 0; \ + info.texture = glyph->atlas; \ + texture = glyph->atlas; \ + glyphinfolist.push_back(info); \ + } \ + glyphinfolist[glyphinfolist.size() - 1].count += 4; \ + TTFGlyph::Bbox& bbox = glyph->bbox; \ + glyphvertices_push(p.x, p.y, bbox.x, bbox.y); \ + glyphvertices_push(p.x, p.y + glyph->height, bbox.x, bbox.y + bbox.h); \ + glyphvertices_push(p.x + glyph->width, p.y + glyph->height, bbox.x + bbox.w, bbox.y + bbox.h); \ + glyphvertices_push(p.x + glyph->width, p.y, bbox.x + bbox.w, bbox.y); \ + }while(0) + + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + /* new line */ + p.y += lineheight; + p.x = 0; + continue; + } + if (c == 0x09) + { + // tab = 4*space + unsigned cw = getCharWidth(0x20); + p.x += cw * 4; + continue; + } + glyphlize(c); + p.x += glyph->width + spacing; + i += 4; + } + getTextBox(text, &page->size.w, &page->size.h, lineheight, spacing); + return page; + } + + Page* TTF::typeset(const Text& text, int lineheight, int spacing) + { + return typeset(*text, lineheight, spacing); + } + + void TTF::render(const Page* page, int x, int y) + { + Shader* shader = Shader::getCurrentShader(); + const vector<GlyphArrayDrawInfo>& glyphinfolist = page->glyphinfolist; + const vector<GlyphVertex>& glyphvertices = page->glyphvertices; + gl.ModelMatrix.setTransformation(x, y, 0, 1, 1, 0, 0); + shader->sendMatrix4(SHADER_MODEL_MATRIX, &gl.ModelMatrix); + shader->sendMatrix4(SHADER_PROJECTION_MATRIX, &gl.ProjectionMatrix); + for (int i = 0; i < glyphinfolist.size(); ++i) + { + const GlyphArrayDrawInfo& info = glyphinfolist[i]; + shader->bindVertexPointer(2, GL_INT, sizeof(GlyphVertex), &glyphvertices[info.start].x); + shader->bindUVPointer(2, GL_FLOAT, sizeof(GlyphVertex), &glyphvertices[info.start].u); + gl.bindTexture(info.texture); + gl.drawArrays(GL_QUADS, 0, info.count); + gl.bindTexture(0); + } + } + + void TTF::render(const Text& text, int x, int y, int lineheight, int spacing /* = 0 */) + { + render(*text, x, y, lineheight, spacing); + } + + int TTF::getCharWidth(int c) + { + int adw, lsb; + ttf->pushTTFsize(mFontSize); + ttf->getHMetrics(c, &adw, &lsb); + ttf->popTTFsize(); + return adw; + } + + int TTF::getCharHeight(int c) + { + return descent; + } + + int TTF::getTextWidth(const Content& t, int spacing) + { + ttf->pushTTFsize(mFontSize); + int res = 0; + int tmp = 0; + for (Codepoint c : t) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + continue; + } + tmp += getCharWidth(c) + spacing; + if (tmp > res) + res = tmp; + } + ttf->popTTFsize(); + return res; + } + + int TTF::getTextHeight(const Content& t, int lineheight) + { + ttf->pushTTFsize(mFontSize); + int res = 0; + bool newline = true; + for (Codepoint c : t) + { + if (c == 0x0A) + newline = true; + else if (c == 0x0D); + else if (newline) + { + newline = false; + res += lineheight; + } + } + ttf->popTTFsize(); + return res; + } + + void TTF::getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing) + { + ttf->pushTTFsize(mFontSize); + *w = 0; + *h = 0; + int tmp = 0; + bool newline = true; + for (Codepoint c : text) + { + if (c == 0x0D) + continue; + if (c == 0x0A) + { + tmp = 0; + newline = true; + continue; + } + else if (newline) + { + newline = false; + *h += lineheight; + } + tmp += getCharWidth(c) + spacing; + if (tmp > *w) + *w = tmp; + } + ttf->popTTFsize(); + } + + TTF::TTFGlyph& TTF::bakeGlyph(unsigned int character) + { + int w, h, xoff, yoff; + ttf->pushTTFsize(mFontSize); + GLuint atlas = atlases.back(); + const Color* bitmap = ttf->getCodepointBitmap(character, &w, &h, &xoff, &yoff); + int adw, lsb; + { + /* bake glyph */ + ttf->getHMetrics(character, &adw, &lsb); + ttf->popTTFsize(); + if (cursor.x + adw > textureWidth) + { + cursor.x = 0; + cursor.y += descent; + if (cursor.y + descent * 2 > textureHeight) + { + /* create new atlas */ + atlas = createAtlas(); + cursor.y = 0; + } + } + gl.bindTexture(atlas); + gl.texSubImage(cursor.x + xoff, cursor.y + yoff + baseline, w, h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap); + gl.bindTexture(); + delete[] bitmap; + } + TTFGlyph glyph; + glyph.atlas = atlas; + glyph.bbox.x = cursor.x / (float)textureWidth; + glyph.bbox.y = cursor.y / (float)textureHeight; + glyph.bbox.w = adw / (float)textureWidth; + glyph.bbox.h = descent / (float)textureHeight; + glyph.width = adw; + glyph.height = descent; + glyphs.insert(std::pair<unsigned int, TTFGlyph>(character, glyph)); + cursor.x += adw; + return glyphs[character]; + } + + TTF::TTFGlyph& TTF::findGlyph(unsigned int character) + { + map<unsigned int, TTFGlyph>::iterator it = glyphs.find(character); + if (it != glyphs.end()) + return it->second; + else + return bakeGlyph(character); + } + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif // defined(jin_graphics)
\ No newline at end of file diff --git a/src/libjin/Graphics/fonts/je_ttf.h b/src/libjin/Graphics/fonts/je_ttf.h new file mode 100644 index 0000000..02017ec --- /dev/null +++ b/src/libjin/Graphics/fonts/je_ttf.h @@ -0,0 +1,292 @@ +#ifndef __JETTF_H +#define __JE_TTF_H +#include "../../core/je_configuration.h" +#if defined(jin_graphics) + +#include <vector> +#include <map> + +#include "stb/stb_truetype.h" + +#include "../../math/je_quad.h" + +#include "../je_color.h" +#include "../je_graphic.h" + +#include "je_page.h" +#include "je_font.h" +#include "je_text.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Fonts + { + + class TTF; + + // + // TTFData + // |- TTF(14px) + // |- TTF(15px) + // . + // . + // . + // + class TTFData + { + public: + + /// + /// + /// + static TTFData* createTTFData(const unsigned char* data, unsigned int size); + + /// + /// + /// + ~TTFData(); + + /// + /// + /// + TTF* createTTF(unsigned ttfsize); + + /// + /// + /// + void pushTTFsize(unsigned ttfsize); + + /// + /// + /// + void popTTFsize(); + + /// + /// + /// + Channel* getCodepointBitmapAlpha(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; + + /// + /// + /// + Color* getCodepointBitmap(unsigned int codepoint, int* width, int* height, int* xoff, int* yoff) const; + + /// + /// + /// + void getVMetrics(int* baseline, int* descent); + + /// + /// + /// + void getHMetrics(unsigned int codepoint, int* advanceWidth, int* leftSideBearing); + + private: + + /// + /// + /// + static const unsigned int FONT_SIZE = 12; + + /// + /// + /// + TTFData(const unsigned char* data, unsigned int size); + + /// + /// + /// + stbtt_fontinfo info; + + /// + /// + /// + struct + { + unsigned char* data; + unsigned int size; + } raw; + + /// + /// + /// + std::vector<float> scales; + + }; + + class TTF : public Font + { + public: + //static TTF* createTTF(TTFData* ttfData, unsigned ttfSzie); + + /// + /// + /// + Page* typeset(const Text& text, int lineheight, int spacing = 0) override; + + /// + /// + /// + Page* typeset(const Content& text, int lineheight, int spacing = 0) override; + + /// + /// + /// + void render(const Text& text, int x, int y, int lineheight, int spacing = 0) override; + + /// + /// + /// + void render(const Content& text, int x, int y, int lineheight, int spacing = 0) override; + + /// + /// + /// + void render(const Page* page, int x, int y) override; + + /// + /// + /// + ~TTF(); + + private: + + friend class TTFData; + + /// + /// + /// + struct TTFGlyph + { + GLuint atlas; + // normalized coordinates + struct Bbox + { + float x, y; + float w, h; + } bbox; + // glyph size in pixel + unsigned int width, height; + }; + + /// + /// + /// + static const int TEXTURE_SIZE_LEVELS_COUNT = 7; + + /// + /// + /// + static const int TEXTURE_SIZE_LEVEL_MAX = TEXTURE_SIZE_LEVELS_COUNT - 1; + + /// + /// + /// + static const int TEXTURE_WIDTHS[TEXTURE_SIZE_LEVELS_COUNT]; + + /// + /// + /// + static const int TEXTURE_HEIGHTS[TEXTURE_SIZE_LEVELS_COUNT]; + + /// + /// + /// + TTF(TTFData* ttf, Codepoint ttfSize); + + /// + /// + /// + void estimateSize(); + + /// + /// + /// + GLuint createAtlas(); + + /// + /// + /// + TTFGlyph& bakeGlyph(Codepoint character); + + /// + /// + /// + TTFGlyph& findGlyph(Codepoint character); + + /// + /// + /// + int getCharWidth(int c); + + /// + /// + /// + int getCharHeight(int c); + + /// + /// + /// + int getTextWidth(const Content& text, int spacing = 0); + + /// + /// + /// + int getTextHeight(const Content& text, int lineheight); + + /// + /// + /// + void getTextBox(const Content& text, int* w, int* h, int lineheight, int spacing = 0); + + /// + /// + /// + int textureWidth; + + /// + /// + /// + int textureHeight; + + /// + /// + /// + std::vector<GLuint> atlases; + + /// + /// + /// + std::map<Codepoint, TTFGlyph> glyphs; + + /// + /// + /// + TTFData* ttf; + + /// + /// + /// + int baseline; + + /// + /// + /// + int descent; + + /// + /// + /// + Math::Vector2<float> cursor; + + }; + + } // namespace Fonts + } // namespace Graphics +} // namespace JinEngine + +#endif // defined(jin_graphics) + +#endif // __JE_FONT_H
\ No newline at end of file diff --git a/src/libjin/Graphics/je_graphic.cpp b/src/libjin/Graphics/je_graphic.cpp index 66fb494..5df202f 100644 --- a/src/libjin/Graphics/je_graphic.cpp +++ b/src/libjin/Graphics/je_graphic.cpp @@ -5,9 +5,11 @@ #include "../math/je_matrix.h" -#include "shader/je_shader.h" +#include "shaders/je_shader.h" #include "je_graphic.h" +using namespace JinEngine::Graphics::Shaders; + namespace JinEngine { namespace Graphics diff --git a/src/libjin/Graphics/je_graphics.h b/src/libjin/Graphics/je_graphics.h index e2e9a2d..bef72c0 100644 --- a/src/libjin/Graphics/je_graphics.h +++ b/src/libjin/Graphics/je_graphics.h @@ -11,13 +11,13 @@ #include "je_bitmap.h" #include "je_image.h" -#include "shader/je_shader.h" +#include "shaders/je_shader.h" -#include "font/je_ttf.h" -#include "font/je_text.h" -#include "font/je_texture_font.h" +#include "fonts/je_ttf.h" +#include "fonts/je_text.h" +#include "fonts/je_texture_font.h" -#include "particle/je_particle_system.h" +#include "particles/je_particle_system.h" #endif // defined(jin_graphics) #endif // __JE_GRAPHICS_H
\ No newline at end of file diff --git a/src/libjin/Graphics/je_shapes.cpp b/src/libjin/Graphics/je_shapes.cpp index 3146f31..f15300d 100644 --- a/src/libjin/Graphics/je_shapes.cpp +++ b/src/libjin/Graphics/je_shapes.cpp @@ -6,9 +6,11 @@ #include "../math/je_matrix.h" #include "../math/je_constant.h" -#include "shader/je_shader.h" +#include "shaders/je_shader.h" #include "je_shapes.h" +using namespace JinEngine::Graphics::Shaders; + namespace JinEngine { namespace Graphics diff --git a/src/libjin/Graphics/je_sprite.h b/src/libjin/Graphics/je_sprite.h index 730e11e..6e6812a 100644 --- a/src/libjin/Graphics/je_sprite.h +++ b/src/libjin/Graphics/je_sprite.h @@ -4,7 +4,7 @@ #include "../common/je_types.h" #include "../math/je_vector2.hpp" -#include "shader/je_shader.h" +#include "shaders/je_shader.h" #include "je_color.h" namespace JinEngine @@ -22,7 +22,7 @@ namespace JinEngine void setPosition(int x, int y); void setScale(float x, float y); void setColor(Color color); - void setShader(const Shader* shader); + void setShader(const Shaders::Shader* shader); void setGraphic(const Graphic* graphic); /// @@ -38,7 +38,7 @@ namespace JinEngine Math::Vector2<int> mOrigin; Math::Vector2<float> mScale; Color mColor; - Shader* mShader; + Shaders::Shader* mShader; Graphic* mGraphic; }; diff --git a/src/libjin/Graphics/je_window.cpp b/src/libjin/Graphics/je_window.cpp index b36a2a3..7265898 100644 --- a/src/libjin/Graphics/je_window.cpp +++ b/src/libjin/Graphics/je_window.cpp @@ -7,11 +7,13 @@ #include "../audio/sdl/je_sdl_audio.h" #include "../utils/je_log.h" -#include "shader/je_shader.h" +#include "shaders/je_shader.h" #include "je_window.h" #include "je_gl.h" #include "je_canvas.h" +using namespace JinEngine::Graphics::Shaders; + namespace JinEngine { namespace Graphics @@ -19,9 +21,7 @@ namespace JinEngine bool Window::initSystem(const SettingBase* s) { - #if defined(jin_debug) - Loghelper::log(Loglevel::LV_INFO, "Init window system"); - #endif + jin_log_info("Initialize window system."); if (SDL_Init(SDL_INIT_VIDEO) < 0) return false; @@ -84,6 +84,7 @@ namespace JinEngine void Window::quitSystem() { + jin_log_info("Quit window system."); // disable opengl gl.disable(GL_BLEND); gl.disable(GL_TEXTURE_2D); diff --git a/src/libjin/Graphics/particle/je_particle.h b/src/libjin/Graphics/particle/je_particle.h deleted file mode 100644 index 089bf35..0000000 --- a/src/libjin/Graphics/particle/je_particle.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef __JE_PARTICLE_H -#define __JE_PARTICLE_H - -#include "../../math/je_vector2.hpp" - -namespace JinEngine -{ - namespace Graphics - { - - class ParticleEmitter; - - struct LifeTimeDef - { - bool enableRandom = false; - union - { - struct - { - float min, max; - } random; - float life; - } life; - }; - - struct LinearAccelaration - { - - }; - - struct SpeedOverTimeDef - { - bool enable = false; - bool enableRandom = false; - union - { - struct - { - Math::Vector2<float> startFloor; - Math::Vector2<float> startCeil; - Math::Vector2<float> endFloor; - Math::Vector2<float> endCeil; - } random; - struct - { - Math::Vector2<float> start; - Math::Vector2<float> end; - } speed; - } speed; - }; - - struct SizeOverTimeDef - { - bool enable = false; - bool enableRandom = false; - union { - struct { - float startFloor = 1; - float startCeil = 1; - float endFloor = 1; - float endCeil = 1; - } random; - struct { - float start = 1; - float end = 1; - } size; - } size; - }; - - struct ColorOverTime - { - bool enable = false; - Color colorStart = Color::WHITE; - Color colorEnd = Color::WHITE; - }; - - /// - /// - /// - struct ParticleDef - { - private: - friend class ParticleEmitter; - - public: - // Basic definitions. - LifeTimeDef lifeTimeDef; ///< - // Optional definitions. - - SpeedOverTimeDef speedOverTimeDef; ///< - SizeOverTimeDef sizeOverTimeDef; ///< - ColorOverTime colorOverTimeDef; ///< - }; - - /// - /// A single particle contains various properties of particle, such as position, accelaration, color and - /// other attributes changed over time. - /// - struct Particle - { - Particle(const ParticleDef& particleDef); - /// - /// Whole life time. - /// - float lifeTime = 0.0f; - - /// - /// Current life time. - /// - float life = 0.0f; - - /// - /// Current position. - /// - float position[2] = {0,0}; - - /// - /// Emitte direction. - /// - float direction = 0; - - Math::Vector2<float> speed; - Math::Vector2<float> linearAcceleration; - float radialAcceleration = 0; - float tangetialAcceleration = 0; - - /// - /// Size over lifetime. - /// - float size = 1; - float sizeBegin = 1; - float sizeEnd = 1; - - float rotation = 0; - float angle = 0; - - /// - /// Color over lifetime. - /// - Color color = Color::WHITE; - Color colorStart = Color::WHITE; - Color colorEnd = Color::WHITE; - - /// - /// Is particle still alive? Alive is equivalent to NOT available in particle pool. - /// - bool alive = false; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_emitter.h b/src/libjin/Graphics/particle/je_particle_emitter.h deleted file mode 100644 index 5e4316d..0000000 --- a/src/libjin/Graphics/particle/je_particle_emitter.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef __JE_PARTICLE_EMITTER_H -#define __JE_PARTICLE_EMITTER_H - -#include "../../common/je_temporary.h" -#include "../../math/je_vector2.hpp" - -#include "je_particle.h" - -namespace JinEngine -{ - namespace Graphics - { - - struct PositionDef - { - bool enableRandom = false; - union - { - struct - { - Math::Vector2<float> min; - Math::Vector2<float> max; - } random; - Math::Vector2<float> position; - } position; - }; - - struct DirectionDef - { - bool enableRandom = false; - union - { - struct - { - float min = 0; - float max = 0; - } random; - float direction = 0; - } direction; - }; - - struct EmitRateDef - { - bool enableRandom = false; - union - { - struct - { - float min = 1; - float max = 1; - } random; - float rate = 1; - } rate; - }; - - /// - /// Definition of particle emitter. - /// - struct ParticleEmitterDef : public Temporary - { - PositionDef positionDef; ///< Emit position(relativily to the particle system center). - DirectionDef directionDef; ///< Emit direction. - EmitRateDef emitRateDef; ///< Emit rate. - }; - - /// - /// Emit a single particle. - /// - class ParticleEmitter - { - public: - /// - /// ParticleEmitter constructor. - /// - /// @param emitterDef Definition of particle emitter. - /// @param particleDef Definition of particle. - /// - ParticleEmitter(const ParticleEmitterDef& emitterDef, const ParticleDef& particleDef); - - /// - /// Emit a particle according to emitter definition and particle definition, particle system should - /// assign particle value to the particle in particle pool, but not use this return particle. - /// - Particle emit(); - - private: - float mDirection; - ParticleEmitterDef mEmitterDef; - ParticleDef mParticleDef; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_pool.h b/src/libjin/Graphics/particle/je_particle_pool.h deleted file mode 100644 index f1f6214..0000000 --- a/src/libjin/Graphics/particle/je_particle_pool.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __JE_PARTICLE_BATCH_H -#define __JE_PARTICLE_BATCH_H - -#include <list> - -#include "je_particle.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Particle pool for reducing memory fragmentation. - /// - class ParticlePool - { - public: - - /// - /// Particle pool constructor. - /// - /// @param count Max count of particles. - /// - ParticlePool(uint count); - - /// - /// Particle pool destructor. - /// - ~ParticlePool(); - - /// - /// Claim a particle if available. - /// - Particle* claim(); - - /// - /// Recycle particle if the particle is no more alive. - /// - void recycle(Particle* particle); - - private: - /// - /// All particles include available and inavailable particles. - /// - std::list<Particle> particles; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_system.h b/src/libjin/Graphics/particle/je_particle_system.h deleted file mode 100644 index 8526da8..0000000 --- a/src/libjin/Graphics/particle/je_particle_system.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef __JE_PARTICLE_EMMITTER_H -#define __JE_PARTICLE_EMMITTER_H - -#include <vector> - -#include "../../common/je_temporary.h" -#include "../../game/je_gameobject.h" - -#include "../je_sprite.h" - -#include "je_particle_emitter.h" -#include "je_particle_pool.h" -#include "je_particle.h" - -namespace JinEngine -{ - namespace Graphics - { - - /// - /// Definition of particle system. - /// - struct ParticleSystemDef : public Temporary - { - uint maxParticleCount = 1; ///< Max count of particles in pool. 1 by default. - - ParticleEmitterDef emitterDef; ///< Particle emitter definition. - ParticleDef particleDef; ///< Particle definition. - }; - - /// - /// Particle emitter, handle all particles it emitts. - /// - class ParticleSystem : public Game::GameObject - { - public: - /// - /// Particle system constructor - /// - /// @param def Definition of particle system. - /// - ParticleSystem(const ParticleSystemDef& def); - - /// - /// Particle system destructor. - /// - ~ParticleSystem(); - - /// - /// Render particle system's all particles. - /// - void render(int x, int y, float sx = 1, float sy = 1, float r = 0, float ax = 0, float ay = 0); - - /// - /// Set sprite to render. - /// - /// @param sprite Sprite to render. - /// - void setSprite(Sprite* sprite); - - /// - /// Release particle and make it available in particle pool. - /// - void releaseParticle(); - - private: - // Disable default constructor. - ParticleSystem(); - - /// - /// Sprite to be drawn. - /// - Sprite* mSprite; - - /// - /// Particle emitter. - /// - ParticleEmitter mEmitter; - ParticlePool mParticlePool; - - /// - /// Alive particles, that means these particles could join to the life cycle loop. - /// - std::vector<Particle*> mAliveParticles; - - }; - - } // namespace Graphics -} // namespace JinEngine - -#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle.cpp b/src/libjin/Graphics/particles/je_particle.cpp index e69de29..e69de29 100644 --- a/src/libjin/Graphics/particle/je_particle.cpp +++ b/src/libjin/Graphics/particles/je_particle.cpp diff --git a/src/libjin/Graphics/particles/je_particle.h b/src/libjin/Graphics/particles/je_particle.h new file mode 100644 index 0000000..819b95c --- /dev/null +++ b/src/libjin/Graphics/particles/je_particle.h @@ -0,0 +1,157 @@ +#ifndef __JE_PARTICLE_H +#define __JE_PARTICLE_H + +#include "../../math/je_vector2.hpp" + +namespace JinEngine +{ + namespace Graphics + { + namespace Particles + { + + class ParticleEmitter; + + struct LifeTimeDef + { + bool enableRandom = false; + union + { + struct + { + float min, max; + } random; + float life; + } life; + }; + + struct LinearAccelaration + { + + }; + + struct SpeedOverTimeDef + { + bool enable = false; + bool enableRandom = false; + union + { + struct + { + Math::Vector2<float> startFloor; + Math::Vector2<float> startCeil; + Math::Vector2<float> endFloor; + Math::Vector2<float> endCeil; + } random; + struct + { + Math::Vector2<float> start; + Math::Vector2<float> end; + } speed; + } speed; + }; + + struct SizeOverTimeDef + { + bool enable = false; + bool enableRandom = false; + union { + struct { + float startFloor = 1; + float startCeil = 1; + float endFloor = 1; + float endCeil = 1; + } random; + struct { + float start = 1; + float end = 1; + } size; + } size; + }; + + struct ColorOverTime + { + bool enable = false; + Color colorStart = Color::WHITE; + Color colorEnd = Color::WHITE; + }; + + /// + /// + /// + struct ParticleDef + { + private: + friend class ParticleEmitter; + + public: + // Basic definitions. + LifeTimeDef lifeTimeDef; ///< + // Optional definitions. + + SpeedOverTimeDef speedOverTimeDef; ///< + SizeOverTimeDef sizeOverTimeDef; ///< + ColorOverTime colorOverTimeDef; ///< + }; + + /// + /// A single particle contains various properties of particle, such as position, accelaration, color and + /// other attributes changed over time. + /// + struct Particle + { + Particle(const ParticleDef& particleDef); + /// + /// Whole life time. + /// + float lifeTime = 0.0f; + + /// + /// Current life time. + /// + float life = 0.0f; + + /// + /// Current position. + /// + float position[2] = { 0,0 }; + + /// + /// Emitte direction. + /// + float direction = 0; + + Math::Vector2<float> speed; + Math::Vector2<float> linearAcceleration; + float radialAcceleration = 0; + float tangetialAcceleration = 0; + + /// + /// Size over lifetime. + /// + float size = 1; + float sizeBegin = 1; + float sizeEnd = 1; + + float rotation = 0; + float angle = 0; + + /// + /// Color over lifetime. + /// + Color color = Color::WHITE; + Color colorStart = Color::WHITE; + Color colorEnd = Color::WHITE; + + /// + /// Is particle still alive? Alive is equivalent to NOT available in particle pool. + /// + bool alive = false; + + }; + + } // namespace Particles + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_emitter.cpp b/src/libjin/Graphics/particles/je_particle_emitter.cpp index 0ab9cf1..0ab9cf1 100644 --- a/src/libjin/Graphics/particle/je_particle_emitter.cpp +++ b/src/libjin/Graphics/particles/je_particle_emitter.cpp diff --git a/src/libjin/Graphics/particles/je_particle_emitter.h b/src/libjin/Graphics/particles/je_particle_emitter.h new file mode 100644 index 0000000..c6e4321 --- /dev/null +++ b/src/libjin/Graphics/particles/je_particle_emitter.h @@ -0,0 +1,99 @@ +#ifndef __JE_PARTICLE_EMITTER_H +#define __JE_PARTICLE_EMITTER_H + +#include "../../common/je_temporary.h" +#include "../../math/je_vector2.hpp" + +#include "je_particle.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Particles + { + + struct PositionDef + { + bool enableRandom = false; + union + { + struct + { + Math::Vector2<float> min; + Math::Vector2<float> max; + } random; + Math::Vector2<float> position; + } position; + }; + + struct DirectionDef + { + bool enableRandom = false; + union + { + struct + { + float min = 0; + float max = 0; + } random; + float direction = 0; + } direction; + }; + + struct EmitRateDef + { + bool enableRandom = false; + union + { + struct + { + float min = 1; + float max = 1; + } random; + float rate = 1; + } rate; + }; + + /// + /// Definition of particle emitter. + /// + struct ParticleEmitterDef : public Temporary + { + PositionDef positionDef; ///< Emit position(relativily to the particle system center). + DirectionDef directionDef; ///< Emit direction. + EmitRateDef emitRateDef; ///< Emit rate. + }; + + /// + /// Emit a single particle. + /// + class ParticleEmitter + { + public: + /// + /// ParticleEmitter constructor. + /// + /// @param emitterDef Definition of particle emitter. + /// @param particleDef Definition of particle. + /// + ParticleEmitter(const ParticleEmitterDef& emitterDef, const ParticleDef& particleDef); + + /// + /// Emit a particle according to emitter definition and particle definition, particle system should + /// assign particle value to the particle in particle pool, but not use this return particle. + /// + Particle emit(); + + private: + float mDirection; + ParticleEmitterDef mEmitterDef; + ParticleDef mParticleDef; + + }; + + } // namespace Particles + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_pool.cpp b/src/libjin/Graphics/particles/je_particle_pool.cpp index e69de29..e69de29 100644 --- a/src/libjin/Graphics/particle/je_particle_pool.cpp +++ b/src/libjin/Graphics/particles/je_particle_pool.cpp diff --git a/src/libjin/Graphics/particles/je_particle_pool.h b/src/libjin/Graphics/particles/je_particle_pool.h new file mode 100644 index 0000000..9bc7d78 --- /dev/null +++ b/src/libjin/Graphics/particles/je_particle_pool.h @@ -0,0 +1,56 @@ +#ifndef __JE_PARTICLE_BATCH_H +#define __JE_PARTICLE_BATCH_H + +#include <list> + +#include "je_particle.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Particles + { + + /// + /// Particle pool for reducing memory fragmentation. + /// + class ParticlePool + { + public: + + /// + /// Particle pool constructor. + /// + /// @param count Max count of particles. + /// + ParticlePool(uint count); + + /// + /// Particle pool destructor. + /// + ~ParticlePool(); + + /// + /// Claim a particle if available. + /// + Particle* claim(); + + /// + /// Recycle particle if the particle is no more alive. + /// + void recycle(Particle* particle); + + private: + /// + /// All particles include available and inavailable particles. + /// + std::list<Particle> particles; + + }; + + } // namespace Particles + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/particle/je_particle_system.cpp b/src/libjin/Graphics/particles/je_particle_system.cpp index 68f8f21..68f8f21 100644 --- a/src/libjin/Graphics/particle/je_particle_system.cpp +++ b/src/libjin/Graphics/particles/je_particle_system.cpp diff --git a/src/libjin/Graphics/particles/je_particle_system.h b/src/libjin/Graphics/particles/je_particle_system.h new file mode 100644 index 0000000..aa7ff99 --- /dev/null +++ b/src/libjin/Graphics/particles/je_particle_system.h @@ -0,0 +1,94 @@ +#ifndef __JE_PARTICLE_EMMITTER_H +#define __JE_PARTICLE_EMMITTER_H + +#include <vector> + +#include "../../common/je_temporary.h" +#include "../../game/je_gameobject.h" + +#include "../je_sprite.h" + +#include "je_particle_emitter.h" +#include "je_particle_pool.h" +#include "je_particle.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Particles + { + + /// + /// Definition of particle system. + /// + struct ParticleSystemDef : public Temporary + { + uint maxParticleCount = 1; ///< Max count of particles in pool. 1 by default. + + ParticleEmitterDef emitterDef; ///< Particle emitter definition. + ParticleDef particleDef; ///< Particle definition. + }; + + /// + /// Particle emitter, handle all particles it emitts. + /// + class ParticleSystem : public Game::GameObject + { + public: + /// + /// Particle system constructor + /// + /// @param def Definition of particle system. + /// + ParticleSystem(const ParticleSystemDef& def); + + /// + /// Particle system destructor. + /// + ~ParticleSystem(); + + /// + /// Render particle system's all particles. + /// + void render(int x, int y, float sx = 1, float sy = 1, float r = 0, float ax = 0, float ay = 0); + + /// + /// Set sprite to render. + /// + /// @param sprite Sprite to render. + /// + void setSprite(Sprite* sprite); + + /// + /// Release particle and make it available in particle pool. + /// + void releaseParticle(); + + private: + // Disable default constructor. + ParticleSystem(); + + /// + /// Sprite to be drawn. + /// + Sprite* mSprite; + + /// + /// Particle emitter. + /// + ParticleEmitter mEmitter; + ParticlePool mParticlePool; + + /// + /// Alive particles, that means these particles could join to the life cycle loop. + /// + std::vector<Particle*> mAliveParticles; + + }; + + } // namespace Particles + } // namespace Graphics +} // namespace JinEngine + +#endif
\ No newline at end of file diff --git a/src/libjin/Graphics/Shader/shaders/je_default.shader.h b/src/libjin/Graphics/shaders/built-in/je_default.shader.h index 3f57c44..3f57c44 100644 --- a/src/libjin/Graphics/Shader/shaders/je_default.shader.h +++ b/src/libjin/Graphics/shaders/built-in/je_default.shader.h diff --git a/src/libjin/Graphics/Shader/shaders/je_font.shader.h b/src/libjin/Graphics/shaders/built-in/je_font.shader.h index e04c225..e04c225 100644 --- a/src/libjin/Graphics/Shader/shaders/je_font.shader.h +++ b/src/libjin/Graphics/shaders/built-in/je_font.shader.h diff --git a/src/libjin/Graphics/Shader/shaders/je_texture.shader.h b/src/libjin/Graphics/shaders/built-in/je_texture.shader.h index d1fc86f..d1fc86f 100644 --- a/src/libjin/Graphics/Shader/shaders/je_texture.shader.h +++ b/src/libjin/Graphics/shaders/built-in/je_texture.shader.h diff --git a/src/libjin/Graphics/Shader/je_base.shader.h b/src/libjin/Graphics/shaders/je_base.shader.h index d6f9d7b..d6f9d7b 100644 --- a/src/libjin/Graphics/Shader/je_base.shader.h +++ b/src/libjin/Graphics/shaders/je_base.shader.h diff --git a/src/libjin/Graphics/shaders/je_jsl_compiler.cpp b/src/libjin/Graphics/shaders/je_jsl_compiler.cpp new file mode 100644 index 0000000..feb88d4 --- /dev/null +++ b/src/libjin/Graphics/shaders/je_jsl_compiler.cpp @@ -0,0 +1,57 @@ +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include "../../Filesystem/je_buffer.h" + +#include "je_jsl_compiler.h" + +using namespace std; +using namespace JinEngine::Filesystem; + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + #include "je_base.shader.h" + + bool JSLCompiler::compile(const string& jsl, string* vertex_shader, string* fragment_shader) + { + // parse shader source, need some optimizations + int loc_VERTEX_SHADER = jsl.find("#VERTEX_SHADER"); + int loc_END_VERTEX_SHADER = jsl.find("#END_VERTEX_SHADER"); + int loc_FRAGMENT_SHADER = jsl.find("#FRAGMENT_SHADER"); + int loc_END_FRAGMENT_SHADER = jsl.find("#END_FRAGMENT_SHADER"); + if (loc_VERTEX_SHADER == string::npos + || loc_END_VERTEX_SHADER == string::npos + || loc_FRAGMENT_SHADER == string::npos + || loc_END_FRAGMENT_SHADER == string::npos + ) + return false; + // Load vertex and fragment shader source into buffers. + { + // Compile JSL vertex program. + int start = loc_VERTEX_SHADER + strlen("#VERTEX_SHADER"); + *vertex_shader = jsl.substr(start, loc_END_VERTEX_SHADER - start); + Buffer vbuffer = Buffer(vertex_shader->length() + BASE_VERTEX_SHADER_SIZE); + formatVertexShader((char*)&vbuffer, vertex_shader->c_str()); + vertex_shader->assign((char*)&vbuffer); + } + { + // Compile JSL fragment program. + int start = loc_FRAGMENT_SHADER + strlen("#FRAGMENT_SHADER"); + *fragment_shader = jsl.substr(start, loc_END_FRAGMENT_SHADER - start); + Buffer fbuffer = Buffer(fragment_shader->length() + BASE_FRAGMENT_SHADER_SIZE); + formatFragmentShader((char*)&fbuffer, fragment_shader->c_str()); + fragment_shader->assign((char*)&fbuffer); + } + return true; + } + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/Graphics/shaders/je_jsl_compiler.h b/src/libjin/Graphics/shaders/je_jsl_compiler.h new file mode 100644 index 0000000..eeb42ae --- /dev/null +++ b/src/libjin/Graphics/shaders/je_jsl_compiler.h @@ -0,0 +1,45 @@ +#ifndef __JE_JSL_COMPILER_H +#define __JE_JSL_COMPILER_H + +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <string> + +#include "../../common/je_singleton.hpp" + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + /// + /// Compile JSL into GLSL. + /// + class JSLCompiler : public Singleton<JSLCompiler> + { + public: + /// + /// Compile JSL shader source into GLSL. + /// + /// @param jsl JSL shader source. + /// @param glsl_vertex Output of vertex glsl shader source. + /// @param glsl_fragment Output of fragment glsl shader source. + /// @return True if compile successful, otherwise return false. + /// + bool compile(const std::string& jsl, std::string* glsl_vertex, std::string* glsl_fragment); + + private: + singleton(JSLCompiler); + + }; + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) + +#endif // __JE_JSL_COMPILER_H
\ No newline at end of file diff --git a/src/libjin/Graphics/shaders/je_shader.cpp b/src/libjin/Graphics/shaders/je_shader.cpp new file mode 100644 index 0000000..3eae5c7 --- /dev/null +++ b/src/libjin/Graphics/shaders/je_shader.cpp @@ -0,0 +1,281 @@ +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <iostream> + +#include "../../filesystem/je_buffer.h" +#include "../../utils/je_macros.h" + +#include "je_jsl_compiler.h" +#include "je_shader.h" + +using namespace std; +using namespace JinEngine::Filesystem; + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + // + // default_texture + // base_shader + // SHADER_FORMAT_SIZE + // formatShader + // +#include "built-in/je_default.shader.h" + +// +// https://stackoverflow.com/questions/27941496/use-sampler-without-passing-through-value +// The default value of a sampler variable is 0. From the GLSL 3.30 spec, +// section "4.3.5 Uniforms": +// +// The link time initial value is either the value of the variable's +// initializer, if present, or 0 if no initializer is present.Sampler +// types cannot have initializers. +// +// Since a value of 0 means that it's sampling from texture unit 0, it will +// work without ever setting the value as long as you bind your textures to +// unit 0. This is well defined behavior. +// +// Since texture unit 0 is also the default until you call glActiveTexture() +// with a value other than GL_TEXTURE0, it's very common to always use unit +// 0 as long as shaders do not need more than one texture.Which means that +// often times, setting the sampler uniforms is redundant for simple +// applications. +// +// I would still prefer to always set the values.If nothing else, it makes +// it clear to anybody reading your code that you really mean to sample from +// texture unit 0, and did not just forget to set the value. +// + const int DEFAULT_TEXTURE_UNIT = 0; + + /*static*/ Shader* Shader::CurrentShader = nullptr; + + Shader* Shader::createShader(const string& program) + { + Shader* shader = nullptr; + try + { + shader = new Shader(program); + } + catch (...) + { + return nullptr; + } + return shader; + } + + Shader::Shader(const string& program) + : mCurrentTextureUnit(DEFAULT_TEXTURE_UNIT) + { + if (!compile(program)) + throw 0; + } + + Shader::~Shader() + { + if (CurrentShader == this) + unuse(); + // delete shader program + glDeleteShader(mPID); + } + + bool Shader::compile(const string& program) + { + string vertex_shader, fragment_shader; + // Compile JSL shader source into GLSL shader source. + JSLCompiler* compiler = JSLCompiler::get(); + if (!compiler->compile(program, &vertex_shader, &fragment_shader)) + { + return false; + } +#define glsl(SHADER_MODE, SHADER, SRC) \ +do{ \ +const GLchar* src = SRC.c_str(); \ +glShaderSource(SHADER, 1, &src, NULL); \ +glCompileShader(SHADER); \ +GLint success; \ +glGetShaderiv(SHADER, GL_COMPILE_STATUS, &success); \ +if (success == GL_FALSE) \ + return false; \ +}while(0) + // Compile vertex shader. + GLuint vid = glCreateShader(GL_VERTEX_SHADER); + glsl(GL_VERTEX_SHADER, vid, vertex_shader); + // Compile fragment shader. + GLuint fid = glCreateShader(GL_FRAGMENT_SHADER); + glsl(GL_FRAGMENT_SHADER, fid, fragment_shader); +#undef glsl + // Create OpenGL shader program. + mPID = glCreateProgram(); + glAttachShader(mPID, vid); + glAttachShader(mPID, fid); + glLinkProgram(mPID); + GLint success; + glGetProgramiv(mPID, GL_LINK_STATUS, &success); + if (success == GL_FALSE) + return false; + } + + static inline GLint getMaxTextureUnits() + { + GLint maxTextureUnits = 0; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + return maxTextureUnits; + } + + void Shader::use() + { + glUseProgram(mPID); + CurrentShader = this; + sendInt(SHADER_MAIN_TEXTURE, DEFAULT_TEXTURE_UNIT); + } + + /*static*/ void Shader::unuse() + { + glUseProgram(0); + CurrentShader = nullptr; + } + + GLint Shader::claimTextureUnit(const std::string& name) + { + std::map<std::string, GLint>::iterator unit = mTextureUnits.find(name); + if (unit != mTextureUnits.end()) + return unit->second; + static GLint MAX_TEXTURE_UNITS = getMaxTextureUnits(); + if (++mCurrentTextureUnit >= MAX_TEXTURE_UNITS) + return 0; + mTextureUnits[name] = mCurrentTextureUnit; + return mCurrentTextureUnit; + } + +#define checkJSL() \ + if (CurrentShader != this) \ + return + + void Shader::sendInt(const char* name, int value) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform1i(loc, value); + } + + void Shader::sendFloat(const char* variable, float number) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, variable); + glUniform1f(loc, number); + } + + // + // https://www.douban.com/note/627332677/ + // struct TextureUnit + // { + // GLuint targetTexture1D; + // GLuint targetTexture2D; + // GLuint targetTexture3D; + // GLuint targetTextureCube; + // ... + // }; + // + // TextureUnit mTextureUnits[GL_MAX_TEXTURE_IMAGE_UNITS] + // GLuint mCurrentTextureUnit = 0; + // + void Shader::sendTexture(const char* variable, const Texture* tex) + { + checkJSL(); + GLint location = glGetUniformLocation(mPID, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + gl.activeTexUnit(unit); + glUniform1i(location, unit); + gl.bindTexture(tex->getGLTexture()); + gl.activeTexUnit(0); + } + + void Shader::sendCanvas(const char* variable, const Canvas* canvas) + { + checkJSL(); + GLint location = glGetUniformLocation(mPID, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + glUniform1i(location, unit); + glActiveTexture(GL_TEXTURE0 + unit); + gl.bindTexture(canvas->getGLTexture()); + + glActiveTexture(GL_TEXTURE0); + } + + void Shader::sendVec2(const char* name, float x, float y) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform2f(loc, x, y); + } + + void Shader::sendVec3(const char* name, float x, float y, float z) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform3f(loc, x, y, z); + } + + void Shader::sendVec4(const char* name, float x, float y, float z, float w) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform4f(loc, x, y, z, w); + } + + void Shader::sendColor(const char* name, const Color* col) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform4f(loc, + col->r / 255.f, + col->g / 255.f, + col->b / 255.f, + col->a / 255.f + ); + } + + void Shader::sendMatrix4(const char* name, const Math::Matrix* mat4) + { + int loc = glGetUniformLocation(mPID, name); + glUniformMatrix4fv(loc, 1, GL_FALSE, mat4->getElements()); + } + + void Shader::bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) + { + GLint loc = glGetAttribLocation(mPID, SHADER_VERTEX_COORDS); + glEnableVertexAttribArray(0); + glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); + } + + void Shader::bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) + { + GLint loc = glGetAttribLocation(mPID, SHADER_TEXTURE_COORDS); + glEnableVertexAttribArray(1); + glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); + } + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/Graphics/shaders/je_shader.h b/src/libjin/Graphics/shaders/je_shader.h new file mode 100644 index 0000000..3a4f65b --- /dev/null +++ b/src/libjin/Graphics/shaders/je_shader.h @@ -0,0 +1,200 @@ +#ifndef __JE_SHADER_H +#define __JE_SHADER_H + +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <string> +#include <map> + +#include "GLee/GLee.h" + +#include "../je_color.h" +#include "../je_texture.h" +#include "../je_canvas.h" + +#include "je_base.shader.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + /// + /// Built in shader program. + /// + /// Built in shader program written with custom shading language called JSL (jin shading language). A JSL + /// program is compiled into glsl, so most glsl built in functions and structs are available in JSL. + /// + class Shader + { + public: + /// + /// Create shader program from source code. + /// + /// @param source The shader source code. + /// + static Shader* createShader(const std::string& source); + + /// + /// Get current shader. + /// + /// @return Current used shader program. + /// + static inline Shader* getCurrentShader() { return CurrentShader; } + + /// + /// Unuse current shader. + /// + static void unuse(); + + /// + /// Destructor of shader. + /// + virtual ~Shader(); + + /// + /// Use specific shader. + /// + void use(); + + /// + /// Send float value to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param number Value of uniform variable to be sent. + /// + void sendFloat(const char* name, float number); + + /// + /// Send texture to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param texture Texture to be sent. + /// + void sendTexture(const char* name, const Texture* texture); + + /// + /// Send integer value to shader + /// + /// @param name Name of the uniform variable to be assigned. + /// @param value Value to be sent. + /// + void sendInt(const char* name, int value); + + /// + /// Send 2D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// + void sendVec2(const char* name, float x, float y); + + /// + /// Send 3D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// @param z Z value of the vector to be sent. + /// + void sendVec3(const char* name, float x, float y, float z); + + /// + /// Send 4D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// @param z Z value of the vector to be sent. + /// @param w W value of the vector to be sent. + /// + void sendVec4(const char* name, float x, float y, float z, float w); + + /// + /// Send canvas to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param canvas Canvas to be sent. + /// + void sendCanvas(const char* name, const Canvas* canvas); + + /// + /// Send color to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param color Color to be sent. + /// + void sendColor(const char* name, const Color* color); + + /// + /// Send 4 by 4 matrix to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param mat4 Matrix to be sent. + /// + void sendMatrix4(const char* name, const Math::Matrix* mat4); + + /// + /// Set vertices value. + /// + /// @param n Number of vertices. + /// @param type Data type of each component in the array. + /// @param stride Byte offset between consecutive generic vertex attributes. + /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. + /// + void bindVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); + + /// + /// Set texture UV coordinates. + /// + /// @param n Number of vertices. + /// @param type Data type of each component in the array. + /// @param stride Byte offset between consecutive generic vertex attributes. + /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. + /// + void bindUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); + + protected: + /// + /// Reference of current used shader. + /// + static Shader* CurrentShader; + + /// + /// Get texture unit of the uniform texture. If not, assign one. + /// + /// @param name Name of the texture uniform variable. + /// @return Texture unit which texture variable be assigned. + /// + GLint claimTextureUnit(const std::string& name); + + /// + /// Shader constructor. + /// + Shader(const std::string& program); + + /// + /// Compile JSL program into GLSL source. + /// + /// @param program JSL source code. + /// @return Return true if compile successed, otherwise return false. + /// + bool compile(const std::string& program); + + GLuint mPID; + GLint mCurrentTextureUnit; + std::map<std::string, GLint> mTextureUnits; + + }; + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) + +#endif // __JE_SHADER_H
\ No newline at end of file diff --git a/src/libjin/Utils/je_log.cpp b/src/libjin/Utils/je_log.cpp index 2bcb25a..1704ce3 100644 --- a/src/libjin/Utils/je_log.cpp +++ b/src/libjin/Utils/je_log.cpp @@ -1,2 +1,81 @@ #define LOGHELPER_IMPLEMENT -#include "je_log.h"
\ No newline at end of file +#include "je_log.h" + +#define hasbit(flag, bit) ((flag & bit) == bit) + +unsigned int Loghelper::dir = Loghelper::Direction::DIR_CERR; +unsigned int Loghelper::levels = Loghelper::Level::LV_ALL; +std::ofstream Loghelper::fs; + +void Loghelper::log(Level _level, const char* _fmt, ...) +{ + if (!hasbit(levels, _level)) + return; +#define FORMAT_MSG_BUFFER_SIZE (204800) + const char* levelStr = nullptr; + switch (_level) + { + case LV_ERROR: + levelStr = "[Jin internal error]: "; + break; + case LV_WARNING: + levelStr = "[Jin internal warning]: "; + break; + case LV_INFO: + levelStr = "[Jin internal info]: "; + break; + case LV_DEBUG: + levelStr = "[Jin internal debug]: "; + break; + default: + levelStr = "[Jin internal unknow]: "; + break; + } + char buffer[FORMAT_MSG_BUFFER_SIZE + 1] = { 0 }; + strcpy(buffer, levelStr); + va_list args; + va_start(args, _fmt); + vsnprintf(buffer + strlen(buffer), FORMAT_MSG_BUFFER_SIZE, _fmt, args); + va_end(args); + if (hasbit(dir, DIR_CERR)) + { + std::cerr << buffer << std::endl; + } + if (hasbit(dir, DIR_FILE)) + { + fs << buffer << std::endl; + } +#undef FORMAT_MSG_BUFFER_SIZE +} + +// ض +void Loghelper::redirect(unsigned int _dir, char* _path) +{ + dir = _dir; + if (hasbit(dir, DIR_FILE)) + { + try + { + fs.open(_path, std::ios_base::app); + } + catch (std::ios_base::failure& e) { + dir = DIR_CERR; + log(Level::LV_WARNING, "ضlog· %s ʧ", _path); + } + } +} + +// ɸѡȼ +void Loghelper::restrict(unsigned int _levels) +{ + levels = _levels; +} + +void Loghelper::close() +{ + if (!fs.fail()) + fs.close(); + fs.clear(); +} + +#undef hasbit diff --git a/src/libjin/Utils/je_log.h b/src/libjin/Utils/je_log.h index 928a009..aeb54d9 100644 --- a/src/libjin/Utils/je_log.h +++ b/src/libjin/Utils/je_log.h @@ -6,6 +6,8 @@ #include <fstream> #include <stdarg.h> +#include "../core/je_configuration.h" + class Loghelper { public: @@ -21,7 +23,7 @@ public: { LV_NONE = 0, // none LV_ERROR = 1 << 1, // error - LV_WARN = 1 << 2, // warn + LV_WARNING = 1 << 2, // warn LV_INFO = 1 << 3, // info LV_DEBUG = 1 << 4, // debug LV_ALL = 0xffffffff @@ -43,89 +45,20 @@ private: static std::ofstream fs; // ļ }; -typedef Loghelper::Level Loglevel; - -#ifdef LOGHELPER_IMPLEMENT - -#define hasbit(flag, bit) ((flag & bit) == bit) - -unsigned int Loghelper::dir = Loghelper::Direction::DIR_CERR; -unsigned int Loghelper::levels = Loghelper::Level::LV_ALL; -std::ofstream Loghelper::fs; - -void Loghelper::log(Level _level, const char* _fmt, ...) -{ - if (!hasbit(levels, _level)) - return; -#define FORMAT_MSG_BUFFER_SIZE (204800) - const char* levelStr = nullptr; - switch (_level) - { - case LV_ERROR: - levelStr = "[Jin Error]:"; - break; - case LV_WARN: - levelStr = "[Jin Warn]:"; - break; - case LV_INFO: - levelStr = "[Jin Info]:"; - break; - case LV_DEBUG: - levelStr = "[Jin Debug]:"; - break; - default: - levelStr = "[Jin Unknown]:"; - break; - } - char buffer[FORMAT_MSG_BUFFER_SIZE + 1] = { 0 }; - strcpy(buffer, levelStr); - va_list args; - va_start(args, _fmt); - vsnprintf(buffer + strlen(buffer), FORMAT_MSG_BUFFER_SIZE, _fmt, args); - va_end(args); - if (hasbit(dir, DIR_CERR)) - { - std::cerr << buffer << std::endl; - } - if (hasbit(dir, DIR_FILE)) - { - fs << buffer << std::endl; - } -#undef FORMAT_MSG_BUFFER_SIZE -} -// ض -void Loghelper::redirect(unsigned int _dir, char* _path) -{ - dir = _dir; - if (hasbit(dir, DIR_FILE)) - { - try - { - fs.open(_path, std::ios_base::app); - } - catch (std::ios_base::failure& e) { - dir = DIR_CERR; - log(Level::LV_WARN, "ضlog· %s ʧ", _path); - } - } -} - -// ɸѡȼ -void Loghelper::restrict(unsigned int _levels) -{ - levels = _levels; -} - -void Loghelper::close() -{ - if (!fs.fail()) - fs.close(); - fs.clear(); -} - -#undef hasbit - -#endif +typedef Loghelper::Level Loglevel; -#endif
\ No newline at end of file +#if defined(jin_debug) + #define jin_log_error(f, ...) Loghelper::log(Loghelper::LV_ERROR, f, __VA_ARGS__) + #define jin_log_info(f, ...) Loghelper::log(Loghelper::LV_INFO, f, __VA_ARGS__) + #define jin_log_warning(f, ...) Loghelper::log(Loghelper::LV_WARNING, f, __VA_ARGS__) + #define jin_log_debug(f, ...) Loghelper::log(Loghelper::LV_DEBUG, f, __VA_ARGS__) +#else + #define jin_debug_log(level, fmt, ...) + #define jin_log_error(f, ...) + #define jin_log_info(f, ...) + #define jin_log_warning(f, ...) + #define jin_log_debug(f, ...) +#endif + +#endif // __LOG_HELPER_H
\ No newline at end of file diff --git a/src/libjin/ai/je_ai.h b/src/libjin/ai/je_ai.h new file mode 100644 index 0000000..74c4fd1 --- /dev/null +++ b/src/libjin/ai/je_ai.h @@ -0,0 +1,7 @@ +#ifndef __JE_AI_H +#define __JE_AI_H + +#include "je_state_machine.h" +#include "je_behavior_tree.h" + +#endif
\ No newline at end of file diff --git a/src/libjin/ai/je_behavior_tree.h b/src/libjin/ai/je_behavior_tree.h index bfd0c6b..6c7c25f 100644 --- a/src/libjin/ai/je_behavior_tree.h +++ b/src/libjin/ai/je_behavior_tree.h @@ -19,8 +19,8 @@ namespace JinEngine }; - } -} + } // namespace AI +} // namespace JinEngine #endif // jin_ai diff --git a/src/libjin/ai/je_state_machine.cpp b/src/libjin/ai/je_state_machine.cpp index 3a8cd0d..2d82a0a 100644 --- a/src/libjin/ai/je_state_machine.cpp +++ b/src/libjin/ai/je_state_machine.cpp @@ -1,5 +1,7 @@ #include "je_state_machine.h" +#include "../utils/je_log.h" + using namespace std; namespace JinEngine @@ -7,120 +9,471 @@ namespace JinEngine namespace AI { - StateMachine::StateMachine() + StateMachine::StateMachine(Mode mode, void* userdata) + : mCurrentState("Empty") + , mUserData(userdata) + , mMode(mode) { - + addState("Empty"); } StateMachine::~StateMachine() { + } + void StateMachine::invokeCallback(const string& from, const string& to) + { + if (mExitCallback != nullptr) + mExitCallback(from, mUserData); + if (mTraslateCallback != nullptr) + mTraslateCallback(from, to, mUserData); + if (mEnterCallback != nullptr) + mEnterCallback(to, mUserData); + map<string, StateChangeCallback*>::iterator it = mOnExitState.find(from); + if (it != mOnExitState.end()) + it->second(mUserData); + map<pair<string, string>, StateTranslateCallback*>::iterator transItr + = mOnStateTranslate.find(pair<string, string>(from, to)); + if (transItr != mOnStateTranslate.end()) + transItr->second(mUserData); + it = mOnEnterState.find(to); + if (it != mOnEnterState.end()) + it->second(mUserData); } - void StateMachine::onUpdate() + void StateMachine::stepwiseProcess() { + map<string, State>::iterator it = mStates.find(mCurrentState); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", mCurrentState); + return; + } + State& state = it->second; + for (int i = 0; i < state.transitions.size(); ++i) + { + if (processCondition(state.transitions[i].condition)) + { + // Traslate + mCurrentState = state.transitions[i].state; + invokeCallback(state.name, mCurrentState); + return; + } + } + } + void StateMachine::iterativeProcess() + { + map<string, State>::iterator it = mStates.find(mCurrentState); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", mCurrentState); + return; + } + State& state = it->second; + for (int i = 0; i < state.transitions.size(); ++i) + { + if (processCondition(state.transitions[i].condition)) + { + // Traslate + mCurrentState = state.transitions[i].state; + invokeCallback(state.name, mCurrentState); + return iterativeProcess(); + } + } } - const string& StateMachine::getCurrentState() + void StateMachine::setMode(Mode mode) { + mMode = mode; + } + //ģʽ״̬ + void StateMachine::update() + { + switch (mMode) + { + case Mode::Iterative: iterativeProcess(); break; + case Mode::Stepwise: stepwiseProcess(); break; + } } - void StateMachine::addParameteri(const std::string& name) + bool StateMachine::processCondition(const Condition& condition) { + map<string, Parameter>::iterator it = mParameters.find(condition.parameter); + if (it == mParameters.end()) + { + jin_log_error("The parameter %s is not exist", condition.parameter); + return false; + } + Parameter& p = it->second; + switch (p.type) + { + case ParameterType::Int: return p.value._int == condition.value._int; + case ParameterType::Float: return p.value._float == condition.value._float; + case ParameterType::Bool: return p.value._bool == condition.value._bool; + case ParameterType::Trigger: + { + bool trigger = p.value._int == true; + if (trigger) p.value._int = false; + return trigger; + } + } + return false; + } + const string& StateMachine::getCurrentState() + { + return mCurrentState; } - void StateMachine::addParameterf(const std::string& name) + void StateMachine::addParameteri(const std::string& name) { + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Int; + p.value._int = 0; + mParameters.insert(pair<string, Parameter>(name, p)); + } + void StateMachine::addParameterf(const std::string& name) + { + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Float; + p.value._float = 0.0f; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addParameterb(const std::string& name) { - + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Bool; + p.value._bool = false; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addParametert(const std::string& name) { - + if (mParameters.find(name) != mParameters.end()) + { + jin_log_error("The parameter %s is already exist.", name); + return; + } + Parameter p; + p.type = ParameterType::Trigger; + p.value._trigger = false; + mParameters.insert(pair<string, Parameter>(name, p)); } void StateMachine::addState(const std::string& name) { + if (mStates.find(name) != mStates.end()) + { + jin_log_error("The state %s is already exist.", name); + return; + } + State state; + state.name = name; + mStates.insert(pair<string, State>(name, state)); + } + const char* StateMachine::parameterTypeString(ParameterType type) + { + switch (type) + { + case ParameterType::Int: return "int"; + case ParameterType::Float: return "float"; + case ParameterType::Bool: return "bool"; + case ParameterType::Trigger: return "trigger"; + } } void StateMachine::addTransitioni(const std::string& stateFrom, const std::string& stateTo, const std::string& name, int value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Int) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a int value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._int = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitionf(const std::string& stateFrom, const std::string& stateTo, const std::string& name, float value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Float) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a float value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._float = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitionb(const std::string& stateFrom, const std::string& stateTo, const std::string& name, bool value) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Bool) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a bool value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._bool = value; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::addTransitiont(const std::string& stateFrom, const std::string& stateTo, const std::string& name) { - + map<string, State>::iterator it; + it = mStates.find(stateFrom); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateFrom); + return; + } + State& from = it->second; + it = mStates.find(stateTo); + if (it == mStates.end()) + { + jin_log_error("The state %s is not exist.", stateTo); + return; + } + State& to = it->second; + map<string, Parameter>::iterator itp; + itp = mParameters.find(name); + if (itp == mParameters.end()) + { + jin_log_error("The parameter is not exist.", name); + return; + } + Parameter& parameter = itp->second; + if (parameter.type != ParameterType::Trigger) + { + jin_log_error("The type of parameter called %s is %s, but the transition gives a trigger value.", name, parameterTypeString(parameter.type)); + return; + } + Transition trasition; + trasition.condition.parameter = name; + trasition.condition.value._trigger = true; + trasition.state = stateTo; + from.transitions.push_back(trasition); } void StateMachine::setParameteri(const std::string& name, int value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Int) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a int value to it", name, parameterTypeString(p.type)); + return; + } + p.value._int = value; } void StateMachine::setParameterf(const std::string& name, float value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Float) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a float value to it", name, parameterTypeString(p.type)); + return; + } + p.value._float = value; } void StateMachine::setParameterb(const std::string& name, bool value) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Bool) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a bool value to it", name, parameterTypeString(p.type)); + return; + } + p.value._bool = value; } void StateMachine::setParametert(const std::string& name) { - + map<string, Parameter>::iterator it = mParameters.find(name); + if (it == mParameters.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + Parameter& p = it->second; + if (p.type != ParameterType::Trigger) + { + jin_log_error("The type of parameter called %s is %s, but try to assign a trigger value to it", name, parameterTypeString(p.type)); + return; + } + p.value._trigger = true; } - void StateMachine::trigger(const std::string& name) + void StateMachine::forceToState(const std::string& name) { - + if (mStates.find(name) == mStates.end()) + { + jin_log_error("The state %s is not exist.", name); + return; + } + mCurrentState = name; } - void StateMachine::forceToState(const std::string& name) + void StateMachine::addEnterListener(const std::string& state, StateChangeCallback* callback) { - + if (mOnEnterState.find(state) != mOnEnterState.end()) + { + jin_log_error("The enter listener of %s is already exist.", state); + return; + } + mOnEnterState.insert(pair<string, StateChangeCallback*>(state, callback)); } - void StateMachine::reset() + void StateMachine::addExitListener(const std::string& state, StateChangeCallback* callback) { - + if (mOnExitState.find(state) != mOnExitState.end()) + { + jin_log_error("The exit listener of %s is already exist.", state); + return; + } + mOnExitState.insert(pair<string, StateChangeCallback*>(state, callback)); } - void StateMachine::addEnterListener(SingleStateCallback callback) + void StateMachine::addTranslateListener(const std::string& from, const std::string& to, StateChangeCallback* callback) { - + if (mOnStateTranslate.find(pair<string, string>(from, to)) != mOnStateTranslate.end()) + { + jin_log_error("The traslate listener of %s to %s is already exist.", from, to); + return; + } + pair<string, string> key(from, to); + mOnStateTranslate.insert(pair<pair<string, string>, StateTranslateCallback*>(key, callback)); } - void StateMachine::addExitListener(SingleStateCallback callback) + void StateMachine::setEnterListener(SingleStateCallback* callback) { - + mEnterCallback = callback; } - void StateMachine::addTranslateListener(DoubleStateCallback callback) + void StateMachine::setExitListener(SingleStateCallback* callback) { + mExitCallback = callback; + } + void StateMachine::setTranslateListener(DoubleStateCallback* callback) + { + mTraslateCallback = callback; } + } // namespace AI } // namespace JinEngine
\ No newline at end of file diff --git a/src/libjin/ai/je_state_machine.h b/src/libjin/ai/je_state_machine.h index 9d7994a..193ab65 100644 --- a/src/libjin/ai/je_state_machine.h +++ b/src/libjin/ai/je_state_machine.h @@ -14,7 +14,6 @@ namespace JinEngine { namespace AI { - // Grab from Unity engine. /// /// A single layer statemachine. @@ -26,17 +25,36 @@ namespace JinEngine /// /// /// - typedef void(*SingleStateCallback)(const std::string& stateName); + enum Mode + { + Iterative, ///< Process until reach condition failed.(May cause endless loop) + Stepwise ///< Process one state each update. + }; /// /// /// - typedef void(*DoubleStateCallback)(const std::string& stateFrom, const std::string& stateTo); + typedef void(StateChangeCallback)(void* userdata); + + /// + /// + /// + typedef void(StateTranslateCallback)(void* userdata); + + /// + /// + /// + typedef void(SingleStateCallback)(const std::string& stateName, void* userdata); + + /// + /// + /// + typedef void(DoubleStateCallback)(const std::string& stateFrom, const std::string& stateTo, void* userdata); /// /// State machine constructor. /// - StateMachine(); + StateMachine(Mode mode = Mode::Stepwise, void* userdata = nullptr); /// /// State machine destructor. @@ -44,9 +62,14 @@ namespace JinEngine ~StateMachine(); /// - /// Update statemachine. /// - void onUpdate(); + /// + void setMode(Mode mode); + + /// + /// Process current state.. + /// + void update(); /// /// Get current state name. @@ -54,7 +77,7 @@ namespace JinEngine const std::string& getCurrentState(); /// - /// + /// Add a integer parameter. /// void addParameteri(const std::string& name); @@ -79,12 +102,12 @@ namespace JinEngine void addState(const std::string& name); /// - /// + /// /// void addTransitioni(const std::string& stateFrom, const std::string& stateTo, const std::string& name, int value); /// - /// + /// /// void addTransitionf(const std::string& stateFrom, const std::string& stateTo, const std::string& name, float value); @@ -119,51 +142,56 @@ namespace JinEngine void setParametert(const std::string& name); /// - /// Equivalent to setParameter(triggername); + /// Force change to state. /// - void trigger(const std::string& name); + void forceToState(const std::string& name); /// - /// Force change to state. + /// /// - void forceToState(const std::string& name); + void addEnterListener(const std::string& state, StateChangeCallback* callback); /// - /// Reset state machine. /// - void reset(); + /// + void addExitListener(const std::string& state, StateChangeCallback* callback); /// - /// /// - void addEnterListener(SingleStateCallback callback); + /// + void addTranslateListener(const std::string& from, const std::string& to, StateChangeCallback* callback); /// /// /// - void addExitListener(SingleStateCallback callback); + void setEnterListener(SingleStateCallback* callback); /// /// /// - void addTranslateListener(DoubleStateCallback callback); + void setExitListener(SingleStateCallback* callback); + + /// + /// + /// + void setTranslateListener(DoubleStateCallback* callback); private: enum ParameterType { Int, ///< A integer value. - FLoat, ///< A float value. + Float, ///< A float value. Bool, ///< A bool value. Trigger ///< A trigger will be reset to false after activated. }; union ParameterValue { - int _int; - float _float; - bool _bool; - byte _trigger; + int _int; ///< 0 by default. + float _float; ///< 0 by default. + bool _bool; ///< false by default. + bool _trigger; ///< false by default. }; struct Parameter @@ -187,7 +215,7 @@ namespace JinEngine struct Transition { Condition condition; ///< Condition to active transition. - std::string state; ///< + std::string state; ///< State to translate to. }; /// @@ -199,12 +227,31 @@ namespace JinEngine std::vector<Transition> transitions; ///< All transitions this state have. }; + const char* parameterTypeString(ParameterType type); + /// /// Check if condition is full filled. /// /// @param condition Condition to check. /// - bool checkCondition(const Condition& condition); + bool processCondition(const Condition& condition); + + typedef void(Processor)(void*); + + /// + /// + /// + void stepwiseProcess(); + + /// + /// + /// + void iterativeProcess(); + + /// + /// + /// + void invokeCallback(const std::string& from, const std::string& to); /// /// All state this state machine keeps. @@ -214,28 +261,47 @@ namespace JinEngine /// /// /// - std::map<std::string, SingleStateCallback> mOnEnterState; + std::map<std::string, StateChangeCallback*> mOnEnterState; /// /// /// - std::map<std::string, SingleStateCallback> mOnExitState; + std::map<std::string, StateChangeCallback*> mOnExitState; /// /// From first to second. /// - std::map<std::pair<std::string, std::string>, DoubleStateCallback> mOnStateTranslate; + std::map<std::pair<std::string, std::string>, StateTranslateCallback*> mOnStateTranslate; + + /// + /// + /// + SingleStateCallback* mEnterCallback; + + /// + /// + /// + SingleStateCallback* mExitCallback; + + /// + /// + /// + DoubleStateCallback* mTraslateCallback; /// /// Current state. /// - const State* mCurrentState; + std::string mCurrentState; /// /// All parameters. /// std::map<std::string, Parameter> mParameters; - + + Mode mMode; + + void* const mUserData; + }; } // namespace Graphics diff --git a/src/libjin/jin.h b/src/libjin/jin.h index a43730d..a8c00b5 100644 --- a/src/libjin/jin.h +++ b/src/libjin/jin.h @@ -16,6 +16,6 @@ #include "time/je_timer.h" #include "multithread/je_thread.h" #include "common/je_common.h" -#include "ai/je_state_machine.h" +#include "ai/je_ai.h" #endif // __JE_H
\ No newline at end of file diff --git a/src/lua/modules/ai/je_lua_behavior_tree.cpp b/src/lua/modules/ai/je_lua_behavior_tree.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/lua/modules/ai/je_lua_behavior_tree.cpp diff --git a/src/lua/modules/ai/je_lua_statemachine.cpp b/src/lua/modules/ai/je_lua_statemachine.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/lua/modules/ai/je_lua_statemachine.cpp diff --git a/src/lua/modules/audio/je_lua_audio.cpp b/src/lua/modules/audio/je_lua_audio.cpp index 8ffa794..0f2f713 100644 --- a/src/lua/modules/audio/je_lua_audio.cpp +++ b/src/lua/modules/audio/je_lua_audio.cpp @@ -4,6 +4,7 @@ #include "libjin/jin.h" using namespace JinEngine::Audio; +using namespace JinEngine::Audio::SDL; using namespace JinEngine::Filesystem; namespace JinEngine diff --git a/src/lua/modules/graphics/je_lua_graphics.cpp b/src/lua/modules/graphics/je_lua_graphics.cpp index d59a67d..7c417a5 100644 --- a/src/lua/modules/graphics/je_lua_graphics.cpp +++ b/src/lua/modules/graphics/je_lua_graphics.cpp @@ -9,6 +9,8 @@ using namespace std; using namespace JinEngine; using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Fonts; +using namespace JinEngine::Graphics::Shaders; using namespace JinEngine::Filesystem; namespace JinEngine diff --git a/src/lua/modules/graphics/je_lua_page.cpp b/src/lua/modules/graphics/je_lua_page.cpp index 7f3d1c8..36754a0 100644 --- a/src/lua/modules/graphics/je_lua_page.cpp +++ b/src/lua/modules/graphics/je_lua_page.cpp @@ -6,6 +6,8 @@ #include <iostream> using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Fonts; +using namespace JinEngine::Graphics::Shaders; namespace JinEngine { diff --git a/src/lua/modules/graphics/je_lua_shader.cpp b/src/lua/modules/graphics/je_lua_shader.cpp index c15e37a..9131815 100644 --- a/src/lua/modules/graphics/je_lua_shader.cpp +++ b/src/lua/modules/graphics/je_lua_shader.cpp @@ -4,6 +4,7 @@ #include "libjin/jin.h" using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Shaders; namespace JinEngine { diff --git a/src/lua/modules/graphics/je_lua_texture_font.cpp b/src/lua/modules/graphics/je_lua_texture_font.cpp index cee1c67..ba0a504 100644 --- a/src/lua/modules/graphics/je_lua_texture_font.cpp +++ b/src/lua/modules/graphics/je_lua_texture_font.cpp @@ -4,6 +4,7 @@ #include "libjin/jin.h" using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Fonts; namespace JinEngine { diff --git a/src/lua/modules/graphics/je_lua_ttf.cpp b/src/lua/modules/graphics/je_lua_ttf.cpp index 2818b06..49f13c0 100644 --- a/src/lua/modules/graphics/je_lua_ttf.cpp +++ b/src/lua/modules/graphics/je_lua_ttf.cpp @@ -4,6 +4,7 @@ #include "libjin/jin.h" using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Fonts; namespace JinEngine { diff --git a/src/lua/modules/graphics/je_lua_ttf_data.cpp b/src/lua/modules/graphics/je_lua_ttf_data.cpp index 269789c..4212778 100644 --- a/src/lua/modules/graphics/je_lua_ttf_data.cpp +++ b/src/lua/modules/graphics/je_lua_ttf_data.cpp @@ -4,6 +4,7 @@ #include "libjin/jin.h" using namespace JinEngine::Graphics; +using namespace JinEngine::Graphics::Fonts; namespace JinEngine { |