framework

This commit is contained in:
Eduardo Bart
2011-02-08 20:48:26 -02:00
parent 3d0b191199
commit b2c61760e5
34 changed files with 81 additions and 108 deletions

62
src/framework/color.h Normal file
View File

@@ -0,0 +1,62 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef COLOR_H
#define COLOR_H
#include "prerequisites.h"
typedef uint32 RGBA;
class Color
{
public:
Color() : color(0) { }
Color(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : color(((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff)) { }
Color(const Color& other) : color(other.color) { }
Color(RGBA rgba) : color(rgba) { }
uint8 red() const { return (color >> 24) & 0xFF; }
uint8 green() const { return (color >> 16) & 0xFF; }
uint8 blue() const { return (color >> 8) & 0xFF; }
uint8 alpha() const { return color & 0xFF; }
RGBA rgba() const { return color; }
const uint8* rgbaPtr() const { return (const uint8*)&color; }
void setRed(uint8 r) { color = ((r & 0xff)<<24) | (color & 0x00ffffff); }
void setGreen(uint8 g) { color = ((g & 0xff)<<16) | (color & 0xff00ffff); }
void setBlue(uint8 b) { color = ((b & 0xff)<<8) | (color & 0xffff00ff); }
void setAlpha(uint8 a) { color = (a & 0xff) | (color & 0xffffff00); }
void setRGBA(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) { color = ((r & 0xff)<<24) | ((g & 0xff)<<16) | ((b & 0xff)<<8) | (a & 0xff); }
void setRGBA(uint32 rgba) { color = rgba; }
Color& operator=(const Color& other) { color = other.color; return *this; }
bool operator==(const Color& other) const { return other.color == color; }
bool operator!=(const Color& other) const { return other.color != color; }
private:
RGBA color;
};
#endif // COLOR_H

View File

@@ -0,0 +1,152 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "configmanager.h"
#include "resourcemanager.h"
#include <yaml-cpp/yaml.h>
ConfigManager g_config;
ConfigManager::ConfigManager()
{
}
ConfigManager::~ConfigManager()
{
}
bool ConfigManager::load(const std::string& fileName)
{
m_fileName = fileName;
if(!g_resources.fileExists(fileName))
return false;
std::string fileContents = g_resources.loadTextFile(fileName);
if(fileContents.size() == 0)
return false;
std::istringstream fin(fileContents);
try {
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
for(YAML::Iterator it = doc.begin(); it != doc.end(); it++) {
std::string key, value;
it.first() >> key;
it.second() >> value;
m_confsMap[key] = value;
dump() << key << value;
}
} catch (YAML::ParserException& e) {
error("Malformed configuration file!");
return false;
}
return true;
}
void ConfigManager::save()
{
if(!m_fileName.empty()) {
YAML::Emitter out;
out << m_confsMap;
g_resources.saveFile(m_fileName, (const unsigned char*)out.c_str(), out.size());
}
}
void ConfigManager::setValue(const std::string &key, const std::string &value)
{
m_confsMap[key] = value;
}
void ConfigManager::setValue(const std::string &key, const char *value)
{
m_confsMap[key] = value;
}
void ConfigManager::setValue(const std::string &key, int value)
{
setValue(key, boost::lexical_cast<std::string>(value));
}
void ConfigManager::setValue(const std::string &key, float value)
{
setValue(key, boost::lexical_cast<std::string>(value));
}
void ConfigManager::setValue(const std::string &key, bool value)
{
if(value)
setValue(key,"true");
else
setValue(key,"false");
}
const std::string &ConfigManager::getString(const std::string &key)
{
std::map<std::string, std::string>::iterator iter = m_confsMap.find(key);
if(iter == m_confsMap.end()) {
warning("Config value %s not found", key.c_str());
static std::string emptystr;
return emptystr;
}
return iter->second;
}
float ConfigManager::getFloat(const std::string &key)
{
std::map<std::string, std::string>::iterator iter = m_confsMap.find(key);
if(iter == m_confsMap.end()) {
warning("Config value %s not found", key.c_str());
return 0;
}
return boost::lexical_cast<float>(iter->second);
}
bool ConfigManager::getBoolean(const std::string &key)
{
std::map<std::string, std::string>::iterator iter = m_confsMap.find(key);
if(iter == m_confsMap.end()) {
warning("Config value %s not found", key.c_str());
return 0;
}
return (iter->second == "true");
}
int ConfigManager::getInteger(const std::string &key)
{
std::map<std::string, std::string>::iterator iter = m_confsMap.find(key);
if(iter == m_confsMap.end()) {
warning("Config value %s not found", key.c_str());
return 0;
}
return boost::lexical_cast<int>(iter->second);
}

View File

@@ -0,0 +1,60 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CONFIGMANAGER_H
#define CONFIGMANAGER_H
#include "prerequisites.h"
class ConfigManager
{
public:
ConfigManager();
~ConfigManager();
/// Read configuration file and parse all settings to memory
bool load(const std::string& fileName);
/// Dump all settings to configuration file
void save();
void setValue(const std::string &key, const std::string &value);
void setValue(const std::string &key, const char *value);
void setValue(const std::string &key, float value);
void setValue(const std::string &key, bool value);
void setValue(const std::string &key, int value);
const std::string &getString(const std::string &key);
float getFloat(const std::string &key);
bool getBoolean(const std::string &key);
int getInteger(const std::string &key);
private:
std::string m_fileName;
std::map<std::string, std::string> m_confsMap;
};
extern ConfigManager g_config;
#endif // CONFIGMANAGER_H

151
src/framework/engine.cpp Normal file
View File

@@ -0,0 +1,151 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "engine.h"
#include "platform.h"
#include "graphics.h"
#include "input.h"
#include "configmanager.h"
#include "gamestate.h"
Engine g_engine;
Engine::Engine() :
m_stopping(false),
m_running(false),
m_currentState(NULL)
{
}
Engine::~Engine()
{
}
void Engine::init()
{
Platform::init();
int width = g_config.getInteger("width");
int height = g_config.getInteger("height");
// create the window
Platform::createWindow(width, height, 550, 450);
Platform::setWindowTitle(APP_NAME);
Platform::setVsync();
// initialize graphics stuff
g_graphics.init();
// finally show the window
onResize(width, height);
Platform::showWindow();
Platform::hideMouseCursor();
}
void Engine::terminate()
{
changeState(NULL);
// save configs
g_config.setValue("width", Platform::getWindowWidth());
g_config.setValue("height", Platform::getWindowHeight());
Platform::showMouseCursor();
Platform::terminate();
g_graphics.terminate();
}
void Engine::run()
{
unsigned long ticks;
static unsigned long lastFrameTicks;
m_running = true;
lastFrameTicks = Platform::getTicks();
while(!m_stopping) {
// fire platform events
Platform::poll();
// update
ticks = Platform::getTicks();
update(ticks - lastFrameTicks);
lastFrameTicks = ticks;
// render
render();
// swap buffers
Platform::swapBuffers();
}
lastFrameTicks = 0;
m_stopping = false;
m_running = false;
}
void Engine::stop()
{
m_stopping = true;
}
void Engine::changeState(GameState* newState)
{
if(m_currentState)
m_currentState->onLeave();
m_currentState = newState;
if(m_currentState)
m_currentState->onEnter();
}
void Engine::render()
{
g_graphics.beginRender();
if(m_currentState)
m_currentState->render();
g_graphics.endRender();
}
void Engine::update(int elapsedTicks)
{
if(m_currentState)
m_currentState->update(elapsedTicks);
}
void Engine::onClose()
{
if(m_currentState)
m_currentState->onClose();
}
void Engine::onResize(int width, int height)
{
g_graphics.resize(width, height);
}
void Engine::onInputEvent(InputEvent *event)
{
if(m_currentState)
m_currentState->onInputEvent(event);
}

77
src/framework/engine.h Normal file
View File

@@ -0,0 +1,77 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ENGINE_H
#define ENGINE_H
#include "prerequisites.h"
struct InputEvent;
class GameState;
class Engine
{
public:
Engine();
~Engine();
void init();
void terminate();
/// Main loop
void run();
/// Stops main loop
void stop();
/// Change current game state
void changeState(GameState *newState);
bool isRunning() const { return m_running; }
bool isStopping() const { return m_stopping; }
/// Fired by platform on window close
void onClose();
/// Fired by platform on window resize
void onResize(int width, int height);
/// Fired by platform on mouse/keyboard input
void onInputEvent(InputEvent *event);
private:
/// Called to render every frame
void render();
/// Called between renders
void update(int elapsedTicks);
bool m_stopping;
bool m_running;
GameState *m_currentState;
};
extern Engine g_engine;
#endif // ENGINE_H

View File

@@ -0,0 +1,133 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "framebuffer.h"
#include "platform.h"
#include "graphics.h"
FrameBuffer::FrameBuffer(int width, int height)
{
m_fbo = 0;
m_width = width;
m_height = height;
// create FBO texture
glGenTextures(1, &m_fboTexture);
glBindTexture(GL_TEXTURE_2D, m_fboTexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// we want bilinear filtering (for a smooth framebuffer)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// use FBO ext only if supported
if(Platform::isExtensionSupported("EXT_framebuffer_object")) {
m_fallbackOldImp = false;
// generate FBO
glGenFramebuffersEXT(1, &m_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
// attach 2D texture to this FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_fboTexture, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
//ok
break;
default: // fallback to old implementation
m_fallbackOldImp = true;
break;
}
} else {
// otherwise fallback to copy texture from screen implementation
m_fallbackOldImp = true;
}
}
FrameBuffer::~FrameBuffer()
{
glDeleteTextures(1, &m_fboTexture);
if(m_fbo)
glDeleteFramebuffersEXT(1, &m_fbo);
}
void FrameBuffer::bind()
{
if(!m_fallbackOldImp) {
// bind framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
}
// setup framebuffer viewport
glViewport(0, 0, m_width, m_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0f, m_width, 0, m_height);
// back to model view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// clear framebuffer
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
}
void FrameBuffer::unbind()
{
if(!m_fallbackOldImp) {
// bind back buffer again
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);
glReadBuffer(GL_BACK);
// restore graphics viewport
g_graphics.restoreViewport();
} else {
// copy screen to texture
glBindTexture(GL_TEXTURE_2D, m_fboTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, m_height);
// restore graphics viewport
g_graphics.restoreViewport();
// clear screen
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
void FrameBuffer::draw(int x, int y, int width, int height)
{
glBindTexture(GL_TEXTURE_2D, m_fboTexture);
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(x, y);
glTexCoord2i(0, 1); glVertex2i(x, y+height);
glTexCoord2i(1, 1); glVertex2i(x+width, y+height);
glTexCoord2i(1, 0); glVertex2i(x+width, y);
glEnd();
}

View File

@@ -0,0 +1,53 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include "prerequisites.h"
class FrameBuffer
{
public:
FrameBuffer(int width, int height);
virtual ~FrameBuffer();
/// Bind the framebuffer, everything rendered will be draw on it
void bind();
/// Unbind the framebuffer, render on back buffer again
void unbind();
/// Draw framebuffer
void draw(int x, int y, int width, int height);
private:
GLuint m_fboTexture;
GLuint m_fbo;
bool m_fallbackOldImp;
int m_width;
int m_height;
};
#endif // FRAMEBUFFER_H

46
src/framework/gamestate.h Normal file
View File

@@ -0,0 +1,46 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef GAMESTATE_H
#define GAMESTATE_H
struct InputEvent;
class GameState
{
public:
GameState() { }
virtual ~GameState() { }
virtual void onEnter() = 0;
virtual void onLeave() = 0;
virtual void onClose() = 0;
virtual void onInputEvent(InputEvent *event) = 0;
virtual void render() = 0;
virtual void update(int elapsedTicks) = 0;
};
#endif // GAMESTATE_H

207
src/framework/graphics.cpp Normal file
View File

@@ -0,0 +1,207 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "graphics.h"
#include "logger.h"
#include "texture.h"
Graphics g_graphics;
Graphics::Graphics()
{
}
Graphics::~Graphics()
{
}
void Graphics::init()
{
// setup opengl
glEnable(GL_ALPHA_TEST); // enable alpha by default
glAlphaFunc(GL_GREATER, 0.0f); // default alpha mode
glDisable(GL_DEPTH_TEST); // we are rendering 2D only, we don't need it
glEnable(GL_TEXTURE_2D); // enable textures by default
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glShadeModel(GL_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
notice("GPU %s", (const char*)glGetString(GL_RENDERER));
notice("OpenGL %s", (const char*)glGetString(GL_VERSION));
}
void Graphics::terminate()
{
}
void Graphics::resize(int width, int height)
{
m_screenSize.setWidth(width);
m_screenSize.setHeight(height);
restoreViewport();
}
void Graphics::restoreViewport()
{
const int& width = m_screenSize.width();
const int& height = m_screenSize.height();
// resize gl viewport
glViewport(0, 0, width, height);
/*
0,0---------0,w
| |
| |
| |
h,0---------h,w
*/
// setup view region like above
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0f, width, height, 0.0f);
// back to model view
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Graphics::beginRender()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
}
void Graphics::endRender()
{
}
void Graphics::drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords)
{
// rect correction for opengl
int right = screenCoords.right()+1;
int bottom = screenCoords.bottom()+1;
int top = screenCoords.top();
int left = screenCoords.left();
float tright;
float tbottom;
float ttop;
float tleft;
if(!texCoords.isEmpty()) {
const Size& textureSize = texture->getSize();
tright = (float)(texCoords.right()+1)/textureSize.width();
tbottom = (float)(texCoords.bottom()+1)/textureSize.height();
ttop = (float)texCoords.top()/textureSize.height();
tleft = (float)texCoords.left()/textureSize.width();
} else {
tright = 0.0f;
tbottom = 1.0f;
ttop = 0.0f;
tleft = 1.0f;
}
glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
glBegin(GL_QUADS);
glTexCoord2f(tleft, ttop); glVertex2i(left, top);
glTexCoord2f(tleft, tbottom); glVertex2i(left, bottom);
glTexCoord2f(tright, tbottom); glVertex2i(right, bottom);
glTexCoord2f(tright, ttop); glVertex2i(right, top);
glEnd();
}
void Graphics::drawColoredRect(const Rect& screenCoords, const Color& color)
{
glDisable(GL_TEXTURE_2D);
glColor4ubv(color.rgbaPtr());
// rect correction for opengl
int right = screenCoords.right()+1;
int bottom = screenCoords.bottom()+1;
int top = screenCoords.top();
int left = screenCoords.left();
glBegin(GL_QUADS);
glVertex2i(left, top);
glVertex2i(left, bottom);
glVertex2i(right, bottom);
glVertex2i(right, top);
glEnd();
glEnable(GL_TEXTURE_2D);
}
void Graphics::drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth)
{
if(2*innerLineWidth > screenCoords.height())
return;
glDisable(GL_TEXTURE_2D);
glColor4ubv(color.rgbaPtr());
// rect correction for opengl
int right = screenCoords.right()+1;
int bottom = screenCoords.bottom()+1;
int top = screenCoords.top();
int left = screenCoords.left();
glBegin(GL_QUADS);
// top line
glVertex2i(left, top);
glVertex2i(left, top+innerLineWidth);
glVertex2i(right, top+innerLineWidth);
glVertex2i(right, top);
// left
glVertex2i(left, screenCoords.top()+innerLineWidth);
glVertex2i(left, bottom-innerLineWidth);
glVertex2i(left+innerLineWidth, bottom-innerLineWidth);
glVertex2i(left+innerLineWidth, screenCoords.top()+innerLineWidth);
// bottom line
glVertex2i(left, bottom);
glVertex2i(left, bottom-innerLineWidth);
glVertex2i(right, bottom-innerLineWidth);
glVertex2i(right, bottom);
// right line
glVertex2i(right, top+innerLineWidth);
glVertex2i(right, bottom-innerLineWidth);
glVertex2i(right-innerLineWidth, bottom-innerLineWidth);
glVertex2i(right-innerLineWidth, top+innerLineWidth);
glEnd();
glEnable(GL_TEXTURE_2D);
}

68
src/framework/graphics.h Normal file
View File

@@ -0,0 +1,68 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include "prerequisites.h"
#include "rect.h"
#include "size.h"
#include "color.h"
class Texture;
class Graphics
{
public:
Graphics();
~Graphics();
void init();
void terminate();
/// Called after every window resize
void resize(int width, int height);
/// Restore original viewport
void restoreViewport();
/// Called before every render
void beginRender();
/// Called after every render
void endRender();
const Size& getScreenSize() const { return m_screenSize; }
void drawTexturedRect(const Rect& screenCoords, const Texture *texture, const Rect& texCoords = Rect());
void drawColoredRect(const Rect& screenCoords, const Color& color);
void drawBoundingRect(const Rect& screenCoords, const Color& color, int innerLineWidth);
private:
Size m_screenSize;
};
extern Graphics g_graphics;
#endif // GRAPHICS_H

211
src/framework/input.h Normal file
View File

@@ -0,0 +1,211 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef INPUT_H
#define INPUT_H
enum EKeyCode {
KC_UNKNOWN = 0x00,
KC_ESCAPE = 0x01,
KC_1 = 0x02,
KC_2 = 0x03,
KC_3 = 0x04,
KC_4 = 0x05,
KC_5 = 0x06,
KC_6 = 0x07,
KC_7 = 0x08,
KC_8 = 0x09,
KC_9 = 0x0A,
KC_0 = 0x0B,
KC_MINUS = 0x0C, // - on main keyboard
KC_EQUALS = 0x0D,
KC_BACK = 0x0E, // backspace
KC_TAB = 0x0F,
KC_Q = 0x10,
KC_W = 0x11,
KC_E = 0x12,
KC_R = 0x13,
KC_T = 0x14,
KC_Y = 0x15,
KC_U = 0x16,
KC_I = 0x17,
KC_O = 0x18,
KC_P = 0x19,
KC_LBRACKET = 0x1A,
KC_RBRACKET = 0x1B,
KC_RETURN = 0x1C, // Enter on main keyboard
KC_LCONTROL = 0x1D,
KC_A = 0x1E,
KC_S = 0x1F,
KC_D = 0x20,
KC_F = 0x21,
KC_G = 0x22,
KC_H = 0x23,
KC_J = 0x24,
KC_K = 0x25,
KC_L = 0x26,
KC_SEMICOLON = 0x27,
KC_APOSTROPHE = 0x28,
KC_GRAVE = 0x29, // accent
KC_LSHIFT = 0x2A,
KC_BACKSLASH = 0x2B,
KC_Z = 0x2C,
KC_X = 0x2D,
KC_C = 0x2E,
KC_V = 0x2F,
KC_B = 0x30,
KC_N = 0x31,
KC_M = 0x32,
KC_COMMA = 0x33,
KC_PERIOD = 0x34, // . on main keyboard
KC_SLASH = 0x35, // / on main keyboard
KC_RSHIFT = 0x36,
KC_MULTIPLY = 0x37, // * on numeric keypad
KC_LALT = 0x38, // left Alt
KC_SPACE = 0x39,
KC_CAPITAL = 0x3A,
KC_F1 = 0x3B,
KC_F2 = 0x3C,
KC_F3 = 0x3D,
KC_F4 = 0x3E,
KC_F5 = 0x3F,
KC_F6 = 0x40,
KC_F7 = 0x41,
KC_F8 = 0x42,
KC_F9 = 0x43,
KC_F10 = 0x44,
KC_NUMLOCK = 0x45,
KC_SCROLL = 0x46, // Scroll Lock
KC_NUMPAD7 = 0x47,
KC_NUMPAD8 = 0x48,
KC_NUMPAD9 = 0x49,
KC_SUBTRACT = 0x4A, // - on numeric keypad
KC_NUMPAD4 = 0x4B,
KC_NUMPAD5 = 0x4C,
KC_NUMPAD6 = 0x4D,
KC_ADD = 0x4E, // + on numeric keypad
KC_NUMPAD1 = 0x4F,
KC_NUMPAD2 = 0x50,
KC_NUMPAD3 = 0x51,
KC_NUMPAD0 = 0x52,
KC_DECIMAL = 0x53, // . on numeric keypad
KC_OEM_102 = 0x56, // < > | on UK/Germany keyboards
KC_F11 = 0x57,
KC_F12 = 0x58,
KC_F13 = 0x64, // (NEC PC98)
KC_F14 = 0x65, // (NEC PC98)
KC_F15 = 0x66, // (NEC PC98)
KC_KANA = 0x70, // (Japanese keyboard)
KC_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards
KC_CONVERT = 0x79, // (Japanese keyboard)
KC_NOCONVERT = 0x7B, // (Japanese keyboard)
KC_YEN = 0x7D, // (Japanese keyboard)
KC_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards
KC_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98)
KC_PREVTRACK = 0x90, // Previous Track (KC_CIRCUMFLEX on Japanese keyboard)
KC_AT = 0x91, // (NEC PC98)
KC_COLON = 0x92, // (NEC PC98)
KC_UNDERLINE = 0x93, // (NEC PC98)
KC_KANJI = 0x94, // (Japanese keyboard)
KC_STOP = 0x95, // (NEC PC98)
KC_AX = 0x96, // (Japan AX)
KC_UNLABELED = 0x97, // (J3100)
KC_NEXTTRACK = 0x99, // Next Track
KC_NUMPADENTER = 0x9C, // Enter on numeric keypad
KC_RCONTROL = 0x9D,
KC_MUTE = 0xA0, // Mute
KC_CALCULATOR = 0xA1, // Calculator
KC_PLAYPAUSE = 0xA2, // Play / Pause
KC_MEDIASTOP = 0xA4, // Media Stop
KC_VOLUMEDOWN = 0xAE, // Volume -
KC_VOLUMEUP = 0xB0, // Volume +
KC_WEBHOME = 0xB2, // Web home
KC_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98)
KC_DIVIDE = 0xB5, // / on numeric keypad
KC_SYSRQ = 0xB7,
KC_RALT = 0xB8, // right Alt
KC_PAUSE = 0xC5, // Pause
KC_HOME = 0xC7, // Home on arrow keypad
KC_UP = 0xC8, // UpArrow on arrow keypad
KC_PGUP = 0xC9, // PgUp on arrow keypad
KC_LEFT = 0xCB, // LeftArrow on arrow keypad
KC_RIGHT = 0xCD, // RightArrow on arrow keypad
KC_END = 0xCF, // End on arrow keypad
KC_DOWN = 0xD0, // DownArrow on arrow keypad
KC_PGDOWN = 0xD1, // PgDn on arrow keypad
KC_INSERT = 0xD2, // Insert on arrow keypad
KC_DELETE = 0xD3, // Delete on arrow keypad
KC_LWIN = 0xDB, // Left Windows key
KC_RWIN = 0xDC, // Right Windows key
KC_APPS = 0xDD, // AppMenu key
KC_POWER = 0xDE, // System Power
KC_SLEEP = 0xDF, // System Sleep
KC_WAKE = 0xE3, // System Wake
KC_WEBSEARCH = 0xE5, // Web Search
KC_WEBFAVORITES= 0xE6, // Web Favorites
KC_WEBREFRESH = 0xE7, // Web Refresh
KC_WEBSTOP = 0xE8, // Web Stop
KC_WEBFORWARD = 0xE9, // Web Forward
KC_WEBBACK = 0xEA, // Web Back
KC_MYCOMPUTER = 0xEB, // My Computer
KC_MAIL = 0xEC, // Mail
KC_MEDIASELECT = 0xED // Media Select
};
enum EEvent {
EV_KEY_DOWN = 0,
EV_KEY_UP,
EV_TEXT_ENTER,
EV_MOUSE_LDOWN,
EV_MOUSE_LUP,
EV_MOUSE_MDOWN,
EV_MOUSE_MUP,
EV_MOUSE_RDOWN,
EV_MOUSE_RUP,
EV_MOUSE_WHEEL_UP,
EV_MOUSE_WHEEL_DOWN,
EV_MOUSE_MOVE
};
struct KeyEvent {
char keychar;
unsigned char keycode;
bool ctrl;
bool shift;
bool alt;
};
struct MouseEvent {
int x, y;
};
struct InputEvent {
EEvent type;
union {
KeyEvent key;
MouseEvent mouse;
};
};
#endif // INPUT_H

66
src/framework/logger.cpp Normal file
View File

@@ -0,0 +1,66 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "logger.h"
void Logger::log(int level, const char *trace, const char *format, ...)
{
va_list args;
std::string strace;
va_start(args, format);
std::string text = vformat(format, args);
va_end(args);
if(trace) {
strace = trace;
strace = strace.substr(0, strace.find_first_of('('));
if(strace.find_last_of(' ') != std::string::npos)
strace = strace.substr(strace.find_last_of(' ') + 1);
}
#ifdef linux
static char const *colors[] = { "\033[01;31m ", "\033[01;31m", "\033[01;33m", "\033[0;32m", "\033[01;34m" };
static bool colored = getenv("COLORED_OUTPUT");
if(colored)
std::cout << colors[level];
#endif
if(!strace.empty())
std::cout << "[" << strace << "] ";
static char const *prefixes[] = { "FATAL ERROR: ", "ERROR: ", "WARNING: ", "", "", "" };
std::cout << prefixes[level];
std::cout << text;
#ifdef linux
if(colored)
std::cout << "\033[0m";
#endif
std::cout << std::endl;
if(level == LFATAL)
exit(-1);
}

64
src/framework/logger.h Normal file
View File

@@ -0,0 +1,64 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LOGGER_H
#define LOGGER_H
#include "prerequisites.h"
namespace Logger {
enum ELogLevel {
LFATAL = 0,
LERROR,
LWARNING,
LNOTICE,
LDEBUG
};
void log(int level, const char *trace, const char *format, ...);
}
#define fatal(...) Logger::log(Logger::LFATAL, NULL, __VA_ARGS__)
#define error(...) Logger::log(Logger::LERROR, NULL, __VA_ARGS__)
#define warning(...) Logger::log(Logger::LWARNING, NULL, __VA_ARGS__)
#define debug(...) Logger::log(Logger::LDEBUG, NULL, __VA_ARGS__)
#define notice(...) Logger::log(Logger::LNOTICE, NULL, __VA_ARGS__)
#define trace() Logger::log(Logger::LDEBUG, __PRETTY_FUNCTION__, "")
#define tdebug(...) Logger::log(Logger::LDEBUG, __PRETTY_FUNCTION__, __VA_ARGS__)
struct Dump {
public:
Dump() { }
~Dump() { debug(m_buf.str().c_str()); }
template<class T> Dump &operator<<(const T &x) { m_buf << x << " "; return *this; }
private:
std::ostringstream m_buf;
};
#define dump() Dump()
#endif

72
src/framework/platform.h Normal file
View File

@@ -0,0 +1,72 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PLATFORM_H
#define PLATFORM_H
#include "prerequisites.h"
namespace Platform
{
void init();
void terminate();
/// Poll platform input/window events
void poll();
/// Get current time in milliseconds since first frame render
unsigned long getTicks();
/// Sleep in current thread
void sleep(unsigned long miliseconds);
bool createWindow(int width, int height, int minWidth, int minHeight);
void destroyWindow();
void showWindow();
void setWindowTitle(const char *title);
bool isWindowFocused();
bool isWindowVisible();
int getWindowWidth();
int getWindowHeight();
/// Get GL extension function address
void *getExtensionProcAddress(const char *ext);
/// Check if GL extension is supported
bool isExtensionSupported(const char *ext);
const char *getTextFromClipboard();
void copyToClipboard(const char *text);
void hideMouseCursor();
void showMouseCursor();
/// Enable/disable vertical synchronization
void setVsync(bool enable = true);
/// Swap GL buffers
void swapBuffers();
/// Get the app user directory, the place to save files configurations files
const char *getAppUserDir();
}
#endif // PLATFORM_H

80
src/framework/point.h Normal file
View File

@@ -0,0 +1,80 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef POINT_H
#define POINT_H
#include "prerequisites.h"
template <class T>
class TSize;
template <class T>
class TPoint
{
public:
inline TPoint() : x(0), y(0) {};
inline TPoint(T x, T y) : x(x), y(y) { };
inline TPoint(const TPoint<T>& other) : x(other.x), y(other.y) { };
inline bool isNull() const { return x==0 && y==0; }
inline TSize<T> toSize() const { return TSize<T>(x, y); }
inline TPoint<T> operator-() const { return TPoint<T>(-x, -y); }
inline TPoint<T> operator+(const TPoint<T>& other) const { return TPoint<T>(x + other.x, y + other.y); }
inline TPoint<T>& operator+=(const TPoint<T>& other) { x+=other.x; y+=other.y; return *this; }
inline TPoint<T> operator-(const TPoint<T>& other) const { return TPoint<T>(x - other.x, y - other.y); }
inline TPoint<T>& operator-=(const TPoint<T>& other) { x-=other.x; y-=other.y; return *this; }
inline TPoint<T> operator*(const TPoint<T>& other) const { return TPoint<T>(x * other.x, y * other.y); }
inline TPoint<T>& operator*=(const TPoint<T>& other) { x*=other.x; y*=other.y; return *this; }
inline TPoint<T> operator*(const T v) const { return TPoint<T>(x * v, y * v); }
inline TPoint<T>& operator*=(const T v) { x*=v; y*=v; return *this; }
inline TPoint<T> operator/(const TPoint<T>& other) const { return TPoint<T>(x/other.x, y/other.y); }
inline TPoint<T>& operator/=(const TPoint<T>& other) { x/=other.x; y/=other.y; return *this; }
inline TPoint<T> operator/(const T v) const { return TPoint<T>(x/v, y/v); }
inline TPoint<T>& operator/=(const T v) { x/=v; y/=v; return *this; }
inline bool operator<=(const TPoint<T>&other) const { return x<=other.x && y<=other.y; }
inline bool operator>=(const TPoint<T>&other) const { return x>=other.x && y>=other.y; }
inline bool operator<(const TPoint<T>&other) const { return x<other.x && y<other.y; }
inline bool operator>(const TPoint<T>&other) const { return x>other.x && y>other.y; }
inline TPoint<T>& operator=(const TPoint<T>& other) { x = other.x; y = other.y; return *this; }
inline bool operator==(const TPoint<T>& other) const { return other.x==x && other.y==y; }
inline bool operator!=(const TPoint<T>& other) const { return other.x!=x || other.y!=y; }
inline float length() const { return sqrtf((float)(x*x + y*y)); }
inline T manhattanLength() const { return std::abs(x) + std::abs(y); }
inline float distanceFrom(const TPoint<T>& other) const {
return TPoint<T>(x - other.x, y - other.y).getLength();
}
T x, y;
};
typedef TPoint<int> Point;
typedef TPoint<float> PointF;
#endif

View File

@@ -0,0 +1,95 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PREREQUISITES_H
#define PREREQUISITES_H
// app name and version
#define APP_NAME "OTClient"
#define APP_LONGNAME APP_NAME " " APP_VERSION
#define APP_VERSION "0.1.0"
// easy typing
#include <stdint.h>
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
typedef int32_t int32;
typedef int16_t int16;
typedef int8_t int8;
// C headers
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cassert>
#include <ctime>
#include <cmath>
#include <csignal>
// STL headers
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <string>
#include <list>
#include <tr1/cinttypes>
// additional string algorithms
#include <boost/algorithm/string.hpp>
// easy casting
#include <boost/lexical_cast.hpp>
// smart pointers
#include <boost/smart_ptr.hpp>
// foreach
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
// GL stuff
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
// internal logger
#include "logger.h"
// additional utilities
#include "util.h"
#endif // PREREQUISITES_H

284
src/framework/rect.h Normal file
View File

@@ -0,0 +1,284 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef RECT_H
#define RECT_H
#include "prerequisites.h"
#include "point.h"
#include "size.h"
template <class T>
class TPoint;
template <class T>
class TSize;
template <class T>
class TRect
{
public:
inline TRect() : x1(0), y1(0), x2(-1), y2(-1) { }
inline TRect(T x, T y, T width, T height) : x1(x), y1(y), x2(x+width-1), y2(y+height-1) { }
inline TRect(const TPoint<T>& topLeft, const TPoint<T>& bottomRight) : x1(topLeft.x), y1(topLeft.y), x2(bottomRight.x), y2(bottomRight.y) { }
inline TRect(const TRect<T>& other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) { }
inline TRect(T x, T y, const TSize<T>& size) : x1(x), y1(y), x2(x+size.width()-1), y2(y+size.height()-1) { }
inline TRect(const TPoint<T>& topLeft, const TSize<T>& size) : x1(topLeft.x), y1(topLeft.y), x2(x+size.width()-1), y2(y+size.height()-1) { }
inline bool isNull() const { return x2 == x1 - 1 && y2 == y1 - 1; }
inline bool isEmpty() const { return x1 > x2 || y1 > y2; }
inline bool isValid() const { return x1 <= x2 && y1 <= y2; }
inline T left() const { return x1; }
inline T top() const { return y1; }
inline T right() const { return x2; }
inline T bottom() const { return y2; }
inline T x() const { return x1; }
inline T y() const { return y1; }
inline TPoint<T> topLeft() const { return TPoint<T>(x1, y1); }
inline TPoint<T> bottomRight() const { return TPoint<T>(x2, y2); }
inline TPoint<T> topRight() const { return TPoint<T>(x2, y1); }
inline TPoint<T> bottomLeft() const { return TPoint<T>(x1, y2); }
inline TPoint<T> center() const { return TPoint<T>((x1+x2)/2, (y1+y2)/2); }
inline T width() const { return x2 - x1 + 1; }
inline T height() const { return y2 - y1 + 1; }
inline TSize<T> size() const { return TSize<T>(width(), height()); }
inline void setLeft(T pos) { x1 = pos; }
inline void setTop(T pos) { y1 = pos; }
inline void setRight(T pos) { x2 = pos; }
inline void setBottom(T pos) { y2 = pos; }
inline void setX(T x) { x1 = x; }
inline void setY(T y) { y1 = y; }
inline void setTopLeft(const TPoint<T> &p) { x1 = p.x; y1 = p.y; }
inline void setBottomRight(const TPoint<T> &p) { x2 = p.x; y2 = p.y; }
inline void setTopRight(const TPoint<T> &p) { x2 = p.x; y1 = p.y; }
inline void setBottomLeft(const TPoint<T> &p) { x1 = p.x; y2 = p.y; }
inline void setWidth(T width) { x2 = x1 + width - 1; }
inline void setHeight(T height) { y2 = y1 + height- 1; }
inline void setSize(T width, T height) { x2 = x1 + width; y2 = y1 + height; }
inline void setSize(const TSize<T>& size) { x2 = x1 + size.width(); y2 = y1 + size.height(); }
inline void setRect(T x, T y, T width, T height) { x1 = x; y1 = y; x2 = (x + width - 1); y2 = (y + height - 1); }
inline void setCoords(int left, int top, int right, int bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; }
inline void translate(T x, T y) { x1 += x; y1 += y; x2 += x; y2 += y; }
inline void translate(const TPoint<T> &p) { x1 += p.x; y1 += p.y; x2 += p.x; y2 += p.y; }
inline void moveTo(T x, T y) { x2 += x - x1; y2 += y - y1; x1 = x; y1 = y; }
inline void moveTo(const TPoint<T> &p) { x2 += p.x - x1; y2 += p.y - y1; x1 = p.x; y1 = p.y; }
inline void moveLeft(T pos) { x2 += (pos - x1); x1 = pos; }
inline void moveTop(T pos) { y2 += (pos - y1); y1 = pos; }
inline void moveRight(T pos) { x1 += (pos - x2); x2 = pos; }
inline void moveBottom(T pos) { y1 += (pos - y2); y2 = pos; }
inline void moveTopLeft(const TPoint<T> &p) { moveLeft(p.x); moveTop(p.y); }
inline void moveBottomRight(const TPoint<T> &p) { moveRight(p.x); moveBottom(p.y); }
inline void moveTopRight(const TPoint<T> &p) { moveRight(p.x); moveTop(p.y); }
inline void moveBottomLeft(const TPoint<T> &p) { moveLeft(p.x); moveBottom(p.y); }
inline TRect<T> translated(int x, int y) const { return TRect<T>(TPoint<T>(x1 + x, y1 + y), TPoint<T>(x2 + x, y2 + y)); }
inline TRect<T> translated(const TPoint<T> &p) const { return TRect<T>(TPoint<T>(x1 + p.x(), y1 + p.y()), TPoint<T>(x2 + p.x(), y2 + p.y())); }
void moveCenter(const TPoint<T> &p) {
T w = x2 - x1;
T h = y2 - y1;
x1 = p.x() - w/2;
y1 = p.y() - h/2;
x2 = x1 + w;
y2 = y1 + h;
}
bool contains(const TPoint<T> &p, bool insideOnly = false) const {
T l, r;
if(x2 < x1 - 1) {
l = x2;
r = x1;
} else {
l = x1;
r = x2;
}
if(insideOnly) {
if(p.x() <= l || p.x() >= r)
return false;
} else {
if(p.x() < l || p.x() > r)
return false;
}
int t, b;
if(y2 < y1 - 1) {
t = y2;
b = y1;
} else {
t = y1;
b = y2;
}
if(insideOnly) {
if(p.y() <= t || p.y() >= b)
return false;
} else {
if(p.y() < t || p.y() > b)
return false;
}
return true;
}
bool intersects(const TRect<T> &r) const {
if(isNull() || r.isNull())
return false;
int l1 = x1;
int r1 = x1;
if(x2 - x1 + 1 < 0)
l1 = x2;
else
r1 = x2;
int l2 = r.x1;
int r2 = r.x1;
if(r.x2 - r.x1 + 1 < 0)
l2 = r.x2;
else
r2 = r.x2;
if (l1 > r2 || l2 > r1)
return false;
int t1 = y1;
int b1 = y1;
if(y2 - y1 + 1 < 0)
t1 = y2;
else
b1 = y2;
int t2 = r.y1;
int b2 = r.y1;
if (r.y2 - r.y1 + 1 < 0)
t2 = r.y2;
else
b2 = r.y2;
if(t1 > b2 || t2 > b1)
return false;
return true;
}
TRect<T> united(const TRect<T> &r) const {
if(isNull() || r.isNull())
return TRect<T>();
int l1 = x1;
int r1 = x1;
if (x2 - x1 + 1 < 0)
l1 = x2;
else
r1 = x2;
int l2 = r.x1;
int r2 = r.x1;
if(r.x2 - r.x1 + 1 < 0)
l2 = r.x2;
else
r2 = r.x2;
if(l1 > r2 || l2 > r1)
return TRect<T>();
int t1 = y1;
int b1 = y1;
if(y2 - y1 + 1 < 0)
t1 = y2;
else
b1 = y2;
int t2 = r.y1;
int b2 = r.y1;
if(r.y2 - r.y1 + 1 < 0)
t2 = r.y2;
else
b2 = r.y2;
if(t1 > b2 || t2 > b1)
return TRect<T>();
TRect<T> tmp;
tmp.x1 = std::max(l1, l2);
tmp.x2 = std::min(r1, r2);
tmp.y1 = std::max(t1, t2);
tmp.y2 = std::min(b1, b2);
return tmp;
}
TRect<T> intersection(const TRect<T> &r) const {
if(isNull())
return r;
if(r.isNull())
return *this;
int l1 = x1;
int r1 = x1;
if(x2 - x1 + 1 < 0)
l1 = x2;
else
r1 = x2;
int l2 = r.x1;
int r2 = r.x1;
if(r.x2 - r.x1 + 1 < 0)
l2 = r.x2;
else
r2 = r.x2;
int t1 = y1;
int b1 = y1;
if(y2 - y1 + 1 < 0)
t1 = y2;
else
b1 = y2;
int t2 = r.y1;
int b2 = r.y1;
if(r.y2 - r.y1 + 1 < 0)
t2 = r.y2;
else
b2 = r.y2;
TRect<T> tmp;
tmp.x1 = std::min(l1, l2);
tmp.x2 = std::max(r1, r2);
tmp.y1 = std::min(t1, t2);
tmp.y2 = std::max(b1, b2);
return tmp;
}
inline TRect<T>& operator=(const TRect<T>& other) { x1 = other.x1; y1 = other.y1; x2 = other.x2; y2 = other.y2; return *this; }
inline bool operator==(const TRect<T>& other) const { return (x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2); }
inline bool operator!=(const TRect<T>& other) const { return (x1 != other.x1 || y1 != other.y1 || x2 != other.x2 || y2 != other.y2); }
private:
T x1, y1, x2, y2;
};
typedef TRect<int> Rect;
typedef TRect<float> RectF;
#endif // RECT_H

View File

@@ -0,0 +1,118 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "resourcemanager.h"
#include <physfs.h>
ResourceManager g_resources;
ResourceManager::ResourceManager()
{
}
ResourceManager::~ResourceManager()
{
}
void ResourceManager::init(const char *argv0)
{
PHYSFS_init(argv0);
}
void ResourceManager::terminate()
{
PHYSFS_deinit();
}
bool ResourceManager::setWriteDir(const std::string& path)
{
bool ret = (bool)PHYSFS_setWriteDir(path.c_str());
if(!ret)
error("Could not set the path %s as write directory, file write will not work.");
return ret;
}
bool ResourceManager::addToSearchPath(const std::string& path, bool insertInFront)
{
if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1)) {
error("Error while adding %s to resources search path: %s", PHYSFS_getLastError());
return false;
}
return true;
}
bool ResourceManager::fileExists(const std::string& filePath)
{
return PHYSFS_exists(filePath.c_str());
}
unsigned char *ResourceManager::loadFile(const std::string& fileName, unsigned int *fileSize)
{
PHYSFS_file *file = PHYSFS_openRead(fileName.c_str());
if(!file) {
error("Failed to load file %s: %s", fileName.c_str(), PHYSFS_getLastError());
*fileSize = 0;
return NULL;
}
*fileSize = PHYSFS_fileLength(file);
unsigned char *buffer = new unsigned char[*fileSize];
PHYSFS_read(file, (void*)buffer, 1, *fileSize);
PHYSFS_close(file);
return buffer;
}
std::string ResourceManager::loadTextFile(const std::string& fileName)
{
std::string text;
unsigned int fileSize;
char *buffer = (char *)loadFile(fileName, &fileSize);
if(buffer) {
text.assign(buffer);
delete[] buffer;
}
return text;
}
bool ResourceManager::saveFile(const std::string &fileName, const unsigned char *data, unsigned int size)
{
PHYSFS_file *file = PHYSFS_openWrite(fileName.c_str());
if(!file) {
error("Failed to save file %s: %s", fileName.c_str(), PHYSFS_getLastError());
return false;
}
PHYSFS_write(file, (void*)data, size, 1);
PHYSFS_close(file);
return true;
}
bool ResourceManager::saveTextFile(const std::string &fileName, std::string text)
{
return saveFile(fileName, (const unsigned char*)text.c_str(), text.size());
}

View File

@@ -0,0 +1,70 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include "prerequisites.h"
class ResourceManager
{
public:
ResourceManager();
~ResourceManager();
void init(const char *argv0);
void terminate();
/// Sets the write directory
bool setWriteDir(const std::string &path);
/// Adds a directory or zip archive to the search path
bool addToSearchPath(const std::string& path, bool insertInFront = true);
/// Checks whether the given file exists in the search path
bool fileExists(const std::string& filePath);
/// Searches for zip files and adds them to the search path
void searchAndAddArchives(const std::string &path,
const std::string &ext,
const bool append);
/** Load a file by allocating a buffer and filling it with the file contents
* where fileSize will be set to the file size.
* The returned buffer must be freed with delete[]. */
unsigned char *loadFile(const std::string &fileName, unsigned int *fileSize);
/// Loads a text file into a std::string
std::string loadTextFile(const std::string &fileName);
/// Save a file into write directory
bool saveFile(const std::string &fileName, const unsigned char *data, unsigned int size);
/// Save a text file into write directory
bool saveTextFile(const std::string &fileName, std::string text);
};
extern ResourceManager g_resources;
#endif // RESOURCEMANAGER_H

113
src/framework/size.h Normal file
View File

@@ -0,0 +1,113 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef SIZE_H
#define SIZE_H
#include "prerequisites.h"
#include "point.h"
enum ESizeScaleMode {
IGNORE_ASPECT_RATIO,
KEEP_ASPECT_RATIO,
KEEP_ASPECT_RATIO_BY_EXPANDING
};
template <class T>
class TSize
{
public:
TSize() : wd(-1), ht(-1) {};
TSize(T width, T height) : wd(width), ht(height) { };
TSize(const TSize<T>& other) : wd(other.wd), ht(other.ht) { };
inline TPoint<T> toPoint() const { return TPoint<T>(wd, ht); }
inline bool isNull() const { return wd==0 && ht==0; }
inline bool isEmpty() const { return wd<1 || ht<1; }
inline bool isValid() const { return wd>=0 && ht>=0; }
inline int width() const { return wd; }
inline int height() const { return ht; }
inline void setWidth(T w) { wd = w; }
inline void setHeight(T h) { ht = h; }
inline TSize<T> operator-() const { return TSize<T>(-wd, -ht); }
inline TSize<T> operator+(const TSize<T>& other) const { return TSize<T>(wd + other.wd, ht + other.ht); }
inline TSize<T>& operator+=(const TSize<T>& other) { wd+=other.wd; ht+=other.ht; return *this; }
inline TSize<T> operator-(const TSize<T>& other) const { return TSize<T>(wd - other.wd, ht - other.ht); }
inline TSize<T>& operator-=(const TSize<T>& other) { wd-=other.wd; ht-=other.ht; return *this; }
inline TSize<T> operator*(const float v) const { return TSize<T>((T)v*wd, (T)ht*v); }
inline TSize<T>& operator*=(const float v) { wd=(T)v*wd; ht=(T)ht*v; return *this; }
inline TSize<T> operator/(const float v) const { return TSize<T>((T)wd/v, (T)ht/v); }
inline TSize<T>& operator/=(const float v) { (T)wd/=v; (T)ht/=v; return *this; }
inline bool operator<=(const TSize<T>&other) const { return wd<=other.wd || ht<=other.ht; }
inline bool operator>=(const TSize<T>&other) const { return wd>=other.wd || ht>=other.ht; }
inline bool operator<(const TSize<T>&other) const { return wd<other.wd || ht<other.ht; }
inline bool operator>(const TSize<T>&other) const { return wd>other.wd || ht>other.ht; }
inline TSize<T>& operator=(const TSize<T>& other) { wd = other.wd; ht = other.ht; return *this; }
inline bool operator==(const TSize<T>& other) const { return other.wd==wd && other.ht==ht; }
inline bool operator!=(const TSize<T>& other) const { return other.wd!=wd || other.ht!=ht; }
inline TSize<T> expandedTo(const TSize<T>& other) const { return TSize<T>(std::max(wd,other.wd), std::max(ht,other.ht)); }
inline TSize<T> boundedTo(const TSize<T>& other) const { return TSize<T>(std::min(wd,other.wd), std::min(ht,other.ht)); }
void scale(const TSize<T>& s, ESizeScaleMode mode) {
if(mode == IGNORE_ASPECT_RATIO || wd == 0 || ht == 0) {
wd = s.wd;
ht = s.ht;
} else {
bool useHeight;
T rw = (s.ht * wd) / ht;
if(mode == KEEP_ASPECT_RATIO)
useHeight = (rw <= s.wd);
else // mode == KEEP_ASPECT_RATIO_BY_EXPANDING
useHeight = (rw >= s.wd);
if(useHeight) {
wd = rw;
ht = s.ht;
} else {
ht = (s.wd * ht)/wd;
wd = s.wd;
}
}
}
void scale(int w, int h, ESizeScaleMode mode) { scale(TSize<T>(w, h)); }
inline float ratio() const { return (float)wd/ht; }
inline T area() const { return wd*ht; }
private:
T wd, ht;
};
typedef TSize<int> Size;
typedef TSize<float> SizeF;
#endif

71
src/framework/texture.cpp Normal file
View File

@@ -0,0 +1,71 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "texture.h"
Texture::Texture(int width, int height, int components, unsigned char *pixels)
{
m_size.setWidth(width);
m_size.setHeight(height);
glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_2D, m_textureId);
GLenum format = 0;
switch(components) {
case 4:
format = GL_RGBA;
break;
case 3:
format = GL_RGB;
break;
case 2:
format = GL_LUMINANCE_ALPHA;
break;
case 1:
format = GL_LUMINANCE;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, format, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
Texture::~Texture()
{
if(m_textureId)
glDeleteTextures(1, &m_textureId);
}
void Texture::enableBilinearFilter()
{
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

53
src/framework/texture.h Normal file
View File

@@ -0,0 +1,53 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TEXTURE_H
#define TEXTURE_H
#include "prerequisites.h"
#include "size.h"
class TextureManager;
class Texture
{
public:
/// Create a texture, width and height must be a multiple of 2
Texture(int width, int height, int components, unsigned char *pixels = NULL);
virtual ~Texture();
/// Enable texture bilinear filter (smooth scaled textures)
void enableBilinearFilter();
const Size& getSize() const { return m_size; }
GLuint getTextureId() const { return m_textureId; }
private:
GLuint m_textureId;
Size m_size;
};
typedef boost::shared_ptr<Texture> TexturePtr;
#endif // TEXTURE_H

View File

@@ -0,0 +1,124 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "textureloader.h"
#include "texture.h"
#include <png.h>
Texture *TextureLoader::loadPNG(const unsigned char *fileData, unsigned int fileSize)
{
FILE *pngFile = fmemopen((void*)fileData, fileSize, "rb");
if(!pngFile)
return NULL;
png_byte sig[8];
if(!fread(&sig, 8, 1, pngFile))
return NULL;
if(png_sig_cmp(sig, 0, 8))
return NULL;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
return NULL;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
png_init_io(png_ptr, pngFile);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int bitDepth = png_get_bit_depth(png_ptr, info_ptr);
int colourType = png_get_color_type(png_ptr, info_ptr);
if(colourType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if(bitDepth < 8 && (colourType == PNG_COLOR_TYPE_GRAY || colourType == PNG_COLOR_TYPE_GRAY_ALPHA))
png_set_expand_gray_1_2_4_to_8(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
if(bitDepth < 8)
png_set_packing(png_ptr);
else if(bitDepth == 16)
png_set_strip_16(png_ptr);
png_read_update_info(png_ptr, info_ptr);
png_uint_32 width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colourType, NULL, NULL, NULL);
int components;
switch(colourType)
{
case PNG_COLOR_TYPE_GRAY:
components = 1;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
components = 2;
break;
case PNG_COLOR_TYPE_RGB:
components = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
components = 4;
break;
default:
if(png_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
};
unsigned char *pixels = new unsigned char[width * height * components];
png_bytep *row_pointers = new png_bytep[height];
for(unsigned int i = 0; i < height; ++i)
row_pointers[i] = (png_bytep)(pixels + (i * width * components));
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(pngFile);
delete[] row_pointers;
Texture *texture = new Texture(width, height, components, pixels);
delete[] pixels;
return texture;
}

View File

@@ -0,0 +1,38 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TEXTURELOADER_H
#define TEXTURELOADER_H
#include "prerequisites.h"
class Texture;
namespace TextureLoader
{
/// Load a png textures using libpng
Texture *loadPNG(const unsigned char *fileData, unsigned int fileSize);
}
#endif // TEXTURELOADER_H

View File

@@ -0,0 +1,68 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "texturemanager.h"
#include "resourcemanager.h"
#include "textureloader.h"
TextureManager g_textures;
TextureManager::TextureManager()
{
}
TextureManager::~TextureManager()
{
m_texturesMap.clear();
}
TexturePtr TextureManager::get(const std::string& textureFile)
{
TexturePtr texture;
// check if the texture is already loaded
TexturesMap::iterator it = m_texturesMap.find(textureFile);
if(it != m_texturesMap.end())
texture = it->second;
else { // load texture
// currently only png textures are supported
if(!boost::ends_with(textureFile, ".png")) {
error("Unable to load texture %s, file format no supported.", textureFile.c_str());
return texture;
}
unsigned int fileSize;
unsigned char *textureFileData = g_resources.loadFile(textureFile, &fileSize);
if(!textureFileData)
return texture;
texture = TexturePtr(TextureLoader::loadPNG(textureFileData, fileSize));
if(!texture)
error("Unable to load texture %s, loading error.", textureFile.c_str());
delete[] textureFileData;
}
return texture;
}

View File

@@ -0,0 +1,47 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TEXTUREMANAGER_H
#define TEXTUREMANAGER_H
#include "prerequisites.h"
#include "texture.h"
class TextureManager
{
public:
TextureManager();
~TextureManager();
/// Load a texture from file, if it was already loaded it will be retrieved from cache
TexturePtr get(const std::string& textureFile);
private:
typedef std::map<std::string, TexturePtr> TexturesMap;
TexturesMap m_texturesMap;
};
extern TextureManager g_textures;
#endif // TEXTUREMANAGER_H

52
src/framework/util.cpp Normal file
View File

@@ -0,0 +1,52 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "util.h"
std::string vformat(const char *format, va_list args)
{
if(!format)
return "";
int result = -1, length = 256;
char *buffer = 0;
while(result == -1) {
if(buffer)
delete [] buffer;
buffer = new char [length + 1];
result = vsnprintf(buffer, length, format, args);
length *= 2;
}
std::string s(buffer);
delete [] buffer;
return s;
}
std::string format(const char *format, ...)
{
va_list args;
va_start(args, format);
std::string s = vformat(format, args);
va_end(args);
return s;
}

36
src/framework/util.h Normal file
View File

@@ -0,0 +1,36 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef UTIL_H
#define UTIL_H
#include "prerequisites.h"
/// Formatting like printf for std::string, va_list input version
std::string vformat(const char *format, va_list args);
/// Formatting like printf for std::string
std::string format(const char *format, ...);
#endif

View File

@@ -0,0 +1,727 @@
/* The MIT License
*
* Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "platform.h"
#include "engine.h"
#include "input.h"
#include "logger.h"
#include <sys/time.h>
#include <sys/stat.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <GL/glx.h>
#include <physfs.h>
struct X11PlatformPrivate {
Display *display;
XVisualInfo *visual;
GLXContext glxContext;
XIM xim;
XIC xic;
Colormap colormap;
Window window;
Cursor cursor;
Atom atomDeleteWindow;
Atom atomClipboard;
Atom atomTargets;
Atom atomText;
Atom atomCompoundText;
Atom atomUTF8String;
bool visible;
bool focused;
int width;
int height;
std::string clipboardText;
std::map<int, unsigned char> keyMap;
} x11;
void Platform::init()
{
x11.display = NULL;
x11.visual = NULL;
x11.glxContext = NULL;
x11.xim = NULL;
x11.xic = NULL;
x11.colormap = None;
x11.window = None;
x11.cursor = None;
x11.visible = false;
x11.focused = false;
x11.width = 0;
x11.height = 0;
// setup keymap
x11.keyMap[XK_1] = KC_1;
x11.keyMap[XK_2] = KC_2;
x11.keyMap[XK_3] = KC_3;
x11.keyMap[XK_4] = KC_4;
x11.keyMap[XK_5] = KC_5;
x11.keyMap[XK_6] = KC_6;
x11.keyMap[XK_7] = KC_7;
x11.keyMap[XK_8] = KC_8;
x11.keyMap[XK_9] = KC_9;
x11.keyMap[XK_0] = KC_0;
x11.keyMap[XK_BackSpace] = KC_BACK;
x11.keyMap[XK_minus] = KC_MINUS;
x11.keyMap[XK_equal] = KC_EQUALS;
x11.keyMap[XK_space] = KC_SPACE;
x11.keyMap[XK_comma] = KC_COMMA;
x11.keyMap[XK_period] = KC_PERIOD;
x11.keyMap[XK_backslash] = KC_BACKSLASH;
x11.keyMap[XK_slash] = KC_SLASH;
x11.keyMap[XK_bracketleft] = KC_LBRACKET;
x11.keyMap[XK_bracketright] = KC_RBRACKET;
x11.keyMap[XK_Escape] = KC_ESCAPE;
x11.keyMap[XK_Caps_Lock] = KC_CAPITAL;
x11.keyMap[XK_Tab] = KC_TAB;
x11.keyMap[XK_Return] = KC_RETURN;
x11.keyMap[XK_Control_L] = KC_LCONTROL;
x11.keyMap[XK_Control_R] = KC_RCONTROL;
x11.keyMap[XK_colon] = KC_COLON;
x11.keyMap[XK_semicolon] = KC_SEMICOLON;
x11.keyMap[XK_apostrophe] = KC_APOSTROPHE;
x11.keyMap[XK_grave] = KC_GRAVE;
x11.keyMap[XK_b] = KC_B;
x11.keyMap[XK_a] = KC_A;
x11.keyMap[XK_c] = KC_C;
x11.keyMap[XK_d] = KC_D;
x11.keyMap[XK_e] = KC_E;
x11.keyMap[XK_f] = KC_F;
x11.keyMap[XK_g] = KC_G;
x11.keyMap[XK_h] = KC_H;
x11.keyMap[XK_i] = KC_I;
x11.keyMap[XK_j] = KC_J;
x11.keyMap[XK_k] = KC_K;
x11.keyMap[XK_l] = KC_L;
x11.keyMap[XK_m] = KC_M;
x11.keyMap[XK_n] = KC_N;
x11.keyMap[XK_o] = KC_O;
x11.keyMap[XK_p] = KC_P;
x11.keyMap[XK_q] = KC_Q;
x11.keyMap[XK_r] = KC_R;
x11.keyMap[XK_s] = KC_S;
x11.keyMap[XK_t] = KC_T;
x11.keyMap[XK_u] = KC_U;
x11.keyMap[XK_v] = KC_V;
x11.keyMap[XK_w] = KC_W;
x11.keyMap[XK_x] = KC_X;
x11.keyMap[XK_y] = KC_Y;
x11.keyMap[XK_z] = KC_Z;
x11.keyMap[XK_F1] = KC_F1;
x11.keyMap[XK_F2] = KC_F2;
x11.keyMap[XK_F3] = KC_F3;
x11.keyMap[XK_F4] = KC_F4;
x11.keyMap[XK_F5] = KC_F5;
x11.keyMap[XK_F6] = KC_F6;
x11.keyMap[XK_F7] = KC_F7;
x11.keyMap[XK_F8] = KC_F8;
x11.keyMap[XK_F9] = KC_F9;
x11.keyMap[XK_F10] = KC_F10;
x11.keyMap[XK_F11] = KC_F11;
x11.keyMap[XK_F12] = KC_F12;
x11.keyMap[XK_F13] = KC_F13;
x11.keyMap[XK_F14] = KC_F14;
x11.keyMap[XK_F15] = KC_F15;
// keypad
x11.keyMap[XK_KP_0] = KC_NUMPAD0;
x11.keyMap[XK_KP_1] = KC_NUMPAD1;
x11.keyMap[XK_KP_2] = KC_NUMPAD2;
x11.keyMap[XK_KP_3] = KC_NUMPAD3;
x11.keyMap[XK_KP_4] = KC_NUMPAD4;
x11.keyMap[XK_KP_5] = KC_NUMPAD5;
x11.keyMap[XK_KP_6] = KC_NUMPAD6;
x11.keyMap[XK_KP_7] = KC_NUMPAD7;
x11.keyMap[XK_KP_8] = KC_NUMPAD8;
x11.keyMap[XK_KP_9] = KC_NUMPAD9;
x11.keyMap[XK_KP_Add] = KC_ADD;
x11.keyMap[XK_KP_Subtract] = KC_SUBTRACT;
x11.keyMap[XK_KP_Decimal] = KC_DECIMAL;
x11.keyMap[XK_KP_Equal] = KC_NUMPADEQUALS;
x11.keyMap[XK_KP_Divide] = KC_DIVIDE;
x11.keyMap[XK_KP_Multiply] = KC_MULTIPLY;
x11.keyMap[XK_KP_Enter] = KC_NUMPADENTER;
// keypad with numlock off
x11.keyMap[XK_KP_Home] = KC_NUMPAD7;
x11.keyMap[XK_KP_Up] = KC_NUMPAD8;
x11.keyMap[XK_KP_Page_Up] = KC_NUMPAD9;
x11.keyMap[XK_KP_Left] = KC_NUMPAD4;
x11.keyMap[XK_KP_Begin] = KC_NUMPAD5;
x11.keyMap[XK_KP_Right] = KC_NUMPAD6;
x11.keyMap[XK_KP_End] = KC_NUMPAD1;
x11.keyMap[XK_KP_Down] = KC_NUMPAD2;
x11.keyMap[XK_KP_Page_Down] = KC_NUMPAD3;
x11.keyMap[XK_KP_Insert] = KC_NUMPAD0;
x11.keyMap[XK_KP_Delete] = KC_DECIMAL;
x11.keyMap[XK_Up] = KC_UP;
x11.keyMap[XK_Down] = KC_DOWN;
x11.keyMap[XK_Left] = KC_LEFT;
x11.keyMap[XK_Right] = KC_RIGHT;
x11.keyMap[XK_Page_Up] = KC_PGUP;
x11.keyMap[XK_Page_Down] = KC_PGDOWN;
x11.keyMap[XK_Home] = KC_HOME;
x11.keyMap[XK_End] = KC_END;
x11.keyMap[XK_Num_Lock] = KC_NUMLOCK;
x11.keyMap[XK_Print] = KC_SYSRQ;
x11.keyMap[XK_Scroll_Lock] = KC_SCROLL;
x11.keyMap[XK_Pause] = KC_PAUSE;
x11.keyMap[XK_Shift_R] = KC_RSHIFT;
x11.keyMap[XK_Shift_L] = KC_LSHIFT;
x11.keyMap[XK_Alt_R] = KC_RALT;
x11.keyMap[XK_Alt_L] = KC_LALT;
x11.keyMap[XK_Insert] = KC_INSERT;
x11.keyMap[XK_Delete] = KC_DELETE;
x11.keyMap[XK_Super_L] = KC_LWIN;
x11.keyMap[XK_Super_R] = KC_RWIN;
x11.keyMap[XK_Menu] = KC_APPS;
// try to set a latin1 locales otherwise fallback to standard C locale
static char locales[][32] = { "en_US.iso88591", "iso88591", "en_US", "C" };
for(int i=0;i<4;++i) {
if(setlocale(LC_ALL, locales[i]))
break;
}
// open display
x11.display = XOpenDisplay(0);
if(!x11.display)
fatal("Failed to open X display");
// check if GLX is supported on this display
if(!glXQueryExtension(x11.display, 0, 0))
fatal("GLX not supported");
// retrieve GLX version
int glxMajor;
int glxMinor;
if(!glXQueryVersion(x11.display, &glxMajor, &glxMinor))
fatal("Unable to query GLX version");
notice("GLX version %d.%d", glxMajor, glxMinor);
// clipboard related atoms
x11.atomClipboard = XInternAtom(x11.display, "CLIPBOARD", False);
x11.atomTargets = XInternAtom(x11.display, "TARGETS", False);
x11.atomUTF8String = XInternAtom(x11.display, "UTF8_STRING", False);
x11.atomText = XInternAtom(x11.display, "TEXT", False);
x11.atomCompoundText = XInternAtom(x11.display, "COMPOUND_TEXT", False);
}
void Platform::terminate()
{
if(x11.window) {
destroyWindow();
x11.window = None;
}
// close display
if(x11.display) {
XCloseDisplay(x11.display);
x11.display = NULL;
}
}
void Platform::poll()
{
XEvent event, peekevent;
static InputEvent inputEvent;
while(XPending(x11.display) > 0) {
XNextEvent(x11.display, &event);
// call filter because xim will discard KeyPress events when keys still composing
if(XFilterEvent(&event, x11.window))
continue;
// discard events of repeated key releases
if(event.type == KeyRelease && XPending(x11.display)) {
XPeekEvent(x11.display, &peekevent);
if((peekevent.type == KeyPress) &&
(peekevent.xkey.keycode == event.xkey.keycode) &&
((peekevent.xkey.time-event.xkey.time) < 2))
continue;
}
switch(event.type) {
case ConfigureNotify:
// window resize
if(x11.width != event.xconfigure.width || x11.height != event.xconfigure.height) {
x11.width = event.xconfigure.width;
x11.height = event.xconfigure.height;
g_engine.onResize(x11.width, x11.height);
}
break;
case KeyPress:
case KeyRelease: {
KeySym keysym;
char buf[32];
int len;
inputEvent.key.ctrl = (event.xkey.state & ControlMask);
inputEvent.key.shift = (event.xkey.state & ShiftMask);
inputEvent.key.alt = (event.xkey.state & Mod1Mask);
// fire enter text event
if(event.type == KeyPress && !inputEvent.key.ctrl && !inputEvent.key.alt) {
if(x11.xic) { // with xim we can get latin1 input correctly
Status status;
len = XmbLookupString(x11.xic, &event.xkey, buf, sizeof(buf), &keysym, &status);
} else { // otherwise use XLookupString, but it doesn't work right with dead keys often
static XComposeStatus compose = {NULL, 0};
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
}
if(len > 0 &&
// for some reason these keys produces characters and we don't want that
keysym != XK_BackSpace &&
keysym != XK_Return &&
keysym != XK_Delete &&
keysym != XK_Escape
) {
//debug("char: %c code: %d", buf[0], (unsigned char)buf[0]);
inputEvent.type = EV_TEXT_ENTER;
inputEvent.key.keychar = buf[0];
inputEvent.key.keycode = KC_UNKNOWN;
g_engine.onInputEvent(&inputEvent);
}
}
// unmask Shift/Lock to get expected results
event.xkey.state &= ~(ShiftMask | LockMask);
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
// fire key up/down event
if(x11.keyMap.find(keysym) != x11.keyMap.end()) {
inputEvent.key.keycode = x11.keyMap[keysym];
inputEvent.type = (event.type == KeyPress) ? EV_KEY_DOWN : EV_KEY_UP;
inputEvent.key.keychar = (len > 0) ? buf[0] : 0;
g_engine.onInputEvent(&inputEvent);
}
break;
}
case ButtonPress:
case ButtonRelease:
switch(event.xbutton.button) {
case Button1:
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_LDOWN : EV_MOUSE_LUP;
break;
case Button3:
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_RDOWN : EV_MOUSE_RUP;
break;
case Button2:
inputEvent.type = (event.type == ButtonPress) ? EV_MOUSE_MDOWN : EV_MOUSE_MUP;
break;
case Button4:
inputEvent.type = EV_MOUSE_WHEEL_UP;
break;
case Button5:
inputEvent.type = EV_MOUSE_WHEEL_DOWN;
break;
}
g_engine.onInputEvent(&inputEvent);
break;
case MotionNotify:
inputEvent.type = EV_MOUSE_MOVE;
inputEvent.mouse.x = event.xbutton.x;
inputEvent.mouse.y = event.xbutton.y;
g_engine.onInputEvent(&inputEvent);
break;
case MapNotify:
x11.visible = true;
break;
case UnmapNotify:
x11.visible = false;
break;
case FocusIn:
x11.focused = true;
break;
case FocusOut:
x11.focused = false;
break;
// clipboard data request
case SelectionRequest:
{
XEvent respond;
XSelectionRequestEvent *req = &(event.xselectionrequest);
if(req->target == x11.atomTargets ) {
Atom typeList[] = {x11.atomText, x11.atomCompoundText, x11.atomUTF8String, XA_STRING};
XChangeProperty(x11.display, req->requestor,
req->property, req->target,
8, PropModeReplace,
(unsigned char *) &typeList,
sizeof(typeList));
respond.xselection.property = req->property;
} else {
XChangeProperty(x11.display,
req->requestor,
req->property, req->target,
8,
PropModeReplace,
(unsigned char*) x11.clipboardText.c_str(),
x11.clipboardText.size());
respond.xselection.property = req->property;
}
respond.xselection.type = SelectionNotify;
respond.xselection.display = req->display;
respond.xselection.requestor = req->requestor;
respond.xselection.selection = req->selection;
respond.xselection.target = req->target;
respond.xselection.time = req->time;
XSendEvent(x11.display, req->requestor, 0, 0, &respond);
XFlush(x11.display);
break;
}
case ClientMessage:
{
if((Atom)event.xclient.data.l[0] == x11.atomDeleteWindow)
g_engine.onClose();
break;
}
}
}
}
unsigned long Platform::getTicks()
{
static timeval tv;
static unsigned long firstTick = 0;
gettimeofday(&tv, 0);
if(!firstTick)
firstTick = tv.tv_sec;
return ((tv.tv_sec - firstTick) * 1000) + (tv.tv_usec / 1000);
}
void Platform::sleep(unsigned long miliseconds)
{
timespec tv;
tv.tv_sec = miliseconds / 1000;
tv.tv_nsec = (miliseconds % 1000) * 1000000;
nanosleep(&tv, NULL);
}
bool Platform::createWindow(int width, int height, int minWidth, int minHeight)
{
static int attrList[] = {
GLX_USE_GL,
GLX_RGBA,
GLX_DOUBLEBUFFER,
None
};
// choose OpenGL, RGBA, double buffered, visual
x11.visual = glXChooseVisual(x11.display, DefaultScreen(x11.display), attrList);
if(!x11.visual)
fatal("RGBA/Double buffered visual not supported");
// create GLX context
x11.glxContext = glXCreateContext(x11.display, x11.visual, 0, GL_TRUE);
if(!x11.glxContext)
fatal("Unable to create GLX context");
// color map
x11.colormap = XCreateColormap(x11.display,
RootWindow(x11.display, x11.visual->screen),
x11.visual->visual,
AllocNone);
// setup window attributes
XSetWindowAttributes wa;
wa.colormap = x11.colormap;
wa.border_pixel = 0;
wa.event_mask = KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
ExposureMask | VisibilityChangeMask |
StructureNotifyMask | FocusChangeMask;
// calculate center position
int x = (XDisplayHeight(x11.display, DefaultScreen(x11.display)) - width) / 2;
int y = (XDisplayHeight(x11.display, DefaultScreen(x11.display)) - height) / 2;
// create the window
x11.window = XCreateWindow(x11.display,
RootWindow(x11.display, x11.visual->screen),
x, y,
width, height,
0,
x11.visual->depth,
InputOutput,
x11.visual->visual,
CWBorderPixel | CWColormap | CWEventMask,
&wa);
if(!x11.window)
fatal("Unable to create X window");
// create input context (to have better key input handling)
if(XSupportsLocale()) {
XSetLocaleModifiers("");
x11.xim = XOpenIM(x11.display, NULL, NULL, NULL);
if(x11.xim) {
x11.xic = XCreateIC(x11.xim,
XNInputStyle,
XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, x11.window, NULL);
if(!x11.xic)
error("Unable to create the input context");
} else
error("Failed to open an input method");
} else
error("X11 does not support the current locale");
if(!x11.xic)
warning("Input of special keys maybe messed up because we couldn't create an input context");
// set window minimum size
XSizeHints xsizehints;
xsizehints.flags = PMinSize;
xsizehints.min_width = minWidth;
xsizehints.min_height= minHeight;
XSetWMSizeHints(x11.display, x11.window, &xsizehints, XA_WM_NORMAL_HINTS);
// handle delete window event
x11.atomDeleteWindow = XInternAtom(x11.display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(x11.display, x11.window, &x11.atomDeleteWindow , 1);
// connect the GLX-context to the window
glXMakeCurrent(x11.display, x11.window, x11.glxContext);
x11.width = width;
x11.height = height;
return true;
}
void Platform::destroyWindow()
{
if(x11.glxContext) {
glXMakeCurrent(x11.display, None, NULL);
glXDestroyContext(x11.display, x11.glxContext);
x11.glxContext = NULL;
}
if(x11.visual) {
XFree(x11.visual);
x11.visual = NULL;
}
if(x11.colormap != None) {
XFreeColormap(x11.display, x11.colormap);
x11.colormap = 0;
}
if(x11.window != None) {
XUnmapWindow(x11.display, x11.window);
XDestroyWindow(x11.display, x11.window);
x11.window = None;
}
if(x11.xic) {
XDestroyIC(x11.xic);
x11.xic = NULL;
}
if(x11.xim) {
XCloseIM(x11.xim);
x11.xim = NULL;
}
}
void Platform::showWindow()
{
XMapWindow(x11.display, x11.window);
}
void Platform::setWindowTitle(const char *title)
{
XStoreName(x11.display, x11.window, title);
XSetIconName(x11.display, x11.window, title);
}
void *Platform::getExtensionProcAddress(const char *ext)
{
return (void*)glXGetProcAddressARB((const GLubyte*)ext);
}
bool Platform::isExtensionSupported(const char *ext)
{
const char *exts = glXQueryExtensionsString(x11.display, DefaultScreen(x11.display));
if(strstr(exts, ext))
return true;
return true;
}
const char *Platform::getTextFromClipboard()
{
Window ownerWindow = XGetSelectionOwner(x11.display, x11.atomClipboard);
if(ownerWindow == x11.window)
return x11.clipboardText.c_str();
std::string clipboard = "";
if(ownerWindow != None) {
XConvertSelection(x11.display, x11.atomClipboard, XA_STRING, 0, ownerWindow, CurrentTime);
XFlush(x11.display);
// hack to wait SelectioNotify event, otherwise we will get wrong clipboard pastes
sleep(100);
// check for data
Atom type;
int format;
unsigned long numItems, bytesLeft, dummy;
unsigned char *data;
XGetWindowProperty(x11.display, ownerWindow,
XA_STRING,
0, 0, 0,
AnyPropertyType,
&type,
&format,
&numItems,
&bytesLeft,
&data);
if(bytesLeft > 0) {
// get the data get
int result = XGetWindowProperty(x11.display, ownerWindow,
XA_STRING,
0,
bytesLeft,
0,
AnyPropertyType,
&type,
&format,
&numItems,
&dummy,
&data);
if(result == Success)
clipboard = (const char*)data;
XFree(data);
}
}
return clipboard.c_str();
}
void Platform::copyToClipboard(const char *text)
{
x11.clipboardText = text;
XSetSelectionOwner(x11.display, x11.atomClipboard, x11.window, CurrentTime);
XFlush(x11.display);
}
void Platform::hideMouseCursor()
{
if(x11.cursor == None) {
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
Pixmap pix = XCreateBitmapFromData(x11.display, x11.window, bm, 8, 8);
XColor black;
memset(&black, 0, sizeof(XColor));
black.flags = DoRed | DoGreen | DoBlue;
x11.cursor = XCreatePixmapCursor(x11.display, pix, pix, &black, &black, 0, 0);
XFreePixmap(x11.display, pix);
}
XDefineCursor(x11.display, x11.window, x11.cursor);
}
void Platform::showMouseCursor()
{
XUndefineCursor(x11.display, x11.window);
if(x11.cursor != None) {
XFreeCursor(x11.display, x11.cursor);
x11.cursor = None;
}
}
void Platform::setVsync(bool enable)
{
typedef GLint (*glSwapIntervalProc)(GLint);
glSwapIntervalProc glSwapInterval = NULL;
if(isExtensionSupported("GLX_MESA_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
else if(isExtensionSupported("GLX_SGI_swap_control"))
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
if(glSwapInterval)
glSwapInterval(enable ? 1 : 0);
}
void Platform::swapBuffers()
{
glXSwapBuffers(x11.display, x11.window);
}
bool Platform::isWindowFocused()
{
return x11.focused;
}
bool Platform::isWindowVisible()
{
return x11.visible;
}
int Platform::getWindowWidth()
{
return x11.width;
}
int Platform::getWindowHeight()
{
return x11.height;
}
const char *Platform::getAppUserDir()
{
std::stringstream sdir;
sdir << PHYSFS_getUserDir() << "/." << APP_NAME << "/";
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
error("Couldn't create directory for saving configuration file. (%s)", sdir.str().c_str());
return sdir.str().c_str();
}