diff --git a/AbeLauncher/AbeLauncher.vcxproj b/AbeLauncher/AbeLauncher.vcxproj new file mode 100644 index 0000000..9daec6c --- /dev/null +++ b/AbeLauncher/AbeLauncher.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {dcbbb50c-24c2-4fd0-8bc4-e531e0bfa079} + AbeLauncher + 10.0 + ReliveLauncher + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\include;%(AdditionalIncludeDirectories) + + + Console + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\lib\x86;%(AdditionalLibraryDirectories) + SDL2main.lib;SDL2.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\lib\x86;%(AdditionalLibraryDirectories) + SDL2main.lib;SDL2.lib;%(AdditionalDependencies) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\include;%(AdditionalIncludeDirectories) + + + Console + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\lib\x64;%(AdditionalLibraryDirectories) + SDL2main.lib;SDL2.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Code\Git\ScarlettEngine\build\SDL2\SDL2-2.0.8\lib\x64;%(AdditionalLibraryDirectories) + SDL2main.lib;SDL2.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AbeLauncher/AbeLauncher.vcxproj.filters b/AbeLauncher/AbeLauncher.vcxproj.filters new file mode 100644 index 0000000..9e30ac1 --- /dev/null +++ b/AbeLauncher/AbeLauncher.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/AbeLauncher/Launcher.cpp b/AbeLauncher/Launcher.cpp new file mode 100644 index 0000000..d7ec27b --- /dev/null +++ b/AbeLauncher/Launcher.cpp @@ -0,0 +1,257 @@ +#include "Launcher.hpp" +#include +#include + +#define CONTENT_DIR "data/" + +enum class GameType : int32_t +{ + eAo = 0, + eAe = 1, +}; + +std::vector LoadMusicFile(const char* filename) +{ + // open the file: + std::ifstream file(filename, std::ios::binary); + + if (!file.is_open()) { + return std::vector(); + } + + // read the data: + return std::vector((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); +} + +inline float lerp(float a, float b, float f) +{ + return a + f * (b - a); +} + +inline MenuSampleStereo sampleLerp(MenuSampleStereo from, MenuSampleStereo to, float t) +{ + return { static_cast(lerp(from.Left, to.Left, t)),static_cast(lerp(from.Right, to.Right, t)) }; +} + +void Launcher::RenderAudio(MenuSampleStereo* pDstSamples, int lengthSamples) +{ + static int sampleIndex = 0; + + const MenuSampleStereo* pSoundDataAo = reinterpret_cast(m_MenuMusicAo.data()); + const MenuSampleStereo* pSoundDataAe = reinterpret_cast(m_MenuMusicAe.data()); + + for (int i = 0; i < lengthSamples; i++) + { + + pDstSamples[i] = sampleLerp(pSoundDataAo[sampleIndex], pSoundDataAe[sampleIndex], m_SelectionSmooth); + + sampleIndex++; + + if (sampleIndex >= m_MenuMusicAo.size() / sizeof(MenuSampleStereo)) + { + sampleIndex = 0; + } + } +} + +void Launcher::SetState(LauncherState state) +{ + m_State = state; +} + +void Launcher::SetProgress(float v) +{ + m_LoadProgress = v; +} + +void Launcher::SetProgressMessage(std::string message) +{ + m_LoadMessage = message; +} + +void Launcher::DrawGameTile(SDL_Rect region, Texture* bgTex, Texture* logoTex, float bgOffX, float darkness) +{ + SDL_RenderSetClipRect(m_pRenderer, ®ion); + + int maxLogoSize = static_cast(m_ScreenHeight / 1.5f); + + int scaledLogoX = region.w; + if (scaledLogoX > maxLogoSize) + scaledLogoX = maxLogoSize; + if (scaledLogoX < m_ScreenWidth * 0.2f) + scaledLogoX = static_cast(m_ScreenWidth * 0.2f); + + int scaledLogoY = static_cast(scaledLogoX * (static_cast(logoTex->m_Height) / logoTex->m_Width)); + + DrawTexture(bgTex, { bgOffX , static_cast(region.y) }, { static_cast(m_ScreenWidth), static_cast(m_ScreenHeight) }, { 0,0 }); + DrawTexture(logoTex, { (region.x + (region.w / 2.0f)) , region.y + (m_ScreenHeight / 2.0f) }, { static_cast(scaledLogoX), static_cast(scaledLogoY) }); + + SDL_SetRenderDrawColor(m_pRenderer, 0, 0, 0, static_cast(darkness * 190)); + SDL_RenderFillRect(m_pRenderer, ®ion); +} + +void Launcher::DrawText(STBTTF_Font* font, std::string text, Vec2 position, uint8_t r, uint8_t g, uint8_t b, uint8_t a, TextAlign align) +{ + float height = 0; + const float textWidth = STBTTF_MeasureText(font, text.c_str(), &height); + + float alignment = 0; + switch (align) + { + case TextAlign_Centre: + alignment = textWidth / 2; + break; + case TextAlign_Right: + alignment = textWidth; + break; + } + + SDL_SetRenderDrawColor(m_pRenderer, 0, 0, 0, a); + STBTTF_RenderText(m_pRenderer, font, (position.x + 2) - alignment, (position.y + height) + 2, text.c_str()); + SDL_SetRenderDrawColor(m_pRenderer, r, g, b, a); + STBTTF_RenderText(m_pRenderer, font, position.x - alignment, (position.y + height), text.c_str()); +} + +void Launcher::DrawProgressBar(Vec2 pos, Vec2 size, float percent) +{ + const int padding = 2; + SDL_Rect dst = { static_cast(pos.x) ,static_cast(pos.y) ,static_cast(size.x) ,static_cast(size.y) }; + SDL_SetRenderDrawColor(m_pRenderer, 0, 0, 0, 255); + SDL_RenderFillRect(m_pRenderer, &dst); + + dst.x += padding; + dst.y += padding; + dst.w -= padding * 2; + dst.h -= padding * 2; + + SDL_SetRenderDrawColor(m_pRenderer, 103 / 3, 44 / 3, 146 / 3, 255); + SDL_RenderFillRect(m_pRenderer, &dst); + + dst.w = static_cast(dst.w * percent); + + SDL_SetRenderDrawColor(m_pRenderer, 103, 44, 146, 255); + SDL_RenderFillRect(m_pRenderer, &dst); +} + +static std::thread workerThread; + +void Launcher::StartGame() +{ + m_State = LauncherState_GameSelected; + + // Dummy thread to simulate how loading/converting will work. + workerThread = std::thread([this] { + SetProgressMessage("Starting Conversion..."); + SDL_Delay(2000); + + for (int i = 0; i < 1000; i++) + { + SetProgressMessage("Converting File " + std::to_string(i)); + SetProgress(i / 1000.0f); + SDL_Delay(20); + } + + SetProgressMessage("Done!"); + }); +} + +void SoundEngineCallback(void* userdata, Uint8* stream, int32_t len) +{ + memset(stream, 0, len); + + const int sampleCount = len / sizeof(MenuSampleStereo); + reinterpret_cast(userdata)->RenderAudio(reinterpret_cast(stream), sampleCount); +} + +void Launcher::Initialize() +{ + m_MenuMusicAo = LoadMusicFile(CONTENT_DIR "ao.dat"); + m_MenuMusicAe = LoadMusicFile(CONTENT_DIR "ae.dat"); + + InitAudio(this, SoundEngineCallback); + + m_TexBG1 = LoadTexture(CONTENT_DIR "bg1.png"); + m_TexBG2 = LoadTexture(CONTENT_DIR "bg2.png"); + m_TexLogoAo = LoadTexture(CONTENT_DIR "logo1.png"); + m_TexLogoAe = LoadTexture(CONTENT_DIR "logo2.png"); + + m_FontSmall = STBTTF_OpenFont(m_pRenderer, CONTENT_DIR "oddfont.ttf", 32); + m_FontMedium = STBTTF_OpenFont(m_pRenderer, CONTENT_DIR "oddfont.ttf", 64); + m_FontLarge = STBTTF_OpenFont(m_pRenderer, CONTENT_DIR "oddfont.ttf", 128); +} + +void Launcher::OnEvent(SDL_Event& pEvent) +{ + if (m_State == LauncherState_GameSelection) + { + if (pEvent.type == SDL_KEYDOWN) + { + if (pEvent.key.keysym.scancode == SDL_SCANCODE_LEFT) + m_SelectionIndex = 0; + else if (pEvent.key.keysym.scancode == SDL_SCANCODE_RIGHT) + m_SelectionIndex = 1; + if (pEvent.key.keysym.scancode == SDL_SCANCODE_SPACE || pEvent.key.keysym.scancode == SDL_SCANCODE_RETURN) + StartGame(); + } + else if (pEvent.type == SDL_CONTROLLERBUTTONDOWN) + { + if (pEvent.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + m_SelectionIndex = 0; + else if (pEvent.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + m_SelectionIndex = 1; + else if (pEvent.cbutton.button == SDL_CONTROLLER_BUTTON_A) + StartGame(); + } + } +} + +void Launcher::Update(float td) +{ +} + +void Launcher::Draw(float td, SDL_Rect region) +{ + SDL_SetRenderDrawColor(m_pRenderer, 255, 0, 0, 255); + SDL_RenderClear(m_pRenderer); + SDL_SetRenderDrawBlendMode(m_pRenderer, SDL_BLENDMODE_BLEND); + + m_SelectionSmooth = lerp(m_SelectionSmooth, static_cast(m_SelectionIndex), 0.1f * td); + float selectionCurtained = 0; + float curtainTarget = 0.2f + (m_SelectionIndex * 0.6f); + + static float clipSmooth = 0; + clipSmooth = lerp(clipSmooth, (m_State == LauncherState_GameSelected) ? m_SelectionIndex : curtainTarget, 0.1f * td); + + int clipXPos = static_cast(m_ScreenWidth * clipSmooth); + + const SDL_Rect regions[2] = { + { 0, 0, m_ScreenWidth - clipXPos, m_ScreenHeight }, + { m_ScreenWidth - clipXPos, 0, m_ScreenWidth - (m_ScreenWidth - clipXPos), m_ScreenHeight } + }; + + + DrawGameTile(regions[0], m_TexBG1, m_TexLogoAo, m_SelectionSmooth * -(m_ScreenWidth / 6.0f), m_SelectionSmooth); + DrawGameTile(regions[1], m_TexBG2, m_TexLogoAe, (1.0f - m_SelectionSmooth) * (m_ScreenWidth / 6.0f), (1.0f - m_SelectionSmooth)); + + SDL_RenderSetClipRect(m_pRenderer, ®ions[m_SelectionIndex]); + + STBTTF_Font* progressFont = m_FontMedium; + + if (m_State == LauncherState_GameSelected) + { + std::string text = m_LoadMessage; + + DrawProgressBar({ regions[m_SelectionIndex].x + (regions[m_SelectionIndex].w * 0.2f), regions[m_SelectionIndex].h / 1.1f }, { regions[m_SelectionIndex].w * 0.6f, 10.0f }, m_LoadProgress); + DrawText(progressFont, text, { regions[m_SelectionIndex].x + (regions[m_SelectionIndex].w / 2.0f), regions[m_SelectionIndex].h / 1.2f }, 255, 255, 255, 255, TextAlign_Centre); + } + + SDL_RenderSetClipRect(m_pRenderer, nullptr); +} + +void Launcher::Shutdown() +{ + STBTTF_CloseFont(m_FontSmall); + STBTTF_CloseFont(m_FontMedium); + STBTTF_CloseFont(m_FontLarge); +} diff --git a/AbeLauncher/Launcher.hpp b/AbeLauncher/Launcher.hpp new file mode 100644 index 0000000..926ed4f --- /dev/null +++ b/AbeLauncher/Launcher.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include "SDLApp.hpp" + +#include "stbttf.h" + +enum TextAlign : uint8_t +{ + TextAlign_Left = 0, + TextAlign_Centre = 1, + TextAlign_Right = 2, +}; + +enum LauncherState : uint8_t +{ + LauncherState_GameSelection = 0, + LauncherState_GameSelected = 1, +}; + +class UIGameSelector : public UIElement +{ + +}; + +class Launcher : public SDLApp +{ +public: + virtual void Initialize() override; + virtual void OnEvent(SDL_Event& pEvent) override; + virtual void Update(float td) override; + virtual void Draw(float td, SDL_Rect region) override; + virtual void Shutdown() override; + + int m_SelectionIndex = 0; + float m_SelectionSmooth = 0; + + void RenderAudio(MenuSampleStereo* pDstSamples, int lengthSamples); + + void SetState(LauncherState state); + void SetProgress(float v); + void SetProgressMessage(std::string message); + +private: + void DrawGameTile(SDL_Rect region, Texture* bgTex, Texture* logoTex, float bgOffX, float darkness); + void DrawText(STBTTF_Font* font, std::string text, Vec2 position, uint8_t r, uint8_t g, uint8_t b, uint8_t a, TextAlign align); + void DrawProgressBar(Vec2 pos, Vec2 size, float percent /* from 0 - 1*/); + + std::vector m_MenuMusicAo; + std::vector m_MenuMusicAe; + + Texture* m_TexBG1 = nullptr; + Texture* m_TexBG2 = nullptr; + Texture* m_TexLogoAo = nullptr; + Texture* m_TexLogoAe = nullptr; + + STBTTF_Font* m_FontSmall = nullptr; + STBTTF_Font* m_FontMedium = nullptr; + STBTTF_Font* m_FontLarge = nullptr; + + float m_LoadProgress = 0.0f; + std::string m_LoadMessage = ""; + + void StartGame(); + + LauncherState m_State = LauncherState_GameSelection; +}; \ No newline at end of file diff --git a/AbeLauncher/SDLApp.cpp b/AbeLauncher/SDLApp.cpp new file mode 100644 index 0000000..c1b692f --- /dev/null +++ b/AbeLauncher/SDLApp.cpp @@ -0,0 +1,196 @@ +#include "SDLApp.hpp" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb/stb_image.h" + +#define STB_RECT_PACK_IMPLEMENTATION +#define STB_TRUETYPE_IMPLEMENTATION +#define STBTTF_IMPLEMENTATION +#include "stbttf.h" + +SDLApp::SDLApp() +{ + g_AppInstance = this; +} + +void SDLApp::Run() +{ + SDL_Init(SDL_INIT_EVERYTHING); + + m_ScreenWidth = 1280; + m_ScreenHeight = 720; + + m_pWindow = SDL_CreateWindow("Select Game", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + m_ScreenWidth, + m_ScreenHeight, + 0); + if (m_pWindow == nullptr) + { + ALIVE_FATAL("Failed to create GAME SELECT Window"); + } + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); + + m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (m_pRenderer == nullptr) + { + ALIVE_FATAL("Failed to create GAME SELECT Renderer"); + } + + m_LastFrameTick = SDL_GetTicks(); + + m_pController = GetGameController(); + + Initialize(); + + while (m_AppRunning) + { + SDL_GetWindowSize(m_pWindow, &m_ScreenWidth, &m_ScreenHeight); + + int newTick = SDL_GetTicks(); + + float frameDelta = ((newTick - m_LastFrameTick) / 1000.0f) * 60.0f; + + if (m_pController == nullptr) + m_pController = GetGameController(); + + // Get the next event + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + m_AppRunning = false; + } + + if (m_pController == nullptr) + m_pController = GetGameController(); + + OnEvent(event); + } + + UpdateTree(frameDelta); + + int w = 0; + int h = 0; + SDL_GetWindowSize(m_pWindow, &w, &h); + DrawTree(frameDelta, { 0, 0, w, h }); + + SDL_RenderPresent(m_pRenderer); + + m_LastFrameTick = newTick; + } + + Shutdown(); + + for (auto& t : m_LoadedTextures) + { + SDL_DestroyTexture(t.second->m_Texture); + delete t.second; + } + + m_LoadedTextures.clear(); + + SDL_DestroyRenderer(m_pRenderer); + SDL_DestroyWindow(m_pWindow); + + SDL_PauseAudio(1); + SDL_CloseAudio(); + + if (m_pController != nullptr) + { + SDL_GameControllerClose(m_pController); + } +} + +void SDLApp::Stop() +{ + m_AppRunning = false; +} + +void UIElement::UpdateTree(float td) +{ + Update(td); + + for (auto& child : m_Children) + { + child->UpdateTree(td); + } +} + +void UIElement::DrawTree(float td, SDL_Rect region) +{ + Draw(td, region); + + for (auto& child : m_Children) + { + const SDL_Rect dst = { region.x + child->m_Transform.x, region.y + child->m_Transform.y, child->m_Transform.w, child->m_Transform.h }; + child->DrawTree(td, dst); + } +} + +void SDLApp::InitAudio(void* userData, SDL_AudioCallback callback) +{ + if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) + { + m_AudioDeviceSpec.callback = callback; + m_AudioDeviceSpec.format = AUDIO_S16; + m_AudioDeviceSpec.channels = 2; + m_AudioDeviceSpec.freq = 44100; + m_AudioDeviceSpec.samples = 2048; + m_AudioDeviceSpec.userdata = userData; + + if (SDL_OpenAudio(&m_AudioDeviceSpec, NULL) >= 0) + { + SDL_PauseAudio(0); + } + } +} + + +SDL_GameController* SDLApp::GetGameController() +{ + for (int i = 0; i < SDL_NumJoysticks(); ++i) { + if (SDL_IsGameController(i)) { + SDL_GameController* controller = NULL; + controller = SDL_GameControllerOpen(i); + return controller; + } + } + + return nullptr; +} + +Texture* SDLApp::LoadTexture(std::string path) +{ + FILE* fh = fopen(path.c_str(), "rb"); + + int32_t x = 0, y = 0; + int32_t comp = 0; + const uint8_t* data = stbi_load_from_file(fh, &x, &y, &comp, 4); + SDL_Texture* texture = SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, x, y); + + SDL_UpdateTexture(texture, NULL, data, x * 4); + stbi_image_free((void*)data); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + fclose(fh); + + Texture * tex = new Texture(texture); + m_LoadedTextures[path] = tex; + + return tex; +} + +void SDLApp::DrawTexture(Texture* pTexture, Vec2 position, Vec2 size, Vec2 centre) +{ + SDL_Rect dst = { position.x - (size.x * centre.x), position.y - (size.y * centre.y), size.x, size.y}; + SDL_RenderCopy(m_pRenderer, pTexture->m_Texture, nullptr, &dst); +} + +Texture::Texture(SDL_Texture* texture) +{ + m_Texture = texture; + SDL_QueryTexture(texture, nullptr, nullptr, &m_Width, &m_Height); +} \ No newline at end of file diff --git a/AbeLauncher/SDLApp.hpp b/AbeLauncher/SDLApp.hpp new file mode 100644 index 0000000..54e76d6 --- /dev/null +++ b/AbeLauncher/SDLApp.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "stb/stb_image.h" + +#define ALIVE_FATAL // TODO Remove this + +struct MenuSampleStereo +{ + short Left; + short Right; +}; + +struct Vec2 +{ + float x; + float y; +}; + +class Texture +{ +public: + Texture(SDL_Texture* texture); + SDL_Texture* m_Texture = nullptr; + int m_Width = 0; + int m_Height = 0; +}; + +class UIElement +{ +public: + virtual void Initialize() = 0; + virtual void OnEvent(SDL_Event& pEvent) = 0; + virtual void Update(float td) = 0; + virtual void Draw(float td, SDL_Rect region) = 0; + + void UpdateTree(float td); + void DrawTree(float td, SDL_Rect region); + + std::vector> m_Children; + + void Close() + { + m_Closing = true; + } + + SDL_Rect m_Transform = { 0,0,64,64 }; + +private: + bool m_Closing = false; +}; + +class SDLApp : public UIElement +{ +public: + SDLApp(); + void Run(); + void Stop(); + + virtual void Shutdown() = 0; + + SDL_Window* m_pWindow = nullptr; + SDL_Renderer* m_pRenderer = nullptr; + +protected: + SDL_AudioSpec m_AudioDeviceSpec = {}; + SDL_GameController* m_pController = nullptr; + + int m_ScreenWidth = 1280; + int m_ScreenHeight = 720; + + void InitAudio(void * userData, SDL_AudioCallback callback); + Texture* LoadTexture(std::string path); + void DrawTexture(Texture* pTexture, Vec2 position, Vec2 size, Vec2 centre = { 0.5f, 0.5f }); +private: + + Uint32 m_LastFrameTick; + bool m_AppRunning = true; + SDL_GameController* GetGameController(); + std::map m_LoadedTextures; +}; + +static SDLApp* g_AppInstance = nullptr; \ No newline at end of file diff --git a/AbeLauncher/data/ae.dat b/AbeLauncher/data/ae.dat new file mode 100644 index 0000000..6a54d47 Binary files /dev/null and b/AbeLauncher/data/ae.dat differ diff --git a/AbeLauncher/data/ao.dat b/AbeLauncher/data/ao.dat new file mode 100644 index 0000000..e2da8fa Binary files /dev/null and b/AbeLauncher/data/ao.dat differ diff --git a/AbeLauncher/data/bg1.png b/AbeLauncher/data/bg1.png new file mode 100644 index 0000000..61b0e08 Binary files /dev/null and b/AbeLauncher/data/bg1.png differ diff --git a/AbeLauncher/data/bg2.png b/AbeLauncher/data/bg2.png new file mode 100644 index 0000000..ffe8a0b Binary files /dev/null and b/AbeLauncher/data/bg2.png differ diff --git a/AbeLauncher/data/logo1.png b/AbeLauncher/data/logo1.png new file mode 100644 index 0000000..a083cba Binary files /dev/null and b/AbeLauncher/data/logo1.png differ diff --git a/AbeLauncher/data/logo2.png b/AbeLauncher/data/logo2.png new file mode 100644 index 0000000..6752fc0 Binary files /dev/null and b/AbeLauncher/data/logo2.png differ diff --git a/AbeLauncher/data/oddfont.ttf b/AbeLauncher/data/oddfont.ttf new file mode 100644 index 0000000..5aa17af Binary files /dev/null and b/AbeLauncher/data/oddfont.ttf differ diff --git a/AbeLauncher/main.cpp b/AbeLauncher/main.cpp new file mode 100644 index 0000000..dad3bfc --- /dev/null +++ b/AbeLauncher/main.cpp @@ -0,0 +1,11 @@ + +#include "Launcher.hpp" + +int main(int ac, char** ap) +{ + Launcher launcher; + + launcher.Run(); + + return 0; +} \ No newline at end of file diff --git a/AbeLauncher/stbttf.h b/AbeLauncher/stbttf.h new file mode 100644 index 0000000..21124dd --- /dev/null +++ b/AbeLauncher/stbttf.h @@ -0,0 +1,216 @@ +#ifndef __STBTTF_H__ +#define __STBTTF_H__ + +#include + +#include "stb/stb_rect_pack.h" +#include "stb/stb_truetype.h" + +/* STBTTF: A quick and dirty SDL2 text renderer based on stb_truetype and stdb_rect_pack. + * Benoit Favre 2019 + * + * This header-only addon to the stb_truetype library allows to draw text with SDL2 from + * TTF fonts with a similar API to SDL_TTF without the bloat. + * The renderer is however limited by the integral positioning of SDL blit functions. + * It also does not parse utf8 text and only prints ASCII characters. + * + * This code is public domain. + */ + +typedef struct { + stbtt_fontinfo* info; + stbtt_packedchar* chars; + SDL_Texture* atlas; + int texture_size; + float size; + float scale; + int ascent; + int baseline; +} STBTTF_Font; + +/* Release the memory and textures associated with a font */ +void STBTTF_CloseFont(STBTTF_Font* font); + +/* Open a TTF font given a SDL abstract IO handler, for a given renderer and a given font size. + * Returns NULL on failure. The font must be deallocated with STBTTF_CloseFont when not used anymore. + * This function creates a texture atlas with prerendered ASCII characters (32-128). + */ +STBTTF_Font* STBTTF_OpenFontRW(SDL_Renderer* renderer, SDL_RWops* rw, float size); + +/* Open a TTF font given a filename, for a given renderer and a given font size. + * Convinience function which calls STBTTF_OpenFontRW. + */ +STBTTF_Font* STBTTF_OpenFont(SDL_Renderer* renderer, const char* filename, float size); + +/* Draw some text using the renderer draw color at location (x, y). + * Characters are copied from the texture atlas using the renderer SDL_RenderCopy function. + * Since that function only supports integral coordinates, the result is not great. + * Only ASCII characters (32 <= c < 128) are supported. Anything outside this range is ignored. + */ +void STBTTF_RenderText(SDL_Renderer* renderer, STBTTF_Font* font, float x, float y, const char *text); + +/* Return the length in pixels of a text. + * You can get the height of a line by using font->baseline. + */ +float STBTTF_MeasureText(STBTTF_Font* font, const char *text, float * height); + +#ifdef STBTTF_IMPLEMENTATION + +void STBTTF_CloseFont(STBTTF_Font* font) { + if(font->atlas) SDL_DestroyTexture(font->atlas); + if(font->info) free(font->info); + if(font->chars) free(font->chars); + free(font); +} + +STBTTF_Font* STBTTF_OpenFontRW(SDL_Renderer* renderer, SDL_RWops* rw, float size) { + Sint64 file_size = SDL_RWsize(rw); + unsigned char* buffer = (unsigned char*)malloc(file_size); + if(SDL_RWread(rw, buffer, file_size, 1) != 1) return NULL; + SDL_RWclose(rw); + + STBTTF_Font* font = (STBTTF_Font * )calloc(sizeof(STBTTF_Font), 1); + font->info = (stbtt_fontinfo*)malloc(sizeof(stbtt_fontinfo)); + font->chars = (stbtt_packedchar*)malloc(sizeof(stbtt_packedchar) * 96); + + if(stbtt_InitFont(font->info, buffer, 0) == 0) { + free(buffer); + STBTTF_CloseFont(font); + return NULL; + } + + // fill bitmap atlas with packed characters + unsigned char* bitmap = NULL; + font->texture_size = 32; + while(1) { + bitmap = (unsigned char* )malloc(font->texture_size * font->texture_size); + stbtt_pack_context pack_context; + stbtt_PackBegin(&pack_context, bitmap, font->texture_size, font->texture_size, 0, 1, 0); + stbtt_PackSetOversampling(&pack_context, 1, 1); + if(!stbtt_PackFontRange(&pack_context, buffer, 0, size, 32, 95, font->chars)) { + // too small + free(bitmap); + stbtt_PackEnd(&pack_context); + font->texture_size *= 2; + } else { + stbtt_PackEnd(&pack_context); + break; + } + } + + // convert bitmap to texture + font->atlas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, font->texture_size, font->texture_size); + SDL_SetTextureBlendMode(font->atlas, SDL_BLENDMODE_BLEND); + + Uint32* pixels = (Uint32 * )malloc(font->texture_size * font->texture_size * sizeof(Uint32)); + static SDL_PixelFormat* format = NULL; + if(format == NULL) format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA32); + for(int i = 0; i < font->texture_size * font->texture_size; i++) { + pixels[i] = SDL_MapRGBA(format, 0xff, 0xff, 0xff, bitmap[i]); + } + SDL_UpdateTexture(font->atlas, NULL, pixels, font->texture_size * sizeof(Uint32)); + free(pixels); + free(bitmap); + + // setup additional info + font->scale = stbtt_ScaleForPixelHeight(font->info, size); + stbtt_GetFontVMetrics(font->info, &font->ascent, 0, 0); + font->baseline = (int) (font->ascent * font->scale); + + free(buffer); + + return font; +} + +STBTTF_Font* STBTTF_OpenFont(SDL_Renderer* renderer, const char* filename, float size) { + SDL_RWops *rw = SDL_RWFromFile(filename, "rb"); + if(rw == NULL) return NULL; + return STBTTF_OpenFontRW(renderer, rw, size); +} + +void STBTTF_RenderText(SDL_Renderer* renderer, STBTTF_Font* font, float x, float y, const char *text) { + Uint8 r, g, b, a; + SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); + SDL_SetTextureColorMod(font->atlas, r, g, b); + SDL_SetTextureAlphaMod(font->atlas, a); + for(int i = 0; text[i]; i++) { + if (text[i] >= 32 && text[i] < 128) { + //if(i > 0) x += stbtt_GetCodepointKernAdvance(font->info, text[i - 1], text[i]) * font->scale; + + stbtt_packedchar* info = &font->chars[text[i] - 32]; + SDL_Rect src_rect = {info->x0, info->y0, info->x1 - info->x0, info->y1 - info->y0}; + SDL_Rect dst_rect = {x + info->xoff, y + info->yoff, info->x1 - info->x0, info->y1 - info->y0}; + + SDL_RenderCopy(renderer, font->atlas, &src_rect, &dst_rect); + x += info->xadvance; + } + } +} + +float STBTTF_MeasureText(STBTTF_Font* font, const char *text, float * height) { + float width = 0; + float h = 0; + for(int i = 0; text[i]; i++) { + if (text[i] >= 32 && text[i] < 128) { + //if(i > 0) width += stbtt_GetCodepointKernAdvance(font->info, text[i - 1], text[i]) * font->scale; + + stbtt_packedchar* info = &font->chars[text[i] - 32]; + width += info->xadvance; + h = std::max((float)(info->y1 - info->y0), h); + } + } + if (height != nullptr) + *height = h; + return width; +} + +/******************* + * Example program * + ******************* + +#include + +#define STB_RECT_PACK_IMPLEMENTATION +#define STB_TRUETYPE_IMPLEMENTATION +#define STBTTF_IMPLEMENTATION + +#include "stbttf.h" + +int main(int argc, char** argv) { + if(argc != 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + SDL_Init(SDL_INIT_VIDEO); + SDL_Window* window = SDL_CreateWindow("stbttf", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL); + SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + SDL_RenderSetLogicalSize(renderer, 640, 480); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + + STBTTF_Font* font = STBTTF_OpenFont(renderer, argv[1], 32); + + while(1) { + SDL_Event event; + while(SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) exit(0); + } + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + // set color and render some text + SDL_SetRenderDrawColor(renderer, 128, 0, 0, 255); + STBTTF_RenderText(renderer, font, 50, 50, "This is a test"); + // render the atlas to check its content + //SDL_Rect dest = {0, 0, font->texturesize, font->texturesize}; + //SDL_RenderCopy(renderer, font->atlas, &dest, &dest); + SDL_RenderPresent(renderer); + SDL_Delay(1000 / 60); + } + STBTTF_CloseFont(font); + SDL_Quit(); +} + +*/ + +#endif + +#endif \ No newline at end of file diff --git a/ReliveLauncher.sln b/ReliveLauncher.sln new file mode 100644 index 0000000..ac6b016 --- /dev/null +++ b/ReliveLauncher.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AbeLauncher", "AbeLauncher\AbeLauncher.vcxproj", "{DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Debug|x64.ActiveCfg = Debug|x64 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Debug|x64.Build.0 = Debug|x64 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Debug|x86.ActiveCfg = Debug|Win32 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Debug|x86.Build.0 = Debug|Win32 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Release|x64.ActiveCfg = Release|x64 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Release|x64.Build.0 = Release|x64 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Release|x86.ActiveCfg = Release|Win32 + {DCBBB50C-24C2-4FD0-8BC4-E531E0BFA079}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1C8CF83C-4765-4FAD-8CCC-9D8A42B26797} + EndGlobalSection +EndGlobal