#include #include #include #include #include #include #include #include #include #include #include "SDL2/SDL.h" #include "SDL2/SDL_ttf.h" #include "Render.hpp" #include "SDL2/SDL_syswm.h" #include "SoLoud/soloud.h" #include "SoLoud/soloud_wav.h" #include "SoLoud/soloud_openmpt.h" #include #include "SDL2/SDL_stbimage.h" #include #include #include "toml.hpp" #include using namespace std; using namespace Render; string SOUNDFONT = "data/gm.sf2"; SDL_Window* Render::window; SDL_Renderer* Render::renderer; SDL_Event Render::event; State* Render::current_state = nullptr; SoLoud::Soloud Render::music; SoLoud::Soloud Render::se; SoLoud::WavStream Render::waveLoader; SoLoud::Openmpt Render::modLoader; SoLoud::Modplug Render::modPlugLoader; SoLoud::Midi Render::midiLoader; SoLoud::SoundFont Render::current_sf; string Render::currentMusic = ""; HWND Render::hwnd; HWND Render::consoleD; int Render::seIndex; SoLoud::Speech Render::SPEAK_BITCH; SoLoud::FFTFilter Render::bass; Render::Object::Object() { } Render::Object::~Object() { // placeholder } Render::State::State() { // placeholder } Render::State::~State() { // placeholder } void Render::Object::create(int x, int y, string path){ this->_tex = STBIMG_LoadTexture(renderer, path.c_str()); SDL_SetTextureBlendMode(_tex, SDL_BLENDMODE_BLEND); if (_tex == nullptr) { cout << "texture failed to lod" << endl; } _x = x; _y = y; _sc_x = x; _sc_y = y; int w_, h_; SDL_QueryTexture(this->_tex, NULL, NULL, &w_, &h_); _sc_w = w_; _sc_h = h_; this->x = x; this->y = y; w = w_; h = h_; _ori_w = w_; _ori_h = h_; } void Render::AnimatedObject::create(int x, int y, string path){ Render::Object::create(x,y,path); startTime = SDL_GetTicks(); } void Render::State::AddObject(Render::Object* object) { object->id = obj.size(); this->obj.push_back(object); } vector Render::State::get_obj() { return this->obj; } void Render::Object::Draw(float dt) { _x = x; _sc_x = x-cam_rect->x; _y = y; _sc_y = y-cam_rect->y; _w = w*scale.x; _sc_w = _w; _h = h*scale.y; _sc_h = _h; if (alpha > 100) alpha = 100; if (alpha < 0) alpha = 0; SDL_SetTextureAlphaMod(this->_tex, (this->alpha/100)*255); } void Render::Object::setCamera(SDL_Rect* cam_p) { cam_rect = cam_p; } void Render::AnimatedObject::Draw(float dt) { Render::Object::Draw(dt); if (current_framename != "") { // this will make it so that current_frame will only advance when it needs to int frameToDraw = ((SDL_GetTicks() - startTime) * framerate / 1000) % frameRects[current_framename].size(); current_frame = frameToDraw; int sx = frameRects[current_framename][current_frame].x; int sy = frameRects[current_framename][current_frame].y; int sw = frameRects[current_framename][current_frame].w; int sh = frameRects[current_framename][current_frame].h; // support scaling :) _sc_w = frameRects[current_framename][current_frame].w*scale.x; _sc_h = frameRects[current_framename][current_frame].h*scale.y; // after setting shit up, we then store it in src_rect. src_rect = {sx, sy, sw, sh}; } } void Render::AnimatedObject::AddAnimation(string anim_name, vector points) { frameRects.insert({anim_name, points}); } void Render::AnimatedObject::PlayAnimation(string anim_name) { current_framename = anim_name; } void Render::TextObject::create(int x, int y, string text, string font_name, SDL_Color color, int style, int size) { Render::Object::create(x,y,"data/smile.png"); // dummy this->text = text; _tex = nullptr; _sc_x = x; _sc_y = y; _sc_w = strlen(text.c_str())*size; _sc_h = strlen(text.c_str())*size; this->x = x; this->y = y; w = strlen(text.c_str())*size; h = strlen(text.c_str())*size; font_size = size; this->color = color; font = FC_CreateFont(); FC_LoadFont(font, renderer, font_name.c_str(), size, color, style); } void Render::TextObject::Draw(float dt) { Render::Object::Draw(dt); FC_Effect eff; eff.alignment = alignment; eff.color = color; eff.scale.x = scale.x; eff.scale.y = scale.y; FC_SetFilterMode(font, (antialiasing ? FC_FILTER_LINEAR : FC_FILTER_NEAREST)); FC_DrawEffect(font, renderer, x-offset.x, y-offset.y, eff, text.c_str()); SDL_Rect rec = FC_GetBounds(font, x-offset.x, y-offset.y, alignment, eff.scale, text.c_str()); w = rec.w; h = rec.h; } void Render::Object::centerSelf(AXIS axis) { switch (axis) { case X: x = (WINDOW_WIDTH/2) - (w*scale.x/2); break; case Y: y = (WINDOW_HEIGHT/2) - (h*scale.y/2); break; case XY: x = (WINDOW_WIDTH/2) - (w*scale.x/2); y = (WINDOW_HEIGHT/2) - (h*scale.y/2); break; } } bool Render::Init(string window_name) { std::ofstream logFile; logFile.open("log.txt", std::ofstream::out | std::ofstream::trunc); logFile.close(); if (!touchFile("conf.toml")) { tomlExport("conf.toml", { {"config", {{"soundfont", "data/gm.sf2"}}} }); } SOUNDFONT = tomlParse("conf.toml", "config", "soundfont"); if (music.init() > 0) { log("SoLoud", " has failed to load. Is your dll broken?", ERROR_, __FILENAME__, __LINE__); return false; } log("SoLoud", " has been successfully initialized.", NORMAL, __FILENAME__, __LINE__); if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { log("SDL", " has failed to load. Is your dll broken? " + string(SDL_GetError()), ERROR_, __FILENAME__, __LINE__); return false; } log("SDL", " has been successfully initialized.", NORMAL, __FILENAME__, __LINE__); if (TTF_Init() < 0) { log("SDL_ttf", " has failed to load. Is your dll broken? " + string(SDL_GetError()), ERROR_, __FILENAME__, __LINE__); return false; } log("SDL_ttf", " has been successfully initialized.", NORMAL, __FILENAME__, __LINE__); window = SDL_CreateWindow(window_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN); if (window == nullptr) { log("A window", " failed to be created. " + string(SDL_GetError()), ERROR_, __FILENAME__, __LINE__); return false; } log("A window", " has been created.", NORMAL, __FILENAME__, __LINE__); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == nullptr) { log("A renderer", " failed to be created. " + string(SDL_GetError()), ERROR_, __FILENAME__, __LINE__); return false; } log("A renderer", " has been created.", NORMAL, __FILENAME__, __LINE__); current_sf.load(SOUNDFONT.c_str()); SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); SDL_GetWindowWMInfo(window, &wmInfo); hwnd = wmInfo.info.win.window; log("", "Finalized initialization. Command over.", NORMAL, __FILENAME__, __LINE__); AddExitButton(); SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); return true; } vector Render::_sec; vector> Render::_call; vector Render::_repeats; vector Render::_ticks; template void remove_a(std::vector& vec, size_t pos) { typename std::vector::iterator it = vec.begin(); std::advance(it, pos); vec.erase(it); } bool Render::Update() { int lastUpdate = SDL_GetTicks(); bool run = true; while (run) { while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { run = false; break; } else if (event.type == SDL_SYSWMEVENT) { if (event.syswm.msg->msg.win.msg == WM_COMMAND) { if (LOWORD(event.syswm.msg->msg.win.wParam) == 1) { run = false; break; } } } } int start = SDL_GetPerformanceCounter(); int current = SDL_GetTicks(); float dT = (current - lastUpdate) / 1000.0f; current_state->Update(dT); // I know this is a shitty way to do this // but bear with me // it was hard to work with lambdas properly man // let me have this just one please :) if (_sec.size() > 0) { for (int i = 0; i < _sec.size(); i++) { if (_ticks[i] != -1) _ticks[i]++; if (_sec[i] != -1) { if (!(_ticks[i] < Sec2Tick(_sec[i]))) { if (_call[i] != NULL) _call[i](NULL); if (!_repeats[i] && _repeats[i] != NULL) { _ticks[i] = -1; _sec[i] = -1; _call[i] = NULL; _repeats[i] = NULL; } } } // cout << i << endl; } } lastUpdate = current; current_state->Draw(dT); int end = SDL_GetPerformanceCounter(); float elapsedMS = (end - start) / SDL_GetPerformanceFrequency() * 1000.0f; SDL_Delay(floor((1000.0f/FRAMERATE) - elapsedMS)); } for (int i = 0; i < current_state->get_obj().size(); i++) { SDL_DestroyTexture(current_state->get_obj()[i]->_tex); } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); music.stopAll(); music.deinit(); TTF_Quit(); SDL_Quit(); ReleaseConsole(); return false; } void Render::SwitchState(State* state) { string state_name = typeid(*state).name(); log("", "Switching current state to " + state_name, NORMAL, __FILENAME__, __LINE__); if (current_state != nullptr) { _ticks = {}; _call = {}; _repeats = {}; _sec = {}; for (int i = 0; i < current_state->get_obj().size(); i++) { SDL_DestroyTexture(current_state->get_obj()[i]->_tex); } } current_state = state; log("Success!", " Calling Create()....", NORMAL, __FILENAME__, __LINE__); current_state->Create(); } bool Render::playSound(string path, bool override) { log("", "Played sound from " + path, NORMAL, __FILENAME__, __LINE__); waveLoader.setLooping(false); if (override) { music.stop(seIndex); } waveLoader.load(path.c_str()); seIndex = music.play(waveLoader); return true; } bool Render::playMusic(string path) { if (path == "") { log("", "Silence." + path, NORMAL, __FILENAME__, __LINE__); music.stopAll(); return true; } log("", "Played music from " + path, NORMAL, __FILENAME__, __LINE__); if (currentMusic == path) { music.stopAll(); } waveLoader.load(path.c_str()); waveLoader.setLooping(true); music.play(waveLoader); currentMusic = path; return true; } bool Render::playModPlug(string path) { if (path == "") { log("", "Silence." + path, NORMAL, __FILENAME__, __LINE__); music.stopAll(); return true; } if (currentMusic == path) { music.stopAll(); } // midis if (path.find(".mid") != string::npos) { log("", "Played midi from " + path + " with soundfont " + SOUNDFONT, NORMAL, __FILENAME__, __LINE__); midiLoader.load(path.c_str(), current_sf); midiLoader.setLooping(true); music.play(midiLoader); currentMusic = path; return true; } log("", "Try to play " + path + " using libopenmpt", NORMAL, __FILENAME__, __LINE__); if (modLoader.load(path.c_str()) != SoLoud::SO_NO_ERROR) { log("", "Playing " + path + " using libmodplug", NORMAL, __FILENAME__, __LINE__); if (modPlugLoader.load(path.c_str()) != SoLoud::SO_NO_ERROR) { log("", "Could not play " + path, NORMAL, __FILENAME__, __LINE__); return false; } modPlugLoader.setLooping(true); music.play(modPlugLoader); currentMusic = path; return true; } modLoader.setLooping(true); music.play(modLoader); currentMusic = path; return true; } void Render::pointTo(SDL_Rect* camera, Object object) { camera->x = ( object.x + (object.w / 2) ) - WINDOW_WIDTH / 2; camera->y = ( object.y + (object.h / 2) ) - WINDOW_HEIGHT / 2; if( camera->x < 0 ) { camera->x = 0; } if( camera->y < 0 ) { camera->y = 0; } if( camera->x > camera->w ) { camera->x = camera->w; } if( camera->y > camera->h ) { camera->y = camera->h; } }