mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-25 09:44:02 +00:00
13eca9785f
This commit is mainly intended to ease packaging for linux. Unless environment variable AQUARIA_DATA_PATH is set, there are two directories which are checked by the game: If AQUARIA_DEFAULT_DATA_DIR is defined, it will chdir there for main operation. If it's not defined, it chdirs into the directory where the executable is located. Then, if AQUARIA_EXTRA_DATA_DIR is defined, it will mount this directory and all contents into the working path, so that the files present there will override those from the working directory when accessed by the game. Setting the environment variable AQUARIA_DATA_PATH will disable this behavior altogether and use *only* AQUARIA_DATA_PATH as working dir.
4876 lines
104 KiB
C++
4876 lines
104 KiB
C++
/*
|
|
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>
|
|
#include <iostream>
|
|
|
|
#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
|
|
|
|
#if BBGE_BUILD_WINDOWS
|
|
#include <shlobj.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
#include "SDL_syswm.h"
|
|
static SDL_Surface *gScreen=0;
|
|
bool ignoreNextMouse=false;
|
|
Vector unchange;
|
|
#endif
|
|
|
|
Core *core = 0;
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
HICON icon_windows = 0;
|
|
#endif
|
|
|
|
void Core::initIcon()
|
|
{
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
HINSTANCE handle = ::GetModuleHandle(NULL);
|
|
//if (icon_windows)
|
|
// ::DestroyIcon(icon_windows);
|
|
|
|
icon_windows = ::LoadIcon(handle, "icon");
|
|
|
|
SDL_SysWMinfo wminfo;
|
|
SDL_VERSION(&wminfo.version)
|
|
if (SDL_GetWMInfo(&wminfo) != 1)
|
|
{
|
|
//errorLog("wrong SDL version");
|
|
// error: wrong SDL version
|
|
}
|
|
|
|
HWND hwnd = wminfo.window;
|
|
|
|
::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()
|
|
{
|
|
for (int i = 0; i < renderObjectLayers.size(); i++)
|
|
{
|
|
RenderObjectLayer *r = &renderObjectLayers[i];
|
|
RenderObject *robj = r->getFirst();
|
|
while (robj)
|
|
{
|
|
robj->unloadDevice();
|
|
robj = r->getNext();
|
|
}
|
|
}
|
|
frameBuffer.unloadDevice();
|
|
|
|
if (afterEffectManager)
|
|
afterEffectManager->unloadDevice();
|
|
}
|
|
|
|
void Core::reloadDevice()
|
|
{
|
|
for (int i = 0; i < renderObjectLayers.size(); i++)
|
|
{
|
|
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);
|
|
|
|
enable2DWide(w, h);
|
|
|
|
reloadResources();
|
|
reloadDevice();
|
|
|
|
|
|
resetTimer();
|
|
}
|
|
|
|
void Core::toggleScreenMode(int t)
|
|
{
|
|
#ifdef BBGE_BUILD_GLFW
|
|
/*
|
|
glfwCloseWindow();
|
|
|
|
createWindow(800,600,32,false,"");
|
|
initGraphicsLibrary(false, true);
|
|
enable2D(800);
|
|
//reloadResources();
|
|
*/
|
|
#endif
|
|
#ifdef BBGE_BUILD_SDL
|
|
sound->pause();
|
|
resetGraphics(-1, -1, t);
|
|
cacheRender();
|
|
resetTimer();
|
|
sound->resume();
|
|
#endif
|
|
}
|
|
|
|
void Core::updateCursorFromJoystick(float dt, int spd)
|
|
{
|
|
//debugLog("updating mouse from joystick");
|
|
|
|
core->mouse.position += joystick.position*dt*spd;
|
|
|
|
/*
|
|
if (!joystick.position.isZero())
|
|
setMousePosition(core->mouse.position);
|
|
*/
|
|
|
|
doMouseConstraint();
|
|
}
|
|
|
|
void Core::setWindowCaption(const std::string &caption, const std::string &icon)
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_WM_SetCaption(caption.c_str(), icon.c_str());
|
|
#endif
|
|
}
|
|
|
|
RenderObjectLayer *Core::getRenderObjectLayer(int i)
|
|
{
|
|
if (i == LR_NONE)
|
|
return 0;
|
|
return &renderObjectLayers[i];
|
|
}
|
|
|
|
#if defined(BBGE_BUILD_WINDOWS) && !defined(BBGE_BUILD_SDL)
|
|
LPDIRECTINPUT8 g_pDI = NULL; // The DirectInput object
|
|
LPDIRECTINPUTDEVICE8 g_pKeyboard = NULL; // The keyboard device
|
|
LPDIRECTINPUTDEVICE8 g_pMouse = NULL;
|
|
|
|
D3DCOLOR d3dColor =0xFFFFFFFF;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
|
|
__int64 timerStart=0, timerEnd=0, timerFreq=0;
|
|
//Direct3D 9 interface
|
|
IDirect3D9* d3d = NULL;
|
|
//Capabilities of graphics adapter
|
|
D3DCAPS9 d3dCaps;
|
|
|
|
//Direct3D present parameters
|
|
D3DPRESENT_PARAMETERS d3dPresent;
|
|
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
|
|
LPD3DXSPRITE d3dSprite = NULL;
|
|
LPD3DXMATRIXSTACK d3dMatrixStack = NULL;
|
|
IDirect3DVertexBuffer9* vertexBuffer = NULL;
|
|
IDirect3DVertexBuffer9* preTransVertexBuffer = NULL;
|
|
|
|
//Custom vertex
|
|
struct TLVERTEX
|
|
{
|
|
float x;
|
|
float y;
|
|
float z;
|
|
//float rhw;
|
|
D3DCOLOR colour;
|
|
float u;
|
|
float v;
|
|
};
|
|
const DWORD D3DFVF_TLVERTEX = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
|
struct PTLVERTEX
|
|
{
|
|
float x;
|
|
float y;
|
|
float z;
|
|
float rhw;
|
|
D3DCOLOR colour;
|
|
float u;
|
|
float v;
|
|
};
|
|
|
|
const DWORD D3DFVF_PTLVERTEX = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
/*
|
|
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
|
|
LPDIRECT3DTEXTURE9 g_pTexture = NULL; // Our texture
|
|
*/
|
|
// A structure for our custom vertex type
|
|
struct CUSTOMVERTEX
|
|
{
|
|
FLOAT x, y, z, rhw; // The transformed position for the vertex
|
|
DWORD color; // The vertex color
|
|
};
|
|
|
|
// Our custom FVF, which describes our custom vertex structure
|
|
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
|
|
|
|
LPD3DXMATRIXSTACK Core::getD3DMatrixStack()
|
|
{
|
|
return d3dMatrixStack;
|
|
}
|
|
|
|
LPDIRECT3DDEVICE9 Core::getD3DDevice()
|
|
{
|
|
return g_pd3dDevice;
|
|
}
|
|
|
|
LPD3DXSPRITE Core::getD3DSprite()
|
|
{
|
|
return d3dSprite;
|
|
}
|
|
|
|
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( msg )
|
|
{
|
|
case WM_DESTROY:
|
|
//Cleanup();
|
|
PostQuitMessage( 0 );
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProc( hWnd, msg, wParam, lParam );
|
|
}
|
|
void Core::blitD3DVerts(IDirect3DTexture9 *texture, float v1x, float v1y, float v2x, float v2y, float v3x, float v3y, float v4x, float v4y)
|
|
{
|
|
TLVERTEX* vertices;
|
|
|
|
//Lock the vertex buffer
|
|
vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
|
|
vertices[0].colour = d3dColor;
|
|
vertices[0].x = v1x;
|
|
vertices[0].y = v1y;
|
|
vertices[0].z = 1.0f;
|
|
vertices[0].u = 0.0f;
|
|
vertices[0].v = 1.0f-1.0f;
|
|
|
|
vertices[1].colour = d3dColor;
|
|
vertices[1].x = v2x;
|
|
vertices[1].y = v2y;
|
|
vertices[1].z = 1.0f;
|
|
vertices[1].u = 1.0f;
|
|
vertices[1].v = 1.0f-1.0f;
|
|
|
|
vertices[2].colour = d3dColor;
|
|
vertices[2].x = v3x;
|
|
vertices[2].y = v3y;
|
|
vertices[2].z = 1.0f;
|
|
vertices[2].u = 1.0f;
|
|
vertices[2].v = 1.0f-0.0f;
|
|
|
|
vertices[3].colour = d3dColor;
|
|
vertices[3].x = v4x;
|
|
vertices[3].y = v4y;
|
|
vertices[3].z = 1.0f;
|
|
vertices[3].u = 0.0f;
|
|
vertices[3].v = 1.0f-0.0f;
|
|
//Unlock the vertex buffer
|
|
vertexBuffer->Unlock();
|
|
|
|
//Set texture
|
|
g_pd3dDevice->SetTexture (0, texture);
|
|
|
|
//Draw image
|
|
g_pd3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
|
|
}
|
|
|
|
void Core::blitD3DEx (IDirect3DTexture9 *texture, int w2, int h2, float u1, float v1, float u2, float v2)
|
|
{
|
|
TLVERTEX* vertices;
|
|
|
|
/*
|
|
int w2=width/2;
|
|
int h2=height/2;
|
|
*/
|
|
//Lock the vertex buffer
|
|
vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
|
|
//Setup vertices
|
|
//A -0.5f modifier is applied to vertex coordinates to match texture
|
|
//and screen coords. Some drivers may compensate for this
|
|
//automatically, but on others texture alignment errors are introduced
|
|
//More information on this can be found in the Direct3D 9 documentation
|
|
vertices[0].colour = d3dColor;
|
|
vertices[0].x = -0.5f*w2;
|
|
vertices[0].y = -0.5f*h2;
|
|
vertices[0].z = 1.0f;
|
|
//vertices[0].rhw = 1.0f;
|
|
vertices[0].u = u1;
|
|
vertices[0].v = 1.0f-v2;
|
|
|
|
vertices[1].colour = d3dColor;
|
|
vertices[1].x = 0.5f*w2;
|
|
vertices[1].y = -0.5f*h2;
|
|
vertices[1].z = 1.0f;
|
|
//vertices[1].rhw = 1.0f;
|
|
vertices[1].u = u2;
|
|
vertices[1].v = 1.0f-v2;
|
|
|
|
vertices[2].colour = d3dColor;
|
|
vertices[2].x = 0.5f*w2;
|
|
vertices[2].y = 0.5f*h2;
|
|
vertices[2].z = 1.0f;
|
|
//vertices[2].rhw = 1.0f;
|
|
vertices[2].u = u2;
|
|
vertices[2].v = 1.0f-v1;
|
|
|
|
vertices[3].colour = d3dColor;
|
|
vertices[3].x = -0.5f*w2;
|
|
vertices[3].y = 0.5f*h2;
|
|
vertices[3].z = 1.0f;
|
|
//vertices[3].rhw = 1.0f;
|
|
vertices[3].u = u1;
|
|
vertices[3].v = 1.0f-v1;
|
|
//Unlock the vertex buffer
|
|
vertexBuffer->Unlock();
|
|
|
|
//Set texture
|
|
g_pd3dDevice->SetTexture (0, texture);
|
|
|
|
//Draw image
|
|
g_pd3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
|
|
}
|
|
|
|
void Core::blitD3DGradient(D3DCOLOR ulc0, D3DCOLOR ulc1, D3DCOLOR ulc2, D3DCOLOR ulc3)
|
|
{
|
|
TLVERTEX* vertices;
|
|
|
|
//Lock the vertex buffer
|
|
vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
vertices[0].colour = ulc0;
|
|
vertices[0].x = -0.5f;
|
|
vertices[0].y = -0.5f;
|
|
vertices[0].z = 1.0f;
|
|
//vertices[0].rhw = 1.0f;
|
|
vertices[0].u = 0.0f;
|
|
vertices[0].v = 1.0f-1.0f;
|
|
|
|
vertices[1].colour = ulc1;
|
|
vertices[1].x = 0.5f;
|
|
vertices[1].y = -0.5f;
|
|
vertices[1].z = 1.0f;
|
|
//vertices[1].rhw = 1.0f;
|
|
vertices[1].u = 1.0f;
|
|
vertices[1].v = 1.0f-1.0f;
|
|
|
|
vertices[2].colour = ulc2;
|
|
vertices[2].x = 0.5f;
|
|
vertices[2].y = 0.5f;
|
|
vertices[2].z = 1.0f;
|
|
//vertices[2].rhw = 1.0f;
|
|
vertices[2].u = 1.0f;
|
|
vertices[2].v = 1.0f-0.0f;
|
|
|
|
vertices[3].colour = ulc3;
|
|
vertices[3].x = -0.5f;
|
|
vertices[3].y = 0.5f;
|
|
vertices[3].z = 1.0f;
|
|
//vertices[3].rhw = 1.0f;
|
|
vertices[3].u = 0.0f;
|
|
vertices[3].v = 1.0f-0.0f;
|
|
//Unlock the vertex buffer
|
|
vertexBuffer->Unlock();
|
|
|
|
//Set texture
|
|
//g_pd3dDevice->SetTexture (0, texture);
|
|
g_pd3dDevice->SetTexture (0, 0);
|
|
|
|
//Draw image
|
|
g_pd3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
|
|
}
|
|
|
|
void Core::blitD3DPreTrans(IDirect3DTexture9 *texture, float x, float y, int w2, int h2)
|
|
{
|
|
/*
|
|
PTLVERTEX* vertices;
|
|
//Lock the vertex buffer
|
|
preTransVertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
*/
|
|
TLVERTEX* vertices;
|
|
//Lock the vertex buffer
|
|
vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
|
|
|
|
//Setup vertices
|
|
//A -0.5f modifier is applied to vertex coordinates to match texture
|
|
//and screen coords. Some drivers may compensate for this
|
|
//automatically, but on others texture alignment errors are introduced
|
|
//More information on this can be found in the Direct3D 9 documentation
|
|
vertices[0].colour = d3dColor;
|
|
vertices[0].x = x-0.5f*w2;
|
|
vertices[0].y = y-0.5f*h2;
|
|
vertices[0].z = 1.0f;
|
|
//vertices[0].rhw = 1.0f;
|
|
vertices[0].u = 0.0f;
|
|
vertices[0].v = 1.0f-1.0f;
|
|
|
|
vertices[1].colour = d3dColor;
|
|
vertices[1].x = x+0.5f*w2;
|
|
vertices[1].y = y-0.5f*h2;
|
|
vertices[1].z = 1.0f;
|
|
//vertices[1].rhw = 1.0f;
|
|
vertices[1].u = 1.0f;
|
|
vertices[1].v = 1.0f-1.0f;
|
|
|
|
vertices[2].colour = d3dColor;
|
|
vertices[2].x = x+0.5f*w2;
|
|
vertices[2].y = y+0.5f*h2;
|
|
vertices[2].z = 1.0f;
|
|
//vertices[2].rhw = 1.0f;
|
|
vertices[2].u = 1.0f;
|
|
vertices[2].v = 1.0f-0.0f;
|
|
|
|
vertices[3].colour = d3dColor;
|
|
vertices[3].x = x-0.5f*w2;
|
|
vertices[3].y = y+0.5f*h2;
|
|
vertices[3].z = 1.0f;
|
|
//vertices[3].rhw = 1.0f;
|
|
vertices[3].u = 0.0f;
|
|
vertices[3].v = 1.0f-0.0f;
|
|
/*
|
|
//Unlock the vertex buffer
|
|
preTransVertexBuffer->Unlock();
|
|
*/
|
|
vertexBuffer->Unlock();
|
|
|
|
|
|
//Set texture
|
|
g_pd3dDevice->SetTexture (0, texture);
|
|
|
|
//Draw image
|
|
g_pd3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
|
|
}
|
|
void Core::blitD3D (IDirect3DTexture9 *texture, int w2, int h2)
|
|
{
|
|
TLVERTEX* vertices;
|
|
//D3DCOLOR d3dColor = 0xFFFFFFFF;
|
|
|
|
/*
|
|
int w2=width/2;
|
|
int h2=height/2;
|
|
*/
|
|
//Lock the vertex buffer
|
|
vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);
|
|
|
|
//Setup verticeserr
|
|
//A -0.5f modifier is applied to vertex coordinates to match texture
|
|
//and screen coords. Some drivers may compensate for this
|
|
//automatically, but on others texture alignment ors are introduced
|
|
//More information on this can be found in the Direct3D 9 documentation
|
|
vertices[0].colour = d3dColor;
|
|
vertices[0].x = -0.5f*w2;
|
|
vertices[0].y = -0.5f*h2;
|
|
vertices[0].z = 1.0f;
|
|
//vertices[0].rhw = 1.0f;
|
|
vertices[0].u = 0.0f;
|
|
vertices[0].v = 1.0f-1.0f;
|
|
|
|
vertices[1].colour = d3dColor;
|
|
vertices[1].x = 0.5f*w2;
|
|
vertices[1].y = -0.5f*h2;
|
|
vertices[1].z = 1.0f;
|
|
//vertices[1].rhw = 1.0f;
|
|
vertices[1].u = 1.0f;
|
|
vertices[1].v = 1.0f-1.0f;
|
|
|
|
vertices[2].colour = d3dColor;
|
|
vertices[2].x = 0.5f*w2;
|
|
vertices[2].y = 0.5f*h2;
|
|
vertices[2].z = 1.0f;
|
|
//vertices[2].rhw = 1.0f;
|
|
vertices[2].u = 1.0f;
|
|
vertices[2].v = 1.0f-0.0f;
|
|
|
|
vertices[3].colour = d3dColor;
|
|
vertices[3].x = -0.5f*w2;
|
|
vertices[3].y = 0.5f*h2;
|
|
vertices[3].z = 1.0f;
|
|
//vertices[3].rhw = 1.0f;
|
|
vertices[3].u = 0.0f;
|
|
vertices[3].v = 1.0f-0.0f;
|
|
//Unlock the vertex buffer
|
|
vertexBuffer->Unlock();
|
|
|
|
//Set texture
|
|
g_pd3dDevice->SetTexture (0, texture);
|
|
|
|
//Draw image
|
|
g_pd3dDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
|
|
}
|
|
|
|
HRESULT InitD3D( HWND hWnd, bool fullscreen, int vsync)
|
|
{
|
|
// Create the D3D object.
|
|
HRESULT hr;
|
|
|
|
//Make Direct3D object
|
|
d3d = Direct3DCreate9(D3D_SDK_VERSION);
|
|
|
|
//Make sure NULL pointer was not returned
|
|
if (!d3d)
|
|
return FALSE;
|
|
|
|
//Get device capabilities
|
|
ZeroMemory (&d3dCaps, sizeof(d3dCaps));
|
|
if (FAILED(d3d->GetDeviceCaps (D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps)))
|
|
return FALSE;
|
|
|
|
//Setup present parameters
|
|
ZeroMemory(&d3dPresent,sizeof(d3dPresent));
|
|
d3dPresent.hDeviceWindow = hWnd;
|
|
|
|
//Check if windowed
|
|
if (!fullscreen)
|
|
{
|
|
D3DDISPLAYMODE d3ddm;
|
|
RECT rWindow;
|
|
|
|
//Get display mode
|
|
d3d->GetAdapterDisplayMode (D3DADAPTER_DEFAULT, &d3ddm);
|
|
|
|
//Get window bounds
|
|
GetClientRect (hWnd, &rWindow);
|
|
|
|
//Setup screen dimensions
|
|
core->width = rWindow.right - rWindow.left;
|
|
core->height = rWindow.bottom - rWindow.top;
|
|
|
|
//Setup backbuffer
|
|
d3dPresent.Windowed = true;
|
|
d3dPresent.BackBufferWidth = rWindow.right - rWindow.left;
|
|
d3dPresent.BackBufferHeight = rWindow.bottom - rWindow.top;
|
|
}
|
|
else
|
|
{
|
|
d3dPresent.Windowed = false;
|
|
d3dPresent.BackBufferWidth = core->width;
|
|
d3dPresent.BackBufferHeight = core->height;
|
|
}
|
|
d3dPresent.BackBufferFormat = D3DFMT_A8R8G8B8;
|
|
d3dPresent.BackBufferCount = 1;
|
|
d3dPresent.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
|
|
if (vsync>0)
|
|
d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
|
|
else
|
|
d3dPresent.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
|
|
|
|
//Check if hardware vertex processing is available
|
|
if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
|
|
{
|
|
debugLog("hardware T&L!");
|
|
//Create device with hardware vertex processing
|
|
hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd,
|
|
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dPresent, &g_pd3dDevice);
|
|
}
|
|
else
|
|
{
|
|
debugLog("no hardware T&L.");
|
|
//Create device with software vertex processing
|
|
hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd,
|
|
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dPresent, &g_pd3dDevice);
|
|
}
|
|
|
|
//Make sure device was created
|
|
if (FAILED(hr))
|
|
{
|
|
errorLog ("directx init failed");
|
|
return false;
|
|
}
|
|
|
|
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
// Turn off culling
|
|
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
|
|
/*
|
|
D3DCULL_NONE = 1,
|
|
D3DCULL_CW = 2,
|
|
D3DCULL_CCW = 3,
|
|
*/
|
|
// Turn off D3D lighting
|
|
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
|
|
// Turn on the zbuffer
|
|
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE);
|
|
|
|
D3DXCreateSprite(core->getD3DDevice(), &d3dSprite);
|
|
D3DXCreateMatrixStack(0, &d3dMatrixStack);
|
|
|
|
//Set vertex shader
|
|
g_pd3dDevice->SetVertexShader(NULL);
|
|
g_pd3dDevice->SetFVF(D3DFVF_TLVERTEX);
|
|
|
|
//Create vertex buffer
|
|
g_pd3dDevice->CreateVertexBuffer(sizeof(TLVERTEX) * 4, NULL, D3DFVF_TLVERTEX, D3DPOOL_MANAGED, &vertexBuffer, NULL);
|
|
g_pd3dDevice->SetStreamSource(0, vertexBuffer, 0, sizeof(TLVERTEX));
|
|
|
|
/*
|
|
g_pd3dDevice->CreateVertexBuffer(sizeof(PTLVERTEX) * 4, NULL, D3DFVF_TLVERTEX, D3DPOOL_MANAGED, &preTransVertexBuffer, NULL);
|
|
g_pd3dDevice->SetStreamSource(0, preTransVertexBuffer, 0, sizeof(PTLVERTEX));
|
|
*/
|
|
|
|
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
|
|
|
|
g_pd3dDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
|
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
|
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
|
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
|
|
|
|
void Core::setColor(float r, float g, float b, float a)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glColor4f(r, g, b, a);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
d3dColor = D3DCOLOR_RGBA(int(r*255), int(g*255), int(b*255), int(a*255));
|
|
#endif
|
|
}
|
|
|
|
void Core::bindTexture(int stage, unsigned int handle)
|
|
{
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
getD3DDevice()->SetTexture(stage, (IDirect3DBaseTexture9*)handle);
|
|
#endif
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
//glBindTexture(GL_TEXTURE_2D, handle);
|
|
#endif
|
|
}
|
|
|
|
void Core::translateMatrixStack(float x, float y, float z)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glTranslatef(x, y, z);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
/*
|
|
D3DXMATRIX matTranslation;
|
|
D3DXMatrixTranslation (&matTranslation, x, y, 0);
|
|
*/
|
|
/*
|
|
float usex, usey;
|
|
usex = x - (float)core->getWindowWidth() / 2;
|
|
usey = -y + (float)core->getWindowHeight() / 2;
|
|
*/
|
|
//core->getD3DMatrixStack()->MultMatrixLocal(&matTranslation);
|
|
core->getD3DMatrixStack()->TranslateLocal(x, y, z);
|
|
#endif
|
|
}
|
|
|
|
void Core::scaleMatrixStack(float x, float y, float z)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glScalef(x, y, z);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
if (x != 1 || y != 1)
|
|
core->getD3DMatrixStack()->ScaleLocal(x, y, 1);
|
|
#endif
|
|
}
|
|
|
|
void Core::rotateMatrixStack(float x, float y, float z)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glRotatef(0, 0, 1, z);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
if (z != 0)
|
|
{
|
|
D3DXVECTOR3 axis(0,0,1);
|
|
core->getD3DMatrixStack()->RotateAxisLocal(&axis,D3DXToRadian(z));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Core::applyMatrixStackToWorld()
|
|
{
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
g_pd3dDevice->SetTransform(D3DTS_WORLD, core->getD3DMatrixStack()->GetTop());
|
|
#endif
|
|
}
|
|
|
|
void Core::rotateMatrixStack(float z)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glRotatef(0, 0, 1, z);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
//core->getD3DMatrixStack()->RotateAxis(0, 0, z);
|
|
/*
|
|
D3DXVECTOR3 axis(0,0,1);
|
|
float angle = D3DXToRadian(z);
|
|
if (angle == D3DX_PI)
|
|
angle += 0.001f;
|
|
core->getD3DMatrixStack()->RotateAxisLocal(&axis,angle);
|
|
*/
|
|
if (z != 0)
|
|
{
|
|
D3DXMATRIX mat;
|
|
D3DXMatrixRotationZ(&mat,D3DXToRadian(z));
|
|
core->getD3DMatrixStack()->MultMatrixLocal(&mat);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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)
|
|
{
|
|
messageBox("Message", s);
|
|
debugLog(s);
|
|
}
|
|
|
|
#if defined(BBGE_BUILD_MACOSX)
|
|
void cocoaMessageBox(const std::string &title, const std::string &msg);
|
|
#endif
|
|
|
|
void Core::messageBox(const std::string &title, const std::string &msg)
|
|
{
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
MessageBox (0,msg.c_str(),title.c_str(),MB_OK);
|
|
#elif defined(BBGE_BUILD_MACOSX)
|
|
cocoaMessageBox(title, msg);
|
|
#elif defined(BBGE_BUILD_UNIX)
|
|
// !!! FIXME: probably don't want the whole GTK+ dependency in here...
|
|
fprintf(stderr, "%s: %s\n", title.c_str(), msg.c_str());
|
|
#else
|
|
#error Please define your platform.
|
|
#endif
|
|
}
|
|
|
|
void Core::debugLog(const std::string &s)
|
|
{
|
|
if (debugLogActive)
|
|
{
|
|
_logOut << s << std::endl;
|
|
}
|
|
#ifdef _DEBUG
|
|
std::cout << s << std::endl;
|
|
#endif
|
|
}
|
|
|
|
#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
|
|
|
|
|
|
const float SORT_DELAY = 10;
|
|
Core::Core(const std::string &filesystem, const std::string& extraDataDir, int numRenderLayers, const std::string &appName, int particleSize, std::string userDataSubFolder)
|
|
: ActionMapper(), StateManager(), appName(appName)
|
|
{
|
|
sound = NULL;
|
|
screenCapScale = Vector(1,1,1);
|
|
timeUpdateType = TIMEUPDATE_DYNAMIC;
|
|
_extraDataDir = extraDataDir;
|
|
|
|
fixedFPS = 60;
|
|
|
|
if (userDataSubFolder.empty())
|
|
userDataSubFolder = appName;
|
|
|
|
#if defined(BBGE_BUILD_UNIX)
|
|
const char *envr = getenv("HOME");
|
|
if (envr == NULL)
|
|
envr = "."; // oh well.
|
|
const std::string home(envr);
|
|
|
|
mkdir(home.c_str(), 0700); // just in case.
|
|
|
|
// "/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;
|
|
mkdir(userDataFolder.c_str(), 0700);
|
|
debugLogPath = userDataFolder + "/";
|
|
mkdir((userDataFolder + "/screenshots").c_str(), 0700);
|
|
std::string prefpath(getPreferencesFolder());
|
|
mkdir(prefpath.c_str(), 0700);
|
|
#else
|
|
debugLogPath = "";
|
|
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
|
|
{
|
|
puts("Working directory is not writeable...");
|
|
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());
|
|
CreateDirectoryA(userDataFolder.c_str(), NULL);
|
|
checkWritable(userDataFolder, true, true);
|
|
}
|
|
else
|
|
puts("Failed to retrieve appdata path, using working dir."); // too bad, but can't do anything about it
|
|
}
|
|
*/
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
_logOut.open((debugLogPath + "debug.log").c_str());
|
|
debugLogActive = true;
|
|
|
|
debugLogTextures = true;
|
|
|
|
grabInputOnReentry = -1;
|
|
|
|
srand(time(NULL));
|
|
old_dt = 0;
|
|
|
|
aspectX = 4;
|
|
aspectY = 3;
|
|
|
|
virtualOffX = virtualOffY = 0;
|
|
vw2 = 0;
|
|
vh2 = 0;
|
|
|
|
viewOffX = viewOffY = 0;
|
|
|
|
/*
|
|
aspectX = 1440; //4.0f;
|
|
aspectY = 900; //3.0f;
|
|
*/
|
|
|
|
particleManager = new ParticleManager(particleSize);
|
|
#ifdef BBGE_BUILD_SDL
|
|
nowTicks = thenTicks = 0;
|
|
#endif
|
|
_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;
|
|
sortFlag = true;
|
|
sortTimer = SORT_DELAY;
|
|
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;
|
|
}
|
|
|
|
aspect = (aspectX/aspectY);//320.0f/240.0f;
|
|
//1.3333334f;
|
|
|
|
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();
|
|
//CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
|
|
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));
|
|
if ( (rc == -1) || (rc >= sizeof (path)) )
|
|
{
|
|
// 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
|
|
if(filesystem.length())
|
|
{
|
|
if(_chdir(filesystem.c_str()) != 0)
|
|
{
|
|
debugLog("chdir failed: " + filesystem);
|
|
}
|
|
}
|
|
// 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",
|
|
_buf, buf, rc ? "found" : "not found");
|
|
}
|
|
#endif
|
|
|
|
return std::string(buf);
|
|
#else
|
|
return std::string(_buf);
|
|
#endif
|
|
}
|
|
|
|
|
|
Core::~Core()
|
|
{
|
|
if (particleManager)
|
|
{
|
|
delete particleManager;
|
|
}
|
|
if (sound)
|
|
{
|
|
delete sound;
|
|
sound = 0;
|
|
}
|
|
debugLog("~Core()");
|
|
_logOut.close();
|
|
core = 0;
|
|
}
|
|
|
|
bool Core::hasFocus()
|
|
{
|
|
return _hasFocus;
|
|
}
|
|
|
|
void Core::setInputGrab(bool on)
|
|
{
|
|
if (isWindowFocus())
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_WM_GrabInput(on?SDL_GRAB_ON:SDL_GRAB_OFF);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
setupFileAccess();
|
|
|
|
flags.set(CF_CLEARBUFFERS);
|
|
quitNestedMainFlag = false;
|
|
#ifdef BBGE_BUILD_GLFW
|
|
if (!glfwInit())
|
|
exit(0);
|
|
#endif
|
|
#ifdef BBGE_BUILD_SDL
|
|
// 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");
|
|
|
|
if((SDL_Init(0))==-1)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
#endif
|
|
/*
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
if (!glfwInit())
|
|
exit(0);
|
|
#endif
|
|
*/
|
|
loopDone = false;
|
|
clearedGarbageFlag = false;
|
|
|
|
initInputCodeMap();
|
|
|
|
//glfwSetWindowSizeCallback(lockWindowSize);
|
|
}
|
|
|
|
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()
|
|
{
|
|
return core->cameraPos + mouse.position * Vector(1/core->globalScale.x, 1/core->globalScale.y, 1);
|
|
}
|
|
|
|
Vector Core::getGamePosition(const Vector &v)
|
|
{
|
|
return core->cameraPos + (v * Vector(1/core->globalScale.x, 1/core->globalScale.y, 1));
|
|
}
|
|
|
|
bool Core::getMouseButtonState(int m)
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
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);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool Core::getKeyState(int k)
|
|
{
|
|
#ifdef BBGE_BUILD_GLFW
|
|
return glfwGetKey(k)==GLFW_PRESS;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
if (k >= KEY_MAXARRAY || k < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return keys[k];
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
if (k >= KEY_MAXARRAY || k < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return keys[k];
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
//#ifdef BBGE_BUILD_DIRECTX
|
|
|
|
//float sensitivity = 1.0;
|
|
|
|
Vector joychange;
|
|
Vector lastjoy;
|
|
void readJoystickData()
|
|
{
|
|
/*
|
|
if (core->joystickEnabled && core->numJoysticks > 0)
|
|
{
|
|
//DIJOYSTATE2 js;
|
|
core->joysticks[0]->poll(&core->joystate);
|
|
|
|
Vector joy = Vector(core->joystate.lX, core->joystate.lY);
|
|
joychange = joy-lastjoy;
|
|
lastjoy = joy;
|
|
core->joystickPosition = Vector(core->joystate.lX - (65536/2), core->joystate.lY - (65536/2));
|
|
core->joystickPosition /= (65536/2);
|
|
|
|
// HACK: super hacky!!
|
|
core->mouse.buttons.left = (core->joystate.rgbButtons[0] & 0x80) ? Buttons::DOWN : Buttons::UP;
|
|
core->mouse.buttons.right = (core->joystate.rgbButtons[1] & 0x80) ? Buttons::DOWN : Buttons::UP;
|
|
}
|
|
*/
|
|
}
|
|
|
|
void readMouseData()
|
|
{
|
|
#if defined(BBGE_BUILD_WINDOWS) && !defined(BBGE_BUILD_SDL)
|
|
if (!core->updateMouse) return;
|
|
HRESULT hr;
|
|
DIMOUSESTATE2 dims2; // DirectInput Mouse state structure
|
|
|
|
if( NULL == g_pMouse )
|
|
return;
|
|
|
|
// Get the input's device state, and put the state in dims
|
|
ZeroMemory( &dims2, sizeof(dims2) );
|
|
hr = g_pMouse->GetDeviceState( sizeof(DIMOUSESTATE2), &dims2 );
|
|
if( FAILED(hr) )
|
|
{
|
|
// DirectInput may be telling us that the input stream has been
|
|
// interrupted. We aren't tracking any state between polls, so
|
|
// we don't have any special reset that needs to be done.
|
|
// We just re-acquire and try again.
|
|
|
|
// If input is lost then acquire and keep trying
|
|
hr = g_pMouse->Acquire();
|
|
while( hr == DIERR_INPUTLOST )
|
|
hr = g_pMouse->Acquire();
|
|
|
|
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
|
|
// may occur when the app is minimized or in the process of
|
|
// switching, so just try again later
|
|
return;
|
|
}
|
|
|
|
//float sensitivity = float(core->width) / float(core->getVirtualWidth());
|
|
float sensitivity = 1;
|
|
core->mouse.position.x += dims2.lX*sensitivity;
|
|
core->mouse.position.y += dims2.lY*sensitivity;
|
|
core->mouse.position.z += dims2.lZ;
|
|
core->mouse.change.x = dims2.lX*sensitivity;
|
|
core->mouse.change.y = dims2.lY*sensitivity;
|
|
core->mouse.change.z = dims2.lZ;
|
|
core->mouse.scrollWheelChange = dims2.lZ;
|
|
if (!core->flipMouseButtons)
|
|
{
|
|
core->mouse.buttons.left = (dims2.rgbButtons[0] & 0x80) ? DOWN : UP;
|
|
core->mouse.buttons.right = (dims2.rgbButtons[1] & 0x80) ? DOWN : UP;
|
|
}
|
|
else
|
|
{
|
|
core->mouse.buttons.left = (dims2.rgbButtons[1] & 0x80) ? DOWN : UP;
|
|
core->mouse.buttons.right = (dims2.rgbButtons[0] & 0x80) ? DOWN : UP;
|
|
}
|
|
core->mouse.buttons.middle = (dims2.rgbButtons[2] & 0x80) ? DOWN : UP;
|
|
|
|
#elif defined(BBGE_BUILD_SDL)
|
|
//core->mouse.position += dMouse;
|
|
#elif defined(BBGE_BUILD_GLFW)
|
|
//HACK: may not always want 800x600 virtual
|
|
/*
|
|
static int lastx=400, lasty=300;
|
|
int x, y;
|
|
glfwGetMousePos(&x,&y);
|
|
int mickeyx,mickeyy;
|
|
mickeyx = x - lastx;
|
|
mickeyy = y - lasty;
|
|
lastx = x;
|
|
lasty = y;
|
|
core->mouse.position.x += mickeyx;
|
|
core->mouse.position.y += mickeyy;
|
|
*/
|
|
|
|
int x,y;
|
|
glfwGetMousePos(&x,&y);
|
|
core->mouse.position = Vector(x, y);
|
|
|
|
|
|
/*
|
|
int mid_x = core->width / 2;
|
|
int mid_y = core->height / 2;
|
|
int dx=0,dy=0;
|
|
int x,y;
|
|
glfwGetMousePos(&x, &y);
|
|
// Don't do anything if mouse hasn't moved
|
|
if (x == mid_x && y == mid_y)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
dx = x - mid_x;
|
|
dy = y - mid_y;
|
|
}
|
|
|
|
std::ostringstream os;
|
|
os << "d(" << dx << ", " << dy <<")";
|
|
debugLog(os.str());
|
|
|
|
core->mouse.position += Vector(dx, dy);
|
|
|
|
|
|
// Now move the mouse back to the middle, because
|
|
// we don't care where it really is, just how much
|
|
// it moves.
|
|
glfwSetMousePos(mid_x, mid_y);
|
|
*/
|
|
|
|
|
|
|
|
core->mouse.buttons.left = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT) ? DOWN : UP;
|
|
core->mouse.buttons.right = glfwGetMouseButton(GLFW_MOUSE_BUTTON_RIGHT) ? DOWN : UP;
|
|
core->mouse.buttons.middle = glfwGetMouseButton(GLFW_MOUSE_BUTTON_MIDDLE) ? DOWN : UP;
|
|
core->mouse.scrollWheel = glfwGetMouseWheel();
|
|
#endif
|
|
}
|
|
|
|
void readKeyData()
|
|
{
|
|
|
|
#if defined(BBGE_BUILD_WINDOWS) && !defined(BBGE_BUILD_SDL)
|
|
if( NULL == g_pKeyboard )
|
|
return;
|
|
HRESULT hr;
|
|
BYTE diks[256];
|
|
// Get the input's device state, and put the state in dims
|
|
ZeroMemory( diks, sizeof(diks) );
|
|
hr = g_pKeyboard->GetDeviceState( sizeof(diks), diks );
|
|
if( FAILED(hr) )
|
|
{
|
|
// DirectInput may be telling us that the input stream has been
|
|
// interrupted. We aren't tracking any state between polls, so
|
|
// we don't have any special reset that needs to be done.
|
|
// We just re-acquire and try again.
|
|
|
|
// If input is lost then acquire and keep trying
|
|
hr = g_pKeyboard->Acquire();
|
|
while( hr == DIERR_INPUTLOST )
|
|
hr = g_pKeyboard->Acquire();
|
|
|
|
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
|
|
// may occur when the app is minimized or in the process of
|
|
// switching, so just try again later
|
|
return;
|
|
}
|
|
|
|
// Make a string of the index values of the keys that are down
|
|
for(int i = 0; i < 256; i++ )
|
|
{
|
|
core->keys[i] = ( diks[i] & 0x80 );
|
|
}
|
|
#endif
|
|
}
|
|
//#endif
|
|
|
|
|
|
bool Core::initJoystickLibrary(int numSticks)
|
|
{
|
|
//joystickEnabled = false;
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
|
#endif
|
|
|
|
if (numSticks > 0)
|
|
joystick.init(0);
|
|
|
|
joystickEnabled = true;
|
|
/*
|
|
numJoysticks = Joystick::deviceCount();
|
|
std::ostringstream os;
|
|
os << "Found " << numJoysticks << " joysticks";
|
|
debugLog(os.str());
|
|
if (numJoysticks > 0)
|
|
{
|
|
if (numJoysticks > 4)
|
|
numJoysticks = 4;
|
|
|
|
// HACK: memory leak... add code to clean this up!
|
|
for (int i = 0; i < numJoysticks; i++) {
|
|
joysticks[i] = new Joystick(i);
|
|
joysticks[i]->open();
|
|
|
|
// Print the name of the joystick.
|
|
char name[MAX_PATH];
|
|
joysticks[i]->deviceName(name);
|
|
std::ostringstream os;
|
|
os << " Joystick " << i << ": " << name;
|
|
debugLog(os.str());
|
|
}
|
|
joystickEnabled = true;
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Core::initInputLibrary()
|
|
{
|
|
core->mouse.position = Vector(getWindowWidth()/2, getWindowHeight()/2);
|
|
|
|
#ifdef BBGE_BUILD_GFLW
|
|
glfwDisable(GLFW_MOUSE_CURSOR);
|
|
//glfwEnable( GLFW_SYSTEM_KEYS );
|
|
#endif
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
{
|
|
keys[i] = 0;
|
|
}
|
|
#if defined(BBGE_BUILD_WINDOWS) && !defined(BBGE_BUILD_SDL)
|
|
|
|
HRESULT hr;
|
|
BOOL bExclusive = true;
|
|
BOOL bForeground = true;
|
|
//BOOL bImmediate = true;
|
|
BOOL bDisableWindowsKey = false;
|
|
DWORD dwCoopFlags;
|
|
|
|
if( bExclusive )
|
|
dwCoopFlags = DISCL_EXCLUSIVE;
|
|
else
|
|
dwCoopFlags = DISCL_NONEXCLUSIVE;
|
|
|
|
if( bForeground )
|
|
dwCoopFlags |= DISCL_FOREGROUND;
|
|
else
|
|
dwCoopFlags |= DISCL_BACKGROUND;
|
|
|
|
// Disabling the windows key is only allowed only if we are in foreground nonexclusive
|
|
if( bDisableWindowsKey && !bExclusive && bForeground )
|
|
dwCoopFlags |= DISCL_NOWINKEY;
|
|
|
|
// Create a DInput object
|
|
if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,
|
|
IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
|
|
return false;
|
|
|
|
// Obtain an interface to the system keyboard device.
|
|
if( FAILED( hr = g_pDI->CreateDevice( GUID_SysKeyboard, &g_pKeyboard, NULL ) ) )
|
|
return false;
|
|
|
|
// Set the data format to "Keyboard format" - a predefined data format
|
|
//
|
|
// A data format specifies which controls on a device we
|
|
// are interested in, and how they should be reported.
|
|
//
|
|
// This tells DirectInput that we will be passing an array
|
|
// of 256 bytes to IDirectInputDevice::GetDeviceState.
|
|
if( FAILED( hr = g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
|
|
return false;
|
|
|
|
// Set the cooperativity level to let DirectInput know how
|
|
// this device should interact with the system and with other
|
|
// DirectInput applications.
|
|
hr = g_pKeyboard->SetCooperativeLevel( this->hWnd, dwCoopFlags );
|
|
if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive )
|
|
{
|
|
debugLog("could not set cooperative level");
|
|
//FreeDirectInput();
|
|
//errorLog ("failed to init input");
|
|
/*
|
|
MessageBox( hDlg, _T("SetCooperativeLevel() returned DIERR_UNSUPPORTED.\n")
|
|
_T("For security reasons, background exclusive Keyboard\n")
|
|
_T("access is not allowed."), _T("Keyboard"), MB_OK );
|
|
*/
|
|
//return false;;
|
|
}
|
|
|
|
/*
|
|
if( FAILED(hr) )
|
|
{
|
|
errorLog("failed to init input");
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
|
|
// Acquire the newly created device
|
|
g_pKeyboard->Acquire();
|
|
|
|
|
|
//#ifdef BBGE_BUILD_DIRECTX
|
|
|
|
if( FAILED( hr = g_pDI->CreateDevice( GUID_SysMouse, &g_pMouse, NULL ) ) )
|
|
return false;
|
|
|
|
// Set the data format to "Mouse format" - a predefined data format
|
|
//
|
|
// A data format specifies which controls on a device we
|
|
// are interested in, and how they should be reported.
|
|
//
|
|
// This tells DirectInput that we will be passing a
|
|
// DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
|
|
if( FAILED( hr = g_pMouse->SetDataFormat( &c_dfDIMouse2 ) ) )
|
|
return false;
|
|
|
|
// Set the cooperativity level to let DirectInput know how
|
|
// this device should interact with the system and with other
|
|
// DirectInput applications.
|
|
hr = g_pMouse->SetCooperativeLevel( this->hWnd, dwCoopFlags );
|
|
if( hr == DIERR_UNSUPPORTED && !bForeground && bExclusive )
|
|
{
|
|
//FreeDirectInput();
|
|
//errorLog ("mouse failed");
|
|
debugLog("could not set cooperative level");
|
|
//return false;
|
|
}
|
|
|
|
/*
|
|
if( FAILED(hr) )
|
|
return false;
|
|
*/
|
|
|
|
// Acquire the newly created device
|
|
g_pMouse->Acquire();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// joystick init
|
|
//#endif
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
std::ostringstream os;
|
|
os << "x: " << joystate.lX << " y: " << joystate.lY;
|
|
os << " frx: " << joystate.lFRx << " fry: " << joystate.lFRy;
|
|
debugLog(os.str());
|
|
*/
|
|
|
|
/*
|
|
if (joystickOverrideMouse && !joychange.isZero())
|
|
{
|
|
Vector joy(joystate.lX, joystate.lY);
|
|
//core->mouse.position += joychange * 0.001f;
|
|
core->mouse.position = Vector(400,300) + ((joy * 600) / (65536/2))-300;
|
|
}
|
|
*/
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
|
|
/*
|
|
if (mouse.position.x < 0)
|
|
mouse.position.x = 0;
|
|
if (mouse.position.x > core->getVirtualWidth())
|
|
mouse.position.x = core->getVirtualWidth();
|
|
if (mouse.position.y < 0)
|
|
mouse.position.y = 0;
|
|
if (mouse.position.y > core->getVirtualHeight())
|
|
mouse.position.y = core->getVirtualHeight();
|
|
*/
|
|
|
|
onMouseInput();
|
|
|
|
/*
|
|
#ifdef BBGE_BUILD_GLFW
|
|
glfwSetMousePos(mouse.position.x, mouse.position.y);
|
|
#endif
|
|
*/
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
#endif
|
|
//core->mouse.change = core->mouse.position - core->mouse.lastPosition;
|
|
|
|
//core->mouse.scrollWheelChange = core->mouse.scrollWheel - core->mouse.lastScrollWheel;
|
|
|
|
|
|
|
|
|
|
|
|
//script.update(dt);
|
|
|
|
cameraPos.update(dt);
|
|
globalScale.update(dt);
|
|
|
|
if (afterEffectManager)
|
|
{
|
|
afterEffectManager->update(dt);
|
|
}
|
|
|
|
if (!sortFlag)
|
|
{
|
|
if (sortTimer>0)
|
|
{
|
|
sortTimer -= dt;
|
|
if (sortTimer <= 0)
|
|
{
|
|
sortTimer = SORT_DELAY;
|
|
sort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector Core::getClearColor()
|
|
{
|
|
return clearColor;
|
|
}
|
|
|
|
void Core::setClearColor(const Vector &c)
|
|
{
|
|
clearColor = c;
|
|
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glClearColor(c.x, c.y, c.z, 0.0);
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
|
|
#endif
|
|
}
|
|
|
|
void Core::setSDLGLAttributes()
|
|
{
|
|
std::ostringstream os;
|
|
os << "setting vsync: " << _vsync;
|
|
debugLog(os.str());
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, _vsync);
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef GLAPIENTRY
|
|
#undef GLAPIENTRY
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
#define GLAPIENTRY APIENTRY
|
|
#else
|
|
#define GLAPIENTRY
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_OPENGL_DYNAMIC
|
|
#define GL_FUNC(ret,fn,params,call,rt) \
|
|
extern "C" { \
|
|
static ret (GLAPIENTRY *p##fn) params = NULL; \
|
|
ret GLAPIENTRY fn params { rt p##fn call; } \
|
|
}
|
|
#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)
|
|
{
|
|
static bool didOnce = false;
|
|
|
|
aspectX = width;
|
|
aspectY = height;
|
|
|
|
aspect = (aspectX/aspectY);
|
|
|
|
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
_vsync = vsync;
|
|
_fullscreen = fullscreen;
|
|
_bpp = bpp;
|
|
|
|
_hasFocus = false;
|
|
|
|
#if defined(BBGE_BUILD_SDL)
|
|
|
|
//setenv("SDL_VIDEO_CENTERED", "1", 1);
|
|
//SDL_putenv("SDL_VIDEO_WINDOW_POS=400,300");
|
|
|
|
// 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");
|
|
SDL_putenv((char *) "LIBGL_DEBUG=verbose"); // temp, to track errors on linux with nouveau drivers.
|
|
|
|
if (recreate)
|
|
{
|
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
|
|
{
|
|
errorLog(std::string("SDL Error: ") + std::string(SDL_GetError()));
|
|
exit(0);
|
|
}
|
|
|
|
#if BBGE_BUILD_OPENGL_DYNAMIC
|
|
if (SDL_GL_LoadLibrary(NULL) == -1)
|
|
{
|
|
errorLog(std::string("SDL_GL_LoadLibrary Error: ") + std::string(SDL_GetError()));
|
|
SDL_Quit();
|
|
exit(0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
setWindowCaption(appName, appName);
|
|
|
|
initIcon();
|
|
// Create window
|
|
|
|
setSDLGLAttributes();
|
|
|
|
//if (!didOnce)
|
|
{
|
|
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();
|
|
errorLog(os.str());
|
|
SDL_Quit();
|
|
exit(0);
|
|
}
|
|
|
|
#if BBGE_BUILD_OPENGL_DYNAMIC
|
|
if (!lookup_all_glsyms())
|
|
{
|
|
std::ostringstream os;
|
|
os << "Couldn't load OpenGL symbols we need\n";
|
|
errorLog(os.str());
|
|
SDL_Quit();
|
|
exit(0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
setWindowCaption(appName, appName);
|
|
|
|
SDL_WM_GrabInput(grabInputOnReentry==0 ? SDL_GRAB_OFF : SDL_GRAB_ON);
|
|
char name[256];
|
|
SDL_VideoDriverName((char*)name, 256);
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
SDL_SysWMinfo wmInfo;
|
|
SDL_GetWMInfo(&wmInfo);
|
|
hWnd = wmInfo.window;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(BBGE_BUILD_OPENGL)
|
|
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);
|
|
|
|
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
//glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
|
|
glLoadIdentity();
|
|
|
|
glFinish();
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
glfwSwapInterval(vsync);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(BBGE_BUILD_DIRECTX)
|
|
|
|
// Initialize Direct3D
|
|
if( SUCCEEDED( InitD3D( this->hWnd, fullscreen, vsync ) ) )
|
|
{
|
|
// Show the window
|
|
ShowWindow( this->hWnd, SW_SHOWDEFAULT );
|
|
UpdateWindow( this->hWnd );
|
|
//initPipeline(PT_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
errorLog("Could not init D3D");
|
|
exit(-1);
|
|
}
|
|
|
|
#endif
|
|
|
|
setClearColor(clearColor);
|
|
|
|
clearBuffers();
|
|
showBuffer();
|
|
|
|
lib_graphics = true;
|
|
|
|
_hasFocus = true;
|
|
|
|
enumerateScreenModes();
|
|
|
|
if (!didOnce)
|
|
didOnce = true;
|
|
|
|
// init success
|
|
return true;
|
|
}
|
|
|
|
void Core::enumerateScreenModes()
|
|
{
|
|
screenModes.clear();
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
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)
|
|
{
|
|
screenModes.push_back(ScreenMode(i, modes[i]->w, modes[i]->h));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Core::shutdownSoundLibrary()
|
|
{
|
|
}
|
|
|
|
void Core::shutdownGraphicsLibrary(bool killVideo)
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
glFinish();
|
|
if (killVideo) {
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
|
|
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
|
|
}
|
|
#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");
|
|
//loopDone = true;
|
|
//popAllStates();
|
|
}
|
|
|
|
void Core::applyState(const std::string &state)
|
|
{
|
|
if (nocasecmp(state, "state_quit")==0)
|
|
{
|
|
loopDone = true;
|
|
}
|
|
StateManager::applyState(state);
|
|
}
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
void GLFWCALL windowResize(int w, int h)
|
|
{
|
|
// this gets called on minimize + restore?
|
|
if (w == 0 && h == 0)
|
|
{
|
|
core->minimized = true;
|
|
return;
|
|
}
|
|
else
|
|
core->minimized = false;
|
|
if (w != core->width || h != core->height)
|
|
glfwSetWindowSize(core->width,core->height);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
void centerWindow(HWND hwnd)
|
|
{
|
|
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
|
|
x = (rcDeskTop.right - rcDeskTop.left)/2;
|
|
y = (rcDeskTop.bottom - rcDeskTop.top)/2;
|
|
x -= (rcWnd.right - rcWnd.left)/2;
|
|
y -= (rcWnd.bottom - rcWnd.top)/2;
|
|
// Set top and left to center main window on desktop
|
|
::SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
|
|
// ::ShowWindow(hwnd, 1);
|
|
}
|
|
#endif
|
|
|
|
void Core::adjustWindowPosition(int x, int y)
|
|
{
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
RECT rcWnd;
|
|
::GetWindowRect(hWnd, &rcWnd);
|
|
rcWnd.left += x;
|
|
rcWnd.top += y;
|
|
::SetWindowPos(hWnd, HWND_TOP, rcWnd.left, rcWnd.top, 0, 0, SWP_NOSIZE);
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
#ifdef BBGE_BUILD_SDL
|
|
return true;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
int redbits, greenbits, bluebits, alphabits;
|
|
redbits = greenbits = bluebits = 8;
|
|
alphabits = 0;
|
|
switch(bits)
|
|
{
|
|
case 16:
|
|
redbits = 5;
|
|
greenbits = 6;
|
|
bluebits = 5;
|
|
break;
|
|
case 24:
|
|
redbits = 8;
|
|
bluebits = 8;
|
|
greenbits = 8;
|
|
alphabits = 0;
|
|
break;
|
|
case 32:
|
|
redbits = 8;
|
|
greenbits = 8;
|
|
bluebits = 8;
|
|
alphabits = 8;
|
|
break;
|
|
case 8:
|
|
redbits = 2;
|
|
greenbits = 2;
|
|
bluebits = 2;
|
|
break;
|
|
}
|
|
if (glfwOpenWindow(width, height, redbits, greenbits, bluebits, 0, 0, 0, fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW) == GL_TRUE)
|
|
{
|
|
glfwSetWindowTitle(windowTitle.c_str());
|
|
resize(width,height);
|
|
|
|
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
this->hWnd = (HWND)glfwGetWindowHandle();
|
|
|
|
if (!fullscreen) centerWindow(hWnd);
|
|
#endif
|
|
|
|
glfwSetWindowSizeCallback(windowResize);
|
|
|
|
redBits = glfwGetWindowParam(GLFW_RED_BITS);
|
|
blueBits = glfwGetWindowParam(GLFW_BLUE_BITS);
|
|
greenBits = glfwGetWindowParam(GLFW_GREEN_BITS);
|
|
alphaBits = glfwGetWindowParam(GLFW_ALPHA_BITS);
|
|
|
|
if (redBits < 8 && (bits == 32 || bits == 24))
|
|
{
|
|
int sayBits = 32;
|
|
std::ostringstream os;
|
|
os << "(" << width << ", " << height << ") " << sayBits << "-bit mode could not be enabled. Please try setting your desktop to " << sayBits << "-bit color depth";
|
|
if (!fullscreen)
|
|
os << ", or try running in fullscreen.";
|
|
else
|
|
os << ".";
|
|
os << " This resolution may not be supported on your machine.";
|
|
errorLog(os.str());
|
|
exit(0); return false;
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
// Register the window class
|
|
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
|
|
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
|
|
windowTitle.c_str(), NULL };
|
|
RegisterClassEx( &wc );
|
|
|
|
this->hWnd = CreateWindow( windowTitle.c_str(), windowTitle.c_str(),
|
|
WS_OVERLAPPEDWINDOW, 100, 100, width, height+10,
|
|
GetDesktopWindow(), NULL, wc.hInstance, NULL );
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
// No longer part of C/C++ standard
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
static void
|
|
bbgePerspective(float fovy, float aspect, float zNear, float zFar)
|
|
{
|
|
float sine, cotangent, deltaZ;
|
|
float radians = fovy / 2.0f * M_PI / 180.0f;
|
|
|
|
deltaZ = zFar - zNear;
|
|
sine = sinf(radians);
|
|
if ((deltaZ == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) {
|
|
return;
|
|
}
|
|
cotangent = cosf(radians) / sine;
|
|
|
|
GLfloat m[4][4] = {
|
|
{ 1.0f, 0.0f, 0.0f, 0.0f },
|
|
{ 0.0f, 1.0f, 0.0f, 0.0f },
|
|
{ 0.0f, 0.0f, 1.0f, 0.0f },
|
|
{ 0.0f, 0.0f, 0.0f, 1.0f }
|
|
};
|
|
m[0][0] = (GLfloat) (cotangent / aspect);
|
|
m[1][1] = (GLfloat) cotangent;
|
|
m[2][2] = (GLfloat) (-(zFar + zNear) / deltaZ);
|
|
m[2][3] = -1.0f;
|
|
m[3][2] = (GLfloat) (-2.0f * zNear * zFar / deltaZ);
|
|
m[3][3] = 0.0f;
|
|
|
|
glMultMatrixf(&m[0][0]);
|
|
}
|
|
|
|
void Core::setPixelScale(int pixelScaleX, int pixelScaleY)
|
|
{
|
|
/*
|
|
piScaleX = pixelScaleX;
|
|
piScaleY = pixelScaleY;
|
|
*/
|
|
virtualWidth = pixelScaleX;
|
|
//MAX(virtualWidth, 800);
|
|
virtualHeight = pixelScaleY;//int((pixelScale*aspectY)/aspectX); //assumes 4:3 aspect ratio
|
|
this->baseCullRadius = sqrtf(sqr(getVirtualWidth()/2) + sqr(getVirtualHeight()/2));
|
|
|
|
std::ostringstream os;
|
|
os << "virtual(" << virtualWidth << ", " << virtualHeight << ")";
|
|
debugLog(os.str());
|
|
|
|
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)));
|
|
//vw = MAX(vw, baseVirtualWidth);
|
|
core->enable2D(vw, baseVirtualHeight, 1);
|
|
}
|
|
else
|
|
{
|
|
int vh = int(float(baseVirtualWidth) * (float(ry)/float(rx)));
|
|
//vh = MAX(vh, baseVirtualHeight);
|
|
core->enable2D(baseVirtualWidth, vh, 1);
|
|
}
|
|
}
|
|
|
|
static void bbgeOrtho2D(float left, float right, float bottom, float top)
|
|
{
|
|
glOrtho(left, right, bottom, top, -1.0, 1.0);
|
|
}
|
|
|
|
void Core::enable2D(int pixelScaleX, int pixelScaleY, bool forcePixelScale)
|
|
{
|
|
// why do this again? don't really get it
|
|
/*
|
|
if (mode == MODE_2D)
|
|
{
|
|
if (forcePixelScale || (pixelScaleX!=0 && core->width!=pixelScaleX) || (pixelScaleY!=0 && core->height!=pixelScaleY))
|
|
{
|
|
float widthFactor = core->width/float(pixelScaleX);
|
|
float heightFactor = core->height/float(pixelScaleY);
|
|
core->globalResolutionScale = Vector(widthFactor,heightFactor,1.0f);
|
|
setPixelScale(pixelScaleX, pixelScaleY);
|
|
|
|
std::ostringstream os;
|
|
os << "top of call: ";
|
|
os << "widthFactor: " << widthFactor;
|
|
os << "heightFactor: " << heightFactor;
|
|
debugLog(os.str());
|
|
}
|
|
return;
|
|
}
|
|
*/
|
|
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
|
|
GLint viewPort[4];
|
|
glGetIntegerv(GL_VIEWPORT, viewPort);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
//glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
vh = float(baseVirtualHeight * viewPort[2]) / float(baseVirtualWidth);
|
|
|
|
viewOffY = (viewPort[3] - vh) * 0.5f;
|
|
*/
|
|
|
|
|
|
/*
|
|
std::ostringstream os;
|
|
os << "vw: " << vw << " OFFX: " << viewOffX << " ";
|
|
os << "vh: " << vh << " OFFY: " << viewOffY;
|
|
debugLog(os.str());
|
|
*/
|
|
|
|
|
|
/*
|
|
float aspect = float(width) / float (height);
|
|
|
|
if (aspect < 1.3f)
|
|
{
|
|
viewOffX *= 0.5f;
|
|
}
|
|
*/
|
|
|
|
|
|
//#else
|
|
// int offx=0,offy=0;
|
|
//#endif
|
|
|
|
//+offx
|
|
//-offx
|
|
//glOrtho(0.0f,viewPort[2],viewPort[3],0.0f,-1000.0f,1000.0f);
|
|
//glOrtho(0.0f+offx,viewPort[2]+offx,viewPort[3]+offy,0.0f+offy,-1.0f,1.0f);
|
|
bbgeOrtho2D(0.0f-viewOffX,viewPort[2]-viewOffX,viewPort[3]-viewOffY,0.0f-viewOffY);
|
|
/*
|
|
static bool doOnce = false;
|
|
if (!doOnce)
|
|
{
|
|
glOrtho(0.0f,viewPort[2],viewPort[3],0.0f,-10.0f,10.0f);
|
|
doOnce = true;
|
|
}
|
|
*/
|
|
//glOrtho(-viewPort[2]/2,viewPort[2]/2,viewPort[3]/2,-viewPort[3]/2,-10.0f,10.0f);
|
|
//glOrtho(0, viewPort[2], 0, viewPort[3], -100, 100);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
//glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
setupRenderPositionAndScale();
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
D3DXMATRIX matOrtho;
|
|
D3DXMATRIX matIdentity;
|
|
|
|
//Setup orthographic projection matrix
|
|
|
|
D3DXMatrixOrthoOffCenterLH(&matOrtho, 0, getWindowWidth(), getWindowHeight(), 0, 1, 10);
|
|
//D3DXMatrixOrthoLH (&matOrtho, getWindowWidth(), getWindowHeight(), 1.0f, 10.0f);
|
|
D3DXMatrixIdentity (&matIdentity);
|
|
g_pd3dDevice->SetTransform (D3DTS_PROJECTION, &matOrtho);
|
|
g_pd3dDevice->SetTransform (D3DTS_WORLD, &matIdentity);
|
|
g_pd3dDevice->SetTransform (D3DTS_VIEW, &matIdentity);
|
|
// For our world matrix, we will just leave it as the identity
|
|
/*
|
|
D3DXMATRIXA16 matWorld;
|
|
D3DXMatrixIdentity( &matWorld );
|
|
//D3DXMatrixRotationX( &matWorld, 0/1000.0f );
|
|
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
|
|
|
|
// Set up our view matrix. A view matrix can be defined given an eye point,
|
|
// a point to lookat, and a direction for which way is up. Here, we set the
|
|
// eye five units back along the z-axis and up three units, look at the
|
|
// origin, and define "up" to be in the y-direction.
|
|
D3DXVECTOR3 vEyePt( 0.0f, 0.0f,0.0f );
|
|
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
|
|
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
|
|
D3DXMATRIXA16 matView;
|
|
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
|
|
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
|
|
|
|
// For the projection matrix, we set up a perspective transform (which
|
|
// transforms geometry from 3D view space to 2D viewport space, with
|
|
// a perspective divide making objects smaller in the distance). To build
|
|
// a perpsective transform, we need the field of view (1/4 pi is common),
|
|
// the aspect ratio, and the near and far clipping planes (which define at
|
|
// what distances geometry should be no longer be rendered).
|
|
///LPDIRECT3DVIEWPORT3 Viewport;
|
|
|
|
D3DVIEWPORT9 viewport;
|
|
viewport.Width = core->getWindowWidth();
|
|
viewport.Height = core->getWindowHeight();
|
|
viewport.MaxZ = 5;
|
|
viewport.MinZ = -5;
|
|
viewport.X = 0;
|
|
viewport.Y = 0;
|
|
|
|
g_pd3dDevice->SetViewport( &viewport );
|
|
|
|
D3DXMATRIXA16 matProj;
|
|
D3DXMatrixOrthoLH(&matProj, 800, 600, -5, 5);
|
|
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
|
|
*/
|
|
|
|
// Create the viewport
|
|
/*
|
|
if (FAILED(g_pd3dDevice->CreateViewport(&Viewport,NULL)))
|
|
{ errorLog("Failed to create a viewport"); };
|
|
if (FAILED(g_pd3dDevice->AddViewport(Viewport)))
|
|
{ errorLog("Failed to add a viewport"); };
|
|
if (FAILED(g_pd3dDevice->SetViewport2(&Viewdata)))
|
|
{ errorLog("Failed to set Viewport data"); };
|
|
g_pd3dDevice->SetCurrentViewport(Viewport);
|
|
*/
|
|
|
|
/*
|
|
D3DXMATRIXA16 matProj;
|
|
D3DXMatrixOrthoLH(&matProj, 4, 3, -5, 5);
|
|
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
|
|
*/
|
|
|
|
/*
|
|
D3DVIEWPORT9 viewport;
|
|
g_pd3dDevice->GetViewport(&viewport);
|
|
D3DXMATRIX matProj;
|
|
D3DXMatrixOrthoLH(&matProj, viewport.Width, viewport.Height, -10, 10);
|
|
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
|
|
*/
|
|
|
|
|
|
#endif
|
|
|
|
if (forcePixelScale || (pixelScaleX!=0 && core->width!=pixelScaleX) || (pixelScaleY!=0 && core->height!=pixelScaleY))
|
|
{
|
|
/*
|
|
float f = core->width/float(pixelScale);
|
|
core->globalResolutionScale = Vector(f,f,1.0f);
|
|
*/
|
|
//debugLog("HEEEREEE");
|
|
float widthFactor = core->width/float(pixelScaleX);
|
|
float heightFactor = core->height/float(pixelScaleY);
|
|
//float heightFactor =
|
|
core->globalResolutionScale = Vector(widthFactor,heightFactor,1.0f);
|
|
setPixelScale(pixelScaleX, pixelScaleY);
|
|
|
|
//core->globalResolutionScale = Vector(1.5,1.5,1);
|
|
/*
|
|
std::ostringstream os;
|
|
os << "bottom of call: ";
|
|
os << "widthFactor: " << widthFactor;
|
|
os << " heightFactor: " << heightFactor;
|
|
debugLog(os.str());
|
|
*/
|
|
}
|
|
setPixelScale(pixelScaleX, pixelScaleY);
|
|
|
|
//core->globalResolutionScale.x = 1.6;
|
|
|
|
//setupRenderPositionAndScale();
|
|
|
|
|
|
}
|
|
|
|
void Core::quitNestedMain()
|
|
{
|
|
if (getNestedMains() > 1)
|
|
{
|
|
quitNestedMainFlag = true;
|
|
}
|
|
}
|
|
|
|
void Core::resetTimer()
|
|
{
|
|
#ifdef BBGE_BUILD_GLFW
|
|
glfwSetTime(0);
|
|
#endif
|
|
#ifdef BBGE_BUILD_SDL
|
|
nowTicks = thenTicks = SDL_GetTicks();
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&timerEnd);
|
|
timerStart = timerEnd;
|
|
#endif
|
|
|
|
for (int i = 0; i < avgFPS.size(); i++)
|
|
{
|
|
avgFPS[i] = 0;
|
|
}
|
|
}
|
|
|
|
void Core::setDockIcon(const std::string &ident)
|
|
{
|
|
}
|
|
|
|
void Core::msg(const std::string &message)
|
|
{
|
|
#ifdef BBGE_BUILD_WINDOWS
|
|
MessageBox(0, message.c_str(), "Message", MB_OK);
|
|
#endif
|
|
}
|
|
|
|
void Core::setMousePosition(const Vector &p)
|
|
{
|
|
Vector lp = core->mouse.position;
|
|
|
|
core->mouse.position = p;
|
|
#if !defined(BBGE_BUILD_WINDOWS) && defined(BBGE_BUILD_GLFW)
|
|
glfwSetMousePos(p.x,p.y);
|
|
#endif
|
|
#ifdef BBGE_BUILD_SDL
|
|
float px = p.x + virtualOffX;
|
|
float py = p.y;// + virtualOffY;
|
|
|
|
SDL_WarpMouse( px * (float(width)/float(virtualWidth)), py * (float(height)/float(virtualHeight)));
|
|
|
|
/*
|
|
ignoreNextMouse = true;
|
|
unchange = core->mouse.position - lp;
|
|
*/
|
|
#endif
|
|
|
|
/*
|
|
std::ostringstream os;
|
|
os << "setting position (" << p.x << ", " << p.y << ")";
|
|
debugLog(os.str());
|
|
*/
|
|
}
|
|
|
|
// used to update all render objects either uniformly or as part of a time sliced update process
|
|
void Core::updateRenderObjects(float dt)
|
|
{
|
|
//HACK: we may not always be assuming virtual 800x600
|
|
Vector cameraC = core->cameraPos + Vector(400,300);
|
|
for (int c = 0; c < renderObjectLayers.size(); c++)
|
|
{
|
|
|
|
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 ++;
|
|
std::string str(os.str());
|
|
if (!core->exists(str)) // keep going until we hit an unused filename.
|
|
return str;
|
|
}
|
|
}
|
|
|
|
uint32 Core::getTicks()
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
return SDL_GetTicks();
|
|
#endif
|
|
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()
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
return ((SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
|
|
//QueryPerformanceCounter((LARGE_INTEGER*)&lastTime);
|
|
//QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
|
float dt;
|
|
float counter = 0;
|
|
int frames = 0;
|
|
float real_dt = 0;
|
|
//std::ofstream out("debug.log");
|
|
|
|
#if (!defined(_DEBUG) || defined(BBGE_BUILD_UNIX)) && defined(BBGE_BUILD_SDL)
|
|
bool wasInactive = false;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
if (runTime == -1)
|
|
glfwSetTime(0);
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
// HACK: find out how to use performance counter again Query
|
|
|
|
|
|
if (verbose) debugLog("Performance Counter");
|
|
|
|
if (!QueryPerformanceFrequency((LARGE_INTEGER*)&freq))
|
|
{
|
|
errorLog ("could not get clock freq");
|
|
return;
|
|
}
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&timerStart);
|
|
/*
|
|
DWORD ticks = GetTickCount();
|
|
DWORD newTicks;
|
|
*/
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
nowTicks = thenTicks = SDL_GetTicks();
|
|
#endif
|
|
|
|
//int i;
|
|
|
|
nestedMains++;
|
|
// HACK: Why block this?
|
|
/*
|
|
if (nestedMains > 1 && runTime <= 0)
|
|
return;
|
|
*/
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
MSG msg;
|
|
ZeroMemory( &msg, sizeof(msg) );
|
|
#endif
|
|
|
|
while((runTime == -1 && !loopDone) || (runTime >0)) // Loop That Runs While done=FALSE
|
|
{
|
|
BBGE_PROF(Core_main);
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
if (verbose) debugLog("glfwSetTime");
|
|
dt = glfwGetTime();
|
|
glfwSetTime(0);
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
/*
|
|
newTicks = GetTickCount();
|
|
*/
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&timerEnd);
|
|
dt = (float(timerEnd-timerStart)/float(freq));
|
|
timerStart = timerEnd;
|
|
// dt = float(newTicks)/1000.0f;
|
|
//dt = float(newTicks - ticks)/1000.0f;
|
|
//ticks = newTicks;
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
if (timeUpdateType == TIMEUPDATE_DYNAMIC)
|
|
{
|
|
nowTicks = SDL_GetTicks();
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
if (nowTicks == 0)
|
|
{
|
|
nowTicks = SDL_GetTicks();
|
|
}
|
|
}
|
|
*/
|
|
dt = (nowTicks-thenTicks)/1000.0;
|
|
thenTicks = nowTicks;
|
|
//thenTicks = SDL_GetTicks();
|
|
#endif
|
|
|
|
if (verbose) debugLog("avgFPS");
|
|
if (!avgFPS.empty())
|
|
{
|
|
/*
|
|
if (avgFPS[0] <= 0)
|
|
{
|
|
for (int i = 0; i < avgFPS.size(); i++)
|
|
avgFPS[i] = dt;
|
|
}
|
|
*/
|
|
int i = 0;
|
|
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 ++;
|
|
}
|
|
}
|
|
if (n > 0) // && n == avgFPS.size() ??
|
|
{
|
|
c /= n;
|
|
dt = c;
|
|
}
|
|
/*
|
|
std::ostringstream os;
|
|
os << dt;
|
|
debugLog(os.str());
|
|
*/
|
|
}
|
|
|
|
#if !defined(_DEBUG) && defined(BBGE_BUILD_SDL)
|
|
if (verbose) debugLog("checking window active");
|
|
|
|
if (lib_graphics && (wasInactive || !settings.runInBackground))
|
|
{
|
|
if (isWindowFocus())
|
|
{
|
|
_hasFocus = true;
|
|
if (wasInactive)
|
|
{
|
|
debugLog("WINDOW ACTIVE");
|
|
|
|
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();
|
|
//debugLog("app not in input focus");
|
|
SDL_Delay(200);
|
|
|
|
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();
|
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (timeUpdateType == TIMEUPDATE_FIXED)
|
|
{
|
|
real_dt = dt;
|
|
dt = 1.0f/float(fixedFPS);
|
|
}
|
|
|
|
old_dt = dt;
|
|
|
|
if (verbose) debugLog("modify dt");
|
|
modifyDt(dt);
|
|
|
|
|
|
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();
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (doScreenshot)
|
|
{
|
|
if (verbose) debugLog("screenshot");
|
|
|
|
doScreenshot = false;
|
|
|
|
saveScreenshotTGA(getScreenshotFilename());
|
|
prepScreen(0);
|
|
}
|
|
|
|
// wait
|
|
if (timeUpdateType == TIMEUPDATE_FIXED)
|
|
{
|
|
static float avg_diff=0;
|
|
static int avg_diff_count=0;
|
|
|
|
float diff = (1.0f/float(fixedFPS)) - real_dt;
|
|
|
|
avg_diff_count++;
|
|
avg_diff += diff;
|
|
|
|
char buf[256];
|
|
sprintf(buf, "real_dt: %5.4f \n realFPS: %5.4f \n fixedFPS: %5.4f \n diff: %5.4f \n delay: %5.4f \n avgdiff: %5.8f", float(real_dt), float(real_dt>0?(1.0f/real_dt):0.0f), float(fixedFPS), float(diff), float(diff*1000), float(avg_diff/(float)avg_diff_count));
|
|
fpsDebugString = buf;
|
|
|
|
/*
|
|
std::ostringstream os;
|
|
os << "real_dt: " << real_dt << "\n realFPS: " << (1.0/real_dt) << "\n fixedFPS: " << fixedFPS << "\n diff: " << diff << "\n delay: " << diff*1000;
|
|
fpsDebugString = os.str();
|
|
*/
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
nowTicks = SDL_GetTicks();
|
|
|
|
if (diff > 0)
|
|
{
|
|
//Sleep(diff*1000);
|
|
//SDL_Delay(diff*1000);
|
|
while ((SDL_GetTicks() - nowTicks) < (diff*1000))
|
|
{
|
|
//wend, bitch
|
|
}
|
|
}
|
|
|
|
//nowTicks = SDL_GetTicks();
|
|
#endif
|
|
|
|
}
|
|
}
|
|
if (verbose) debugLog("bottom of function");
|
|
quitNestedMainFlag = false;
|
|
if (nestedMains==1)
|
|
clearGarbage();
|
|
nestedMains--;
|
|
if (verbose) debugLog("exit Core::main");
|
|
}
|
|
|
|
// less than through pointer
|
|
bool RenderObject_lt(RenderObject* x, RenderObject* y)
|
|
{
|
|
return x->getSortDepth() < y->getSortDepth();
|
|
}
|
|
|
|
// greater than through pointer
|
|
bool RenderObject_gt(RenderObject* x, RenderObject* y)
|
|
{
|
|
return x->getSortDepth() > y->getSortDepth();
|
|
}
|
|
|
|
void Core::sortLayer(int layer)
|
|
{
|
|
if (layer >= 0 && layer < renderObjectLayers.size())
|
|
renderObjectLayers[layer].sort();
|
|
}
|
|
|
|
void Core::sort()
|
|
{
|
|
/*
|
|
if (sortEnabled)
|
|
renderObjects.sort(RenderObject_lt);
|
|
*/
|
|
// sort layeres independantly
|
|
|
|
/*
|
|
for (int i = renderObjects.size()-1; i >= 0; i--)
|
|
{
|
|
bool flipped = false;
|
|
for (int j = 0; j < i; j++)
|
|
{
|
|
//position.z
|
|
//position.z
|
|
//!renderObjects[j]->parent && !renderObjects[j+1]->parent &&
|
|
if (renderObjects[j]->getSortDepth() > renderObjects[j+1]->getSortDepth())
|
|
{
|
|
RenderObject *temp;
|
|
temp = renderObjects[j];
|
|
renderObjects[j] = renderObjects[j+1];
|
|
renderObjects[j+1] = temp;
|
|
flipped = true;
|
|
}
|
|
}
|
|
if (!flipped) break;
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
void Core::clearBuffers()
|
|
{
|
|
if (flags.get(CF_CLEARBUFFERS))
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(int(clearColor.x*255),int(clearColor.y*255),int(clearColor.z*255)), 1.0f, 0 );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Core::setupRenderPositionAndScale()
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
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));
|
|
#endif
|
|
}
|
|
|
|
void Core::setupGlobalResolutionScale()
|
|
{
|
|
glScalef(globalResolutionScale.x, globalResolutionScale.y, globalResolutionScale.z);
|
|
}
|
|
|
|
void Core::initFrameBuffer()
|
|
{
|
|
frameBuffer.init(-1, -1, true);
|
|
}
|
|
|
|
void Core::setMouseConstraint(bool on)
|
|
{
|
|
/*
|
|
if (mouseConstraint && !on)
|
|
{
|
|
setMousePosition(mouse.position);
|
|
}
|
|
*/
|
|
mouseConstraint = on;
|
|
}
|
|
|
|
void Core::setMouseConstraintCircle(int circle)
|
|
{
|
|
mouseConstraint = true;
|
|
mouseCircle = circle;
|
|
}
|
|
|
|
/*
|
|
void Core::clearKeys()
|
|
{
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
{
|
|
keys[i] = 0;
|
|
}
|
|
}
|
|
*/
|
|
|
|
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)
|
|
{
|
|
//- core->getVirtualOffX()
|
|
//- virtualOffX
|
|
Vector h = Vector(core->center.x , core->center.y);
|
|
Vector d = mouse.position - h;
|
|
if (!d.isLength2DIn(mouseCircle))
|
|
{
|
|
d.setLength2D(mouseCircle);
|
|
mouse.position = h+d;
|
|
//warpMouse = true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Core::pollEvents()
|
|
{
|
|
#if defined(BBGE_BUILD_SDL)
|
|
bool warpMouse=false;
|
|
|
|
/*
|
|
Uint8 *keystate = SDL_GetKeyState(NULL);
|
|
for (int i = 0; i < KEY_MAXARRAY; i++)
|
|
{
|
|
keys[i] = keystate[i];
|
|
}
|
|
*/
|
|
|
|
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;
|
|
|
|
|
|
|
|
while ( SDL_PollEvent (&event) ) {
|
|
switch (event.type) {
|
|
case SDL_KEYDOWN:
|
|
{
|
|
#if __APPLE__
|
|
if ((event.key.keysym.sym == SDLK_q) && (event.key.keysym.mod & KMOD_META))
|
|
#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))
|
|
{
|
|
// toggle mouse grab with the magic hotkey.
|
|
grabInputOnReentry = (grabInputOnReentry)?0:-1;
|
|
setReentryInputGrab(1);
|
|
}
|
|
else if (_hasFocus)
|
|
{
|
|
int k = (int)event.key.keysym.sym;
|
|
keys[k] = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
{
|
|
if (_hasFocus)
|
|
{
|
|
int k = (int)event.key.keysym.sym;
|
|
keys[k] = 0;
|
|
}
|
|
}
|
|
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;
|
|
|
|
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;
|
|
|
|
case SDL_QUIT:
|
|
SDL_Quit();
|
|
_exit(0);
|
|
//loopDone = true;
|
|
//quit();
|
|
break;
|
|
|
|
case SDL_SYSWMEVENT:
|
|
{
|
|
/*
|
|
debugLog("SYSWM!");
|
|
if (event.syswm.type == WM_ACTIVATE)
|
|
{
|
|
debugLog("ACTIVE");
|
|
this->unloadDevice();
|
|
this->reloadDevice();
|
|
}
|
|
else
|
|
{
|
|
debugLog("NOT ACTIVE");
|
|
this->unloadDevice();
|
|
}
|
|
*/
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (updateMouse)
|
|
{
|
|
mouse.scrollWheel += mouse.scrollWheelChange;
|
|
|
|
if (warpMouse)
|
|
{
|
|
setMousePosition(mouse.position);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
#define _VLN(x, y, x2, y2) glVertex2f(x, y); glVertex2f(x2, y2);
|
|
|
|
void Core::print(int x, int y, const char *str, float sz)
|
|
{
|
|
//Prof(Core_print);
|
|
/*
|
|
glLoadIdentity();
|
|
core->setupRenderPositionAndScale();
|
|
*/
|
|
///glPushAttrib(GL_ALL_ATTRIB_BITS);
|
|
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glPushMatrix();
|
|
//sz *= 8;
|
|
//float osz = sz;
|
|
float xx = x;
|
|
float yy = y;
|
|
glTranslatef(x, y-0.5f*sz, 0);
|
|
x = y = 0;
|
|
xx = 0; yy = 0;
|
|
bool isLower = false, wasLower = false;
|
|
int c=0;
|
|
|
|
/*
|
|
if (a == 1)
|
|
glDisable(GL_BLEND);
|
|
else
|
|
glEnable(GL_BLEND);
|
|
glColor4f(r,g,b,a);
|
|
*/
|
|
glLineWidth(1);
|
|
glScalef(sz*0.75f, sz, 1);
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
while (str[c] != '\0')
|
|
{
|
|
if (str[c] <= 'z' && str[c] >= 'a')
|
|
isLower = true;
|
|
else
|
|
isLower = false;
|
|
|
|
/*
|
|
if (isLower)
|
|
glScalef(sz*0.5f, sz*0.5f, 1);
|
|
else if (wasLower)
|
|
{
|
|
glScalef(sz, sz, 1);
|
|
wasLower = false;
|
|
}
|
|
*/
|
|
|
|
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:
|
|
/*
|
|
std::ostringstream os;
|
|
os << "Core::print doesn't know char: " << str[c];
|
|
debugLog(os.str());
|
|
*/
|
|
break;
|
|
}
|
|
if (isLower)
|
|
{
|
|
wasLower = true;
|
|
|
|
}
|
|
c++;
|
|
xx += 1.4f;
|
|
}
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
//glPopAttrib();
|
|
|
|
#endif
|
|
}
|
|
|
|
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()
|
|
{
|
|
// update cull data
|
|
//this->cullRadius = int((getVirtualWidth())*invGlobalScale);
|
|
this->cullRadius = baseCullRadius * invGlobalScale;
|
|
this->cullRadiusSqr = (float)this->cullRadius * (float)this->cullRadius;
|
|
this->cullCenter = cameraPos + Vector(400.0f*invGlobalScale,300.0f*invGlobalScale);
|
|
screenCullX1 = cameraPos.x;
|
|
screenCullX2 = cameraPos.x + 800*invGlobalScale;
|
|
screenCullY1 = cameraPos.y;
|
|
screenCullY2 = cameraPos.y + 600*invGlobalScale;
|
|
|
|
|
|
int cx = core->cameraPos.x + 400*invGlobalScale;
|
|
int cy = core->cameraPos.y + 300*invGlobalScale;
|
|
screenCenter = Vector(cx, cy);
|
|
}
|
|
|
|
void Core::render(int startLayer, int endLayer, bool useFrameBufferIfAvail)
|
|
{
|
|
|
|
BBGE_PROF(Core_render);
|
|
//HWND hwnd = _glfwWin.Wnd;
|
|
|
|
if (startLayer == -1 && endLayer == -1 && overrideStartLayer != 0)
|
|
{
|
|
startLayer = overrideStartLayer;
|
|
endLayer = overrideEndLayer;
|
|
}
|
|
|
|
if (core->minimized) return;
|
|
onRender();
|
|
|
|
invGlobalScale = 1.0f/globalScale.x;
|
|
invGlobalScaleSqr = invGlobalScale * invGlobalScale;
|
|
|
|
RenderObject::lastTextureApplied = 0;
|
|
|
|
updateCullData();
|
|
|
|
|
|
|
|
renderObjectCount = 0;
|
|
processedRenderObjectCount = 0;
|
|
totalRenderObjectCount = 0;
|
|
|
|
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glLoadIdentity(); // Reset The View
|
|
clearBuffers();
|
|
|
|
if (afterEffectManager && frameBuffer.isInited() && useFrameBufferIfAvail)
|
|
{
|
|
frameBuffer.startCapture();
|
|
}
|
|
|
|
setupRenderPositionAndScale();
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
bool doRender = false;
|
|
|
|
core->getD3DMatrixStack()->LoadIdentity();
|
|
|
|
|
|
core->scaleMatrixStack(globalScale.x*globalResolutionScale.x, globalScale.y*globalResolutionScale.y);
|
|
core->translateMatrixStack(-(cameraPos.x+cameraOffset.x), -(cameraPos.y+cameraOffset.y));
|
|
|
|
clearBuffers();
|
|
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
|
|
{
|
|
doRender = true;
|
|
//d3dSprite->Begin(D3DXSPRITE_BILLBOARD | D3DXSPRITE_ALPHABLEND);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
//default
|
|
if (renderObjectLayerOrder.empty())
|
|
{
|
|
renderObjectLayerOrder.resize(renderObjectLayers.size());
|
|
for (int i = 0; i < renderObjectLayerOrder.size(); i++)
|
|
{
|
|
renderObjectLayerOrder[i] = i;
|
|
}
|
|
}
|
|
*/
|
|
RenderObject::rlayer = 0;
|
|
|
|
for (int c = 0; c < renderObjectLayerOrder.size(); c++)
|
|
//for (int i = 0; i < renderObjectLayers.size(); i++)
|
|
{
|
|
int i = renderObjectLayerOrder[c];
|
|
if (i == -1) continue;
|
|
if ((startLayer != -1 && endLayer != -1) && (i < startLayer || i > endLayer)) continue;
|
|
if (afterEffectManager && afterEffectManager->active && i == afterEffectManagerLayer)
|
|
{
|
|
afterEffectManager->render();
|
|
}
|
|
|
|
if (i == postProcessingFx.layer)
|
|
{
|
|
postProcessingFx.preRender();
|
|
}
|
|
if (i == postProcessingFx.renderLayer)
|
|
{
|
|
postProcessingFx.render();
|
|
}
|
|
|
|
if (darkLayer.isUsed() )
|
|
{
|
|
/*
|
|
if (i == darkLayer.getLayer())
|
|
{
|
|
darkLayer.preRender();
|
|
}
|
|
*/
|
|
if (i == darkLayer.getRenderLayer())
|
|
{
|
|
darkLayer.render();
|
|
}
|
|
|
|
if (i == darkLayer.getLayer() && startLayer != i)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
if (doRender)
|
|
{
|
|
// End the scene
|
|
//d3dSprite->End();
|
|
//core->getD3DMatrixStack()->Pop();
|
|
g_pd3dDevice->EndScene();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void Core::showBuffer()
|
|
{
|
|
BBGE_PROF(Core_showBuffer);
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_GL_SwapBuffers();
|
|
//glFlush();
|
|
#endif
|
|
#ifdef BBGE_BUILD_GLFW
|
|
glfwSwapBuffers();
|
|
//_glfwPlatSwapBuffers();
|
|
#endif
|
|
#ifdef BBGE_BUILD_DIRECTX
|
|
// Present the backbuffer contents to the display
|
|
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
|
|
#endif
|
|
}
|
|
|
|
// WARNING: only for use during shutdown
|
|
// otherwise, textures will try to remove themselves
|
|
// when destroy is called on them
|
|
void Core::clearResources()
|
|
{
|
|
std::vector<Resource*> deletedResources;
|
|
int i;
|
|
for (i = 0; i < resources.size(); i++)
|
|
{
|
|
int j = 0;
|
|
for (j = 0; j < deletedResources.size(); j++)
|
|
{
|
|
if (deletedResources[j] == resources[i])
|
|
break;
|
|
}
|
|
if (j == deletedResources.size())
|
|
{
|
|
deletedResources.push_back (resources[i]);
|
|
Resource *r = resources[i];
|
|
try
|
|
{
|
|
r->destroy();
|
|
delete r;
|
|
}
|
|
catch(...)
|
|
{
|
|
errorLog("Resource could not be deleted " + resourceNames[i]);
|
|
}
|
|
}
|
|
}
|
|
resourceNames.clear();
|
|
resources.clear();
|
|
}
|
|
|
|
void Core::shutdownInputLibrary()
|
|
{
|
|
#if defined(BBGE_BUILD_WINDOWS) && !defined(BBGE_BUILD_SDL)
|
|
g_pKeyboard->Unacquire();
|
|
g_pKeyboard->Release();
|
|
g_pKeyboard = 0;
|
|
g_pMouse->Unacquire();
|
|
g_pMouse->Release();
|
|
g_pMouse = 0;
|
|
#endif
|
|
}
|
|
|
|
void Core::shutdownJoystickLibrary()
|
|
{
|
|
if (joystickEnabled) {
|
|
joystick.shutdown();
|
|
#ifdef BBGE_BUIDL_SDL
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
#endif
|
|
joystickEnabled = false;
|
|
}
|
|
}
|
|
|
|
void Core::clearRenderObjects()
|
|
{
|
|
for (int i = 0; i < renderObjectLayers.size(); i++)
|
|
{
|
|
/*
|
|
for (int j = 0; j < renderObjectLayers[i].renderObjects.size(); j++)
|
|
{
|
|
RenderObject *r = renderObjectLayers[i].renderObjects[j];
|
|
*/
|
|
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");
|
|
|
|
|
|
|
|
#ifdef BBGE_BUILD_GLFW
|
|
debugLog("Terminate GLFW...");
|
|
//killGlWindow();
|
|
glfwTerminate();
|
|
debugLog("OK");
|
|
#endif
|
|
|
|
#ifdef BBGE_BUILD_VFS
|
|
debugLog("Unload VFS...");
|
|
vfs.Clear();
|
|
debugLog("OK");
|
|
#endif
|
|
|
|
|
|
#ifdef BBGE_BUILD_SDL
|
|
debugLog("SDL Quit...");
|
|
SDL_Quit();
|
|
debugLog("OK");
|
|
#endif
|
|
}
|
|
|
|
//util funcs
|
|
|
|
void Core::instantQuit()
|
|
{
|
|
#ifdef BBGE_BUILD_SDL
|
|
SDL_Event event;
|
|
event.type = SDL_QUIT;
|
|
SDL_PushEvent(&event);
|
|
#endif
|
|
}
|
|
|
|
bool Core::exists(const std::string &filename)
|
|
{
|
|
return ::exists(filename, false); // defined in Base.cpp
|
|
}
|
|
|
|
Resource* Core::findResource(const std::string &name)
|
|
{
|
|
for (int i = 0; i < resources.size(); i++)
|
|
{
|
|
if (resources[i]->name == name)
|
|
{
|
|
return resources[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
Texture* Core::findTexture(const std::string &name)
|
|
{
|
|
//stringToUpper(name);
|
|
//std::ofstream out("texturefind.log");
|
|
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)
|
|
{
|
|
return (Texture*)resources[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::string Core::getInternalTextureName(const std::string &name)
|
|
{
|
|
std::string n = name;
|
|
stringToUpper(n);
|
|
return n;
|
|
}
|
|
|
|
// 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] == ':'))
|
|
|
|
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;
|
|
}
|
|
|
|
Texture *Core::doTextureAdd(const std::string &texture, const std::string &loadName, std::string internalTextureName)
|
|
{
|
|
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);
|
|
Texture *t = core->findTexture(internalTextureName);
|
|
if (t)
|
|
{
|
|
t->addRef();
|
|
|
|
Texture::textureError = TEXERR_OK;
|
|
|
|
/*
|
|
std::ostringstream os;
|
|
os << "reference texture: " << internalTextureName << " ref: " << t->getRef();
|
|
debugLog(os.str());
|
|
*/
|
|
|
|
//msg ("found texture " + internalTextureName);
|
|
return t;
|
|
}
|
|
|
|
t = new Texture;
|
|
t->name = internalTextureName;
|
|
t->load(loadName);
|
|
t->addRef();
|
|
//resources.push_back (t);
|
|
addResource(t);
|
|
|
|
if (debugLogTextures)
|
|
{
|
|
std::ostringstream os;
|
|
os << "LOADED TEXTURE FROM DISK: [" << internalTextureName << "] ref: " << t->getRef() << " idx: " << resources.size()-1;
|
|
debugLog(os.str());
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
Texture* Core::addTexture(const std::string &textureName)
|
|
{
|
|
if (textureName.empty()) return 0;
|
|
|
|
BBGE_PROF(Core_addTexture);
|
|
|
|
Texture *texPointer = 0;
|
|
|
|
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;
|
|
texPointer = doTextureAdd(texture, loadName, internalTextureName);
|
|
if (Texture::textureError != TEXERR_OK)
|
|
{
|
|
if (texPointer)
|
|
{
|
|
texPointer->destroy();
|
|
texPointer = 0;
|
|
}
|
|
texPointer = doTextureAdd(t, ln, internalTextureName);
|
|
}
|
|
}
|
|
else
|
|
texPointer = doTextureAdd(texture, loadName, internalTextureName);
|
|
|
|
return texPointer;
|
|
}
|
|
|
|
void Core::removeTexture(std::string texture)
|
|
{
|
|
//std::string internalName = baseTextureDirectory + texture;
|
|
removeResource(texture, DESTROY);
|
|
}
|
|
|
|
|
|
void Core::addRenderObject(RenderObject *o, int layer)
|
|
{
|
|
if (!o) return;
|
|
o->layer = layer;
|
|
if (layer < 0 || layer >= renderObjectLayers.size())
|
|
{
|
|
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()
|
|
{
|
|
for (int i = 0; i < resources.size(); i++)
|
|
{
|
|
resources[i]->unload();
|
|
}
|
|
}
|
|
|
|
void Core::onReloadResources()
|
|
{
|
|
}
|
|
|
|
void Core::reloadResources()
|
|
{
|
|
for (int i = 0; i < resources.size(); i++)
|
|
{
|
|
resources[i]->reload();
|
|
}
|
|
onReloadResources();
|
|
}
|
|
|
|
void Core::addResource(Resource *r)
|
|
{
|
|
resources.push_back(r);
|
|
resourceNames.push_back(r->name);
|
|
if (r->name.empty())
|
|
{
|
|
debugLog("Empty name resource added");
|
|
}
|
|
}
|
|
|
|
void Core::removeResource(std::string name, RemoveResource removeFlag)
|
|
{
|
|
//Resource *r = findResource(name);
|
|
//int idx = 0;
|
|
int i = 0;
|
|
std::vector<Resource*>copy;
|
|
copy = resources;
|
|
resources.clear();
|
|
|
|
|
|
std::vector <std::string> copyNames;
|
|
copyNames = resourceNames;
|
|
resourceNames.clear();
|
|
|
|
bool isDestroyed = false;
|
|
|
|
|
|
for (i = 0; i < copy.size(); i++)
|
|
{
|
|
#ifdef _DEBUG
|
|
std::string s = copy[i]->name;
|
|
#endif
|
|
if (!isDestroyed && copy[i]->name == name)
|
|
{
|
|
if (removeFlag == DESTROY)
|
|
{
|
|
copy[i]->destroy();
|
|
delete copy[i];
|
|
isDestroyed = true;
|
|
}
|
|
continue;
|
|
}
|
|
// also remove other entries of the same resource
|
|
else if (isDestroyed && copyNames[i] == name)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
resources.push_back(copy[i]);
|
|
resourceNames.push_back(copy[i]->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Core::deleteRenderObjectMemory(RenderObject *r)
|
|
{
|
|
//if (!r->allocStatic)
|
|
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)
|
|
{
|
|
if (!object->_dead) // && !object->staticallyAllocated)
|
|
{
|
|
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();
|
|
|
|
// to clear resources
|
|
for (std::vector<Resource*>::iterator i = resources.begin(); i != resources.end(); )
|
|
{
|
|
if ((*i)->getRef() == 0)
|
|
{
|
|
clearedGarbageFlag = true;
|
|
delete (*i);
|
|
i = resources.erase(i);
|
|
continue;
|
|
}
|
|
|
|
if ((*i)->getRef() < 0)
|
|
{
|
|
errorLog("Texture ref < 0");
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
bool Core::canChangeState()
|
|
{
|
|
return (nestedMains<=1);
|
|
}
|
|
|
|
/*
|
|
int Core::getVirtualWidth()
|
|
{
|
|
return virtualWidth;
|
|
}
|
|
|
|
int Core::getVirtualHeight()
|
|
{
|
|
return virtualHeight;
|
|
}
|
|
*/
|
|
|
|
// 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)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
|
|
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;
|
|
|
|
#else
|
|
|
|
#warning FIXME: Need to implement non-GL grabScreenshot().
|
|
// Avoid crashing, at least.
|
|
return new unsigned char[sizeof(unsigned char) * w * h * 4];
|
|
|
|
#endif
|
|
}
|
|
|
|
// 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);
|
|
|
|
float wbit = fsz;//+1;
|
|
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);
|
|
|
|
/*
|
|
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);
|
|
*/
|
|
|
|
//glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
|
|
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");
|
|
//glPopAttrib();
|
|
|
|
debugLog("done");
|
|
}
|
|
|
|
void Core::save64x64ScreenshotTGA(const std::string &filename)
|
|
{
|
|
#ifdef BBGE_BUILD_OPENGL
|
|
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);
|
|
#endif
|
|
|
|
// do NOT free imageData here
|
|
// it IS freed in tgaSave
|
|
//free(imageData);
|
|
}
|
|
|
|
|
|
|
|
|
|
// saves an array of pixels as a TGA image (frees the image data passed in)
|
|
int Core::tgaSave( const char *filename,
|
|
short int width,
|
|
short int height,
|
|
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) {
|
|
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;
|
|
|
|
// 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);
|
|
delete [] imageData;
|
|
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);
|
|
delete [] imageData;
|
|
return (int)false;
|
|
}
|
|
|
|
fclose(file);
|
|
delete [] imageData;
|
|
|
|
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;
|
|
// ilutGLScreenie();
|
|
}
|
|
|
|
|
|
#include "DeflateCompressor.h"
|
|
|
|
// saves an array of pixels as a TGA image (frees the image data passed in)
|
|
int Core::zgaSave( const char *filename,
|
|
short int w,
|
|
short int h,
|
|
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())
|
|
exit(1);
|
|
|
|
vfs.AddArchiveLoader(new ttvfs::VFSZipArchiveLoader);
|
|
|
|
if(!vfs.LoadFileSysRoot(false))
|
|
{
|
|
errorLog("Failed to setup file access");
|
|
exit(1);
|
|
}
|
|
|
|
vfs.Prepare();
|
|
|
|
// TODO: mount and other stuff
|
|
|
|
//vfs.AddArchive("aqfiles.zip", false, "");
|
|
|
|
if(_extraDataDir.length())
|
|
vfs.MountExternalPath(_extraDataDir.c_str(), "", true, true);
|
|
|
|
|
|
debugLog("Done");
|
|
#endif
|
|
}
|