1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-26 06:35:51 +00:00
Aquaria/BBGE/Core.cpp
2013-12-12 10:34:15 +00:00

5170 lines
112 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"
#ifdef BBGE_BUILD_SDL2
static SDL_Window *gScreen=0;
static SDL_GLContext gGLctx=0;
#else
static SDL_Surface *gScreen=0;
#endif
bool ignoreNextMouse=false;
Vector unchange;
#endif
Core *core = 0;
#ifdef BBGE_BUILD_WINDOWS
HICON icon_windows = 0;
#endif
#ifndef KMOD_GUI
#define KMOD_GUI KMOD_META
#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_GetWindowWMInfo(gScreen, &wminfo) != 1)
{
//errorLog("wrong SDL version");
// error: wrong SDL version
}
HWND hwnd = wminfo.info.win.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
#ifndef BBGE_BUILD_SDL2
SDL_WM_SetCaption(caption.c_str(), icon.c_str());
#endif
#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("Error!", s);
debugLog(s);
}
void Core::messageBox(const std::string &title, const std::string &msg)
{
::messageBox(title, msg);
}
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;
current_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
#ifdef BBGE_BUILD_SDL2
SDL_SetWindowGrab(gScreen, on ? SDL_TRUE : SDL_FALSE);
#else
SDL_WM_GrabInput(on?SDL_GRAB_ON:SDL_GRAB_OFF);
#endif
#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
#ifndef BBGE_BUILD_SDL2
// 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");
#endif
if((SDL_Init(0))==-1)
{
exit_error("Failed to init SDL");
}
#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
#ifdef BBGE_BUILD_SDL2
SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER);
#else
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
#endif
#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
#ifndef BBGE_BUILD_SDL2
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, _vsync);
#endif
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#endif
}
#ifdef GLAPIENTRY
#undef GLAPIENTRY
#endif
#ifdef BBGE_BUILD_WINDOWS
#define GLAPIENTRY APIENTRY
#else
#define GLAPIENTRY
#endif
unsigned int Core::dbg_numRenderCalls = 0;
#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 { ++Core::dbg_numRenderCalls; 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");
#ifndef BBGE_BUILD_SDL2
#if !defined(BBGE_BUILD_MACOSX)
// 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");
#endif
#endif
//SDL_putenv((char *) "LIBGL_DEBUG=verbose"); // temp, to track errors on linux with nouveau drivers.
if (recreate)
{
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
{
exit_error(std::string("SDL Error: ") + std::string(SDL_GetError()));
}
#if BBGE_BUILD_OPENGL_DYNAMIC
if (SDL_GL_LoadLibrary(NULL) == -1)
{
std::string err = std::string("SDL_GL_LoadLibrary Error: ") + std::string(SDL_GetError());
SDL_Quit();
exit_error(err);
}
#endif
}
setWindowCaption(appName, appName);
initIcon();
// Create window
setSDLGLAttributes();
//if (!didOnce)
{
#ifdef BBGE_BUILD_SDL2
Uint32 flags = 0;
flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
if (fullscreen)
flags |= SDL_WINDOW_FULLSCREEN;
gScreen = SDL_CreateWindow(appName.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
if (gScreen == NULL)
{
std::ostringstream os;
os << "Couldn't set resolution [" << width << "x" << height << "]\n" << SDL_GetError();
errorLog(os.str());
SDL_Quit();
exit(0);
}
gGLctx = SDL_GL_CreateContext(gScreen);
if (gGLctx == NULL)
{
std::ostringstream os;
os << "Couldn't create OpenGL context!\n" << SDL_GetError();
errorLog(os.str());
SDL_Quit();
exit(0);
}
#else
Uint32 flags = 0;
flags = SDL_OPENGL;
if (fullscreen)
flags |= SDL_FULLSCREEN;
gScreen = SDL_SetVideoMode(width, height, bpp, flags);
if (gScreen == NULL)
{
std::ostringstream os;
os << "Couldn't set resolution [" << width << "x" << height << "]\n" << SDL_GetError();
SDL_Quit();
exit_error(os.str());
}
#endif
#if BBGE_BUILD_OPENGL_DYNAMIC
if (!lookup_all_glsyms())
{
std::ostringstream os;
os << "Couldn't load OpenGL symbols we need\n";
SDL_Quit();
exit_error(os.str());
}
#endif
}
setWindowCaption(appName, appName);
#ifdef BBGE_BUILD_SDL2
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SDL_GL_SwapWindow(gScreen);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SDL_GL_SwapWindow(gScreen);
if ((_vsync != 1) || (SDL_GL_SetSwapInterval(-1) == -1))
SDL_GL_SetSwapInterval(_vsync);
const char *name = SDL_GetCurrentVideoDriver();
SDL_SetWindowGrab(gScreen, SDL_TRUE);
#else
SDL_WM_GrabInput(grabInputOnReentry==0 ? SDL_GRAB_OFF : SDL_GRAB_ON);
char name[256];
SDL_VideoDriverName((char*)name, 256);
#endif
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
#ifdef BBGE_BUILD_SDL2
SDL_DisplayMode mode;
const int modecount = SDL_GetNumDisplayModes(0);
if(modecount == 0){
debugLog("No modes available!");
return;
}
for (int i = 0; i < modecount; i++) {
SDL_GetDisplayMode(0, i, &mode);
if (mode.w && mode.h && (mode.w > mode.h))
{
screenModes.push_back(ScreenMode(i, mode.w, mode.h));
}
}
#else
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
#endif
}
void Core::shutdownSoundLibrary()
{
}
void Core::shutdownGraphicsLibrary(bool killVideo)
{
#ifdef BBGE_BUILD_SDL
glFinish();
if (killVideo) {
#ifdef BBGE_BUILD_SDL2
SDL_SetWindowGrab(gScreen, SDL_FALSE);
SDL_GL_MakeCurrent(gScreen, NULL);
SDL_GL_DeleteContext(gGLctx);
SDL_DestroyWindow(gScreen);
gGLctx = 0;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
#else
SDL_QuitSubSystem(SDL_INIT_VIDEO);
SDL_WM_GrabInput(SDL_GRAB_OFF);
#endif
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::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;
#ifdef BBGE_BUILD_SDL2
SDL_WarpMouseInWindow(gScreen, px * (float(width)/float(virtualWidth)), py * (float(height)/float(virtualHeight)));
#else
SDL_WarpMouse( px * (float(width)/float(virtualWidth)), py * (float(height)/float(virtualHeight)));
#endif
/*
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)
{
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
#ifdef BBGE_BUILD_SDL2
return ((SDL_GetWindowFlags(gScreen) & SDL_WINDOW_INPUT_FOCUS) != 0);
#else
return ((SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0);
#endif
#endif
return true;
}
void Core::onBackgroundUpdate()
{
#if BBGE_BUILD_SDL
SDL_Delay(200);
#endif
}
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");
onBackgroundUpdate();
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);
current_dt = 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();
dbg_numRenderCalls = 0;
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;
}
}
sound->setListenerPos(screenCenter.x, screenCenter.y);
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;
}
#if defined(BBGE_BUILD_SDL)
#if defined(BBGE_BUILD_SDL2)
typedef std::map<SDL_Keycode,int> sdlKeyMap;
#else
typedef std::map<SDLKey,int> sdlKeyMap;
#endif
static sdlKeyMap *initSDLKeymap(void)
{
sdlKeyMap *_retval = new sdlKeyMap;
sdlKeyMap &retval = *_retval;
#define SETKEYMAP(gamekey,sdlkey) retval[sdlkey] = gamekey
#ifdef BBGE_BUILD_SDL2
SETKEYMAP(KEY_LSUPER, SDLK_LGUI);
SETKEYMAP(KEY_RSUPER, SDLK_RGUI);
SETKEYMAP(KEY_LMETA, SDLK_LGUI);
SETKEYMAP(KEY_RMETA, SDLK_RGUI);
SETKEYMAP(KEY_PRINTSCREEN, SDLK_PRINTSCREEN);
SETKEYMAP(KEY_NUMPAD1, SDLK_KP_1);
SETKEYMAP(KEY_NUMPAD2, SDLK_KP_2);
SETKEYMAP(KEY_NUMPAD3, SDLK_KP_3);
SETKEYMAP(KEY_NUMPAD4, SDLK_KP_4);
SETKEYMAP(KEY_NUMPAD5, SDLK_KP_5);
SETKEYMAP(KEY_NUMPAD6, SDLK_KP_6);
SETKEYMAP(KEY_NUMPAD7, SDLK_KP_7);
SETKEYMAP(KEY_NUMPAD8, SDLK_KP_8);
SETKEYMAP(KEY_NUMPAD9, SDLK_KP_9);
SETKEYMAP(KEY_NUMPAD0, SDLK_KP_0);
#else
SETKEYMAP(KEY_LSUPER, SDLK_LSUPER);
SETKEYMAP(KEY_RSUPER, SDLK_RSUPER);
SETKEYMAP(KEY_LMETA, SDLK_LMETA);
SETKEYMAP(KEY_RMETA, SDLK_RMETA);
SETKEYMAP(KEY_PRINTSCREEN, SDLK_PRINT);
SETKEYMAP(KEY_NUMPAD1, SDLK_KP1);
SETKEYMAP(KEY_NUMPAD2, SDLK_KP2);
SETKEYMAP(KEY_NUMPAD3, SDLK_KP3);
SETKEYMAP(KEY_NUMPAD4, SDLK_KP4);
SETKEYMAP(KEY_NUMPAD5, SDLK_KP5);
SETKEYMAP(KEY_NUMPAD6, SDLK_KP6);
SETKEYMAP(KEY_NUMPAD7, SDLK_KP7);
SETKEYMAP(KEY_NUMPAD8, SDLK_KP8);
SETKEYMAP(KEY_NUMPAD9, SDLK_KP9);
SETKEYMAP(KEY_NUMPAD0, SDLK_KP0);
#endif
SETKEYMAP(KEY_BACKSPACE, SDLK_BACKSPACE);
//SETKEYMAP(KEY_CAPSLOCK, DIK_CAPSLOCK);
//SETKEYMAP(KEY_CIRCUMFLEX, DIK_CIRCUMFLEX);
SETKEYMAP(KEY_LALT, SDLK_LALT);
SETKEYMAP(KEY_RALT, SDLK_RALT);
SETKEYMAP(KEY_LSHIFT, SDLK_LSHIFT);
SETKEYMAP(KEY_RSHIFT, SDLK_RSHIFT);
SETKEYMAP(KEY_LCONTROL, SDLK_LCTRL);
SETKEYMAP(KEY_RCONTROL, SDLK_RCTRL);
SETKEYMAP(KEY_NUMPADMINUS, SDLK_KP_MINUS);
SETKEYMAP(KEY_NUMPADPERIOD, SDLK_KP_PERIOD);
SETKEYMAP(KEY_NUMPADPLUS, SDLK_KP_PLUS);
SETKEYMAP(KEY_NUMPADSLASH, SDLK_KP_DIVIDE);
SETKEYMAP(KEY_NUMPADSTAR, SDLK_KP_MULTIPLY);
SETKEYMAP(KEY_PGDN, SDLK_PAGEDOWN);
SETKEYMAP(KEY_PGUP, SDLK_PAGEUP);
SETKEYMAP(KEY_APOSTROPHE, SDLK_QUOTE);
SETKEYMAP(KEY_EQUALS, SDLK_EQUALS);
SETKEYMAP(KEY_SEMICOLON, SDLK_SEMICOLON);
SETKEYMAP(KEY_LBRACKET, SDLK_LEFTBRACKET);
SETKEYMAP(KEY_RBRACKET, SDLK_RIGHTBRACKET);
//SETKEYMAP(KEY_RALT, GLFW_SETKEYMAP(KEY_RALT);
SETKEYMAP(KEY_TILDE, SDLK_BACKQUOTE);
SETKEYMAP(KEY_0, SDLK_0);
SETKEYMAP(KEY_1, SDLK_1);
SETKEYMAP(KEY_2, SDLK_2);
SETKEYMAP(KEY_3, SDLK_3);
SETKEYMAP(KEY_4, SDLK_4);
SETKEYMAP(KEY_5, SDLK_5);
SETKEYMAP(KEY_6, SDLK_6);
SETKEYMAP(KEY_7, SDLK_7);
SETKEYMAP(KEY_8, SDLK_8);
SETKEYMAP(KEY_9, SDLK_9);
SETKEYMAP(KEY_A, SDLK_a);
SETKEYMAP(KEY_B, SDLK_b);
SETKEYMAP(KEY_C, SDLK_c);
SETKEYMAP(KEY_D, SDLK_d);
SETKEYMAP(KEY_E, SDLK_e);
SETKEYMAP(KEY_F, SDLK_f);
SETKEYMAP(KEY_G, SDLK_g);
SETKEYMAP(KEY_H, SDLK_h);
SETKEYMAP(KEY_I, SDLK_i);
SETKEYMAP(KEY_J, SDLK_j);
SETKEYMAP(KEY_K, SDLK_k);
SETKEYMAP(KEY_L, SDLK_l);
SETKEYMAP(KEY_M, SDLK_m);
SETKEYMAP(KEY_N, SDLK_n);
SETKEYMAP(KEY_O, SDLK_o);
SETKEYMAP(KEY_P, SDLK_p);
SETKEYMAP(KEY_Q, SDLK_q);
SETKEYMAP(KEY_R, SDLK_r);
SETKEYMAP(KEY_S, SDLK_s);
SETKEYMAP(KEY_T, SDLK_t);
SETKEYMAP(KEY_U, SDLK_u);
SETKEYMAP(KEY_V, SDLK_v);
SETKEYMAP(KEY_W, SDLK_w);
SETKEYMAP(KEY_X, SDLK_x);
SETKEYMAP(KEY_Y, SDLK_y);
SETKEYMAP(KEY_Z, SDLK_z);
SETKEYMAP(KEY_LEFT, SDLK_LEFT);
SETKEYMAP(KEY_RIGHT, SDLK_RIGHT);
SETKEYMAP(KEY_UP, SDLK_UP);
SETKEYMAP(KEY_DOWN, SDLK_DOWN);
SETKEYMAP(KEY_DELETE, SDLK_DELETE);
SETKEYMAP(KEY_SPACE, SDLK_SPACE);
SETKEYMAP(KEY_RETURN, SDLK_RETURN);
SETKEYMAP(KEY_PERIOD, SDLK_PERIOD);
SETKEYMAP(KEY_MINUS, SDLK_MINUS);
SETKEYMAP(KEY_CAPSLOCK, SDLK_CAPSLOCK);
SETKEYMAP(KEY_SYSRQ, SDLK_SYSREQ);
SETKEYMAP(KEY_TAB, SDLK_TAB);
SETKEYMAP(KEY_HOME, SDLK_HOME);
SETKEYMAP(KEY_END, SDLK_END);
SETKEYMAP(KEY_COMMA, SDLK_COMMA);
SETKEYMAP(KEY_SLASH, SDLK_SLASH);
SETKEYMAP(KEY_F1, SDLK_F1);
SETKEYMAP(KEY_F2, SDLK_F2);
SETKEYMAP(KEY_F3, SDLK_F3);
SETKEYMAP(KEY_F4, SDLK_F4);
SETKEYMAP(KEY_F5, SDLK_F5);
SETKEYMAP(KEY_F6, SDLK_F6);
SETKEYMAP(KEY_F7, SDLK_F7);
SETKEYMAP(KEY_F8, SDLK_F8);
SETKEYMAP(KEY_F9, SDLK_F9);
SETKEYMAP(KEY_F10, SDLK_F10);
SETKEYMAP(KEY_F11, SDLK_F11);
SETKEYMAP(KEY_F12, SDLK_F12);
SETKEYMAP(KEY_F13, SDLK_F13);
SETKEYMAP(KEY_F14, SDLK_F14);
SETKEYMAP(KEY_F15, SDLK_F15);
SETKEYMAP(KEY_ESCAPE, SDLK_ESCAPE);
//SETKEYMAP(KEY_ANYKEY, 4059);
//SETKEYMAP(KEY_MAXARRAY, SDLK_LAST+1
#undef SETKEYMAP
return _retval;
}
#if defined(BBGE_BUILD_SDL2)
static int mapSDLKeyToGameKey(const SDL_Keycode val)
#else
static int mapSDLKeyToGameKey(const SDLKey val)
#endif
{
static sdlKeyMap *keymap = NULL;
if (keymap == NULL)
keymap = initSDLKeymap();
return (*keymap)[val];
}
#endif
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_GUI))
#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)
{
keys[mapSDLKeyToGameKey(event.key.keysym.sym)] = 1;
}
}
break;
case SDL_KEYUP:
{
if (_hasFocus)
{
keys[mapSDLKeyToGameKey(event.key.keysym.sym)] = 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;
#ifdef BBGE_BUILD_SDL2
case SDL_WINDOWEVENT:
{
if (event.window.event == SDL_WINDOWEVENT_CLOSE)
{
SDL_Quit();
_exit(0);
//loopDone = true;
//quit();
}
}
break;
case SDL_MOUSEWHEEL:
{
if (_hasFocus && updateMouse)
{
if (event.wheel.y > 0)
mouse.scrollWheelChange = 1;
else if (event.wheel.y < 0)
mouse.scrollWheelChange = -1;
}
}
break;
#else
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;
#endif
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 (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;
}
}
if (afterEffectManager && afterEffectManager->active && i == afterEffectManagerLayer)
{
afterEffectManager->render();
}
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_SDL2
SDL_GL_SwapWindow(gScreen);
#elif 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];
r->destroy();
delete r;
}
}
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_error("ttvfs not compatible");
vfs.AddArchiveLoader(new ttvfs::VFSZipArchiveLoader);
if(!vfs.LoadFileSysRoot(false))
{
exit_error("Failed to setup file access");
}
vfs.Prepare();
ttvfs::VFSDir *override = vfs.GetDir("override");
if(override)
{
debugLog("Mounting override dir...");
override->load(true);
vfs.Mount("override", "", true);
}
// If we ever want to read from a container...
//vfs.AddArchive("aqfiles.zip", false, "");
if(_extraDataDir.length())
{
debugLog("Mounting extra data dir: " + _extraDataDir);
vfs.MountExternalPath(_extraDataDir.c_str(), "", true, true);
}
debugLog("Done");
#endif
}