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"
|
|
|
|
#include "AfterEffect.h"
|
|
|
|
#include "Particles.h"
|
|
|
|
|
|
|
|
#include <time.h>
|
2011-08-11 00:26:46 +00:00
|
|
|
#include <iostream>
|
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
|
|
|
|
#include <shlobj.h>
|
2013-06-19 00:08:24 +00:00
|
|
|
#include <direct.h>
|
2011-11-20 22:47:24 +00:00
|
|
|
#endif
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
#include "SDL_syswm.h"
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
static SDL_Window *gScreen=0;
|
|
|
|
static SDL_GLContext gGLctx=0;
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
static SDL_Surface *gScreen=0;
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
bool ignoreNextMouse=false;
|
|
|
|
Vector unchange;
|
|
|
|
|
2014-04-15 17:48:06 +00:00
|
|
|
#ifdef BBGE_BUILD_VFS
|
|
|
|
#include "ttvfs.h"
|
|
|
|
#endif
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
Core *core = 0;
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
HICON icon_windows = 0;
|
|
|
|
#endif
|
|
|
|
|
2013-12-12 10:34:15 +00:00
|
|
|
#ifndef KMOD_GUI
|
|
|
|
#define KMOD_GUI KMOD_META
|
|
|
|
#endif
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
void Core::initIcon()
|
|
|
|
{
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
HINSTANCE handle = ::GetModuleHandle(NULL);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
icon_windows = ::LoadIcon(handle, "icon");
|
|
|
|
|
|
|
|
SDL_SysWMinfo wminfo;
|
|
|
|
SDL_VERSION(&wminfo.version)
|
2013-07-18 21:29:55 +00:00
|
|
|
if (SDL_GetWindowWMInfo(gScreen, &wminfo) != 1)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
HWND hwnd = wminfo.info.win.window;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
::SetClassLong(hwnd, GCL_HICON, (LONG) icon_windows);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
core->getTopStateData()->addRenderObject(e, layer);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::resetGraphics(int w, int h, int fullscreen, int vsync, int bpp)
|
|
|
|
{
|
|
|
|
if (fullscreen == -1)
|
|
|
|
fullscreen = _fullscreen;
|
|
|
|
|
|
|
|
if (vsync == -1)
|
|
|
|
vsync = _vsync;
|
|
|
|
|
|
|
|
if (w == -1)
|
|
|
|
w = width;
|
|
|
|
|
|
|
|
if (h == -1)
|
|
|
|
h = height;
|
|
|
|
|
|
|
|
if (bpp == -1)
|
|
|
|
bpp = _bpp;
|
|
|
|
|
|
|
|
unloadDevice();
|
|
|
|
unloadResources();
|
|
|
|
|
|
|
|
shutdownGraphicsLibrary();
|
|
|
|
|
|
|
|
initGraphicsLibrary(w, h, fullscreen, vsync, bpp);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2012-02-19 03:57:04 +00:00
|
|
|
enable2DWide(w, h);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
reloadResources();
|
|
|
|
reloadDevice();
|
|
|
|
|
|
|
|
|
|
|
|
resetTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::toggleScreenMode(int t)
|
|
|
|
{
|
|
|
|
sound->pause();
|
|
|
|
resetGraphics(-1, -1, t);
|
|
|
|
cacheRender();
|
|
|
|
resetTimer();
|
|
|
|
sound->resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::updateCursorFromJoystick(float dt, int spd)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
core->mouse.position += joystick.position*dt*spd;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
doMouseConstraint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setWindowCaption(const std::string &caption, const std::string &icon)
|
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifndef BBGE_BUILD_SDL2
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_WM_SetCaption(caption.c_str(), icon.c_str());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
RenderObjectLayer *Core::getRenderObjectLayer(int i)
|
|
|
|
{
|
|
|
|
if (i == LR_NONE)
|
|
|
|
return 0;
|
|
|
|
return &renderObjectLayers[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Core::setColor(float r, float g, float b, float a)
|
|
|
|
{
|
|
|
|
glColor4f(r, g, b, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::bindTexture(int stage, unsigned int handle)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::translateMatrixStack(float x, float y, float z)
|
|
|
|
{
|
|
|
|
glTranslatef(x, y, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::scaleMatrixStack(float x, float y, float z)
|
|
|
|
{
|
|
|
|
glScalef(x, y, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::rotateMatrixStack(float x, float y, float z)
|
|
|
|
{
|
|
|
|
glRotatef(0, 0, 1, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::applyMatrixStackToWorld()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::rotateMatrixStack(float z)
|
|
|
|
{
|
|
|
|
glRotatef(0, 0, 1, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::getMetaState()
|
|
|
|
{
|
|
|
|
return getKeyState(KEY_LMETA) || getKeyState(KEY_RMETA);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::errorLog(const std::string &s)
|
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
messageBox("Error!", s);
|
2011-08-03 20:05:33 +00:00
|
|
|
debugLog(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void Core::debugLog(const std::string &s)
|
|
|
|
{
|
|
|
|
if (debugLogActive)
|
|
|
|
{
|
2011-08-11 00:26:46 +00:00
|
|
|
_logOut << s << std::endl;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2011-08-11 00:26:46 +00:00
|
|
|
#ifdef _DEBUG
|
|
|
|
std::cout << s << std::endl;
|
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2011-11-20 22:47:24 +00:00
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
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.";
|
|
|
|
MessageBoxA(NULL, os.str().c_str(), "Need to write but can't!", MB_OK | MB_ICONERROR);
|
|
|
|
}
|
|
|
|
if(critical)
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return writeable;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2011-08-11 00:26:46 +00:00
|
|
|
sound = NULL;
|
2011-08-03 20:05:33 +00:00
|
|
|
screenCapScale = Vector(1,1,1);
|
2013-06-19 00:08:24 +00:00
|
|
|
_extraDataDir = extraDataDir;
|
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;
|
|
|
|
|
|
|
|
debugLogTextures = true;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
grabInputOnReentry = -1;
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
aspectX = 4;
|
|
|
|
aspectY = 3;
|
|
|
|
|
|
|
|
virtualOffX = virtualOffY = 0;
|
|
|
|
vw2 = 0;
|
|
|
|
vh2 = 0;
|
|
|
|
|
|
|
|
viewOffX = viewOffY = 0;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
particleManager = new ParticleManager(particleSize);
|
|
|
|
nowTicks = thenTicks = 0;
|
|
|
|
_hasFocus = false;
|
|
|
|
lib_graphics = lib_sound = lib_input = false;
|
|
|
|
clearColor = Vector(0,0,0);
|
|
|
|
updateCursorFromMouse = true;
|
|
|
|
mouseConstraint = false;
|
|
|
|
mouseCircle = 0;
|
|
|
|
overrideStartLayer = 0;
|
|
|
|
overrideEndLayer = 0;
|
|
|
|
coreVerboseDebug = false;
|
|
|
|
frameOutputMode = false;
|
|
|
|
updateMouse = true;
|
|
|
|
particlesPaused = false;
|
|
|
|
joystickAsMouse = false;
|
|
|
|
currentLayerPass = 0;
|
|
|
|
flipMouseButtons = 0;
|
|
|
|
joystickOverrideMouse = false;
|
|
|
|
joystickEnabled = false;
|
|
|
|
doScreenshot = false;
|
|
|
|
baseCullRadius = 1;
|
|
|
|
width = height = 0;
|
|
|
|
afterEffectManagerLayer = 0;
|
|
|
|
renderObjectLayers.resize(1);
|
|
|
|
invGlobalScale = 1.0;
|
|
|
|
invGlobalScaleSqr = 1.0;
|
|
|
|
renderObjectCount = 0;
|
|
|
|
avgFPS.resize(1);
|
|
|
|
minimized = false;
|
|
|
|
numSavedScreenshots = 0;
|
|
|
|
shuttingDown = false;
|
|
|
|
clearedGarbageFlag = false;
|
|
|
|
nestedMains = 0;
|
|
|
|
afterEffectManager = 0;
|
|
|
|
loopDone = false;
|
|
|
|
core = this;
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
hRC = 0;
|
|
|
|
hDC = 0;
|
|
|
|
hWnd = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
|
|
{
|
|
|
|
keys[i] = 0;
|
|
|
|
}
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
aspect = (aspectX/aspectY);
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
globalResolutionScale = globalScale = Vector(1,1,1);
|
|
|
|
|
|
|
|
initRenderObjectLayers(numRenderLayers);
|
|
|
|
|
|
|
|
initPlatform(filesystem);
|
|
|
|
}
|
|
|
|
|
|
|
|
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!
|
|
|
|
debugLog("CFURLGetFileSystemRepresentation");
|
|
|
|
}
|
|
|
|
CFRelease(resourcesURL);
|
|
|
|
debugLog(path);
|
|
|
|
chdir(path);
|
|
|
|
#elif defined(BBGE_BUILD_UNIX)
|
|
|
|
if (!filesystem.empty())
|
|
|
|
{
|
|
|
|
if (chdir(filesystem.c_str()) == 0)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
debugLog("Failed to chdir to filesystem path " + filesystem);
|
|
|
|
}
|
|
|
|
#ifdef BBGE_DATA_PREFIX
|
|
|
|
if (chdir(BBGE_DATA_PREFIX) == 0 && chdir(appName.c_str()) == 0)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
debugLog("Failed to chdir to filesystem path " BBGE_DATA_PREFIX + appName);
|
|
|
|
#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!
|
|
|
|
debugLog("readlink");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
path[rc] = '\0';
|
|
|
|
char *ptr = strrchr(path, '/');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
|
|
|
debugLog(path);
|
|
|
|
if (chdir(path) != 0)
|
|
|
|
debugLog("Failed to chdir to executable path" + std::string(path));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
2013-06-19 00:08:24 +00:00
|
|
|
if(filesystem.length())
|
|
|
|
{
|
|
|
|
if(_chdir(filesystem.c_str()) != 0)
|
|
|
|
{
|
|
|
|
debugLog("chdir failed: " + filesystem);
|
|
|
|
}
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BBGE_BUILD_UNIX
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
// based on code I wrote for PhysicsFS: http://icculus.org/physfs/
|
|
|
|
// the zlib license on physfs allows this cut-and-pasting.
|
|
|
|
static int locateOneElement(char *buf)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
DIR *dirp;
|
|
|
|
|
|
|
|
if (access(buf, F_OK) == 0)
|
|
|
|
return(1); // quick rejection: exists in current case.
|
|
|
|
|
|
|
|
ptr = strrchr(buf, '/'); // find entry at end of path.
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
dirp = opendir(".");
|
|
|
|
ptr = buf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ptr = '\0';
|
|
|
|
dirp = opendir(buf);
|
|
|
|
*ptr = '/';
|
|
|
|
ptr++; // point past dirsep to entry itself.
|
|
|
|
}
|
|
|
|
|
|
|
|
struct dirent *dent;
|
|
|
|
while ((dent = readdir(dirp)) != NULL)
|
|
|
|
{
|
|
|
|
if (strcasecmp(dent->d_name, ptr) == 0)
|
|
|
|
{
|
|
|
|
strcpy(ptr, dent->d_name); // found a match. Overwrite with this case.
|
|
|
|
closedir(dirp);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no match at all...
|
|
|
|
closedir(dirp);
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
std::string Core::adjustFilenameCase(const char *_buf)
|
|
|
|
{
|
|
|
|
#ifdef BBGE_BUILD_UNIX // any case is fine if not Linux.
|
|
|
|
int rc = 1;
|
|
|
|
char *buf = (char *) alloca(strlen(_buf) + 1);
|
|
|
|
strcpy(buf, _buf);
|
|
|
|
|
|
|
|
char *ptr = buf;
|
|
|
|
while ((ptr = strchr(ptr + 1, '/')) != 0)
|
|
|
|
{
|
|
|
|
*ptr = '\0'; // block this path section off
|
|
|
|
rc = locateOneElement(buf);
|
|
|
|
*ptr = '/'; // restore path separator
|
|
|
|
if (!rc)
|
|
|
|
break; // missing element in path.
|
|
|
|
}
|
|
|
|
|
|
|
|
// check final element...
|
|
|
|
if (rc)
|
|
|
|
rc = locateOneElement(buf);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (strcmp(_buf, buf) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Corrected filename case: '%s' => '%s (%s)'\n",
|
2017-01-12 21:51:46 +00:00
|
|
|
_buf, buf, rc ? "found" : "not found");
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return std::string(buf);
|
|
|
|
#else
|
|
|
|
return std::string(_buf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Core::~Core()
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::hasFocus()
|
|
|
|
{
|
|
|
|
return _hasFocus;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setInputGrab(bool on)
|
|
|
|
{
|
|
|
|
if (isWindowFocus())
|
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_SetWindowGrab(gScreen, on ? SDL_TRUE : SDL_FALSE);
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_WM_GrabInput(on?SDL_GRAB_ON:SDL_GRAB_OFF);
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setReentryInputGrab(int on)
|
|
|
|
{
|
|
|
|
if (grabInputOnReentry == -1)
|
|
|
|
{
|
|
|
|
setInputGrab(on);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setInputGrab(grabInputOnReentry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::isFullscreen()
|
|
|
|
{
|
|
|
|
return _fullscreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
quitNestedMainFlag = false;
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifndef BBGE_BUILD_SDL2
|
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
|
|
|
|
|
|
|
if((SDL_Init(0))==-1)
|
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error("Failed to init SDL");
|
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;
|
|
|
|
clearedGarbageFlag = false;
|
|
|
|
|
|
|
|
initInputCodeMap();
|
|
|
|
|
2013-11-14 16:58:33 +00:00
|
|
|
initLocalization();
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (k >= KEY_MAXARRAY || k < 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return keys[k];
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
if (k >= KEY_MAXARRAY || k < 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return keys[k];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vector joychange;
|
|
|
|
Vector lastjoy;
|
|
|
|
void readJoystickData()
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void readMouseData()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void readKeyData()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool Core::initJoystickLibrary(int numSticks)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER);
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (numSticks > 0)
|
|
|
|
joystick.init(0);
|
|
|
|
|
|
|
|
joystickEnabled = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::initInputLibrary()
|
|
|
|
{
|
|
|
|
core->mouse.position = Vector(getWindowWidth()/2, getWindowHeight()/2);
|
|
|
|
|
|
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
|
|
{
|
|
|
|
keys[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::onUpdate(float dt)
|
|
|
|
{
|
|
|
|
if (minimized) return;
|
|
|
|
ActionMapper::onUpdate(dt);
|
|
|
|
StateManager::onUpdate(dt);
|
|
|
|
|
|
|
|
|
|
|
|
core->mouse.lastPosition = core->mouse.position;
|
|
|
|
core->mouse.lastScrollWheel = core->mouse.scrollWheel;
|
|
|
|
|
|
|
|
readKeyData();
|
|
|
|
readMouseData();
|
|
|
|
readJoystickData();
|
|
|
|
pollEvents();
|
|
|
|
joystick.update(dt);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMouseInput();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
globalScale.update(dt);
|
2014-03-07 16:59:36 +00:00
|
|
|
core->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
|
|
|
Vector Core::getClearColor()
|
|
|
|
{
|
|
|
|
return clearColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setClearColor(const Vector &c)
|
|
|
|
{
|
|
|
|
clearColor = c;
|
|
|
|
|
|
|
|
glClearColor(c.x, c.y, c.z, 0.0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setSDLGLAttributes()
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "setting vsync: " << _vsync;
|
|
|
|
debugLog(os.str());
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifndef BBGE_BUILD_SDL2
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, _vsync);
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef GLAPIENTRY
|
|
|
|
#undef GLAPIENTRY
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
#define GLAPIENTRY APIENTRY
|
|
|
|
#else
|
|
|
|
#define GLAPIENTRY
|
|
|
|
#endif
|
|
|
|
|
2013-04-22 21:36:31 +00:00
|
|
|
unsigned int Core::dbg_numRenderCalls = 0;
|
|
|
|
|
2011-08-11 02:56:27 +00:00
|
|
|
#ifdef BBGE_BUILD_OPENGL_DYNAMIC
|
2011-08-03 20:05:33 +00:00
|
|
|
#define GL_FUNC(ret,fn,params,call,rt) \
|
2017-01-12 21:51:46 +00:00
|
|
|
extern "C" { \
|
|
|
|
static ret (GLAPIENTRY *p##fn) params = NULL; \
|
|
|
|
ret GLAPIENTRY fn params { ++Core::dbg_numRenderCalls; rt p##fn call; } \
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
#include "OpenGLStubs.h"
|
|
|
|
#undef GL_FUNC
|
|
|
|
|
|
|
|
static bool lookup_glsym(const char *funcname, void **func)
|
|
|
|
{
|
|
|
|
*func = SDL_GL_GetProcAddress(funcname);
|
|
|
|
if (*func == NULL)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Failed to find OpenGL symbol \"" << funcname << "\"\n";
|
|
|
|
errorLog(os.str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool lookup_all_glsyms(void)
|
|
|
|
{
|
|
|
|
bool retval = true;
|
|
|
|
#define GL_FUNC(ret,fn,params,call,rt) \
|
|
|
|
if (!lookup_glsym(#fn, (void **) &p##fn)) retval = false;
|
|
|
|
#include "OpenGLStubs.h"
|
|
|
|
#undef GL_FUNC
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
bool Core::initGraphicsLibrary(int width, int height, bool fullscreen, int vsync, int bpp, bool recreate)
|
2016-05-05 17:40:28 +00:00
|
|
|
{
|
2011-08-03 20:05:33 +00:00
|
|
|
static bool didOnce = false;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
aspectX = width;
|
|
|
|
aspectY = height;
|
|
|
|
|
|
|
|
aspect = (aspectX/aspectY);
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
this->width = width;
|
|
|
|
this->height = height;
|
|
|
|
_vsync = vsync;
|
|
|
|
_fullscreen = fullscreen;
|
|
|
|
_bpp = bpp;
|
|
|
|
|
|
|
|
_hasFocus = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifndef BBGE_BUILD_SDL2
|
|
|
|
#if !defined(BBGE_BUILD_MACOSX)
|
2011-08-03 20:05:33 +00:00
|
|
|
// have to cast away constness, since SDL_putenv() might be #defined to
|
|
|
|
// putenv(), which takes a (char *), and freaks out newer GCC releases
|
|
|
|
// when you try to pass a (const!) string literal here... --ryan.
|
|
|
|
SDL_putenv((char *) "SDL_VIDEO_CENTERED=1");
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (recreate)
|
|
|
|
{
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
|
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error(std::string("SDL Error: ") + std::string(SDL_GetError()));
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if BBGE_BUILD_OPENGL_DYNAMIC
|
|
|
|
if (SDL_GL_LoadLibrary(NULL) == -1)
|
|
|
|
{
|
2013-06-23 16:50:10 +00:00
|
|
|
std::string err = std::string("SDL_GL_LoadLibrary Error: ") + std::string(SDL_GetError());
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_Quit();
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error(err);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
setWindowCaption(appName, appName);
|
|
|
|
|
|
|
|
initIcon();
|
2017-01-12 21:51:46 +00:00
|
|
|
// Create window
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
setSDLGLAttributes();
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
Uint32 flags = 0;
|
|
|
|
flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
|
|
|
if (fullscreen)
|
|
|
|
flags |= SDL_WINDOW_FULLSCREEN;
|
|
|
|
gScreen = SDL_CreateWindow(appName.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
|
|
|
|
if (gScreen == NULL)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Couldn't set resolution [" << width << "x" << height << "]\n" << SDL_GetError();
|
|
|
|
errorLog(os.str());
|
|
|
|
SDL_Quit();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
gGLctx = SDL_GL_CreateContext(gScreen);
|
|
|
|
if (gGLctx == NULL)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Couldn't create OpenGL context!\n" << SDL_GetError();
|
|
|
|
errorLog(os.str());
|
|
|
|
SDL_Quit();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
Uint32 flags = 0;
|
|
|
|
flags = SDL_OPENGL;
|
|
|
|
if (fullscreen)
|
|
|
|
flags |= SDL_FULLSCREEN;
|
|
|
|
|
|
|
|
gScreen = SDL_SetVideoMode(width, height, bpp, flags);
|
|
|
|
if (gScreen == NULL)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Couldn't set resolution [" << width << "x" << height << "]\n" << SDL_GetError();
|
|
|
|
SDL_Quit();
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error(os.str());
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
#if BBGE_BUILD_OPENGL_DYNAMIC
|
|
|
|
if (!lookup_all_glsyms())
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Couldn't load OpenGL symbols we need\n";
|
|
|
|
SDL_Quit();
|
2013-06-23 16:50:10 +00:00
|
|
|
exit_error(os.str());
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
setWindowCaption(appName, appName);
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
SDL_GL_SwapWindow(gScreen);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
SDL_GL_SwapWindow(gScreen);
|
|
|
|
if ((_vsync != 1) || (SDL_GL_SetSwapInterval(-1) == -1))
|
|
|
|
SDL_GL_SetSwapInterval(_vsync);
|
|
|
|
const char *name = SDL_GetCurrentVideoDriver();
|
|
|
|
SDL_SetWindowGrab(gScreen, SDL_TRUE);
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_WM_GrabInput(grabInputOnReentry==0 ? SDL_GRAB_OFF : SDL_GRAB_ON);
|
|
|
|
char name[256];
|
|
|
|
SDL_VideoDriverName((char*)name, 256);
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
glScissor(0, 0, width, height);
|
|
|
|
|
|
|
|
std::ostringstream os2;
|
|
|
|
os2 << "Video Driver Name [" << name << "]";
|
|
|
|
debugLog(os2.str());
|
|
|
|
|
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
SDL_PumpEvents();
|
|
|
|
|
|
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
|
|
{
|
|
|
|
keys[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
|
|
|
|
glClearDepth(1.0); // Depth Buffer Setup
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
glLoadIdentity();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
glFinish();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setClearColor(clearColor);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
clearBuffers();
|
|
|
|
showBuffer();
|
|
|
|
|
|
|
|
lib_graphics = true;
|
|
|
|
|
|
|
|
_hasFocus = true;
|
|
|
|
|
|
|
|
enumerateScreenModes();
|
|
|
|
|
|
|
|
if (!didOnce)
|
|
|
|
didOnce = true;
|
|
|
|
|
|
|
|
// init success
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::enumerateScreenModes()
|
|
|
|
{
|
|
|
|
screenModes.clear();
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_DisplayMode mode;
|
|
|
|
const int modecount = SDL_GetNumDisplayModes(0);
|
|
|
|
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++) {
|
|
|
|
SDL_GetDisplayMode(0, i, &mode);
|
|
|
|
if (mode.w && mode.h && (mode.w > mode.h))
|
|
|
|
{
|
2015-07-12 18:25:46 +00:00
|
|
|
screenModes.push_back(ScreenMode(i, 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)
|
|
|
|
{
|
2015-08-03 18:32:41 +00:00
|
|
|
screenModes.push_back(ScreenMode(i, modes[i]->w, modes[i]->h, 0));
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownSoundLibrary()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownGraphicsLibrary(bool killVideo)
|
|
|
|
{
|
|
|
|
glFinish();
|
|
|
|
if (killVideo) {
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_SetWindowGrab(gScreen, SDL_FALSE);
|
|
|
|
SDL_GL_MakeCurrent(gScreen, NULL);
|
|
|
|
SDL_GL_DeleteContext(gGLctx);
|
|
|
|
SDL_DestroyWindow(gScreen);
|
|
|
|
gGLctx = 0;
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
FrameBuffer::resetOpenGL();
|
|
|
|
|
|
|
|
gScreen = 0;
|
|
|
|
|
|
|
|
#if BBGE_BUILD_OPENGL_DYNAMIC
|
|
|
|
// reset all the entry points to NULL, so we know exactly what happened
|
|
|
|
// if we call a GL function after shutdown.
|
|
|
|
#define GL_FUNC(ret,fn,params,call,rt) \
|
|
|
|
p##fn = NULL;
|
|
|
|
#include "OpenGLStubs.h"
|
|
|
|
#undef GL_FUNC
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
_hasFocus = false;
|
|
|
|
|
|
|
|
lib_graphics = false;
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
if (icon_windows)
|
|
|
|
{
|
|
|
|
::DestroyIcon(icon_windows);
|
|
|
|
icon_windows = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::quit()
|
|
|
|
{
|
|
|
|
enqueueJumpState("STATE_QUIT");
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::applyState(const std::string &state)
|
|
|
|
{
|
|
|
|
if (nocasecmp(state, "state_quit")==0)
|
|
|
|
{
|
|
|
|
loopDone = true;
|
|
|
|
}
|
|
|
|
StateManager::applyState(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
|
|
void centerWindow(HWND hwnd)
|
|
|
|
{
|
2017-01-12 21:51:46 +00:00
|
|
|
int x, y;
|
|
|
|
HWND hwndDeskTop;
|
|
|
|
RECT rcWnd, rcDeskTop;
|
|
|
|
// Get a handle to the desktop window
|
|
|
|
hwndDeskTop = ::GetDesktopWindow();
|
|
|
|
// Get dimension of desktop in a rect
|
|
|
|
::GetWindowRect(hwndDeskTop, &rcDeskTop);
|
|
|
|
// Get dimension of main window in a rect
|
|
|
|
::GetWindowRect(hwnd, &rcWnd);
|
|
|
|
// Find center of desktop
|
2011-08-03 20:05:33 +00:00
|
|
|
x = (rcDeskTop.right - rcDeskTop.left)/2;
|
|
|
|
y = (rcDeskTop.bottom - rcDeskTop.top)/2;
|
2017-01-12 21:51:46 +00:00
|
|
|
x -= (rcWnd.right - rcWnd.left)/2;
|
2011-08-03 20:05:33 +00:00
|
|
|
y -= (rcWnd.bottom - rcWnd.top)/2;
|
2017-01-12 21:51:46 +00:00
|
|
|
// Set top and left to center main window on desktop
|
|
|
|
::SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
bool Core::createWindow(int width, int height, int bits, bool fullscreen, std::string windowTitle)
|
|
|
|
{
|
|
|
|
this->width = width;
|
|
|
|
this->height = height;
|
|
|
|
|
|
|
|
redBits = greenBits = blueBits = alphaBits = 0;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// No longer part of C/C++ standard
|
|
|
|
#ifndef M_PI
|
2017-01-12 21:51:46 +00:00
|
|
|
#define M_PI 3.14159265358979323846
|
2011-08-03 20:05:33 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void Core::setPixelScale(int pixelScaleX, int pixelScaleY)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
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
|
|
|
vw2 = virtualWidth/2;
|
|
|
|
vh2 = virtualHeight/2;
|
|
|
|
|
|
|
|
center = Vector(baseVirtualWidth/2, baseVirtualHeight/2);
|
|
|
|
|
|
|
|
|
|
|
|
virtualOffX = 0;
|
|
|
|
virtualOffY = 0;
|
|
|
|
|
|
|
|
int diff = 0;
|
|
|
|
|
|
|
|
diff = virtualWidth-baseVirtualWidth;
|
|
|
|
if (diff > 0)
|
|
|
|
virtualOffX = ((virtualWidth-baseVirtualWidth)/2);
|
|
|
|
else
|
|
|
|
virtualOffX = 0;
|
|
|
|
|
|
|
|
|
|
|
|
diff = virtualHeight-baseVirtualHeight;
|
|
|
|
if (diff > 0)
|
|
|
|
virtualOffY = ((virtualHeight-baseVirtualHeight)/2);
|
|
|
|
else
|
|
|
|
virtualOffY = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// forcePixelScale used by Celu
|
|
|
|
|
|
|
|
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-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
core->enable2D(vw, baseVirtualHeight, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int vh = int(float(baseVirtualWidth) * (float(ry)/float(rx)));
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
core->enable2D(baseVirtualWidth, vh, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bbgeOrtho2D(float left, float right, float bottom, float top)
|
|
|
|
{
|
2017-01-12 21:51:46 +00:00
|
|
|
glOrtho(left, right, bottom, top, -1.0, 1.0);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::enable2D(int pixelScaleX, int pixelScaleY, bool forcePixelScale)
|
|
|
|
{
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2017-01-12 21:51:46 +00:00
|
|
|
GLint viewPort[4];
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2017-01-12 21:51:46 +00:00
|
|
|
glMatrixMode(GL_PROJECTION);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2017-01-12 21:51:46 +00:00
|
|
|
glLoadIdentity();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
float vw=0,vh=0;
|
|
|
|
|
|
|
|
viewOffX = viewOffY = 0;
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-12 21:51:46 +00:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2017-01-12 21:51:46 +00:00
|
|
|
glLoadIdentity();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
setupRenderPositionAndScale();
|
|
|
|
|
|
|
|
|
|
|
|
if (forcePixelScale || (pixelScaleX!=0 && core->width!=pixelScaleX) || (pixelScaleY!=0 && core->height!=pixelScaleY))
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
float widthFactor = core->width/float(pixelScaleX);
|
|
|
|
float heightFactor = core->height/float(pixelScaleY);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
core->globalResolutionScale = Vector(widthFactor,heightFactor,1.0f);
|
|
|
|
setPixelScale(pixelScaleX, pixelScaleY);
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
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::setDockIcon(const std::string &ident)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::setMousePosition(const Vector &p)
|
|
|
|
{
|
|
|
|
core->mouse.position = p;
|
|
|
|
float px = p.x + virtualOffX;
|
2016-05-05 17:40:28 +00:00
|
|
|
float py = p.y;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_WarpMouseInWindow(gScreen, px * (float(width)/float(virtualWidth)), py * (float(height)/float(virtualHeight)));
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_WarpMouse( px * (float(width)/float(virtualWidth)), py * (float(height)/float(virtualHeight)));
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
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;
|
|
|
|
|
|
|
|
if (clearedGarbageFlag)
|
|
|
|
{
|
|
|
|
clearedGarbageFlag = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Core::getEnqueuedJumpState()
|
|
|
|
{
|
|
|
|
return this->enqueuedJumpState;
|
|
|
|
}
|
|
|
|
|
|
|
|
int screenshotNum = 0;
|
|
|
|
std::string getScreenshotFilename()
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << core->getUserDataFolder() << "/screenshots/screen" << screenshotNum << ".tga";
|
|
|
|
screenshotNum ++;
|
2017-01-12 21:51:46 +00:00
|
|
|
std::string str(os.str());
|
2011-08-03 20:05:33 +00:00
|
|
|
if (!core->exists(str)) // keep going until we hit an unused filename.
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-05 18:05:38 +00:00
|
|
|
unsigned Core::getTicks()
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
return SDL_GetTicks();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
float Core::stopWatch(int d)
|
|
|
|
{
|
|
|
|
if (d)
|
|
|
|
{
|
|
|
|
stopWatchStartTime = getTicks()/1000.0f;
|
|
|
|
return stopWatchStartTime;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return (getTicks()/1000.0f) - stopWatchStartTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::isWindowFocus()
|
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
return ((SDL_GetWindowFlags(gScreen) & SDL_WINDOW_INPUT_FOCUS) != 0);
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
return ((SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0);
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-24 01:39:48 +00:00
|
|
|
void Core::onBackgroundUpdate()
|
|
|
|
{
|
|
|
|
SDL_Delay(200);
|
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
void Core::main(float runTime)
|
|
|
|
{
|
|
|
|
bool verbose = coreVerboseDebug;
|
|
|
|
if (verbose) debugLog("entered Core::main");
|
|
|
|
// 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;
|
2017-01-12 21:51:46 +00:00
|
|
|
int frames = 0;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
#if (!defined(_DEBUG) || defined(BBGE_BUILD_UNIX)) && defined(BBGE_BUILD_SDL)
|
|
|
|
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
|
|
|
{
|
|
|
|
BBGE_PROF(Core_main);
|
|
|
|
|
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 (verbose) debugLog("avgFPS");
|
|
|
|
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
|
|
|
}
|
|
|
|
|
[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
|
|
|
#if !defined(_DEBUG) && defined(BBGE_BUILD_SDL)
|
2011-08-03 20:05:33 +00:00
|
|
|
if (verbose) debugLog("checking window active");
|
|
|
|
|
|
|
|
if (lib_graphics && (wasInactive || !settings.runInBackground))
|
|
|
|
{
|
|
|
|
if (isWindowFocus())
|
|
|
|
{
|
|
|
|
_hasFocus = true;
|
|
|
|
if (wasInactive)
|
|
|
|
{
|
|
|
|
debugLog("WINDOW ACTIVE");
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
setReentryInputGrab(1);
|
|
|
|
|
|
|
|
wasInactive = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_hasFocus)
|
|
|
|
{
|
|
|
|
if (!wasInactive)
|
|
|
|
debugLog("WINDOW INACTIVE");
|
|
|
|
|
|
|
|
wasInactive = true;
|
|
|
|
_hasFocus = false;
|
|
|
|
|
|
|
|
setReentryInputGrab(0);
|
|
|
|
|
|
|
|
sound->pause();
|
|
|
|
|
|
|
|
core->joystick.rumble(0,0,0);
|
|
|
|
|
|
|
|
while (!isWindowFocus())
|
|
|
|
{
|
|
|
|
pollEvents();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2013-06-24 01:39:48 +00:00
|
|
|
onBackgroundUpdate();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
resetTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
debugLog("app back in focus, reset");
|
|
|
|
|
|
|
|
// Don't do this on Linux, it's not necessary and causes big stalls.
|
|
|
|
// We don't actually _lose_ the device like Direct3D anyhow.
|
|
|
|
#ifndef BBGE_BUILD_UNIX
|
|
|
|
if (_fullscreen)
|
|
|
|
{
|
|
|
|
// calls reload device - reloadDevice()
|
|
|
|
resetGraphics(width, height);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
resetTimer();
|
|
|
|
|
|
|
|
sound->resume();
|
|
|
|
|
|
|
|
resetTimer();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
old_dt = dt;
|
|
|
|
|
|
|
|
if (verbose) debugLog("modify dt");
|
|
|
|
modifyDt(dt);
|
|
|
|
|
2013-07-15 01:22:41 +00:00
|
|
|
current_dt = dt;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (verbose) debugLog("check runtime/quit");
|
|
|
|
|
|
|
|
if (quitNestedMainFlag)
|
|
|
|
{
|
|
|
|
quitNestedMainFlag = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (runTime>0)
|
|
|
|
{
|
|
|
|
runTime -= dt;
|
|
|
|
if (runTime < 0)
|
|
|
|
runTime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// UPDATE
|
|
|
|
if (verbose) debugLog("post processing fx update");
|
|
|
|
postProcessingFx.update(dt);
|
|
|
|
|
|
|
|
if (verbose) debugLog("update eventQueue");
|
|
|
|
eventQueue.update(dt);
|
|
|
|
|
|
|
|
if (verbose) debugLog("Update render objects");
|
|
|
|
|
|
|
|
updateRenderObjects(dt);
|
|
|
|
|
|
|
|
if (verbose) debugLog("Update particle manager");
|
|
|
|
|
|
|
|
if (particleManager)
|
|
|
|
particleManager->update(dt);
|
|
|
|
|
|
|
|
if (verbose) debugLog("sound update");
|
|
|
|
sound->update(dt);
|
|
|
|
|
|
|
|
if (verbose) debugLog("onUpdate");
|
|
|
|
onUpdate(dt);
|
|
|
|
|
|
|
|
if (nestedMains == 1)
|
|
|
|
clearGarbage();
|
|
|
|
|
|
|
|
if (loopDone)
|
|
|
|
break;
|
|
|
|
|
|
|
|
updateCullData();
|
|
|
|
|
2013-04-22 21:36:31 +00:00
|
|
|
dbg_numRenderCalls = 0;
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (settings.renderOn)
|
|
|
|
{
|
|
|
|
if (verbose) debugLog("dark layer prerender");
|
|
|
|
if (darkLayer.isUsed())
|
|
|
|
{
|
|
|
|
darkLayer.preRender();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose) debugLog("render");
|
|
|
|
render();
|
|
|
|
|
|
|
|
if (verbose) debugLog("showBuffer");
|
|
|
|
showBuffer();
|
|
|
|
|
|
|
|
BBGE_PROF(STOP);
|
|
|
|
|
|
|
|
if (verbose) debugLog("clearGarbage");
|
|
|
|
if (nestedMains == 1)
|
|
|
|
clearGarbage();
|
|
|
|
|
|
|
|
|
|
|
|
if (verbose) debugLog("frame counter");
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (verbose) debugLog("screenshot");
|
|
|
|
|
|
|
|
doScreenshot = false;
|
|
|
|
|
|
|
|
saveScreenshotTGA(getScreenshotFilename());
|
|
|
|
prepScreen(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (verbose) debugLog("bottom of function");
|
|
|
|
quitNestedMainFlag = false;
|
|
|
|
if (nestedMains==1)
|
|
|
|
clearGarbage();
|
|
|
|
nestedMains--;
|
|
|
|
if (verbose) debugLog("exit Core::main");
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
glScalef(globalScale.x*globalResolutionScale.x*screenCapScale.x, globalScale.y*globalResolutionScale.y*screenCapScale.y, globalScale.z*globalResolutionScale.z);
|
|
|
|
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::initFrameBuffer()
|
|
|
|
{
|
|
|
|
frameBuffer.init(-1, -1, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
int Core::getVirtualOffX()
|
|
|
|
{
|
|
|
|
return virtualOffX;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Core::getVirtualOffY()
|
|
|
|
{
|
|
|
|
return virtualOffY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::centerMouse()
|
|
|
|
{
|
|
|
|
setMousePosition(Vector((virtualWidth/2) - core->getVirtualOffX(), virtualHeight/2));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::doMouseConstraint()
|
|
|
|
{
|
|
|
|
if (mouseConstraint)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2014-03-10 01:26:01 +00:00
|
|
|
Vector h = mouseConstraintCenter;
|
2011-08-03 20:05:33 +00:00
|
|
|
Vector d = mouse.position - h;
|
|
|
|
if (!d.isLength2DIn(mouseCircle))
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
|
|
|
|
#if defined(BBGE_BUILD_SDL2)
|
|
|
|
typedef std::map<SDL_Keycode,int> sdlKeyMap;
|
|
|
|
#else
|
|
|
|
typedef std::map<SDLKey,int> sdlKeyMap;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static sdlKeyMap *initSDLKeymap(void)
|
|
|
|
{
|
|
|
|
sdlKeyMap *_retval = new sdlKeyMap;
|
|
|
|
sdlKeyMap &retval = *_retval;
|
|
|
|
|
|
|
|
#define SETKEYMAP(gamekey,sdlkey) retval[sdlkey] = gamekey
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SETKEYMAP(KEY_LSUPER, SDLK_LGUI);
|
|
|
|
SETKEYMAP(KEY_RSUPER, SDLK_RGUI);
|
|
|
|
SETKEYMAP(KEY_LMETA, SDLK_LGUI);
|
|
|
|
SETKEYMAP(KEY_RMETA, SDLK_RGUI);
|
|
|
|
SETKEYMAP(KEY_PRINTSCREEN, SDLK_PRINTSCREEN);
|
|
|
|
SETKEYMAP(KEY_NUMPAD1, SDLK_KP_1);
|
|
|
|
SETKEYMAP(KEY_NUMPAD2, SDLK_KP_2);
|
|
|
|
SETKEYMAP(KEY_NUMPAD3, SDLK_KP_3);
|
|
|
|
SETKEYMAP(KEY_NUMPAD4, SDLK_KP_4);
|
|
|
|
SETKEYMAP(KEY_NUMPAD5, SDLK_KP_5);
|
|
|
|
SETKEYMAP(KEY_NUMPAD6, SDLK_KP_6);
|
|
|
|
SETKEYMAP(KEY_NUMPAD7, SDLK_KP_7);
|
|
|
|
SETKEYMAP(KEY_NUMPAD8, SDLK_KP_8);
|
|
|
|
SETKEYMAP(KEY_NUMPAD9, SDLK_KP_9);
|
|
|
|
SETKEYMAP(KEY_NUMPAD0, SDLK_KP_0);
|
|
|
|
#else
|
|
|
|
SETKEYMAP(KEY_LSUPER, SDLK_LSUPER);
|
|
|
|
SETKEYMAP(KEY_RSUPER, SDLK_RSUPER);
|
|
|
|
SETKEYMAP(KEY_LMETA, SDLK_LMETA);
|
|
|
|
SETKEYMAP(KEY_RMETA, SDLK_RMETA);
|
|
|
|
SETKEYMAP(KEY_PRINTSCREEN, SDLK_PRINT);
|
|
|
|
SETKEYMAP(KEY_NUMPAD1, SDLK_KP1);
|
|
|
|
SETKEYMAP(KEY_NUMPAD2, SDLK_KP2);
|
|
|
|
SETKEYMAP(KEY_NUMPAD3, SDLK_KP3);
|
|
|
|
SETKEYMAP(KEY_NUMPAD4, SDLK_KP4);
|
|
|
|
SETKEYMAP(KEY_NUMPAD5, SDLK_KP5);
|
|
|
|
SETKEYMAP(KEY_NUMPAD6, SDLK_KP6);
|
|
|
|
SETKEYMAP(KEY_NUMPAD7, SDLK_KP7);
|
|
|
|
SETKEYMAP(KEY_NUMPAD8, SDLK_KP8);
|
|
|
|
SETKEYMAP(KEY_NUMPAD9, SDLK_KP9);
|
|
|
|
SETKEYMAP(KEY_NUMPAD0, SDLK_KP0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SETKEYMAP(KEY_BACKSPACE, SDLK_BACKSPACE);
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
SETKEYMAP(KEY_LALT, SDLK_LALT);
|
|
|
|
SETKEYMAP(KEY_RALT, SDLK_RALT);
|
|
|
|
SETKEYMAP(KEY_LSHIFT, SDLK_LSHIFT);
|
|
|
|
SETKEYMAP(KEY_RSHIFT, SDLK_RSHIFT);
|
|
|
|
SETKEYMAP(KEY_LCONTROL, SDLK_LCTRL);
|
|
|
|
SETKEYMAP(KEY_RCONTROL, SDLK_RCTRL);
|
|
|
|
SETKEYMAP(KEY_NUMPADMINUS, SDLK_KP_MINUS);
|
|
|
|
SETKEYMAP(KEY_NUMPADPERIOD, SDLK_KP_PERIOD);
|
|
|
|
SETKEYMAP(KEY_NUMPADPLUS, SDLK_KP_PLUS);
|
|
|
|
SETKEYMAP(KEY_NUMPADSLASH, SDLK_KP_DIVIDE);
|
|
|
|
SETKEYMAP(KEY_NUMPADSTAR, SDLK_KP_MULTIPLY);
|
|
|
|
SETKEYMAP(KEY_PGDN, SDLK_PAGEDOWN);
|
|
|
|
SETKEYMAP(KEY_PGUP, SDLK_PAGEUP);
|
|
|
|
SETKEYMAP(KEY_APOSTROPHE, SDLK_QUOTE);
|
|
|
|
SETKEYMAP(KEY_EQUALS, SDLK_EQUALS);
|
|
|
|
SETKEYMAP(KEY_SEMICOLON, SDLK_SEMICOLON);
|
|
|
|
SETKEYMAP(KEY_LBRACKET, SDLK_LEFTBRACKET);
|
|
|
|
SETKEYMAP(KEY_RBRACKET, SDLK_RIGHTBRACKET);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
SETKEYMAP(KEY_TILDE, SDLK_BACKQUOTE);
|
|
|
|
SETKEYMAP(KEY_0, SDLK_0);
|
|
|
|
SETKEYMAP(KEY_1, SDLK_1);
|
|
|
|
SETKEYMAP(KEY_2, SDLK_2);
|
|
|
|
SETKEYMAP(KEY_3, SDLK_3);
|
|
|
|
SETKEYMAP(KEY_4, SDLK_4);
|
|
|
|
SETKEYMAP(KEY_5, SDLK_5);
|
|
|
|
SETKEYMAP(KEY_6, SDLK_6);
|
|
|
|
SETKEYMAP(KEY_7, SDLK_7);
|
|
|
|
SETKEYMAP(KEY_8, SDLK_8);
|
|
|
|
SETKEYMAP(KEY_9, SDLK_9);
|
|
|
|
SETKEYMAP(KEY_A, SDLK_a);
|
|
|
|
SETKEYMAP(KEY_B, SDLK_b);
|
|
|
|
SETKEYMAP(KEY_C, SDLK_c);
|
|
|
|
SETKEYMAP(KEY_D, SDLK_d);
|
|
|
|
SETKEYMAP(KEY_E, SDLK_e);
|
|
|
|
SETKEYMAP(KEY_F, SDLK_f);
|
|
|
|
SETKEYMAP(KEY_G, SDLK_g);
|
|
|
|
SETKEYMAP(KEY_H, SDLK_h);
|
|
|
|
SETKEYMAP(KEY_I, SDLK_i);
|
|
|
|
SETKEYMAP(KEY_J, SDLK_j);
|
|
|
|
SETKEYMAP(KEY_K, SDLK_k);
|
|
|
|
SETKEYMAP(KEY_L, SDLK_l);
|
|
|
|
SETKEYMAP(KEY_M, SDLK_m);
|
|
|
|
SETKEYMAP(KEY_N, SDLK_n);
|
|
|
|
SETKEYMAP(KEY_O, SDLK_o);
|
|
|
|
SETKEYMAP(KEY_P, SDLK_p);
|
|
|
|
SETKEYMAP(KEY_Q, SDLK_q);
|
|
|
|
SETKEYMAP(KEY_R, SDLK_r);
|
|
|
|
SETKEYMAP(KEY_S, SDLK_s);
|
|
|
|
SETKEYMAP(KEY_T, SDLK_t);
|
|
|
|
SETKEYMAP(KEY_U, SDLK_u);
|
|
|
|
SETKEYMAP(KEY_V, SDLK_v);
|
|
|
|
SETKEYMAP(KEY_W, SDLK_w);
|
|
|
|
SETKEYMAP(KEY_X, SDLK_x);
|
|
|
|
SETKEYMAP(KEY_Y, SDLK_y);
|
|
|
|
SETKEYMAP(KEY_Z, SDLK_z);
|
|
|
|
|
|
|
|
SETKEYMAP(KEY_LEFT, SDLK_LEFT);
|
|
|
|
SETKEYMAP(KEY_RIGHT, SDLK_RIGHT);
|
|
|
|
SETKEYMAP(KEY_UP, SDLK_UP);
|
|
|
|
SETKEYMAP(KEY_DOWN, SDLK_DOWN);
|
|
|
|
|
|
|
|
SETKEYMAP(KEY_DELETE, SDLK_DELETE);
|
|
|
|
SETKEYMAP(KEY_SPACE, SDLK_SPACE);
|
|
|
|
SETKEYMAP(KEY_RETURN, SDLK_RETURN);
|
|
|
|
SETKEYMAP(KEY_PERIOD, SDLK_PERIOD);
|
|
|
|
SETKEYMAP(KEY_MINUS, SDLK_MINUS);
|
|
|
|
SETKEYMAP(KEY_CAPSLOCK, SDLK_CAPSLOCK);
|
|
|
|
SETKEYMAP(KEY_SYSRQ, SDLK_SYSREQ);
|
|
|
|
SETKEYMAP(KEY_TAB, SDLK_TAB);
|
|
|
|
SETKEYMAP(KEY_HOME, SDLK_HOME);
|
|
|
|
SETKEYMAP(KEY_END, SDLK_END);
|
|
|
|
SETKEYMAP(KEY_COMMA, SDLK_COMMA);
|
|
|
|
SETKEYMAP(KEY_SLASH, SDLK_SLASH);
|
|
|
|
|
|
|
|
SETKEYMAP(KEY_F1, SDLK_F1);
|
|
|
|
SETKEYMAP(KEY_F2, SDLK_F2);
|
|
|
|
SETKEYMAP(KEY_F3, SDLK_F3);
|
|
|
|
SETKEYMAP(KEY_F4, SDLK_F4);
|
|
|
|
SETKEYMAP(KEY_F5, SDLK_F5);
|
|
|
|
SETKEYMAP(KEY_F6, SDLK_F6);
|
|
|
|
SETKEYMAP(KEY_F7, SDLK_F7);
|
|
|
|
SETKEYMAP(KEY_F8, SDLK_F8);
|
|
|
|
SETKEYMAP(KEY_F9, SDLK_F9);
|
|
|
|
SETKEYMAP(KEY_F10, SDLK_F10);
|
|
|
|
SETKEYMAP(KEY_F11, SDLK_F11);
|
|
|
|
SETKEYMAP(KEY_F12, SDLK_F12);
|
|
|
|
SETKEYMAP(KEY_F13, SDLK_F13);
|
|
|
|
SETKEYMAP(KEY_F14, SDLK_F14);
|
|
|
|
SETKEYMAP(KEY_F15, SDLK_F15);
|
|
|
|
|
|
|
|
SETKEYMAP(KEY_ESCAPE, SDLK_ESCAPE);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
|
|
|
|
#undef SETKEYMAP
|
|
|
|
|
|
|
|
return _retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(BBGE_BUILD_SDL2)
|
|
|
|
static int mapSDLKeyToGameKey(const SDL_Keycode val)
|
|
|
|
#else
|
|
|
|
static int mapSDLKeyToGameKey(const SDLKey val)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
static sdlKeyMap *keymap = NULL;
|
|
|
|
if (keymap == NULL)
|
|
|
|
keymap = initSDLKeymap();
|
|
|
|
|
|
|
|
return (*keymap)[val];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
void Core::pollEvents()
|
|
|
|
{
|
|
|
|
bool warpMouse=false;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (updateMouse)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
Uint8 mousestate = SDL_GetMouseState(&x,&y);
|
|
|
|
|
|
|
|
if (mouse.buttonsEnabled)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
mouse.pure_buttons = mouse.buttons;
|
|
|
|
|
|
|
|
if (flipMouseButtons)
|
|
|
|
{
|
|
|
|
std::swap(mouse.buttons.left, mouse.buttons.right);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mouse.buttons.left = mouse.buttons.right = mouse.buttons.middle = UP;
|
|
|
|
}
|
|
|
|
|
|
|
|
mouse.scrollWheelChange = 0;
|
|
|
|
mouse.change = Vector(0,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SDL_Event event;
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
while ( SDL_PollEvent (&event) ) {
|
|
|
|
switch (event.type) {
|
|
|
|
case SDL_KEYDOWN:
|
|
|
|
{
|
|
|
|
#if __APPLE__
|
2013-12-11 02:06:59 +00:00
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
|
|
|
if ((event.key.keysym.sym == SDLK_q) && (event.key.keysym.mod & KMOD_GUI))
|
|
|
|
#else
|
|
|
|
if ((event.key.keysym.sym == SDLK_q) && (event.key.keysym.mod & KMOD_META))
|
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
#else
|
|
|
|
if ((event.key.keysym.sym == SDLK_F4) && (event.key.keysym.mod & KMOD_ALT))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
quitNestedMain();
|
|
|
|
quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((event.key.keysym.sym == SDLK_g) && (event.key.keysym.mod & KMOD_CTRL))
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
grabInputOnReentry = (grabInputOnReentry)?0:-1;
|
|
|
|
setReentryInputGrab(1);
|
|
|
|
}
|
|
|
|
else if (_hasFocus)
|
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
keys[mapSDLKeyToGameKey(event.key.keysym.sym)] = 1;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SDL_KEYUP:
|
|
|
|
{
|
|
|
|
if (_hasFocus)
|
|
|
|
{
|
2013-07-18 21:29:55 +00:00
|
|
|
keys[mapSDLKeyToGameKey(event.key.keysym.sym)] = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SDL_MOUSEMOTION:
|
|
|
|
{
|
|
|
|
if (_hasFocus && updateMouse)
|
|
|
|
{
|
|
|
|
mouse.lastPosition = mouse.position;
|
|
|
|
|
|
|
|
mouse.position.x = ((event.motion.x) * (float(virtualWidth)/float(getWindowWidth()))) - getVirtualOffX();
|
|
|
|
mouse.position.y = event.motion.y * (float(virtualHeight)/float(getWindowHeight()));
|
|
|
|
|
|
|
|
mouse.change = mouse.position - mouse.lastPosition;
|
|
|
|
|
|
|
|
if (doMouseConstraint()) warpMouse = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
case SDL_WINDOWEVENT:
|
|
|
|
{
|
|
|
|
if (event.window.event == SDL_WINDOWEVENT_CLOSE)
|
|
|
|
{
|
|
|
|
SDL_Quit();
|
|
|
|
_exit(0);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2013-07-18 21:29:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SDL_MOUSEWHEEL:
|
|
|
|
{
|
|
|
|
if (_hasFocus && updateMouse)
|
|
|
|
{
|
|
|
|
if (event.wheel.y > 0)
|
|
|
|
mouse.scrollWheelChange = 1;
|
|
|
|
else if (event.wheel.y < 0)
|
|
|
|
mouse.scrollWheelChange = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
{
|
|
|
|
if (_hasFocus && updateMouse)
|
|
|
|
{
|
|
|
|
switch(event.button.button)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
mouse.scrollWheelChange = 1;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
mouse.scrollWheelChange = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
{
|
|
|
|
if (_hasFocus && updateMouse)
|
|
|
|
{
|
|
|
|
switch(event.button.button)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
mouse.scrollWheelChange = 1;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
mouse.scrollWheelChange = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-07-18 21:29:55 +00:00
|
|
|
#endif
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
case SDL_QUIT:
|
|
|
|
SDL_Quit();
|
|
|
|
_exit(0);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SDL_SYSWMEVENT:
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (updateMouse)
|
|
|
|
{
|
|
|
|
mouse.scrollWheel += mouse.scrollWheelChange;
|
|
|
|
|
|
|
|
if (warpMouse)
|
|
|
|
{
|
|
|
|
setMousePosition(mouse.position);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
|
|
|
|
|
|
|
BBGE_PROF(Core_render);
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
if (startLayer == -1 && endLayer == -1 && overrideStartLayer != 0)
|
|
|
|
{
|
|
|
|
startLayer = overrideStartLayer;
|
|
|
|
endLayer = overrideEndLayer;
|
|
|
|
}
|
|
|
|
|
2014-03-07 16:59:36 +00:00
|
|
|
globalScaleChanged();
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
if (core->minimized) return;
|
|
|
|
onRender();
|
|
|
|
|
|
|
|
RenderObject::lastTextureApplied = 0;
|
|
|
|
|
|
|
|
updateCullData();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
renderObjectCount = 0;
|
|
|
|
processedRenderObjectCount = 0;
|
|
|
|
totalRenderObjectCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glLoadIdentity(); // Reset The View
|
|
|
|
clearBuffers();
|
|
|
|
|
|
|
|
if (afterEffectManager && frameBuffer.isInited() && useFrameBufferIfAvail)
|
|
|
|
{
|
|
|
|
frameBuffer.startCapture();
|
|
|
|
}
|
|
|
|
|
|
|
|
setupRenderPositionAndScale();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RenderObject::rlayer = 0;
|
|
|
|
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t c = 0; c < renderObjectLayerOrder.size(); c++)
|
2016-05-05 17:40:28 +00:00
|
|
|
|
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;
|
|
|
|
|
2011-11-20 14:44:17 +00:00
|
|
|
if (i == postProcessingFx.layer)
|
|
|
|
{
|
|
|
|
postProcessingFx.preRender();
|
|
|
|
}
|
|
|
|
if (i == postProcessingFx.renderLayer)
|
|
|
|
{
|
|
|
|
postProcessingFx.render();
|
|
|
|
}
|
2011-10-31 17:28:57 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
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];
|
|
|
|
RenderObject::rlayer = r;
|
|
|
|
if (r->visible)
|
|
|
|
{
|
|
|
|
if (r->startPass == r->endPass)
|
|
|
|
{
|
|
|
|
r->renderPass(RenderObject::RENDER_ALL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int pass = r->startPass; pass <= r->endPass; pass++)
|
|
|
|
{
|
|
|
|
r->renderPass(pass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::showBuffer()
|
|
|
|
{
|
|
|
|
BBGE_PROF(Core_showBuffer);
|
2013-07-18 21:29:55 +00:00
|
|
|
#ifdef BBGE_BUILD_SDL2
|
|
|
|
SDL_GL_SwapWindow(gScreen);
|
2016-05-05 01:49:41 +00:00
|
|
|
#else
|
2011-08-03 20:05:33 +00:00
|
|
|
SDL_GL_SwapBuffers();
|
2013-07-18 21:29:55 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
#endif
|
2013-07-18 21:29:55 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// WARNING: only for use during shutdown
|
|
|
|
// otherwise, textures will try to remove themselves
|
|
|
|
// when destroy is called on them
|
|
|
|
void Core::clearResources()
|
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
if(resources.size())
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
debugLog("Warning: The following resources were not cleared:");
|
|
|
|
for(size_t i = 0; i < resources.size(); ++i)
|
|
|
|
debugLog(resources[i]->name);
|
|
|
|
resources.clear(); // nothing we can do; refcounting is messed up
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownInputLibrary()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::shutdownJoystickLibrary()
|
|
|
|
{
|
|
|
|
if (joystickEnabled) {
|
|
|
|
joystick.shutdown();
|
|
|
|
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...");
|
|
|
|
clearResources();
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
void Core::instantQuit()
|
|
|
|
{
|
2017-01-12 21:51:46 +00:00
|
|
|
SDL_Event event;
|
|
|
|
event.type = SDL_QUIT;
|
|
|
|
SDL_PushEvent(&event);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Core::exists(const std::string &filename)
|
|
|
|
{
|
2011-08-11 00:26:46 +00:00
|
|
|
return ::exists(filename, false); // defined in Base.cpp
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2015-03-23 23:06:51 +00:00
|
|
|
CountedPtr<Texture> Core::findTexture(const std::string &name)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
int sz = resources.size();
|
|
|
|
for (int i = 0; i < sz; i++)
|
|
|
|
{
|
|
|
|
//out << resources[i]->name << " is " << name << " ?" << std::endl;
|
|
|
|
//NOTE: ensure all names are lowercase before this point
|
|
|
|
if (resources[i]->name == name)
|
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
return resources[i];
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-20 22:47:24 +00:00
|
|
|
// This handles unix/win32 relative paths: ./rel/path
|
|
|
|
// Unix abs paths: /home/user/...
|
|
|
|
// Win32 abs paths: C:/Stuff/.. and also C:\Stuff\...
|
|
|
|
#define ISPATHROOT(x) (x[0] == '.' || x[0] == '/' || ((x).length() > 1 && x[1] == ':'))
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
std::string Core::getTextureLoadName(const std::string &texture)
|
|
|
|
{
|
|
|
|
std::string loadName = texture;
|
|
|
|
|
|
|
|
if (texture.empty() || !ISPATHROOT(texture))
|
|
|
|
{
|
|
|
|
if (texture.find(baseTextureDirectory) == std::string::npos)
|
|
|
|
loadName = baseTextureDirectory + texture;
|
|
|
|
}
|
|
|
|
return loadName;
|
|
|
|
}
|
|
|
|
|
2016-03-13 00:37:43 +00:00
|
|
|
CountedPtr<Texture> Core::doTextureAdd(const std::string &texture, const std::string &loadName, std::string internalTextureName)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
if (texture.empty() || !ISPATHROOT(texture))
|
|
|
|
{
|
|
|
|
if (texture.find(baseTextureDirectory) != std::string::npos)
|
|
|
|
internalTextureName = internalTextureName.substr(baseTextureDirectory.size(), internalTextureName.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (internalTextureName.size() > 4)
|
|
|
|
{
|
|
|
|
if (internalTextureName[internalTextureName.size()-4] == '.')
|
|
|
|
{
|
|
|
|
internalTextureName = internalTextureName.substr(0, internalTextureName.size()-4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stringToLowerUserData(internalTextureName);
|
2015-03-23 23:06:51 +00:00
|
|
|
CountedPtr<Texture> t = core->findTexture(internalTextureName);
|
2011-08-03 20:05:33 +00:00
|
|
|
if (t)
|
2016-03-13 00:37:43 +00:00
|
|
|
return t;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
t = new Texture;
|
|
|
|
t->name = internalTextureName;
|
|
|
|
|
2016-03-15 02:38:01 +00:00
|
|
|
if(t->load(loadName))
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "LOADED TEXTURE FROM DISK: [" << internalTextureName << "] idx: " << resources.size()-1;
|
|
|
|
debugLog(os.str());
|
|
|
|
}
|
|
|
|
else
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
t->width = 64;
|
|
|
|
t->height = 64;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-03-13 00:37:43 +00:00
|
|
|
return t;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
2016-03-13 00:37:43 +00:00
|
|
|
CountedPtr<Texture> Core::addTexture(const std::string &textureName)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
BBGE_PROF(Core_addTexture);
|
|
|
|
|
2015-06-09 23:49:12 +00:00
|
|
|
if (textureName.empty())
|
|
|
|
return NULL;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-03-13 00:37:43 +00:00
|
|
|
CountedPtr<Texture> ptex;
|
2011-08-03 20:05:33 +00:00
|
|
|
std::string texture = textureName;
|
|
|
|
stringToLowerUserData(texture);
|
|
|
|
std::string internalTextureName = texture;
|
|
|
|
std::string loadName = getTextureLoadName(texture);
|
|
|
|
|
|
|
|
if (!texture.empty() && texture[0] == '@')
|
|
|
|
{
|
|
|
|
texture = secondaryTexturePath + texture.substr(1, texture.size());
|
|
|
|
loadName = texture;
|
|
|
|
}
|
|
|
|
else if (!secondaryTexturePath.empty() && texture[0] != '.' && texture[0] != '/')
|
|
|
|
{
|
|
|
|
std::string t = texture;
|
|
|
|
std::string ln = loadName;
|
|
|
|
texture = secondaryTexturePath + texture;
|
|
|
|
loadName = texture;
|
2016-03-13 00:37:43 +00:00
|
|
|
ptex = doTextureAdd(texture, loadName, internalTextureName);
|
|
|
|
if (!ptex || ptex->getLoadResult() == TEX_FAILED)
|
|
|
|
ptex = doTextureAdd(t, ln, internalTextureName);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
else
|
2016-03-13 00:37:43 +00:00
|
|
|
ptex = doTextureAdd(texture, loadName, internalTextureName);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2016-03-13 00:37:43 +00:00
|
|
|
addTexture(ptex.content());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2015-03-23 23:06:51 +00:00
|
|
|
if(debugLogTextures)
|
|
|
|
{
|
2016-03-15 02:38:01 +00:00
|
|
|
if(!ptex || ptex->getLoadResult() != TEX_SUCCESS)
|
2015-03-23 23:06:51 +00:00
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "FAILED TO LOAD TEXTURE: [" << internalTextureName << "] idx: " << resources.size()-1;
|
|
|
|
debugLog(os.str());
|
|
|
|
}
|
|
|
|
}
|
2016-03-13 00:37:43 +00:00
|
|
|
return ptex;
|
2015-03-23 23:06:51 +00:00
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2017-01-14 17:10:20 +00:00
|
|
|
void Core::addRenderObject(RenderObject *o, size_t layer)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
if (!o) return;
|
|
|
|
o->layer = layer;
|
2017-01-14 17:10:20 +00:00
|
|
|
if (layer >= renderObjectLayers.size())
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "attempted to add render object to invalid layer [" << layer << "]";
|
|
|
|
errorLog(os.str());
|
|
|
|
}
|
|
|
|
renderObjectLayers[layer].add(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::switchRenderObjectLayer(RenderObject *o, int toLayer)
|
|
|
|
{
|
|
|
|
if (!o) return;
|
|
|
|
renderObjectLayers[o->layer].remove(o);
|
|
|
|
renderObjectLayers[toLayer].add(o);
|
|
|
|
o->layer = toLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::unloadResources()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < resources.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
resources[i]->unload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::onReloadResources()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::reloadResources()
|
|
|
|
{
|
2017-01-14 17:10:20 +00:00
|
|
|
for (size_t i = 0; i < resources.size(); i++)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
|
|
|
resources[i]->reload();
|
|
|
|
}
|
|
|
|
onReloadResources();
|
|
|
|
}
|
|
|
|
|
2015-03-23 23:06:51 +00:00
|
|
|
void Core::addTexture(Texture *r)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
for(size_t i = 0; i < resources.size(); ++i)
|
|
|
|
if(resources[i] == r)
|
|
|
|
return;
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
resources.push_back(r);
|
|
|
|
if (r->name.empty())
|
|
|
|
{
|
|
|
|
debugLog("Empty name resource added");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-23 23:06:51 +00:00
|
|
|
void Core::removeTexture(Texture *res)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
std::vector<Texture*> copy;
|
|
|
|
copy.swap(resources);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
2015-03-23 23:06:51 +00:00
|
|
|
for (size_t i = 0; i < copy.size(); ++i)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
if (copy[i] == res)
|
2011-08-03 20:05:33 +00:00
|
|
|
{
|
2015-03-23 23:06:51 +00:00
|
|
|
copy[i]->destroy();
|
|
|
|
copy[i] = copy.back();
|
|
|
|
copy.pop_back();
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-23 23:06:51 +00:00
|
|
|
|
|
|
|
resources.swap(copy);
|
2011-08-03 20:05:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Core::deleteRenderObjectMemory(RenderObject *r)
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
delete r;
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
deleteRenderObjectMemory(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
BBGE_PROF(Core_clearGarbage);
|
|
|
|
// HACK: optimize this (use a list instead of a queue)
|
|
|
|
|
|
|
|
for (RenderObjectList::iterator i = garbage.begin(); i != garbage.end(); i++)
|
|
|
|
{
|
|
|
|
removeRenderObject(*i, DO_NOT_DESTROY_RENDER_OBJECT);
|
|
|
|
|
|
|
|
(*i)->destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (RenderObjectList::iterator i = garbage.begin(); i != garbage.end(); i++)
|
|
|
|
{
|
|
|
|
deleteRenderObjectMemory(*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
unsigned char *Core::grabScreenshot(int x, int y, int w, int h)
|
|
|
|
{
|
|
|
|
|
|
|
|
unsigned char *imageData;
|
|
|
|
|
|
|
|
unsigned int size = sizeof(unsigned char) * w * h * 4;
|
|
|
|
imageData = new unsigned char[size];
|
|
|
|
|
|
|
|
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;
|
|
|
|
for (int x = 0; x < w; x++)
|
|
|
|
{
|
|
|
|
for (int y = 0; y < h; y++, c += 4)
|
|
|
|
{
|
|
|
|
c[3] = 255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return imageData;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Like grabScreenshot(), but grab from the center of the screen.
|
|
|
|
unsigned char *Core::grabCenteredScreenshot(int w, int h)
|
|
|
|
{
|
|
|
|
return grabScreenshot(core->width/2 - w/2, core->height/2 - h/2, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
// takes a screen shot and saves it to a TGA image
|
|
|
|
int Core::saveScreenshotTGA(const std::string &filename)
|
|
|
|
{
|
|
|
|
int w = getWindowWidth(), h = getWindowHeight();
|
|
|
|
unsigned char *imageData = grabCenteredScreenshot(w, h);
|
|
|
|
return tgaSave(filename.c_str(),w,h,32,imageData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::saveCenteredScreenshotTGA(const std::string &filename, int sz)
|
|
|
|
{
|
|
|
|
int w=sz, h=sz;
|
|
|
|
int hsm = (w * 3.0f) / 4.0f;
|
|
|
|
unsigned char *imageData = grabCenteredScreenshot(w, hsm);
|
|
|
|
|
|
|
|
int imageDataSize = sizeof(unsigned char) * w * hsm * 4;
|
|
|
|
int tgaImageSize = sizeof(unsigned char) * w * h * 4;
|
|
|
|
unsigned char *tgaImage = new unsigned char[tgaImageSize];
|
|
|
|
memcpy(tgaImage, imageData, imageDataSize);
|
|
|
|
memset(tgaImage + imageDataSize, 0, tgaImageSize - imageDataSize);
|
|
|
|
delete[] imageData;
|
|
|
|
|
|
|
|
int savebits = 32;
|
|
|
|
tgaSave(filename.c_str(),w,h,savebits,tgaImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::saveSizedScreenshotTGA(const std::string &filename, int sz, int crop34)
|
|
|
|
{
|
|
|
|
debugLog("saveSizedScreenshot");
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
unsigned char *imageData;
|
|
|
|
w = sz;
|
|
|
|
h = sz;
|
|
|
|
float fsz = (float)sz;
|
|
|
|
|
|
|
|
unsigned int size = sizeof(unsigned char) * w * h * 3;
|
|
|
|
imageData = (unsigned char *)malloc(size);
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
float wbit = fsz;
|
2011-08-03 20:05:33 +00:00
|
|
|
float hbit = ((fsz)*(3.0f/4.0f));
|
|
|
|
|
|
|
|
int width = core->width-1;
|
|
|
|
int height = core->height-1;
|
|
|
|
int diff = 0;
|
|
|
|
|
|
|
|
if (crop34)
|
|
|
|
{
|
|
|
|
width = int((core->height*4.0f)/3.0f);
|
|
|
|
diff = (core->width - width)/2;
|
|
|
|
width--;
|
|
|
|
}
|
|
|
|
|
|
|
|
float zx = wbit/(float)width;
|
|
|
|
float zy = hbit/(float)height;
|
|
|
|
|
|
|
|
float copyw = w*(1/zx);
|
|
|
|
float copyh = h*(1/zy);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "wbit: " << wbit << " hbit: " << hbit << std::endl;
|
|
|
|
os << "zx: " << zx << " zy: " << zy << std::endl;
|
|
|
|
os << "w: " << w << " h: " << h << std::endl;
|
|
|
|
os << "width: " << width << " height: " << height << std::endl;
|
|
|
|
os << "copyw: " << copyw << " copyh: " << copyh << std::endl;
|
|
|
|
debugLog(os.str());
|
|
|
|
|
|
|
|
glRasterPos2i(0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
debugLog("pixel zoom");
|
|
|
|
glPixelZoom(zx,zy);
|
|
|
|
glFlush();
|
|
|
|
|
|
|
|
glPixelZoom(1,1);
|
|
|
|
debugLog("copy pixels");
|
|
|
|
glCopyPixels(diff, 0, width, height, GL_COLOR);
|
|
|
|
glFlush();
|
|
|
|
|
|
|
|
debugLog("read pixels");
|
|
|
|
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)imageData);
|
|
|
|
glFlush();
|
|
|
|
|
|
|
|
int savebits = 24;
|
|
|
|
debugLog("saving bpp");
|
|
|
|
tgaSave(filename.c_str(),w,h,savebits,imageData);
|
|
|
|
|
|
|
|
debugLog("pop");
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
debugLog("done");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::save64x64ScreenshotTGA(const std::string &filename)
|
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
unsigned char *imageData;
|
|
|
|
|
|
|
|
// compute width and heidth of the image
|
|
|
|
//w = xmax - xmin;
|
|
|
|
//h = ymax - ymin;
|
|
|
|
w = 64;
|
|
|
|
h = 64;
|
|
|
|
|
|
|
|
// allocate memory for the pixels
|
|
|
|
imageData = (unsigned char *)malloc(sizeof(unsigned char) * w * h * 4);
|
|
|
|
|
|
|
|
// read the pixels from the frame buffer
|
|
|
|
|
|
|
|
//glReadPixels(xmin,ymin,xmax,ymax,GL_RGBA,GL_UNSIGNED_BYTE, (GLvoid *)imageData);
|
|
|
|
glPixelZoom(64.0f/(float)getVirtualWidth(), 48.0f/(float)getVirtualHeight());
|
|
|
|
glCopyPixels(0, 0, getVirtualWidth(), getVirtualHeight(), GL_COLOR);
|
|
|
|
|
|
|
|
glReadPixels(0,0,64,64,GL_RGBA,GL_UNSIGNED_BYTE, (GLvoid *)imageData);
|
|
|
|
|
|
|
|
|
|
|
|
unsigned char *c = imageData;
|
|
|
|
for (int x=0; x < w; x++)
|
|
|
|
{
|
|
|
|
for (int y=0; y< h; y++)
|
|
|
|
{
|
|
|
|
c += 3;
|
|
|
|
(*c) = 255;
|
|
|
|
c ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// save the image
|
|
|
|
tgaSave(filename.c_str(),64,64,32,imageData);
|
|
|
|
glPixelZoom(1,1);
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
}
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
// saves an array of pixels as a TGA image (frees the image data passed in)
|
|
|
|
int Core::tgaSave( const char *filename,
|
2017-01-14 17:10:20 +00:00
|
|
|
short unsigned int width,
|
|
|
|
short unsigned int height,
|
2011-08-03 20:05:33 +00:00
|
|
|
unsigned char pixelDepth,
|
|
|
|
unsigned char *imageData) {
|
|
|
|
|
|
|
|
unsigned char cGarbage = 0, type,mode,aux;
|
|
|
|
short int iGarbage = 0;
|
|
|
|
int i;
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
// open file and check for errors
|
|
|
|
file = fopen(adjustFilenameCase(filename).c_str(), "wb");
|
|
|
|
if (file == NULL) {
|
2011-11-20 21:58:36 +00:00
|
|
|
delete [] imageData;
|
2011-08-03 20:05:33 +00:00
|
|
|
return (int)false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute image type: 2 for RGB(A), 3 for greyscale
|
|
|
|
mode = pixelDepth / 8;
|
|
|
|
if ((pixelDepth == 24) || (pixelDepth == 32))
|
|
|
|
type = 2;
|
|
|
|
else
|
|
|
|
type = 3;
|
|
|
|
|
|
|
|
// write the header
|
|
|
|
if (fwrite(&cGarbage, sizeof(unsigned char), 1, file) != 1
|
|
|
|
|| fwrite(&cGarbage, sizeof(unsigned char), 1, file) != 1
|
|
|
|
|| fwrite(&type, sizeof(unsigned char), 1, file) != 1
|
|
|
|
|| fwrite(&iGarbage, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&iGarbage, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&cGarbage, sizeof(unsigned char), 1, file) != 1
|
|
|
|
|| fwrite(&iGarbage, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&iGarbage, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&width, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&height, sizeof(short int), 1, file) != 1
|
|
|
|
|| fwrite(&pixelDepth, sizeof(unsigned char), 1, file) != 1
|
|
|
|
|| fwrite(&cGarbage, sizeof(unsigned char), 1, file) != 1)
|
|
|
|
{
|
|
|
|
fclose(file);
|
2011-11-20 21:58:36 +00:00
|
|
|
delete [] imageData;
|
2011-08-03 20:05:33 +00:00
|
|
|
return (int)false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert the image data from RGB(A) to BGR(A)
|
|
|
|
if (mode >= 3)
|
|
|
|
for (i=0; i < width * height * mode ; i+= mode) {
|
|
|
|
aux = imageData[i];
|
|
|
|
imageData[i] = imageData[i+2];
|
|
|
|
imageData[i+2] = aux;
|
|
|
|
}
|
|
|
|
|
|
|
|
// save the image data
|
|
|
|
if (fwrite(imageData, sizeof(unsigned char),
|
|
|
|
width * height * mode, file) != width * height * mode)
|
|
|
|
{
|
|
|
|
fclose(file);
|
2011-11-20 21:58:36 +00:00
|
|
|
delete [] imageData;
|
2011-08-03 20:05:33 +00:00
|
|
|
return (int)false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(file);
|
2011-11-20 21:58:36 +00:00
|
|
|
delete [] imageData;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
return (int)true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// saves a series of files with names "filenameX"
|
|
|
|
int Core::tgaSaveSeries(char *filename,
|
|
|
|
short int width,
|
|
|
|
short int height,
|
|
|
|
unsigned char pixelDepth,
|
|
|
|
unsigned char *imageData) {
|
|
|
|
|
|
|
|
char *newFilename;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
// compute the new filename by adding the
|
|
|
|
// series number and the extension
|
|
|
|
newFilename = (char *)malloc(sizeof(char) * strlen(filename)+8);
|
|
|
|
|
|
|
|
sprintf(newFilename,"%s%d",filename,numSavedScreenshots);
|
|
|
|
|
|
|
|
// save the image
|
|
|
|
status = tgaSave(newFilename,width,height,pixelDepth,imageData);
|
|
|
|
|
|
|
|
//increase the counter
|
|
|
|
if (status == (int)true)
|
|
|
|
numSavedScreenshots++;
|
|
|
|
free(newFilename);
|
|
|
|
return(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Core::screenshot()
|
|
|
|
{
|
|
|
|
doScreenshot = true;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
2011-08-03 20:05:33 +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
|
|
|
|
|
|
|
#include "DeflateCompressor.h"
|
|
|
|
|
|
|
|
// saves an array of pixels as a TGA image (frees the image data passed in)
|
|
|
|
int Core::zgaSave( const char *filename,
|
2017-01-14 17:10:20 +00:00
|
|
|
short unsigned int w,
|
|
|
|
short unsigned int h,
|
[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
|
|
|
unsigned char depth,
|
|
|
|
unsigned char *imageData) {
|
|
|
|
|
|
|
|
ByteBuffer::uint8 type,mode,aux, pixelDepth = depth;
|
|
|
|
ByteBuffer::uint8 cGarbage = 0;
|
|
|
|
ByteBuffer::uint16 iGarbage = 0;
|
|
|
|
ByteBuffer::uint16 width = w, height = h;
|
|
|
|
|
|
|
|
// open file and check for errors
|
|
|
|
FILE *file = fopen(adjustFilenameCase(filename).c_str(), "wb");
|
|
|
|
if (file == NULL) {
|
|
|
|
delete [] imageData;
|
|
|
|
return (int)false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute image type: 2 for RGB(A), 3 for greyscale
|
|
|
|
mode = pixelDepth / 8;
|
|
|
|
if ((pixelDepth == 24) || (pixelDepth == 32))
|
|
|
|
type = 2;
|
|
|
|
else
|
|
|
|
type = 3;
|
|
|
|
|
|
|
|
// convert the image data from RGB(A) to BGR(A)
|
|
|
|
if (mode >= 3)
|
|
|
|
for (int i=0; i < width * height * mode ; i+= mode) {
|
|
|
|
aux = imageData[i];
|
|
|
|
imageData[i] = imageData[i+2];
|
|
|
|
imageData[i+2] = aux;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZlibCompressor z;
|
|
|
|
z.SetForceCompression(true);
|
|
|
|
z.reserve(width * height * mode + 30);
|
|
|
|
z << cGarbage
|
|
|
|
<< cGarbage
|
|
|
|
<< type
|
|
|
|
<< iGarbage
|
|
|
|
<< iGarbage
|
|
|
|
<< cGarbage
|
|
|
|
<< iGarbage
|
|
|
|
<< iGarbage
|
|
|
|
<< width
|
|
|
|
<< height
|
|
|
|
<< pixelDepth
|
|
|
|
<< cGarbage;
|
|
|
|
|
|
|
|
z.append(imageData, width * height * mode);
|
|
|
|
z.Compress(3);
|
|
|
|
|
|
|
|
// save the image data
|
|
|
|
if (fwrite(z.contents(), 1, z.size(), file) != z.size())
|
|
|
|
{
|
|
|
|
fclose(file);
|
|
|
|
delete [] imageData;
|
|
|
|
return (int)false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
delete [] imageData;
|
|
|
|
|
|
|
|
return (int)true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "ttvfs_zip/VFSZipArchiveLoader.h"
|
|
|
|
|
|
|
|
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;
|
|
|
|
std::map<unsigned char, unsigned char> trans;
|
|
|
|
while(in)
|
|
|
|
{
|
|
|
|
in >> low >> up;
|
|
|
|
trans[low[0]] = up[0];
|
|
|
|
}
|
|
|
|
initCharTranslationTables(trans);
|
|
|
|
}
|
|
|
|
|