2011-08-03 20:05:33 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2007, 2010 - Bit-Blot
|
|
|
|
|
|
|
|
This file is part of Aquaria.
|
|
|
|
|
|
|
|
Aquaria is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include "Core.h"
|
|
|
|
#include "Texture.h"
|
2022-03-31 19:03:40 +00:00
|
|
|
#include "Image.h"
|
2011-08-03 20:05:33 +00:00
|
|
|
#include "AfterEffect.h"
|
|
|
|
#include "Particles.h"
|
2016-07-09 02:18:40 +00:00
|
|
|
#include "GLLoad.h"
|
|
|
|
#include "RenderBase.h"
|
2019-01-28 23:36:48 +00:00
|
|
|
#include "Window.h"
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
#include <time.h>
|
2011-08-11 00:26:46 +00:00
|
|
|
#include <iostream>
|
2016-07-09 02:18:40 +00:00
|
|
|
#include <fstream>
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_UNIX
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#if __APPLE__
|
|
|
|
#include <Carbon/Carbon.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-20 22:47:24 +00:00
|
|
|
#if BBGE_BUILD_WINDOWS
|
2013-06-19 00:08:24 +00:00
|
|
|
#include <direct.h>
|
2011-11-20 22:47:24 +00:00
|
|
|
#endif
|
|
|
|
|
2014-04-15 17:48:06 +00:00
|
|
|
#ifdef BBGE_BUILD_VFS
|
|
|
|
#include "ttvfs.h"
|
|
|
|
#endif
|
2022-04-07 00:38:39 +00:00
|
|
|
#include "ttvfs_stdio.h"
|
2014-04-15 17:48:06 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
Core *core = 0;
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
static std::ofstream _logOut;
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
CoreWindow::~CoreWindow()
|
|
|
|
{
|
|
|
|
}
|
2013-12-12 10:34:15 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
void CoreWindow::onResize(unsigned w, unsigned h)
|
|
|
|
{
|
|
|
|
core->updateWindowDrawSize(w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreWindow::onQuit()
|
|
|
|
{
|
|
|
|
// smooth
|
2023-05-31 15:40:41 +00:00
|
|
|
//quitNestedMain();
|
|
|
|
//quit();
|
2019-01-28 23:36:48 +00:00
|
|
|
|
|
|
|
// instant
|
|
|
|
SDL_Quit();
|
|
|
|
_exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CoreWindow::onEvent(const SDL_Event& ev)
|
|
|
|
{
|
|
|
|
core->onEvent(ev);
|
|
|
|
}
|
2017-01-13 12:06:31 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
void Core::resetCamera()
|
|
|
|
{
|
|
|
|
cameraPos = Vector(0,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParticleEffect* Core::createParticleEffect(const std::string &name, const Vector &position, int layer, float rotz)
|
|
|
|
{
|
|
|
|
ParticleEffect *e = new ParticleEffect();
|
|
|
|
e->load(name);
|
|
|
|
e->position = position;
|
|
|
|
e->start();
|
|
|
|
e->setDie(true);
|
|
|
|
e->rotation.z = rotz;
|
2023-05-31 15:40:41 +00:00
|
|
|
getTopStateData()->addRenderObject(e, layer);
|
2011-08-03 20:05:33 +00:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::unloadDevice()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < renderObjectLayers.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
RenderObjectLayer *r = &renderObjectLayers[i];
|
|
|
|
RenderObject *robj = r->getFirst();
|
|
|
|
while (robj)
|
|
|
|
{
|
|
|
|
robj->unloadDevice();
|
|
|
|
robj = r->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
frameBuffer.unloadDevice();
|
|
|
|
|
|
|
|
if (afterEffectManager)
|
|
|
|
afterEffectManager->unloadDevice();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::reloadDevice()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < renderObjectLayers.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
RenderObjectLayer *r = &renderObjectLayers[i];
|
|
|
|
r->reloadDevice();
|
|
|
|
RenderObject *robj = r->getFirst();
|
|
|
|
while (robj)
|
|
|
|
{
|
|
|
|
robj->reloadDevice();
|
|
|
|
robj = r->getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
frameBuffer.reloadDevice();
|
|
|
|
|
|
|
|
if (afterEffectManager)
|
|
|
|
afterEffectManager->reloadDevice();
|
|
|
|
}
|
|
|
|
|
2016-11-09 00:16:55 +00:00
|
|
|
void Core::setup_opengl()
|
|
|
|
{
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
|
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
|
|
|
|
glClearDepth(1.0); // Depth Buffer Setup
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
setClearColor(clearColor);
|
|
|
|
|
2016-11-15 12:00:30 +00:00
|
|
|
frameBuffer.init(-1, -1, true);
|
|
|
|
if(afterEffectManager)
|
|
|
|
afterEffectManager->updateDevice();
|
2016-11-09 00:16:55 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
void Core::resizeWindow(int w, int h, int full, int bpp, int vsync, int display, int hz)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
window->open(w, h, full, bpp, vsync, display, hz);
|
2021-01-12 10:06:09 +00:00
|
|
|
window->updateSize();
|
2017-01-13 12:06:31 +00:00
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2017-01-13 12:06:31 +00:00
|
|
|
void Core::updateWindowDrawSize(int w, int h)
|
|
|
|
{
|
|
|
|
width = w;
|
|
|
|
height = h;
|
|
|
|
setup_opengl();
|
|
|
|
enable2DWide(w, h);
|
|
|
|
reloadDevice();
|
2011-08-03 20:05:33 +00:00
|
|
|
resetTimer();
|
|
|
|
}
|
|
|
|
|
2016-11-14 02:13:34 +00:00
|
|
|
void Core::onWindowResize(int w, int h)
|
|
|
|
{
|
2017-01-13 12:06:31 +00:00
|
|
|
updateWindowDrawSize(w, h);
|
2019-01-28 23:36:48 +00:00
|
|
|
|
|
|
|
bool reloadRes = false;
|
2022-04-05 03:20:01 +00:00
|
|
|
#if !SDL_VERSION_ATLEAST(2,0,0)
|
2019-01-28 23:36:48 +00:00
|
|
|
reloadRes = true; // SDL1.2 loses the GL context on resize, so all resources must be reloaded
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if(reloadRes)
|
|
|
|
{
|
|
|
|
unloadResources();
|
|
|
|
reloadResources();
|
|
|
|
resetTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
updateWindowDrawSize(w, h);
|
2016-11-14 02:13:34 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 00:16:55 +00:00
|
|
|
void Core::setFullscreen(bool full)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
//sound->pause();
|
|
|
|
window->setFullscreen(full);
|
2011-08-03 20:05:33 +00:00
|
|
|
cacheRender();
|
|
|
|
resetTimer();
|
2019-01-28 23:36:48 +00:00
|
|
|
//sound->resume();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RenderObjectLayer *Core::getRenderObjectLayer(int i)
|
|
|
|
{
|
|
|
|
if (i == LR_NONE)
|
|
|
|
return 0;
|
|
|
|
return &renderObjectLayers[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getShiftState()
|
|
|
|
{
|
|
|
|
return getKeyState(KEY_LSHIFT) || getKeyState(KEY_RSHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getAltState()
|
|
|
|
{
|
|
|
|
return getKeyState(KEY_LALT) || getKeyState(KEY_RALT);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getCtrlState()
|
|
|
|
{
|
|
|
|
return getKeyState(KEY_LCONTROL) || getKeyState(KEY_RCONTROL);
|
|
|
|
}
|
|
|
|
|
2023-05-31 15:37:20 +00:00
|
|
|
void Core::_errorLog(const std::string &s)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
messageBox("Error!", s);
|
2023-05-31 15:37:20 +00:00
|
|
|
this->_debugLog(s);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::messageBox(const std::string &title, const std::string &msg)
|
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
::messageBox(title, msg);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2023-05-31 15:37:20 +00:00
|
|
|
void Core::_debugLog(const std::string &s)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
if (debugLogActive)
|
|
|
|
{
|
2011-08-11 00:26:46 +00:00
|
|
|
_logOut << s << std::endl;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2022-04-08 17:31:16 +00:00
|
|
|
|
|
|
|
#if !defined(_DEBUG)
|
|
|
|
if(debugOutputActive)
|
2011-08-11 00:26:46 +00:00
|
|
|
#endif
|
2022-04-08 17:31:16 +00:00
|
|
|
std::cout << s << std::endl;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2011-11-20 22:47:24 +00:00
|
|
|
static bool checkWritable(const std::string& path, bool warn, bool critical)
|
|
|
|
{
|
|
|
|
bool writeable = false;
|
|
|
|
std::string f = path + "/~chk_wrt.tmp";
|
|
|
|
FILE *fh = fopen(f.c_str(), "w");
|
|
|
|
if(fh)
|
|
|
|
{
|
|
|
|
writeable = fwrite("abcdef", 5, 1, fh) == 1;
|
|
|
|
fclose(fh);
|
|
|
|
unlink(f.c_str());
|
|
|
|
}
|
|
|
|
if(!writeable)
|
|
|
|
{
|
|
|
|
if(warn)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Trying to use \"" << path << "\" as user data path, but it is not writeable.\n"
|
|
|
|
<< "Please make sure the game is allowed to write to that directory.\n"
|
|
|
|
<< "You can move the game to another location and run it there,\n"
|
|
|
|
<< "or try running it as administrator, that may help as well.";
|
|
|
|
if(critical)
|
|
|
|
os << "\n\nWill now exit.";
|
2019-01-28 23:36:48 +00:00
|
|
|
errorLog(os.str());
|
2011-11-20 22:47:24 +00:00
|
|
|
}
|
|
|
|
if(critical)
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return writeable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-19 00:08:24 +00:00
|
|
|
Core::Core(const std::string &filesystem, const std::string& extraDataDir, int numRenderLayers, const std::string &appName, int particleSize, std::string userDataSubFolder)
|
2011-08-03 20:05:33 +00:00
|
|
|
: ActionMapper(), StateManager(), appName(appName)
|
|
|
|
{
|
2019-04-15 00:26:48 +00:00
|
|
|
window = NULL;
|
2011-08-11 00:26:46 +00:00
|
|
|
sound = NULL;
|
2013-06-19 00:08:24 +00:00
|
|
|
_extraDataDir = extraDataDir;
|
2022-08-24 12:16:25 +00:00
|
|
|
sdlUserMouseEventID = SDL_RegisterEvents(1);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (userDataSubFolder.empty())
|
|
|
|
userDataSubFolder = appName;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
#if defined(BBGE_BUILD_UNIX)
|
|
|
|
const char *envr = getenv("HOME");
|
|
|
|
if (envr == NULL)
|
2017-01-12 21:51:46 +00:00
|
|
|
envr = "."; // oh well.
|
2011-08-03 20:05:33 +00:00
|
|
|
const std::string home(envr);
|
|
|
|
|
2013-11-14 19:07:39 +00:00
|
|
|
createDir(home); // just in case.
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
// "/home/icculus/.Aquaria" or something. Spaces are okay.
|
|
|
|
#ifdef BBGE_BUILD_MACOSX
|
|
|
|
const std::string prefix("Library/Application Support/");
|
|
|
|
#else
|
|
|
|
const std::string prefix(".");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
userDataFolder = home + "/" + prefix + userDataSubFolder;
|
2013-11-14 19:07:39 +00:00
|
|
|
createDir(userDataFolder);
|
2011-08-03 20:05:33 +00:00
|
|
|
debugLogPath = userDataFolder + "/";
|
2013-11-14 19:07:39 +00:00
|
|
|
createDir(userDataFolder + "/screenshots");
|
2011-08-03 20:05:33 +00:00
|
|
|
std::string prefpath(getPreferencesFolder());
|
2013-11-14 19:07:39 +00:00
|
|
|
createDir(prefpath);
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
#else
|
|
|
|
debugLogPath = "";
|
2011-11-20 22:47:24 +00:00
|
|
|
userDataFolder = ".";
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
{
|
|
|
|
if(checkWritable(userDataFolder, true, true)) // working dir?
|
|
|
|
{
|
|
|
|
puts("Using working directory as user directory.");
|
|
|
|
}
|
|
|
|
// TODO: we may want to use a user-specific path under windows as well
|
|
|
|
// if the code below gets actually used, pass 2x false to checkWritable() above.
|
|
|
|
// not sure about this right now -- FG
|
|
|
|
/*else
|
|
|
|
{
|
2013-11-14 19:07:39 +00:00
|
|
|
puts("Working directory is not writable...");
|
2011-11-20 22:47:24 +00:00
|
|
|
char pathbuf[MAX_PATH];
|
|
|
|
if(SHGetSpecialFolderPathA(NULL, &pathbuf[0], CSIDL_APPDATA, 0))
|
|
|
|
{
|
|
|
|
userDataFolder = pathbuf;
|
|
|
|
userDataFolder += '/';
|
|
|
|
userDataFolder += userDataSubFolder;
|
|
|
|
for(uint32 i = 0; i < userDataFolder.length(); ++i)
|
|
|
|
if(userDataFolder[i] == '\\')
|
|
|
|
userDataFolder[i] = '/';
|
|
|
|
debugLogPath = userDataFolder + "/";
|
|
|
|
puts(("Using \"" + userDataFolder + "\" as user directory.").c_str());
|
2013-11-14 19:07:39 +00:00
|
|
|
createDir(userDataFolder);
|
2011-11-20 22:47:24 +00:00
|
|
|
checkWritable(userDataFolder, true, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
puts("Failed to retrieve appdata path, using working dir."); // too bad, but can't do anything about it
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
#endif
|
2011-11-20 15:27:55 +00:00
|
|
|
|
|
|
|
_logOut.open((debugLogPath + "debug.log").c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
debugLogActive = true;
|
2022-04-08 17:31:16 +00:00
|
|
|
debugOutputActive = false;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-11-14 02:41:48 +00:00
|
|
|
grabInput = false;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
srand(time(NULL));
|
|
|
|
old_dt = 0;
|
2013-07-15 01:22:41 +00:00
|
|
|
current_dt = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
virtualOffX = virtualOffY = 0;
|
|
|
|
|
|
|
|
particleManager = new ParticleManager(particleSize);
|
|
|
|
nowTicks = thenTicks = 0;
|
|
|
|
lib_graphics = lib_sound = lib_input = false;
|
|
|
|
mouseConstraint = false;
|
|
|
|
mouseCircle = 0;
|
|
|
|
particlesPaused = false;
|
|
|
|
joystickAsMouse = false;
|
|
|
|
flipMouseButtons = 0;
|
|
|
|
joystickEnabled = false;
|
|
|
|
doScreenshot = false;
|
|
|
|
baseCullRadius = 1;
|
|
|
|
width = height = 0;
|
2017-06-26 06:34:30 +00:00
|
|
|
_lastEnumeratedDisplayIndex = -1;
|
2011-08-03 20:05:33 +00:00
|
|
|
afterEffectManagerLayer = 0;
|
|
|
|
renderObjectLayers.resize(1);
|
|
|
|
invGlobalScale = 1.0;
|
|
|
|
invGlobalScaleSqr = 1.0;
|
|
|
|
renderObjectCount = 0;
|
2022-05-22 05:38:23 +00:00
|
|
|
processedRenderObjectCount = 0;
|
|
|
|
totalRenderObjectCount = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
avgFPS.resize(1);
|
|
|
|
minimized = false;
|
|
|
|
shuttingDown = false;
|
|
|
|
nestedMains = 0;
|
|
|
|
afterEffectManager = 0;
|
|
|
|
loopDone = false;
|
|
|
|
core = this;
|
|
|
|
|
|
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
|
|
{
|
|
|
|
keys[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
globalResolutionScale = globalScale = Vector(1,1,1);
|
|
|
|
|
|
|
|
initRenderObjectLayers(numRenderLayers);
|
|
|
|
|
|
|
|
initPlatform(filesystem);
|
2023-05-30 22:55:16 +00:00
|
|
|
|
|
|
|
texmgr.spawnThreads(3);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::initPlatform(const std::string &filesystem)
|
|
|
|
{
|
|
|
|
#if defined(BBGE_BUILD_MACOSX) && !defined(BBGE_BUILD_MACOSX_NOBUNDLEPATH)
|
|
|
|
// FIXME: filesystem not handled
|
|
|
|
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
CFURLRef resourcesURL = CFBundleCopyBundleURL(mainBundle);
|
|
|
|
char path[PATH_MAX];
|
|
|
|
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
|
|
|
|
{
|
|
|
|
// error!
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("Core::initPlatform: CFURLGetFileSystemRepresentation error");
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
CFRelease(resourcesURL);
|
|
|
|
debugLog(path);
|
|
|
|
chdir(path);
|
|
|
|
#elif defined(BBGE_BUILD_UNIX)
|
|
|
|
if (!filesystem.empty())
|
|
|
|
{
|
|
|
|
if (chdir(filesystem.c_str()) == 0)
|
|
|
|
return;
|
|
|
|
else
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("Core::initPlatform: Failed to chdir to filesystem path " + filesystem);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
#ifdef BBGE_DATA_PREFIX
|
|
|
|
if (chdir(BBGE_DATA_PREFIX) == 0 && chdir(appName.c_str()) == 0)
|
|
|
|
return;
|
|
|
|
else
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("Core::initPlatform: Failed to chdir to filesystem path " BBGE_DATA_PREFIX + appName);
|
2011-08-03 20:05:33 +00:00
|
|
|
#endif
|
|
|
|
char path[PATH_MAX];
|
|
|
|
// always a symlink to this process's binary, on modern Linux systems.
|
|
|
|
const ssize_t rc = readlink("/proc/self/exe", path, sizeof (path));
|
2017-01-14 17:10:20 +00:00
|
|
|
if ( (rc == -1) || (rc >= (ssize_t) sizeof (path)) )
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
// error!
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("Core::initPlatform: readlink error");
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
path[rc] = '\0';
|
|
|
|
char *ptr = strrchr(path, '/');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
|
|
|
debugLog(path);
|
|
|
|
if (chdir(path) != 0)
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("Core::initPlatform: Failed to chdir to executable path" + std::string(path));
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
2013-06-19 00:08:24 +00:00
|
|
|
if(filesystem.length())
|
|
|
|
{
|
|
|
|
if(_chdir(filesystem.c_str()) != 0)
|
|
|
|
{
|
2022-06-20 02:25:18 +00:00
|
|
|
errorLog("chdir failed: " + filesystem);
|
2013-06-19 00:08:24 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
// FIXME: filesystem not handled
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Core::getPreferencesFolder()
|
|
|
|
{
|
|
|
|
#ifdef BBGE_BUILD_UNIX
|
|
|
|
return userDataFolder + "/preferences";
|
|
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
return "";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Core::getUserDataFolder()
|
|
|
|
{
|
|
|
|
return userDataFolder;
|
|
|
|
}
|
|
|
|
|
2022-06-20 02:25:18 +00:00
|
|
|
std::string Core::getDebugLogPath()
|
|
|
|
{
|
|
|
|
return debugLogPath;
|
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
Core::~Core()
|
|
|
|
{
|
2016-07-17 20:25:24 +00:00
|
|
|
clearActionButtons();
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (particleManager)
|
|
|
|
{
|
|
|
|
delete particleManager;
|
|
|
|
}
|
|
|
|
if (sound)
|
|
|
|
{
|
|
|
|
delete sound;
|
|
|
|
sound = 0;
|
|
|
|
}
|
2011-08-11 00:26:46 +00:00
|
|
|
debugLog("~Core()");
|
|
|
|
_logOut.close();
|
2011-08-03 20:05:33 +00:00
|
|
|
core = 0;
|
|
|
|
}
|
|
|
|
|
2016-11-14 02:41:48 +00:00
|
|
|
void Core::updateInputGrab()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-11-14 02:41:48 +00:00
|
|
|
// Can and MUST always ungrab if window is not in focus
|
|
|
|
const bool on = grabInput && isWindowFocus();
|
2019-01-28 23:36:48 +00:00
|
|
|
window->setGrabInput(on);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-11-14 02:41:48 +00:00
|
|
|
void Core::setInputGrab(bool on)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-11-14 02:41:48 +00:00
|
|
|
grabInput = on;
|
|
|
|
updateInputGrab();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::isFullscreen()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
return window->isFullscreen();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 12:06:31 +00:00
|
|
|
bool Core::isDesktopResolution()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
return window->isDesktopResolution();
|
2017-01-13 12:06:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int Core::getDisplayIndex()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
return window->getDisplayIndex();
|
2017-01-13 12:06:31 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 12:06:31 +00:00
|
|
|
int Core::getRefreshRate()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
return window->getRefreshRate();
|
2017-01-13 12:06:31 +00:00
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
bool Core::isShuttingDown()
|
|
|
|
{
|
|
|
|
return shuttingDown;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::init()
|
|
|
|
{
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
setupFileAccess();
|
|
|
|
|
2021-01-23 12:23:33 +00:00
|
|
|
// Don't want to use SDL_INIT_EVERYTHING, in case future changes to SDL add any flags.
|
|
|
|
// Ie. At some point SDL2 added a sensors subsystem, which may cause SDL_Init() to fail
|
|
|
|
// due to win10 group policies that forbid sensor usage. Probably similar things on OSX.
|
2021-01-23 12:52:10 +00:00
|
|
|
unsigned sdlflags = SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
|
2018-04-16 23:28:23 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
quitNestedMainFlag = false;
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2018-04-16 23:28:23 +00:00
|
|
|
// Haptic is inited separately, in Jostick.cpp, when a joystick is actually plugged in
|
2021-01-23 12:23:33 +00:00
|
|
|
sdlflags |= SDL_INIT_GAMECONTROLLER;
|
2018-04-16 23:28:23 +00:00
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
// Disable relative mouse motion at the edges of the screen, which breaks
|
|
|
|
// mouse control for absolute input devices like Wacom tablets and touchscreens.
|
|
|
|
SDL_putenv((char *) "SDL_MOUSE_RELATIVE=0");
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2018-04-16 23:28:23 +00:00
|
|
|
if((SDL_Init(sdlflags))==-1)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2017-01-17 10:15:47 +00:00
|
|
|
std::string msg("Failed to init SDL: ");
|
|
|
|
msg.append(SDL_GetError());
|
|
|
|
exit_error(msg);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
loopDone = false;
|
|
|
|
|
2013-11-14 16:58:33 +00:00
|
|
|
initLocalization();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::initRenderObjectLayers(int num)
|
|
|
|
{
|
|
|
|
renderObjectLayers.resize(num);
|
|
|
|
renderObjectLayerOrder.resize(num);
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
renderObjectLayerOrder[i] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::initSoundLibrary(const std::string &defaultDevice)
|
|
|
|
{
|
|
|
|
debugLog("Creating SoundManager");
|
|
|
|
sound = new SoundManager(defaultDevice);
|
|
|
|
debugLog("Done");
|
|
|
|
return sound != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector Core::getGameCursorPosition()
|
|
|
|
{
|
2014-03-07 16:59:36 +00:00
|
|
|
return getGamePosition(mouse.position);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector Core::getGamePosition(const Vector &v)
|
|
|
|
{
|
2014-03-07 16:59:36 +00:00
|
|
|
return cameraPos + (v * invGlobalScale);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getMouseButtonState(int m)
|
|
|
|
{
|
|
|
|
int mcode=m;
|
|
|
|
|
|
|
|
switch(m)
|
|
|
|
{
|
|
|
|
case 0: mcode=1; break;
|
|
|
|
case 1: mcode=3; break;
|
|
|
|
case 2: mcode=2; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint8 mousestate = SDL_GetMouseState(0,0);
|
|
|
|
|
|
|
|
return mousestate & SDL_BUTTON(mcode);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getKeyState(int k)
|
|
|
|
{
|
2017-04-04 17:27:53 +00:00
|
|
|
assert(k < KEY_MAXARRAY);
|
2016-07-03 13:48:40 +00:00
|
|
|
return k > 0 && k < KEY_MAXARRAY ? keys[k] : 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2016-07-03 16:07:13 +00:00
|
|
|
void Core::initJoystickLibrary()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-05 03:20:01 +00:00
|
|
|
#if !SDL_VERSION_ATLEAST(2,0,0)
|
2016-07-13 03:00:19 +00:00
|
|
|
detectJoysticks();
|
2011-08-03 20:05:33 +00:00
|
|
|
#endif
|
|
|
|
|
2016-07-13 03:00:19 +00:00
|
|
|
joystickEnabled = true;
|
2016-07-03 16:07:13 +00:00
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-07-03 16:07:13 +00:00
|
|
|
void Core::clearJoysticks()
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < joysticks.size(); ++i)
|
|
|
|
delete joysticks[i];
|
|
|
|
joysticks.clear();
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-07-13 03:00:19 +00:00
|
|
|
|
|
|
|
// Only used for SDL 1.2 code path.
|
|
|
|
// SDL2 automatically fires joystick added events upon startup
|
2016-07-03 16:07:13 +00:00
|
|
|
void Core::detectJoysticks()
|
|
|
|
{
|
|
|
|
clearJoysticks();
|
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
const unsigned n = SDL_NumJoysticks();
|
|
|
|
os << "Found [" << n << "] joysticks";
|
|
|
|
debugLog(os.str());
|
|
|
|
|
2016-07-13 03:00:19 +00:00
|
|
|
joysticks.reserve(n);
|
2016-07-03 16:07:13 +00:00
|
|
|
for(unsigned i = 0; i < n; ++i)
|
|
|
|
{
|
|
|
|
Joystick *j = new Joystick;
|
|
|
|
if(j->init(i))
|
|
|
|
joysticks.push_back(j);
|
|
|
|
else
|
|
|
|
delete j;
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::initInputLibrary()
|
|
|
|
{
|
2023-05-31 15:40:41 +00:00
|
|
|
mouse.position = Vector(getWindowWidth()/2, getWindowHeight()/2);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
|
|
{
|
|
|
|
keys[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::onUpdate(float dt)
|
|
|
|
{
|
|
|
|
if (minimized) return;
|
|
|
|
|
2016-07-18 21:14:20 +00:00
|
|
|
pollEvents(dt);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-08-03 23:55:32 +00:00
|
|
|
|
|
|
|
|
2016-07-18 21:22:42 +00:00
|
|
|
ActionMapper::onUpdate(dt);
|
|
|
|
StateManager::onUpdate(dt);
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
onMouseInput();
|
|
|
|
|
|
|
|
globalScale.update(dt);
|
2023-05-31 15:40:41 +00:00
|
|
|
globalScaleChanged();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (afterEffectManager)
|
|
|
|
{
|
|
|
|
afterEffectManager->update(dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-07 16:59:36 +00:00
|
|
|
void Core::globalScaleChanged()
|
|
|
|
{
|
|
|
|
invGlobalScale = 1.0f/globalScale.x;
|
|
|
|
invGlobalScaleSqr = invGlobalScale * invGlobalScale;
|
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
void Core::setClearColor(const Vector &c)
|
|
|
|
{
|
|
|
|
glClearColor(c.x, c.y, c.z, 0.0);
|
2019-01-28 23:36:48 +00:00
|
|
|
clearColor = c;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
void Core::initGraphicsLibrary(int width, int height, bool fullscreen, bool vsync, int bpp, int display, int hz)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
if(!window)
|
|
|
|
window = new CoreWindow;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
window->open(width, height, fullscreen, bpp, vsync, display, hz);
|
|
|
|
window->setTitle(appName.c_str());
|
2016-11-15 03:49:53 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
// get GL symbols AFTER opening the window, otherwise we get a super old GL context on windows and nothing works
|
2016-11-15 03:49:53 +00:00
|
|
|
if (!lookup_all_glsyms())
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Couldn't load OpenGL symbols we need\n";
|
|
|
|
SDL_Quit();
|
|
|
|
exit_error(os.str());
|
|
|
|
}
|
|
|
|
|
2016-11-14 02:13:34 +00:00
|
|
|
debugLog("GL vendor, renderer & version:");
|
|
|
|
debugLog((const char*)glGetString(GL_VENDOR));
|
|
|
|
debugLog((const char*)glGetString(GL_RENDERER));
|
|
|
|
debugLog((const char*)glGetString(GL_VERSION));
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
enumerateScreenModes(window->getDisplayIndex());
|
2016-11-14 02:13:34 +00:00
|
|
|
|
2021-01-12 10:06:09 +00:00
|
|
|
window->updateSize();
|
2019-01-28 23:36:48 +00:00
|
|
|
cacheRender(); // Clears the window bg to black early; prevents flickering
|
2017-02-19 00:45:55 +00:00
|
|
|
lib_graphics = true;
|
2017-01-13 12:06:31 +00:00
|
|
|
}
|
|
|
|
|
2017-06-26 06:34:30 +00:00
|
|
|
void Core::enumerateScreenModesIfNecessary(int display /* = -1 */)
|
|
|
|
{
|
|
|
|
if(display == -1)
|
|
|
|
{
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2019-01-28 23:36:48 +00:00
|
|
|
if(window)
|
|
|
|
display = window->getDisplayIndex();
|
2017-06-26 06:34:30 +00:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
display = 0;
|
|
|
|
}
|
|
|
|
if(_lastEnumeratedDisplayIndex == display)
|
|
|
|
return;
|
|
|
|
|
|
|
|
enumerateScreenModes(display);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::enumerateScreenModes(int display)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2017-06-26 06:34:30 +00:00
|
|
|
_lastEnumeratedDisplayIndex = display;
|
2011-08-03 20:05:33 +00:00
|
|
|
screenModes.clear();
|
|
|
|
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2017-01-13 12:06:31 +00:00
|
|
|
screenModes.push_back(ScreenMode(0, 0, 0)); // "Desktop" screen mode
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
SDL_DisplayMode mode;
|
2017-06-26 06:34:30 +00:00
|
|
|
const int modecount = SDL_GetNumDisplayModes(display);
|
2013-07-18 21:29:55 +00:00
|
|
|
if(modecount == 0){
|
|
|
|
debugLog("No modes available!");
|
|
|
|
return;
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
for (int i = 0; i < modecount; i++) {
|
2017-06-26 06:34:30 +00:00
|
|
|
SDL_GetDisplayMode(display, i, &mode);
|
2013-07-18 21:29:55 +00:00
|
|
|
if (mode.w && mode.h && (mode.w > mode.h))
|
|
|
|
{
|
2021-01-12 00:57:29 +00:00
|
|
|
// In order to prevent cluttering the list of supported screen modes,
|
|
|
|
// only record the one per resolution with the highest refresh rate
|
|
|
|
bool add = true;
|
|
|
|
for(size_t k = 0; k < screenModes.size(); ++k)
|
|
|
|
if(screenModes[k].x == mode.w && screenModes[k].y == mode.h)
|
|
|
|
{
|
|
|
|
add = false;
|
|
|
|
if(screenModes[k].hz < mode.refresh_rate)
|
|
|
|
{
|
|
|
|
screenModes[k].hz = mode.refresh_rate;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(add)
|
|
|
|
screenModes.push_back(ScreenMode(mode.w, mode.h, mode.refresh_rate));
|
2013-07-18 21:29:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_Rect **modes;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
modes=SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
|
|
|
|
|
|
|
|
if(modes == (SDL_Rect **)0){
|
|
|
|
debugLog("No modes available!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(modes == (SDL_Rect **)-1){
|
|
|
|
debugLog("All resolutions available.");
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
int c=0;
|
|
|
|
for(i=0;modes[i];++i){
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
for (i=c-1;i>=0;i--)
|
|
|
|
{
|
|
|
|
if (modes[i]->w > modes[i]->h)
|
|
|
|
{
|
2017-02-15 03:34:32 +00:00
|
|
|
screenModes.push_back(ScreenMode(i, modes[i]->w, modes[i]->h));
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2016-11-14 02:13:34 +00:00
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Screen modes available: " << screenModes.size();
|
|
|
|
debugLog(os.str());
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownSoundLibrary()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-11-14 02:41:48 +00:00
|
|
|
void Core::shutdownGraphicsLibrary()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-11-14 02:41:48 +00:00
|
|
|
setInputGrab(false);
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
glFinish();
|
2016-11-14 02:41:48 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
delete window;
|
2019-04-15 00:26:48 +00:00
|
|
|
window = NULL;
|
2016-11-14 02:41:48 +00:00
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
|
|
unload_all_glsyms();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
lib_graphics = false;
|
|
|
|
|
2016-08-06 17:50:07 +00:00
|
|
|
destroyIcon();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::quit()
|
|
|
|
{
|
|
|
|
enqueueJumpState("STATE_QUIT");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::applyState(const std::string &state)
|
|
|
|
{
|
|
|
|
if (nocasecmp(state, "state_quit")==0)
|
|
|
|
{
|
|
|
|
loopDone = true;
|
|
|
|
}
|
|
|
|
StateManager::applyState(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setPixelScale(int pixelScaleX, int pixelScaleY)
|
|
|
|
{
|
|
|
|
virtualWidth = pixelScaleX;
|
2016-05-05 17:40:28 +00:00
|
|
|
virtualHeight = pixelScaleY; //assumes 4:3 aspect ratio
|
2014-03-07 16:59:36 +00:00
|
|
|
this->baseCullRadius = 1.1f * sqrtf(sqr(getVirtualWidth()/2) + sqr(getVirtualHeight()/2));
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "virtual(" << virtualWidth << ", " << virtualHeight << ")";
|
|
|
|
debugLog(os.str());
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
center = Vector(baseVirtualWidth/2, baseVirtualHeight/2);
|
|
|
|
|
2016-11-14 00:46:06 +00:00
|
|
|
int diffw = virtualWidth-baseVirtualWidth;
|
|
|
|
if (diffw > 0)
|
2011-08-03 20:05:33 +00:00
|
|
|
virtualOffX = ((virtualWidth-baseVirtualWidth)/2);
|
|
|
|
else
|
|
|
|
virtualOffX = 0;
|
|
|
|
|
2016-11-14 00:46:06 +00:00
|
|
|
int diffh = virtualHeight-baseVirtualHeight;
|
|
|
|
if (diffh > 0)
|
2011-08-03 20:05:33 +00:00
|
|
|
virtualOffY = ((virtualHeight-baseVirtualHeight)/2);
|
|
|
|
else
|
|
|
|
virtualOffY = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::enable2DWide(int rx, int ry)
|
|
|
|
{
|
|
|
|
float aspect = float(rx) / float(ry);
|
|
|
|
if (aspect >= 1.3f)
|
|
|
|
{
|
|
|
|
int vw = int(float(baseVirtualHeight) * (float(rx)/float(ry)));
|
2016-11-14 00:46:06 +00:00
|
|
|
enable2D(vw, baseVirtualHeight);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int vh = int(float(baseVirtualWidth) * (float(ry)/float(rx)));
|
2016-11-14 00:46:06 +00:00
|
|
|
enable2D(baseVirtualWidth, vh);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bbgeOrtho2D(float left, float right, float bottom, float top)
|
|
|
|
{
|
2016-11-09 00:16:55 +00:00
|
|
|
glOrtho(left, right, bottom, top, -1.0, 1.0);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-11-14 00:46:06 +00:00
|
|
|
void Core::enable2D(int pixelScaleX, int pixelScaleY)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-11-14 00:46:06 +00:00
|
|
|
assert(pixelScaleX && pixelScaleY);
|
|
|
|
|
2016-11-09 00:16:55 +00:00
|
|
|
GLint viewPort[4];
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
float vw=0,vh=0;
|
|
|
|
|
2016-11-14 00:46:06 +00:00
|
|
|
int viewOffX = 0;
|
|
|
|
int viewOffY = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
float aspect = float(width)/float(height);
|
|
|
|
|
|
|
|
if (aspect >= 1.4f)
|
|
|
|
{
|
|
|
|
vw = float(baseVirtualWidth * viewPort[3]) / float(baseVirtualHeight);
|
|
|
|
viewOffX = (viewPort[2] - vw) * 0.5f;
|
|
|
|
}
|
|
|
|
else if (aspect < 1.3f)
|
|
|
|
{
|
|
|
|
vh = float(baseVirtualHeight * viewPort[2]) / float(baseVirtualWidth);
|
|
|
|
viewOffY = (viewPort[3] - vh) * 0.5f;
|
|
|
|
}
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
bbgeOrtho2D(0.0f-viewOffX,viewPort[2]-viewOffX,viewPort[3]-viewOffY,0.0f-viewOffY);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-11-09 00:16:55 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
2011-08-03 20:05:33 +00:00
|
|
|
setupRenderPositionAndScale();
|
|
|
|
|
2023-05-31 15:40:41 +00:00
|
|
|
float widthFactor = width/float(pixelScaleX);
|
|
|
|
float heightFactor = height/float(pixelScaleY);
|
|
|
|
globalResolutionScale = Vector(widthFactor,heightFactor,1.0f);
|
2011-08-03 20:05:33 +00:00
|
|
|
setPixelScale(pixelScaleX, pixelScaleY);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::quitNestedMain()
|
|
|
|
{
|
|
|
|
if (getNestedMains() > 1)
|
|
|
|
{
|
|
|
|
quitNestedMainFlag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::resetTimer()
|
|
|
|
{
|
|
|
|
nowTicks = thenTicks = SDL_GetTicks();
|
|
|
|
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < avgFPS.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
avgFPS[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setMousePosition(const Vector &p)
|
|
|
|
{
|
2023-10-28 04:08:19 +00:00
|
|
|
int ix, iy;
|
|
|
|
virtualCoordsToPixelPos(ix, iy, p);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
SDL_Event ev = { sdlUserMouseEventID };
|
2023-10-28 04:08:19 +00:00
|
|
|
ev.motion.x = ix;
|
|
|
|
ev.motion.y = iy;
|
|
|
|
ev.motion.xrel = 0;
|
|
|
|
ev.motion.yrel = 0;
|
2022-08-24 12:16:25 +00:00
|
|
|
ev.motion.state = 0;
|
|
|
|
SDL_PushEvent(&ev);
|
|
|
|
|
2023-10-28 04:08:19 +00:00
|
|
|
window->warpMouse(ix, iy);
|
2022-08-24 12:16:25 +00:00
|
|
|
|
|
|
|
ev.motion.state = 1;
|
|
|
|
SDL_PushEvent(&ev);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// used to update all render objects either uniformly or as part of a time sliced update process
|
|
|
|
void Core::updateRenderObjects(float dt)
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t c = 0; c < renderObjectLayers.size(); c++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
RenderObjectLayer *rl = &renderObjectLayers[c];
|
|
|
|
|
|
|
|
if (!rl->update)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (RenderObject *r = rl->getFirst(); r; r = rl->getNext())
|
|
|
|
{
|
|
|
|
r->update(dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loopDone)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Core::getEnqueuedJumpState()
|
|
|
|
{
|
|
|
|
return this->enqueuedJumpState;
|
|
|
|
}
|
|
|
|
|
2023-05-31 15:40:41 +00:00
|
|
|
static int screenshotNum = 0;
|
|
|
|
static std::string getScreenshotFilename(bool png)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-09-26 01:44:15 +00:00
|
|
|
std::string prefix = core->getUserDataFolder() + "/screenshots/screen";
|
|
|
|
std::string ext = png ? ".png" : ".tga";
|
2011-08-03 20:05:33 +00:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
2016-09-26 01:44:15 +00:00
|
|
|
os << prefix << screenshotNum << ext;
|
2011-08-03 20:05:33 +00:00
|
|
|
screenshotNum ++;
|
2017-01-12 21:51:46 +00:00
|
|
|
std::string str(os.str());
|
2023-05-31 15:40:41 +00:00
|
|
|
if (!exists(str)) // keep going until we hit an unused filename.
|
2011-08-03 20:05:33 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 18:05:38 +00:00
|
|
|
unsigned Core::getTicks()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
return SDL_GetTicks();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::isWindowFocus()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
return window->hasInputFocus();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2013-06-24 01:39:48 +00:00
|
|
|
void Core::onBackgroundUpdate()
|
|
|
|
{
|
|
|
|
SDL_Delay(200);
|
|
|
|
}
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
void Core::run(float runTime)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
// cannot nest loops when the game is over
|
|
|
|
if (loopDone) return;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
float dt;
|
|
|
|
float counter = 0;
|
|
|
|
int frames = 0;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2016-10-24 21:58:20 +00:00
|
|
|
#if !defined(_DEBUG)
|
2011-08-03 20:05:33 +00:00
|
|
|
bool wasInactive = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nowTicks = thenTicks = SDL_GetTicks();
|
|
|
|
nestedMains++;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
while((runTime == -1 && !loopDone) || (runTime >0))
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-05-14 15:23:48 +00:00
|
|
|
nowTicks = SDL_GetTicks();
|
2011-08-03 20:05:33 +00:00
|
|
|
dt = (nowTicks-thenTicks)/1000.0;
|
|
|
|
thenTicks = nowTicks;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (!avgFPS.empty())
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2017-01-14 17:10:20 +00:00
|
|
|
size_t i = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
for (i = avgFPS.size()-1; i > 0; i--)
|
|
|
|
{
|
|
|
|
avgFPS[i] = avgFPS[i-1];
|
|
|
|
}
|
|
|
|
avgFPS[0] = dt;
|
|
|
|
|
|
|
|
float c=0;
|
|
|
|
int n = 0;
|
|
|
|
for (i = 0; i < avgFPS.size(); i++)
|
|
|
|
{
|
|
|
|
if (avgFPS[i] > 0)
|
|
|
|
{
|
|
|
|
c += avgFPS[i];
|
|
|
|
n ++;
|
|
|
|
}
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
if (n > 0)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
c /= n;
|
|
|
|
dt = c;
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-24 21:58:20 +00:00
|
|
|
#if !defined(_DEBUG)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (lib_graphics && (wasInactive || !settings.runInBackground))
|
|
|
|
{
|
|
|
|
if (isWindowFocus())
|
|
|
|
{
|
|
|
|
if (wasInactive)
|
|
|
|
{
|
|
|
|
debugLog("WINDOW ACTIVE");
|
2016-11-14 02:41:48 +00:00
|
|
|
updateInputGrab();
|
2011-08-03 20:05:33 +00:00
|
|
|
wasInactive = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-03-24 20:15:27 +00:00
|
|
|
if (!wasInactive)
|
|
|
|
debugLog("WINDOW INACTIVE");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
wasInactive = true;
|
|
|
|
updateInputGrab();
|
|
|
|
sound->pause();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
while (!isWindowFocus())
|
|
|
|
{
|
|
|
|
pollEvents(dt);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
onBackgroundUpdate();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
resetTimer();
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
debugLog("app back in focus");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
resetTimer();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
sound->resume();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
resetTimer();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-03-24 20:15:27 +00:00
|
|
|
continue;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
old_dt = dt;
|
|
|
|
|
|
|
|
modifyDt(dt);
|
|
|
|
|
2013-07-15 01:22:41 +00:00
|
|
|
current_dt = dt;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (quitNestedMainFlag)
|
|
|
|
{
|
|
|
|
quitNestedMainFlag = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (runTime>0)
|
|
|
|
{
|
|
|
|
runTime -= dt;
|
|
|
|
if (runTime < 0)
|
|
|
|
runTime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateRenderObjects(dt);
|
|
|
|
|
|
|
|
if (particleManager)
|
|
|
|
particleManager->update(dt);
|
|
|
|
|
2022-09-11 22:12:41 +00:00
|
|
|
if(sound)
|
|
|
|
sound->update(dt);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
onUpdate(dt);
|
|
|
|
|
|
|
|
if (nestedMains == 1)
|
|
|
|
clearGarbage();
|
|
|
|
|
|
|
|
if (loopDone)
|
|
|
|
break;
|
|
|
|
|
|
|
|
updateCullData();
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
g_dbg_numRenderCalls = 0;
|
2013-04-22 21:36:31 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (settings.renderOn)
|
|
|
|
{
|
|
|
|
if (darkLayer.isUsed())
|
|
|
|
{
|
|
|
|
darkLayer.preRender();
|
|
|
|
}
|
|
|
|
|
|
|
|
render();
|
|
|
|
|
|
|
|
showBuffer();
|
|
|
|
|
|
|
|
if (nestedMains == 1)
|
|
|
|
clearGarbage();
|
|
|
|
|
|
|
|
frames++;
|
|
|
|
|
|
|
|
counter += dt;
|
|
|
|
if (counter > 1)
|
|
|
|
{
|
|
|
|
fps = frames;
|
|
|
|
frames = counter = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-22 01:29:57 +00:00
|
|
|
sound->setListenerPos(screenCenter.x, screenCenter.y);
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (doScreenshot)
|
|
|
|
{
|
|
|
|
doScreenshot = false;
|
2016-09-26 01:44:15 +00:00
|
|
|
const bool png = true;
|
|
|
|
saveScreenshot(getScreenshotFilename(png), png);
|
2011-08-03 20:05:33 +00:00
|
|
|
prepScreen(0);
|
2016-09-26 01:44:15 +00:00
|
|
|
resetTimer();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
quitNestedMainFlag = false;
|
|
|
|
if (nestedMains==1)
|
|
|
|
clearGarbage();
|
|
|
|
nestedMains--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::clearBuffers()
|
|
|
|
{
|
2016-05-05 18:05:38 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setupRenderPositionAndScale()
|
|
|
|
{
|
2016-11-09 00:16:55 +00:00
|
|
|
glScalef(globalScale.x*globalResolutionScale.x, globalScale.y*globalResolutionScale.y, globalScale.z*globalResolutionScale.z);
|
2011-08-03 20:05:33 +00:00
|
|
|
glTranslatef(-(cameraPos.x+cameraOffset.x), -(cameraPos.y+cameraOffset.y), -(cameraPos.z+cameraOffset.z));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setupGlobalResolutionScale()
|
|
|
|
{
|
|
|
|
glScalef(globalResolutionScale.x, globalResolutionScale.y, globalResolutionScale.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setMouseConstraint(bool on)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
mouseConstraint = on;
|
|
|
|
}
|
|
|
|
|
2014-03-10 01:26:01 +00:00
|
|
|
void Core::setMouseConstraintCircle(const Vector& pos, float circle)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
mouseConstraint = true;
|
|
|
|
mouseCircle = circle;
|
2014-03-10 01:26:01 +00:00
|
|
|
mouseConstraintCenter = pos;
|
|
|
|
mouseConstraintCenter.z = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2023-10-28 04:08:19 +00:00
|
|
|
int Core::getVirtualOffX() const
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
return virtualOffX;
|
|
|
|
}
|
|
|
|
|
2023-10-28 04:08:19 +00:00
|
|
|
int Core::getVirtualOffY() const
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
return virtualOffY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::centerMouse()
|
|
|
|
{
|
2023-05-31 15:40:41 +00:00
|
|
|
setMousePosition(Vector((virtualWidth/2) - getVirtualOffX(), virtualHeight/2));
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::doMouseConstraint()
|
|
|
|
{
|
|
|
|
if (mouseConstraint)
|
|
|
|
{
|
2014-03-10 01:26:01 +00:00
|
|
|
Vector h = mouseConstraintCenter;
|
2011-08-03 20:05:33 +00:00
|
|
|
Vector d = mouse.position - h;
|
2022-05-04 01:04:26 +00:00
|
|
|
if (!d.isLength2DIn(mouseCircle + 1)) // Only move mouse if it'll actually move (works around issues in SDL > 2.0.20)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
d.setLength2D(mouseCircle);
|
|
|
|
mouse.position = h+d;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-28 04:08:19 +00:00
|
|
|
Vector Core::pixelPosToVirtualCoords(int x, int y) const
|
|
|
|
{
|
|
|
|
const float mx = float(virtualWidth)/float(getWindowWidth());
|
|
|
|
const float my = float(virtualHeight)/float(getWindowHeight());
|
|
|
|
|
|
|
|
return Vector(
|
|
|
|
(x * mx) - getVirtualOffX(),
|
|
|
|
y * my
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-17 00:39:46 +00:00
|
|
|
void Core::virtualCoordsToPixelPos(int& x, int& y, const Vector& p) const
|
2023-10-28 04:08:19 +00:00
|
|
|
{
|
|
|
|
const float px = p.x + getVirtualOffX();
|
|
|
|
const float py = p.y;
|
|
|
|
x = px * (float(getWindowWidth())/float(virtualWidth));
|
|
|
|
y = py * (float(getWindowHeight())/float(virtualHeight));
|
|
|
|
}
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
void Core::onEvent(const SDL_Event& event)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
const bool focus = window->hasFocus();
|
2022-08-24 12:16:25 +00:00
|
|
|
if(event.type == sdlUserMouseEventID)
|
|
|
|
{
|
2023-10-28 04:08:19 +00:00
|
|
|
mouse._enableMotionEvents = !!event.motion.state;
|
|
|
|
if(event.motion.state) // If 1, the generated mouse move is done and the rest is true mouse events
|
|
|
|
{
|
|
|
|
// We just set the position, so lets make sure that this mouse move isn't picked up
|
|
|
|
// as a relative change, ie. there was no actual user mouse move.
|
|
|
|
// There may be regular mouse move events after this one, which will be picked up normally.
|
|
|
|
mouse.lastPosition = pixelPosToVirtualCoords(event.motion.x, event.motion.y);
|
|
|
|
goto motion; // All the needed data are there, use this like a regular motion event
|
|
|
|
}
|
2022-08-24 12:16:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
switch (event.type)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_KEYDOWN:
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
if ((event.key.keysym.sym == SDLK_g) && (event.key.keysym.mod & KMOD_CTRL))
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
setInputGrab(!grabInput);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
else if (focus)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2019-01-28 23:36:48 +00:00
|
|
|
unsigned kidx = event.key.keysym.scancode;
|
2016-07-03 13:48:40 +00:00
|
|
|
#else
|
2019-01-28 23:36:48 +00:00
|
|
|
unsigned kidx = event.key.keysym.sym;
|
2016-07-03 13:48:40 +00:00
|
|
|
#endif
|
2019-01-28 23:36:48 +00:00
|
|
|
if(kidx < KEY_MAXARRAY)
|
|
|
|
keys[kidx] = 1;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_KEYUP:
|
|
|
|
{
|
|
|
|
if (focus)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2019-01-28 23:36:48 +00:00
|
|
|
unsigned kidx = event.key.keysym.scancode;
|
2016-07-03 13:48:40 +00:00
|
|
|
#else
|
2019-01-28 23:36:48 +00:00
|
|
|
unsigned kidx = event.key.keysym.sym;
|
2016-07-03 13:48:40 +00:00
|
|
|
#endif
|
2019-01-28 23:36:48 +00:00
|
|
|
if(kidx < KEY_MAXARRAY)
|
|
|
|
keys[kidx] = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2023-10-28 04:08:19 +00:00
|
|
|
// This event is also sent when SDL sets the mouse position!
|
|
|
|
// Since there's no way to distinguish the generated event from a true "user moved the mouse" event,
|
|
|
|
// sdlUserMouseEventID (above) is used to guard a generated motion event.
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_MOUSEMOTION:
|
|
|
|
{
|
2023-10-28 04:08:19 +00:00
|
|
|
if (focus && mouse._enableMotionEvents)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-10-28 04:08:19 +00:00
|
|
|
motion:
|
|
|
|
mouse.position = pixelPosToVirtualCoords(event.motion.x, event.motion.y);
|
|
|
|
mouse._wasMoved = true;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-04-05 03:20:01 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2,0,0)
|
2013-07-18 21:29:55 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_MOUSEWHEEL:
|
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
if (focus)
|
2013-07-18 21:29:55 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
if (event.wheel.y > 0)
|
|
|
|
mouse.scrollWheelChange = 1;
|
|
|
|
else if (event.wheel.y < 0)
|
|
|
|
mouse.scrollWheelChange = -1;
|
2013-07-18 21:29:55 +00:00
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-06-25 21:59:34 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_JOYDEVICEADDED:
|
|
|
|
onJoystickAdded(event.jdevice.which);
|
|
|
|
break;
|
2016-06-25 21:59:34 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_JOYDEVICEREMOVED:
|
|
|
|
onJoystickRemoved(event.jdevice.which);
|
|
|
|
break;
|
2016-06-25 21:59:34 +00:00
|
|
|
|
2016-11-14 02:13:34 +00:00
|
|
|
#else
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
if (focus)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
switch(event.button.button)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
case 4:
|
|
|
|
mouse.scrollWheelChange = 1;
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
2019-01-28 23:36:48 +00:00
|
|
|
case 5:
|
|
|
|
mouse.scrollWheelChange = -1;
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
if (focus)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
switch(event.button.button)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
case 4:
|
|
|
|
mouse.scrollWheelChange = 1;
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
2019-01-28 23:36:48 +00:00
|
|
|
case 5:
|
|
|
|
mouse.scrollWheelChange = -1;
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-11-14 02:13:34 +00:00
|
|
|
#endif
|
2019-01-28 23:36:48 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2019-01-28 23:36:48 +00:00
|
|
|
void Core::pollEvents(float dt)
|
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
int x, y;
|
|
|
|
unsigned mousestate = SDL_GetMouseState(&x,&y);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
if (mouse.buttonsEnabled)
|
2019-01-28 23:36:48 +00:00
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
mouse.buttons.left = mousestate & SDL_BUTTON(1)?DOWN:UP;
|
|
|
|
mouse.buttons.right = mousestate & SDL_BUTTON(3)?DOWN:UP;
|
|
|
|
mouse.buttons.middle = mousestate & SDL_BUTTON(2)?DOWN:UP;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
for(unsigned i = 0; i < mouseExtraButtons; ++i)
|
|
|
|
mouse.buttons.extra[i] = mousestate & SDL_BUTTON(3+i)?DOWN:UP;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
mouse.pure_buttons = mouse.buttons;
|
|
|
|
mouse.rawButtonMask = mousestate;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
if (flipMouseButtons)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
std::swap(mouse.buttons.left, mouse.buttons.right);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-24 12:16:25 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
mouse.buttons.left = mouse.buttons.right = mouse.buttons.middle = UP;
|
|
|
|
}
|
|
|
|
|
|
|
|
mouse.scrollWheelChange = 0;
|
|
|
|
mouse.lastPosition = mouse.position;
|
|
|
|
mouse.change = Vector(0, 0);
|
|
|
|
mouse._wasMoved = false;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
// This polls SDL events and causes Core::onEvent() to be called,
|
|
|
|
// which also updates mouse position etc
|
2019-01-28 23:36:48 +00:00
|
|
|
window->handleInput();
|
|
|
|
|
2022-08-24 12:16:25 +00:00
|
|
|
if(mouse._wasMoved)
|
2022-05-04 01:04:26 +00:00
|
|
|
{
|
2022-08-24 12:16:25 +00:00
|
|
|
if(doMouseConstraint())
|
2022-05-04 01:04:26 +00:00
|
|
|
setMousePosition(mouse.position);
|
|
|
|
mouse.change = mouse.position - mouse.lastPosition;
|
|
|
|
}
|
|
|
|
|
2016-07-18 21:14:20 +00:00
|
|
|
for(size_t i = 0; i < joysticks.size(); ++i)
|
|
|
|
if(joysticks[i])
|
|
|
|
joysticks[i]->update(dt);
|
|
|
|
|
|
|
|
// all input done; update button states
|
|
|
|
updateActionButtons();
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define _VLN(x, y, x2, y2) glVertex2f(x, y); glVertex2f(x2, y2);
|
|
|
|
|
|
|
|
void Core::print(int x, int y, const char *str, float sz)
|
|
|
|
{
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
glPushMatrix();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
float xx = x;
|
|
|
|
glTranslatef(x, y-0.5f*sz, 0);
|
|
|
|
x = y = 0;
|
2017-01-14 17:10:20 +00:00
|
|
|
xx = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
int c=0;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
glLineWidth(1);
|
|
|
|
glScalef(sz*0.75f, sz, 1);
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
|
|
|
|
while (str[c] != '\0')
|
|
|
|
{
|
|
|
|
switch(toupper(str[c]))
|
|
|
|
{
|
|
|
|
case '_':
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
_VLN(xx, y+0.5f, xx+0.25f, y+0.4f)
|
|
|
|
_VLN(xx+0.25f, y+0.4f, xx+0.75f, y+0.6f)
|
|
|
|
_VLN(xx+0.75f, y+0.6f, xx+1, y+0.5f)
|
|
|
|
break;
|
|
|
|
case 'A':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
_VLN(xx, y, xx+1, y+0.2f)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx+1, y+0.2f, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
break;
|
|
|
|
case 'G':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'I':
|
|
|
|
_VLN(xx+0.5f, y, xx+0.5f, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'J':
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx, y+0.75f)
|
|
|
|
break;
|
|
|
|
case 'K':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.25f, xx+1, y)
|
|
|
|
_VLN(xx, y+0.25f, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+0.5f, y+0.5f)
|
|
|
|
_VLN(xx+1, y, xx+0.5f, y+0.5f)
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y)
|
|
|
|
break;
|
|
|
|
case 'Q':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y+0.5f, xx+1.25f, y+1.25f)
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+0.5f)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+0.5f, y, xx+0.5f, y+1)
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
_VLN(xx, y, xx+0.5f, y+1)
|
|
|
|
_VLN(xx+1, y, xx+0.5f, y+1)
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
_VLN(xx, y, xx+0.25f, y+1)
|
|
|
|
_VLN(xx+0.25f, y+1, xx+0.5f, y+0.5f)
|
|
|
|
_VLN(xx+0.5f, y+0.5f, xx+0.75f, y+1)
|
|
|
|
_VLN(xx+1, y, xx+0.75f, y+1)
|
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
_VLN(xx, y, xx+1, y+1)
|
|
|
|
_VLN(xx+1, y, xx, y+1)
|
|
|
|
break;
|
|
|
|
case 'Y':
|
|
|
|
_VLN(xx, y, xx+0.5f, y+0.5f)
|
|
|
|
_VLN(xx+1, y, xx+0.5f, y+0.5f)
|
|
|
|
_VLN(xx+0.5f, y+0.5f, xx+0.5f, y+1)
|
|
|
|
break;
|
|
|
|
case 'Z':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y+1, xx+1, y)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '1':
|
|
|
|
_VLN(xx+0.5f, y, xx+0.5f, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx+0.5f, y, xx+0.25f, y+0.25f)
|
|
|
|
break;
|
|
|
|
case '2':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+1, y, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx, y+0.5f)
|
|
|
|
_VLN(xx, y+0.5f, xx, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '3':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '4':
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx+1, y, xx, y+0.5f)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
break;
|
|
|
|
case '5':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y+0.5f, xx, y+0.5f)
|
|
|
|
_VLN(xx+1, y+0.5f, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '7':
|
|
|
|
_VLN(xx+1, y, xx+0.5f, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
break;
|
|
|
|
case '8':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '9':
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y+0.5f, xx+1, y+0.5f)
|
|
|
|
_VLN(xx, y+0.5f, xx, y)
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
_VLN(xx, y, xx, y+1)
|
|
|
|
_VLN(xx+1, y, xx+1, y+1)
|
|
|
|
_VLN(xx, y+1, xx+1, y+1)
|
|
|
|
_VLN(xx, y, xx+1, y)
|
|
|
|
_VLN(xx, y, xx+1, y+1)
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
_VLN(xx+0.4f, y+1, xx+0.6f, y+1)
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
_VLN(xx+0.5f, y+0.75f, xx+0.5f, y+1.0f);
|
|
|
|
_VLN(xx+0.5f, y+1.0f, xx+0.2f, y+1.25f);
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
break;
|
|
|
|
case '(':
|
|
|
|
case '[':
|
|
|
|
_VLN(xx, y, xx, y+1);
|
|
|
|
_VLN(xx, y, xx+0.25f, y);
|
|
|
|
_VLN(xx, y+1, xx+0.25f, y+1);
|
|
|
|
break;
|
|
|
|
case ')':
|
|
|
|
case ']':
|
|
|
|
_VLN(xx+1, y, xx+1, y+1);
|
|
|
|
_VLN(xx+1, y, xx+0.75f, y);
|
|
|
|
_VLN(xx+1, y+1, xx+0.75f, y+1);
|
|
|
|
break;
|
|
|
|
case ':':
|
|
|
|
_VLN(xx+0.5f, y, xx+0.5f, y+0.25f);
|
|
|
|
_VLN(xx+0.5f, y+0.75f, xx+0.5f, y+1);
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
_VLN(xx, y+1, xx+1, y);
|
|
|
|
break;
|
|
|
|
default:
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
c++;
|
|
|
|
xx += 1.4f;
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::cacheRender()
|
|
|
|
{
|
|
|
|
render();
|
|
|
|
// what if the screen was full white? then you wouldn't want to clear buffers
|
|
|
|
//clearBuffers();
|
|
|
|
showBuffer();
|
|
|
|
resetTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::updateCullData()
|
|
|
|
{
|
2014-03-07 16:59:36 +00:00
|
|
|
cullRadius = baseCullRadius * invGlobalScale;
|
|
|
|
cullRadiusSqr = cullRadius * cullRadius;
|
|
|
|
screenCenter = cullCenter = cameraPos + Vector(400.0f*invGlobalScale,300.0f*invGlobalScale);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::render(int startLayer, int endLayer, bool useFrameBufferIfAvail)
|
|
|
|
{
|
2022-05-22 05:38:23 +00:00
|
|
|
renderObjectCount = 0;
|
|
|
|
processedRenderObjectCount = 0;
|
|
|
|
totalRenderObjectCount = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2014-03-07 16:59:36 +00:00
|
|
|
globalScaleChanged();
|
|
|
|
|
2023-05-31 15:40:41 +00:00
|
|
|
if (minimized) return;
|
2011-08-03 20:05:33 +00:00
|
|
|
onRender();
|
|
|
|
|
|
|
|
RenderObject::lastTextureApplied = 0;
|
|
|
|
|
|
|
|
updateCullData();
|
|
|
|
|
2022-05-22 05:38:23 +00:00
|
|
|
// TODO: this could be done in parallel
|
|
|
|
for (size_t i = 0; i < renderObjectLayers.size(); ++i)
|
|
|
|
{
|
|
|
|
if(renderObjectLayers[i].visible)
|
|
|
|
renderObjectLayers[i].prepareRender();
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glLoadIdentity(); // Reset The View
|
|
|
|
clearBuffers();
|
|
|
|
|
|
|
|
if (afterEffectManager && frameBuffer.isInited() && useFrameBufferIfAvail)
|
|
|
|
{
|
|
|
|
frameBuffer.startCapture();
|
|
|
|
}
|
|
|
|
|
|
|
|
setupRenderPositionAndScale();
|
|
|
|
|
|
|
|
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t c = 0; c < renderObjectLayerOrder.size(); c++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
int i = renderObjectLayerOrder[c];
|
|
|
|
if (i == -1) continue;
|
|
|
|
if ((startLayer != -1 && endLayer != -1) && (i < startLayer || i > endLayer)) continue;
|
|
|
|
|
|
|
|
if (darkLayer.isUsed() )
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (i == darkLayer.getRenderLayer())
|
|
|
|
{
|
|
|
|
darkLayer.render();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == darkLayer.getLayer() && startLayer != i)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-15 01:00:20 +00:00
|
|
|
if (afterEffectManager && afterEffectManager->active && i == afterEffectManagerLayer)
|
|
|
|
{
|
|
|
|
afterEffectManager->render();
|
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
RenderObjectLayer *r = &renderObjectLayers[i];
|
2022-05-22 05:38:23 +00:00
|
|
|
if(!r->visible)
|
|
|
|
continue;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2022-05-22 05:38:23 +00:00
|
|
|
r->render();
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::showBuffer()
|
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
window->present();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownInputLibrary()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownJoystickLibrary()
|
|
|
|
{
|
|
|
|
if (joystickEnabled) {
|
2016-07-03 16:07:13 +00:00
|
|
|
clearJoysticks();
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
|
|
joystickEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::clearRenderObjects()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < renderObjectLayers.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
RenderObject *r = renderObjectLayers[i].getFirst();
|
|
|
|
while (r)
|
|
|
|
{
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
removeRenderObject(r, DESTROY_RENDER_OBJECT);
|
|
|
|
}
|
|
|
|
r = renderObjectLayers[i].getNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdown()
|
|
|
|
{
|
|
|
|
// pop all the states
|
|
|
|
|
|
|
|
|
|
|
|
debugLog("Core::shutdown");
|
|
|
|
shuttingDown = true;
|
|
|
|
|
|
|
|
debugLog("Shutdown Joystick Library...");
|
|
|
|
shutdownJoystickLibrary();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Shutdown Input Library...");
|
|
|
|
shutdownInputLibrary();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Shutdown All States...");
|
|
|
|
popAllStates();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Clear State Instances...");
|
|
|
|
clearStateInstances();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Clear All Remaining RenderObjects...");
|
|
|
|
clearRenderObjects();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Clear All Resources...");
|
2023-06-23 12:27:41 +00:00
|
|
|
texmgr.unloadAll();
|
2011-08-03 20:05:33 +00:00
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
|
|
|
|
debugLog("Clear State Objects...");
|
|
|
|
clearStateObjects();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
if (afterEffectManager)
|
|
|
|
{
|
|
|
|
debugLog("Delete AEManager...");
|
|
|
|
delete afterEffectManager;
|
|
|
|
afterEffectManager = 0;
|
|
|
|
debugLog("OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (sound)
|
|
|
|
{
|
|
|
|
debugLog("Shutdown Sound Library...");
|
|
|
|
sound->stopAll();
|
|
|
|
delete sound;
|
|
|
|
sound = 0;
|
|
|
|
debugLog("OK");
|
|
|
|
}
|
|
|
|
|
2017-02-08 21:11:55 +00:00
|
|
|
debugLog("Dark layer...");
|
|
|
|
darkLayer.unloadDevice();
|
|
|
|
debugLog("OK");
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
debugLog("Core's framebuffer...");
|
|
|
|
frameBuffer.unloadDevice();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
debugLog("Shutdown Graphics Library...");
|
|
|
|
shutdownGraphicsLibrary();
|
|
|
|
debugLog("OK");
|
|
|
|
|
|
|
|
|
|
|
|
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
#ifdef BBGE_BUILD_VFS
|
|
|
|
debugLog("Unload VFS...");
|
|
|
|
vfs.Clear();
|
|
|
|
debugLog("OK");
|
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
debugLog("SDL Quit...");
|
|
|
|
SDL_Quit();
|
|
|
|
debugLog("OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
//util funcs
|
|
|
|
|
2023-05-30 22:55:16 +00:00
|
|
|
CountedPtr<Texture> Core::getTexture(const std::string &name)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-30 22:55:16 +00:00
|
|
|
return texmgr.getOrLoad(name);
|
2015-03-23 23:06:51 +00:00
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2023-05-25 14:58:08 +00:00
|
|
|
void Core::addRenderObject(RenderObject *o, unsigned layer)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-25 14:58:08 +00:00
|
|
|
assert(o->layer == LR_NONE);
|
|
|
|
assert(layer < renderObjectLayers.size());
|
2011-08-03 20:05:33 +00:00
|
|
|
o->layer = layer;
|
|
|
|
renderObjectLayers[layer].add(o);
|
|
|
|
}
|
|
|
|
|
2023-05-25 14:58:08 +00:00
|
|
|
void Core::switchRenderObjectLayer(RenderObject *o, unsigned toLayer)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-25 14:58:08 +00:00
|
|
|
assert(o->layer != LR_NONE);
|
|
|
|
assert(toLayer < renderObjectLayers.size());
|
2011-08-03 20:05:33 +00:00
|
|
|
renderObjectLayers[o->layer].remove(o);
|
|
|
|
renderObjectLayers[toLayer].add(o);
|
|
|
|
o->layer = toLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::unloadResources()
|
|
|
|
{
|
2023-06-23 12:27:41 +00:00
|
|
|
this->texmgr.unloadAll();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::onReloadResources()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::reloadResources()
|
|
|
|
{
|
2023-06-23 12:27:41 +00:00
|
|
|
this->texmgr.reloadAll(TextureMgr::OVERWRITE);
|
|
|
|
this->onReloadResources();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2023-05-30 22:55:16 +00:00
|
|
|
const std::string & Core::getBaseTexturePath() const
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-30 22:55:16 +00:00
|
|
|
return texmgr.loadFromPaths.back();
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2023-05-30 22:55:16 +00:00
|
|
|
void Core::setExtraTexturePath(const char * dir)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-30 22:55:16 +00:00
|
|
|
texmgr.loadFromPaths.resize(size_t(1) + !!dir);
|
|
|
|
size_t w = 0;
|
|
|
|
if(dir)
|
|
|
|
texmgr.loadFromPaths[w++] = dir;
|
|
|
|
texmgr.loadFromPaths[w] = "gfx/";
|
|
|
|
}
|
2015-03-23 23:06:51 +00:00
|
|
|
|
2023-05-30 22:55:16 +00:00
|
|
|
const char *Core::getExtraTexturePath() const
|
|
|
|
{
|
|
|
|
return texmgr.loadFromPaths.size() > 1 ? texmgr.loadFromPaths[0].c_str() : NULL;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::removeRenderObject(RenderObject *r, RemoveRenderObjectFlag flag)
|
|
|
|
{
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
if (r->layer != LR_NONE && !renderObjectLayers[r->layer].empty())
|
|
|
|
{
|
|
|
|
renderObjectLayers[r->layer].remove(r);
|
|
|
|
}
|
|
|
|
if (flag != DO_NOT_DESTROY_RENDER_OBJECT )
|
|
|
|
{
|
|
|
|
r->destroy();
|
2019-01-28 23:36:48 +00:00
|
|
|
delete r;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::enqueueRenderObjectDeletion(RenderObject *object)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
if (!object->_dead)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
garbage.push_back (object);
|
|
|
|
object->_dead = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::clearGarbage()
|
|
|
|
{
|
|
|
|
// HACK: optimize this (use a list instead of a queue)
|
|
|
|
|
2016-06-25 22:39:48 +00:00
|
|
|
for (RenderObjects::iterator i = garbage.begin(); i != garbage.end(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
removeRenderObject(*i, DO_NOT_DESTROY_RENDER_OBJECT);
|
|
|
|
|
|
|
|
(*i)->destroy();
|
|
|
|
}
|
|
|
|
|
2016-06-25 22:39:48 +00:00
|
|
|
for (RenderObjects::iterator i = garbage.begin(); i != garbage.end(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2019-01-28 23:36:48 +00:00
|
|
|
delete *i;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
garbage.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::canChangeState()
|
|
|
|
{
|
|
|
|
return (nestedMains<=1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Take a screenshot of the specified region of the screen and store it
|
|
|
|
// in a 32bpp pixel buffer. delete[] the returned buffer when it's no
|
|
|
|
// longer needed.
|
2022-04-29 08:26:25 +00:00
|
|
|
unsigned char *Core::grabScreenshot(size_t x, size_t y, size_t w, size_t h)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-29 08:26:25 +00:00
|
|
|
const size_t N = w * h;
|
|
|
|
const size_t size = sizeof(unsigned char) * N * 4;
|
|
|
|
unsigned char * const imageData = new unsigned char[size];
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_FOG);
|
|
|
|
glDisable(GL_LIGHTING); glDisable(GL_LOGIC_OP);
|
|
|
|
glDisable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_1D);
|
|
|
|
glDisable(GL_TEXTURE_2D); glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
|
|
|
|
glPixelTransferi(GL_RED_SCALE, 1); glPixelTransferi(GL_RED_BIAS, 0);
|
|
|
|
glPixelTransferi(GL_GREEN_SCALE, 1); glPixelTransferi(GL_GREEN_BIAS, 0);
|
|
|
|
glPixelTransferi(GL_BLUE_SCALE, 1); glPixelTransferi(GL_BLUE_BIAS, 0);
|
|
|
|
glPixelTransferi(GL_ALPHA_SCALE, 1); glPixelTransferi(GL_ALPHA_BIAS, 0);
|
|
|
|
glRasterPos2i(0, 0);
|
|
|
|
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)imageData);
|
|
|
|
glPopAttrib();
|
|
|
|
|
|
|
|
// Force all alpha values to 255.
|
|
|
|
unsigned char *c = imageData;
|
2022-04-29 08:26:25 +00:00
|
|
|
for (size_t i = 0; i < N; ++i, c += 4)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-29 08:26:25 +00:00
|
|
|
c[3] = 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenGL outputs the image upside down -> flip pixel rows
|
|
|
|
const ptrdiff_t rowOffs = 4 * w;
|
|
|
|
unsigned char * row0 = imageData;
|
|
|
|
unsigned char * row1 = imageData + size - rowOffs;
|
|
|
|
while(row0 < row1)
|
|
|
|
{
|
|
|
|
std::swap_ranges(row0, row0 + rowOffs, row1);
|
|
|
|
row0 += rowOffs;
|
|
|
|
row1 -= rowOffs;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return imageData;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Like grabScreenshot(), but grab from the center of the screen.
|
2022-04-29 08:26:25 +00:00
|
|
|
unsigned char *Core::grabCenteredScreenshot(size_t w, size_t h)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2023-05-31 15:40:41 +00:00
|
|
|
return grabScreenshot(width/2 - w/2, height/2 - h/2, w, h);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-09-25 23:54:45 +00:00
|
|
|
// takes a screen shot and saves it to a TGA or PNG image
|
2016-09-26 01:44:15 +00:00
|
|
|
bool Core::saveScreenshot(const std::string &filename, bool png)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2022-04-29 08:26:25 +00:00
|
|
|
size_t w = getWindowWidth(), h = getWindowHeight();
|
2011-08-03 20:05:33 +00:00
|
|
|
unsigned char *imageData = grabCenteredScreenshot(w, h);
|
2016-09-26 01:44:15 +00:00
|
|
|
bool ok = png
|
2022-04-29 08:34:10 +00:00
|
|
|
? pngSaveRGBA(filename.c_str(), w, h, imageData, 3)
|
2022-03-31 19:03:40 +00:00
|
|
|
: tgaSaveRGBA(filename.c_str(), w, h, imageData);
|
2016-09-26 01:44:15 +00:00
|
|
|
delete [] imageData;
|
|
|
|
return ok;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-07-14 03:01:30 +00:00
|
|
|
void Core::screenshot()
|
|
|
|
{
|
|
|
|
doScreenshot = true;
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
#ifdef BBGE_BUILD_VFS
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
#include "ttvfs_zip/VFSZipArchiveLoader.h"
|
2016-07-09 02:18:40 +00:00
|
|
|
#include "ttvfs.h"
|
|
|
|
#include "ttvfs_stdio.h"
|
|
|
|
#endif
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
|
|
|
|
void Core::setupFileAccess()
|
|
|
|
{
|
|
|
|
#ifdef BBGE_BUILD_VFS
|
|
|
|
debugLog("Init VFS...");
|
|
|
|
|
|
|
|
if(!ttvfs::checkCompat())
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error("ttvfs not compatible");
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
|
2014-04-07 00:10:05 +00:00
|
|
|
ttvfs_setroot(&vfs);
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
|
2014-04-07 00:10:05 +00:00
|
|
|
vfs.AddLoader(new ttvfs::DiskLoader);
|
|
|
|
vfs.AddArchiveLoader(new ttvfs::VFSZipArchiveLoader);
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
|
2014-04-07 00:10:05 +00:00
|
|
|
vfs.Mount("override", "");
|
2013-06-19 16:44:24 +00:00
|
|
|
|
|
|
|
// If we ever want to read from a container...
|
2014-04-07 00:10:05 +00:00
|
|
|
//vfs.AddArchive("aqfiles.zip");
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
|
2013-06-19 00:08:24 +00:00
|
|
|
if(_extraDataDir.length())
|
2013-06-19 16:45:19 +00:00
|
|
|
{
|
|
|
|
debugLog("Mounting extra data dir: " + _extraDataDir);
|
2014-04-07 00:10:05 +00:00
|
|
|
vfs.Mount(_extraDataDir.c_str(), "");
|
2013-06-19 16:45:19 +00:00
|
|
|
}
|
2013-06-19 00:08:24 +00:00
|
|
|
|
[vfs, #3] All file reading code goes through the VFS now, new mod downloader & mod selector in place. Also a bunch of other stuff. (...)
- HTTP networking support, mods can be downloaded via the builtin downloader.
All network activity runs in a seperate thread, which is started
as soon as any network activity is requested.
- The master server is hard-coded to fg.wzff.de/aqmods/ if not specified otherwise;
this setting can be overridden in the config file.
- The mod selector screen is now a grid-view for much better navigation;
also works with joystick.
- VFS code is functionally similar to the old molebox-packed release
for win32. The game could also have its data shipped in a Zip file
or any other kind of archive.
- It is still possible to build without VFS support, but then the mod
downloader and soft-patching will not be available.
The full commit history can be found here:
https://github.com/fgenesis/Aquaria_clean/compare/master...vfs
The most important commit messages follow:
[...]
This replaces all std::ifstream with InStream, and fopen(), ... with vfopen(), ...
Some code is #ifdef'd for better performance and less memory-copying.
VFILE is defined to whatever type of file is in use:
- FILE if BBGE_BUILD_VFS is not defined
- tttvfs::VFSFile if it is.
Other changes:
- [un]packFile() is now unused and obsolete. That code has not been adjusted to use VFILE.
- glpng can now load from a memory buffer.
- TinyXML uses the VFS for reading operations now.
- The rather clunky binary stream loading of glfont2 got replaced with ByteBuffer,
which gets its data in one block (necessary to use the VFS without implementing
a somewhat STL-compliant std::ifstream replacement.)
-------------
Implement loading mods from zip files.
-------------
Implement soft-patching game data files. (Replacing textures/audio/... on the fly)
-------------
Misc bits:
- Extended GUI focus handling a bit
- Fixed weirdness in texture loading... not sure but this seems more correct to me.
Actually, considering that the texture will have its native size after restarting the game,
the lines removed with this commit seem pretty useless.
2012-06-01 15:52:19 +00:00
|
|
|
debugLog("Done");
|
|
|
|
#endif
|
|
|
|
}
|
2013-11-14 16:58:33 +00:00
|
|
|
|
|
|
|
void Core::initLocalization()
|
|
|
|
{
|
|
|
|
InStream in(localisePath("data/localecase.txt"));
|
|
|
|
if(!in)
|
|
|
|
{
|
|
|
|
debugLog("data/localecase.txt does not exist, using internal locale data");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string low, up;
|
2016-07-09 02:18:40 +00:00
|
|
|
CharTranslationTable trans;
|
|
|
|
memset(&trans[0], -1, sizeof(trans));
|
2013-11-14 16:58:33 +00:00
|
|
|
while(in)
|
|
|
|
{
|
|
|
|
in >> low >> up;
|
2022-04-07 00:38:39 +00:00
|
|
|
|
2016-07-18 01:21:24 +00:00
|
|
|
trans[(unsigned char)(low[0])] = (unsigned char)up[0];
|
2013-11-14 16:58:33 +00:00
|
|
|
}
|
2016-07-09 02:18:40 +00:00
|
|
|
initCharTranslationTables(&trans);
|
2013-11-14 16:58:33 +00:00
|
|
|
}
|
|
|
|
|
2016-06-25 21:59:34 +00:00
|
|
|
void Core::onJoystickAdded(int deviceID)
|
|
|
|
{
|
2016-06-30 00:58:55 +00:00
|
|
|
debugLog("Add new joystick");
|
|
|
|
Joystick *j = new Joystick;
|
|
|
|
j->init(deviceID);
|
|
|
|
for(size_t i = 0; i < joysticks.size(); ++i)
|
|
|
|
if(!joysticks[i])
|
|
|
|
{
|
|
|
|
joysticks[i] = j;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
joysticks.push_back(j);
|
|
|
|
done:
|
2016-07-17 03:54:09 +00:00
|
|
|
;
|
2016-06-25 21:59:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::onJoystickRemoved(int instanceID)
|
|
|
|
{
|
2016-07-03 13:48:40 +00:00
|
|
|
debugLog("Joystick removed");
|
2016-06-30 00:58:55 +00:00
|
|
|
for(size_t i = 0; i < joysticks.size(); ++i)
|
2016-07-17 03:54:09 +00:00
|
|
|
if(Joystick *j = joysticks[i])
|
|
|
|
if(j->getInstanceID() == instanceID)
|
|
|
|
{
|
|
|
|
delete j;
|
|
|
|
joysticks[i] = NULL;
|
|
|
|
}
|
2016-06-25 21:59:34 +00:00
|
|
|
}
|
2016-07-15 01:22:27 +00:00
|
|
|
|
2017-01-20 03:51:38 +00:00
|
|
|
Joystick *Core::getJoystick(size_t idx)
|
2016-07-15 01:22:27 +00:00
|
|
|
{
|
|
|
|
size_t i = idx;
|
|
|
|
return i < joysticks.size() ? joysticks[i] : NULL;
|
|
|
|
}
|
2016-07-17 20:25:24 +00:00
|
|
|
|
|
|
|
void Core::updateActionButtons()
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < actionStatus.size(); ++i)
|
|
|
|
actionStatus[i]->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::clearActionButtons()
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < actionStatus.size(); ++i)
|
|
|
|
delete actionStatus[i];
|
|
|
|
actionStatus.clear();
|
|
|
|
}
|
|
|
|
|
2016-08-07 03:20:04 +00:00
|
|
|
Joystick *Core::getJoystickForSourceID(int sourceID)
|
2016-07-17 20:25:24 +00:00
|
|
|
{
|
2016-08-07 03:20:04 +00:00
|
|
|
if(unsigned(sourceID+1) < (unsigned)actionStatus.size())
|
|
|
|
return getJoystick(actionStatus[sourceID+1]->getJoystickID());
|
2016-07-17 20:25:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|