1
0
Fork 0

Initial commit

This commit is contained in:
Henrik Hautakoski 2015-12-22 17:43:51 +01:00
commit edfc5298e1
252 changed files with 93965 additions and 0 deletions

25
source/Core/String.cpp Normal file
View file

@ -0,0 +1,25 @@
#include <cstdio>
#include <Spectre/Core/String.h>
std::string core::to_string(unsigned int value)
{
char buf[32];
sprintf(buf, "%u", value);
return std::string(buf);
}
std::string core::to_string(float value)
{
char buf[32];
sprintf(buf, "%f", value);
return std::string(buf);
}
std::string core::to_string(float value, unsigned int precision)
{
char buf[32];
std::string format = "%." + to_string(precision) + "f";
sprintf(buf, format.c_str(), value);
return std::string(buf);
}

150
source/Display/Display.cpp Normal file
View file

@ -0,0 +1,150 @@
#include <iostream>
#include <Spectre/Display/Display.h>
#include <Spectre/Display/GLContext.h>
#include <Spectre/System/SystemEvent.h>
#include <Platform/PlatformDisplay.h>
#define CAPTION_DEFAULT "Spectre"
#define ICON_DEFAULT "./assets/app.ico"
Display::Display()
{
m_caption = CAPTION_DEFAULT;
m_fmode = WINDOWED;
m_context = GLContext::create();
m_impl = PlatformDisplay::make(this);
}
Display::~Display()
{
delete m_context;
delete m_impl;
}
bool Display::create(DisplayDescription description)
{
destroy();
if (!m_impl->create(description)) {
return false;
}
if (!m_context->create(m_impl, description.mode.bpp)) {
return false;
}
init();
m_description = description;
return true;
}
void Display::init()
{
m_impl->setCaption(m_caption);
setIcon(ICON_DEFAULT);
activate(true);
enableVSync(false);
showCursor(true);
}
void Display::destroy()
{
m_context->destroy();
m_impl->destroy();
}
void Display::setCaption(const std::string& caption)
{
m_caption = caption;
m_impl->setCaption(m_caption);
}
const std::string& Display::getCaption() const
{
return m_caption;
}
void Display::setIcon(const std::string& filename)
{
m_impl->setIcon(filename);
}
void Display::setSize(unsigned int width, unsigned int height)
{
m_description.mode.width = width;
m_description.mode.height = height;
m_impl->setSize(width, height);
}
void Display::setVideoMode(Mode mode)
{
DisplayDescription desc;
if (m_fmode == mode) {
return;
}
if (mode == FULLSCREEN || mode == WINDOWEDFULLSCREEN) {
// True fullscreen
if (mode == FULLSCREEN) {
desc.mode = m_description.mode;
} else {
desc.mode = DisplayMode::getDesktopMode();
m_cacheDesc = m_description;
}
desc.decoration = DisplayDecorate::None;
} else {
desc = m_cacheDesc;
}
create(desc);
m_fmode = mode;
}
enum Display::Mode Display::getVideoMode() const
{
return m_fmode;
}
void Display::showCursor(bool value)
{
m_impl->showCursor(value);
}
bool Display::activate(bool value)
{
if (value) {
return m_context->activate();
}
return m_context->deactivate();
}
bool Display::enableVSync(bool value)
{
return m_context->setSwapInterval(value ? 1 : 0);
}
void Display::swapBuffers()
{
if (activate(true)) {
m_context->swapBuffers();
}
}
void Display::onReshape(int width, int height)
{
// Resize context if the windows resizes.
m_context->setSize(width, height);
}

View file

@ -0,0 +1,14 @@
#include <Spectre/Display/DisplayDescription.h>
DisplayDescription::DisplayDescription() :
mode (),
decoration (DisplayDecorate::Default)
{
}
DisplayDescription::DisplayDescription(DisplayMode mode, unsigned decoration) :
mode (mode),
decoration (decoration)
{
}

View file

@ -0,0 +1,54 @@
#include <Spectre/Display/DisplayMode.h>
#include <Platform/PlatformMisc.h>
#include <algorithm>
struct DisplayModeCmp
{
inline bool operator() (const DisplayMode& a, const DisplayMode& b)
{
if (a.bpp == b.bpp) {
if (a.width == b.width) {
return a.height > b.height;
}
return a.width > b.width;
}
return a.bpp > b.bpp;
}
};
DisplayMode::DisplayMode() :
width (0),
height (0),
bpp (32)
{
}
DisplayMode::DisplayMode(unsigned int width, unsigned int height, unsigned int bpp) :
width (width),
height (height),
bpp (bpp)
{
}
std::vector<DisplayMode> DisplayMode::getFullscreenModes()
{
static std::vector<DisplayMode> modes;
if (modes.size() < 1) {
PlatformMisc::GetDisplayModes(modes);
// Sort.
std::sort(modes.begin(), modes.end(), DisplayModeCmp());
// remove duplicates
modes.erase(std::unique(modes.begin(), modes.end()), modes.end());
}
return modes;
}
DisplayMode DisplayMode::getDesktopMode()
{
return PlatformMisc::GetDesktopMode();
}

View file

@ -0,0 +1,19 @@
#include <Spectre/Display/GLContext.h>
#ifdef _WIN32
#include <Platform/Win32/Win32GLContext.h>
typedef Win32GLContext ContextType;
#else
#error "No GLContext implementation exists"
#endif
GLContext* GLContext::create()
{
return new ContextType();
}
GLContext::~GLContext()
{
// Nothing to do.
}

109
source/Game.cpp Normal file
View file

@ -0,0 +1,109 @@
#include <iostream>
#include <Spectre/Game/GameTime.h>
#include <Spectre/Game/FPSCounter.h>
#include <Spectre/Input/InputModule.h>
#include <Spectre/System/MessageHandler.h>
#include <Platform/PlatformMisc.h>
#include <Platform/Win32/Win32Application.h>
#include <Spectre/Game.h>
Game::Game()
{
m_platform = new Win32Application();
m_running = false;
m_graphics = new Graphics(m_platform);
m_input = new InputModule(&m_platform->getInput());
m_messageHandler = new MessageHandler();
}
Game::~Game()
{
delete m_input;
delete m_graphics;
delete m_platform;
delete m_messageHandler;
}
void Game::setup()
{
m_graphics->init();
m_graphics->setClearColor(0.0f, 0.0f, 0.0f);
init();
}
void Game::run()
{
setup();
gameLoop();
}
void Game::gameLoop()
{
GameTime time;
time.setTimeStep(120);
m_running = true;
while(m_running) {
processEvents();
if (time.beginFrame()) {
while(time.tick()) {
update(time.getTimeStep());
}
render();
m_fpsCounter.addFrame();
}
}
}
void Game::processEvents()
{
MessageQueue& queue = m_platform->getMessageQueue();
SysEvent event;
m_platform->update();
while(queue.pollEvent(event)) {
if (event.type == SysEvent::Quit) {
exit();
break;
}
// Call message handler.
if (event.type == SysEvent::Size) {
m_messageHandler->onSizeChanged(event.size.display, event.size.width, event.size.height);
}
}
}
void Game::exit()
{
m_running = false;
}
Graphics* Game::getGraphics() const
{
return m_graphics;
}
InputModule* Game::getInput() const
{
return m_input;
}
FPSCounter& Game::getFpsCounter()
{
return m_fpsCounter;
}

View file

@ -0,0 +1,55 @@
#include <Spectre/Game/FPSCounter.h>
#include <Spectre/System/System.h>
FPSCounter::FPSCounter() :
m_fps (60.0f),
m_updateRate (2000)
{
reset();
}
void FPSCounter::addFrame()
{
m_count++;
}
float FPSCounter::getFPS() const
{
return m_fps;
}
void FPSCounter::setUpdateRate(unsigned int ups)
{
// Clamp to 1.
if (ups < 1) {
ups = 1;
}
m_updateRate = ups * 1000;
// Must reset the counter.
reset();
}
bool FPSCounter::update()
{
unsigned int current = System::getMilliseconds();
unsigned int elapsed = current - m_time;
if (elapsed >= m_updateRate) {
float fraction = m_count / ((float) elapsed);
m_fps = fraction * 1000.f;
m_time = current;
m_count = 0;
return true;
}
return false;
}
void FPSCounter::reset()
{
m_time = System::getMilliseconds();
m_count = 0;
}

76
source/Game/GameTime.cpp Normal file
View file

@ -0,0 +1,76 @@
#include <iostream>
#include <Spectre/Game/GameTime.h>
#include <Spectre/System/System.h>
GameTime::GameTime(unsigned long updates_per_sec)
{
m_acc = 0;
m_current = System::getMilliseconds();
m_lastUpdate = m_current;
setTimeStep(updates_per_sec);
}
double GameTime::getTimeStep() const
{
return m_slice;
}
void GameTime::setTimeStep(unsigned long updates_per_sec)
{
m_slice = (1000.0f / ((double) updates_per_sec));
reset();
}
unsigned long GameTime::getElapsed() const
{
return m_current - m_lastUpdate;
}
bool GameTime::beginFrame()
{
reset();
accumulateTime();
if (m_acc > m_slice) {
m_inLoop = true;
}
return m_inLoop;
}
bool GameTime::tick()
{
if (m_acc > m_slice) {
m_acc -= m_slice;
return true;
}
return false;
}
void GameTime::reset()
{
m_lastUpdate = m_current;
m_inLoop = false;
}
void GameTime::accumulateTime()
{
updateTime();
m_acc += (double) (m_current - m_lastUpdate);
if (m_acc > (1000.f / m_slice)) {
m_acc = 1000.f / m_slice;
}
}
void GameTime::updateTime()
{
m_current = System::getMilliseconds();
// Just to be safe. check so we don't get a negative interval.
if (m_current < m_lastUpdate) {
m_lastUpdate = m_current;
}
}

View file

@ -0,0 +1,259 @@
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/Renderable.h>
#include <Spectre/Graphics/RenderState.h>
#include <Spectre/Graphics/ShaderProgram.h>
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Graphics/BatchRenderer2D.h>
#include <Spectre/Math/Math.h>
#include <algorithm>
static bool compare_renderable(const Renderable2D* a, const Renderable2D* b) {
if (a->getRenderType() != b->getRenderType()) {
return a->getRenderType() < b->getRenderType();
}
if (a->getTexture() != b->getTexture()) {
return a->getTexture() < b->getTexture();
}
return false;
}
BatchRenderer2D::BatchRenderer2D()
{
// Generate buffer objects.
glGenBuffers(1, &m_IBO);
glGenBuffers(1, &m_VBO);
setBatchSize(10000);
m_textShader.create();
if (!m_textShader.loadFromFile("assets/shaders/text.shader.glsl")) {
std::cout << "Failed to load shader: " << m_textShader.getLastError() << std::endl;
}
if (!m_textShader.link()) {
std::cout << "Failed to link shader: " << m_textShader.getLastError() << std::endl;
}
m_spriteShader.create();
if (!m_spriteShader.loadFromFile("assets/shaders/standard.shader.glsl")) {
std::cout << "Failed to load shader: " << m_spriteShader.getLastError() << std::endl;
}
if (!m_spriteShader.link()) {
std::cout << "Failed to link shader: " << m_spriteShader.getLastError() << std::endl;
}
}
BatchRenderer2D::~BatchRenderer2D()
{
glDeleteBuffers(1, &m_VBO);
glDeleteBuffers(1, &m_IBO);
}
void BatchRenderer2D::setBatchSize(unsigned short size)
{
std::vector<unsigned short> indices;
int vtx = 0;
if (size > 10000) {
size = 10000;
}
m_size = size;
indices.resize(size * 6);
for(int i = 0; i < m_size * 6; i += 6) {
indices[i + 0] = vtx + 0;
indices[i + 1] = vtx + 1;
indices[i + 2] = vtx + 2;
indices[i + 3] = vtx + 2;
indices[i + 4] = vtx + 3;
indices[i + 5] = vtx + 0;
vtx += 4;
}
// Upload to GPU
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Allocate memory for vertex buffer.
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, m_size * sizeof(Vertex2D), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Log
log("BatchRenderer - BatchSize\n");
log(" num sprites: %i\n", m_size);
log(" num indices: %i\n", m_size * 6);
log(" num vertices: %i\n", m_size);
log("------\n");
}
void BatchRenderer2D::begin()
{
}
void BatchRenderer2D::end()
{
}
void BatchRenderer2D::submit(const Renderable2D& renderable)
{
m_queue.push_back(&renderable);
}
void BatchRenderer2D::render()
{
Matrix4f viewMatrix = m_camera ? m_camera->getViewMatrix() : Matrix4f::Identity;
Matrix4f projMatrix = m_camera ? m_camera->getProjectionMatrix() : Matrix4f::Identity;
Matrix4f guiMatrix = math::orthoProjection(0.0f, 800.0f, 600.0f, 0.0f);
Matrix4f MVP = projMatrix * viewMatrix;
// Nothing to render.
if (m_queue.size() < 1) {
return;
}
// Bind buffers.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
// Setup position.
glEnableVertexAttribArray(VertexAttribPosition);
glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 0);
// Setup color
glEnableVertexAttribArray(VertexAttribColor0);
glVertexAttribPointer(VertexAttribColor0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 8);
glEnableVertexAttribArray(VertexAttribTexCoord0);
glVertexAttribPointer(VertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 20);
// Set shader uniforms.
m_textShader.enable();
m_textShader.setUniform("u_MVP", MVP);
m_textShader.disable();
m_spriteShader.enable();
m_spriteShader.setUniform("u_MVP", MVP);
m_spriteShader.disable();
prepareQueue();
glDisableVertexAttribArray(VertexAttribPosition);
glDisableVertexAttribArray(VertexAttribColor0);
glDisableVertexAttribArray(VertexAttribTexCoord0);
// Unbind all buffers.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_queue.clear();
m_state.cleanup();
}
void BatchRenderer2D::prepareQueue()
{
Vertex2D *buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
Batch current;
std::sort(m_queue.begin(), m_queue.end(), compare_renderable);
current.type = m_queue[0]->getRenderType();
current.texture = m_queue[0]->getTexture();
current.count = 0;
current.offset = 0;
for(int i = 0; i < m_queue.size(); i++) {
const Texture *tex = m_queue[i]->getTexture();
RenderType type = m_queue[i]->getRenderType();
unsigned int num_vert = m_queue[i]->getVertices().size();
// TODO: Only upload and draw if buffer is full :)
if (current.type != type || current.texture != tex || current.count >= m_size) {
glUnmapBuffer(GL_ARRAY_BUFFER);
drawBatch(current);
buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
current.type = m_queue[i]->getRenderType();
current.count = 0;
current.offset = 0;
current.texture = tex;
}
buffer += addRenderable(buffer, m_queue[i]);
current.count += num_vert;
}
glUnmapBuffer(GL_ARRAY_BUFFER);
if (current.count > 0) {
drawBatch(current);
}
}
void BatchRenderer2D::uploadBatch(const Batch& batch)
{
Vertex2D *buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
unsigned int count = 0;
for(int i = 0; i < batch.count; i++) {
buffer += addRenderable(buffer, m_queue[batch.offset + i]);
}
// Upload gpu data and draw.
glUnmapBuffer(GL_ARRAY_BUFFER);
}
unsigned int BatchRenderer2D::addRenderable(Vertex2D* buffer, const Renderable2D* renderable)
{
const Transform& transform = renderable->getTransform();
const std::vector<Vertex2D>& vertices = renderable->getVertices();
// Pretransform vertex positions to skip setting a uniform model
// matrix in the shader for each renderable reducing the number of draw calls.
for(int i = 0; i < vertices.size(); i++) {
buffer[i].position = transform * vertices[i].position;
buffer[i].color = vertices[i].color;
buffer[i].uv = vertices[i].uv;
}
return vertices.size();
}
void BatchRenderer2D::drawBatch(Batch& batch)
{
const ShaderProgram* shader;
if (batch.type == RenderType_UI) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shader = &m_textShader;
} else {
shader = &m_spriteShader;
}
// enable shader.
m_state.enableShader(shader);
// enable batch texture
m_state.enableTexture(batch.texture);
glDrawElements(GL_TRIANGLES, (batch.count / 4) * 6, GL_UNSIGNED_SHORT, 0);
if (batch.type == RenderType_UI) {
glDisable(GL_BLEND);
}
}

View file

@ -0,0 +1,72 @@
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/Renderable.h>
#include <Spectre/Graphics/DefaultRenderer2D.h>
DefaultRenderer2D::DefaultRenderer2D()
{
m_shader.create();
if (!m_shader.loadFromFile("assets/shaders/standard.shader.glsl")) {
std::cout << "Failed to load shader: " << m_shader.getLastError() << std::endl;
}
if (!m_shader.link()) {
std::cout << "Failed to link shader: " << m_shader.getLastError() << std::endl;
}
}
void DefaultRenderer2D::submit(const Renderable2D& renderable)
{
m_queue.push_back(&renderable);
}
void DefaultRenderer2D::render()
{
Matrix4f viewMatrix;
if (m_camera) {
viewMatrix = m_camera->getViewMatrix();
} else {
viewMatrix = Matrix4f::Identity;
}
m_shader.enable();
glEnableVertexAttribArray(VertexAttribPosition);
glEnableVertexAttribArray(VertexAttribColor0);
glEnableVertexAttribArray(VertexAttribTexCoord0);
for(int i = 0; i < m_queue.size(); i++) {
const Renderable2D* obj = m_queue[i];
const std::vector<Vertex2D> vertices = obj->getVertices();
const std::vector<unsigned short> indices = obj->getIndices();
unsigned char *data = (unsigned char*) &vertices[0];
const Texture *tex = obj->getTexture();
Matrix4f modelViewMatrix = viewMatrix * obj->getTransform().getMatrix();
m_shader.setMVPMatrix(modelViewMatrix);
glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), data + 0);
glVertexAttribPointer(VertexAttribColor0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), data + 8);
glVertexAttribPointer(VertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), data + 20);
if (tex) {
tex->enable();
}
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
if (tex) {
tex->disable();
}
}
glDisableVertexAttribArray(VertexAttribPosition);
glDisableVertexAttribArray(VertexAttribColor0);
glDisableVertexAttribArray(VertexAttribTexCoord0);
m_shader.disable();
m_queue.clear();
}

127
source/Graphics/Font.cpp Normal file
View file

@ -0,0 +1,127 @@
#include <Spectre/System/File.h>
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/Font.h>
#include <Spectre/Graphics/Image.h>
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Math/Math.h>
#include "Font/FreeTypeDriver.h"
Font::Font() :
m_size (22),
m_driver (new FreeTypeDriver())
{
}
Font::~Font()
{
delete m_driver;
}
bool Font::loadFromFile(const std::string& filename, unsigned int size)
{
if (!m_driver->loadFromFile(filename)) {
return false;
}
if (!m_driver->setCharacterSize(size)) {
return false;
}
m_size = size;
m_shelf = 0;
m_texpos = vec2u(0, 0);
createTexture();
return true;
}
bool Font::loadFromMemory(const void *data, unsigned int size)
{
return false;
}
Font::Glyph Font::getGlyph(unsigned int code) const
{
if (m_charset.find(code) == m_charset.end()) {
loadChar(code);
}
return m_charset[code];
}
void Font::loadChar(unsigned char code) const
{
Image img;
Font::Glyph glyph;
if (!m_driver) {
return;
}
glyph = m_driver->loadGlyph(code, img);
if (glyph.size > vec2b(0, 0)) {
Vector2u pos = findTextureRegion(img);
m_texture.enable();
m_texture.update(pos, img);
glyph.texture = &m_texture;
glyph.texture_origin = vec2u(pos.x, pos.y);
} else {
glyph.texture = NULL;
}
m_charset[code] = glyph;
}
void Font::createTexture()
{
m_texture.create(128, 32, PixelFormat::PF_Alpha);
m_texture.enable();
m_texture.setSmooth(true);
m_texture.disable();
}
void Font::resizeTexture() const
{
unsigned int nextSize = math::nextPowerOfTwo(m_texture.getSize().y + 1);
Image tmpImg = m_texture.copyToImage();
// recreate texture.
m_texture.create(m_texture.getSize().x, nextSize, PixelFormat::PF_Alpha);
m_texture.update(vec2u(0, 0), tmpImg);
}
Vector2u Font::findTextureRegion(const Image& img) const
{
Vector2u pos;
if (m_texpos.x + img.getWidth() + 1 > m_texture.getSize().x) {
m_texpos.y += m_shelf;
m_texpos.x = 0;
m_shelf = 0;
}
if (img.getHeight() + 1 > m_shelf) {
m_shelf = img.getHeight() + 1;
if (m_texpos.y + m_shelf > m_texture.getSize().y) {
resizeTexture();
}
}
pos = m_texpos;
m_texpos.x += img.getWidth() + 1;
return pos;
}
const Texture* Font::getTexture() const
{
return &m_texture;
}

View file

@ -0,0 +1,12 @@
#include "FontDriver.h"
FontDriver::FontDriver() :
m_hinting (true)
{
}
void FontDriver::setHinting(bool value)
{
m_hinting = value;
}

View file

@ -0,0 +1,31 @@
#ifndef SPECTRE_GRAPHICS_FONT_FONTDRIVER_H
#define SPECTRE_GRAPHICS_FONT_FONTDRIVER_H
#include <string>
#include <Spectre/Graphics/Image.h>
#include <Spectre/Graphics/Font.h>
class FontDriver
{
public :
FontDriver();
void setHinting(bool value);
virtual bool setCharacterSize(unsigned int size) = 0;
virtual bool loadFromFile(const std::string& filename) = 0;
virtual Font::Glyph loadGlyph(unsigned int codepoint, Image& img) = 0;
virtual std::string getName() = 0;
protected :
// True if hinting is enabled. false otherwise.
bool m_hinting;
};
#endif /* SPECTRE_GRAPHICS_FONT_FONTDRIVER_H */

View file

@ -0,0 +1,131 @@
#include <ft2build.h>
#include FT_MODULE_H
#include FT_LCD_FILTER_H
#include <Spectre/System/Log.h>
#include "FreeTypeError.h"
#include "FreeTypeDriver.h"
class LibWrapper
{
public :
static LibWrapper& getInstance()
{
static LibWrapper _inst;
return _inst;
};
// Do not implement.
LibWrapper(const LibWrapper&);
void operator=(const LibWrapper&);
FT_Library handle;
private :
LibWrapper();
~LibWrapper();
};
LibWrapper::LibWrapper()
{
FT_Error error = FT_Init_FreeType(&handle);
if (error) {
log("Could not initialize FreeType\n");
} else {
log("FreeType font driver was initialized.\n");
}
}
LibWrapper::~LibWrapper()
{
FT_Error error = FT_Done_FreeType(handle);
if (error) {
log("Could not close FreeType\n");
}
}
FreeTypeDriver::FreeTypeDriver() :
m_face (NULL)
{
}
FreeTypeDriver::~FreeTypeDriver()
{
if (m_face) {
FT_Done_Face(m_face);
}
}
bool FreeTypeDriver::setCharacterSize(unsigned int size)
{
FT_Error error = FT_Set_Pixel_Sizes(m_face, 0, size);
if (error) {
log("FreeType: failed to set character size\n");
return false;
}
return true;
}
bool FreeTypeDriver::loadFromFile(const std::string& filename)
{
FT_Face face;
FT_Error error;
error = FT_New_Face(LibWrapper::getInstance().handle, filename.c_str(), 0, &face);
if (error) {
log("FreeType: could not load file (%s): %s\n",
filename.c_str(), FT_GetErrorString(error));
return false;
}
error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
if (error) {
log("FreeType: (%s) failed to set unicode charmap\n", filename.c_str());
return false;
}
m_face = face;
return true;
}
Font::Glyph FreeTypeDriver::loadGlyph(unsigned int codepoint, Image& img)
{
Font::Glyph glyph;
FT_Int32 flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
if (m_hinting) {
flags |= FT_LOAD_FORCE_AUTOHINT;
} else {
flags |= FT_LOAD_NO_AUTOHINT;
}
FT_Error error = FT_Load_Char(m_face, codepoint, flags);
if (!error) {
FT_GlyphSlot slot = m_face->glyph;
if (slot->bitmap.buffer) {
img.create(PixelFormat::PF_Alpha,
slot->bitmap.width,
slot->bitmap.rows,
slot->bitmap.buffer);
}
glyph.offset = vec2b(slot->bitmap_left, slot->bitmap_top);
glyph.size = vec2b(slot->bitmap.width, slot->bitmap.rows);
glyph.advance = static_cast<unsigned char>(slot->advance.x >> 6);
} else {
log("FreeType: failed to load glyph for character code '%c'\n", codepoint);
}
return glyph;
}
std::string FreeTypeDriver::getName()
{
return m_face->family_name;
}

View file

@ -0,0 +1,29 @@
#ifndef SPECTRE_GRAPHICS_FONT_FREETYPEDRIVER_H
#define SPECTRE_GRAPHICS_FONT_FREETYPEDRIVER_H
#include <ft2build.h>
#include FT_FREETYPE_H
#include "FontDriver.h"
class FreeTypeDriver : public FontDriver
{
public:
FreeTypeDriver();
~FreeTypeDriver();
virtual bool setCharacterSize(unsigned int size);
virtual bool loadFromFile(const std::string& filename);
virtual Font::Glyph loadGlyph(unsigned int codepoint, Image& img);
virtual std::string getName();
private :
FT_Face m_face;
};
#endif /* SPECTRE_GRAPHICS_FONT_FREETYPEDRIVER_H */

View file

@ -0,0 +1,28 @@
#include "FreeTypeError.h"
#include <ft2build.h>
#undef __FTERRORS_H__
#define FT_ERROR_START_LIST {
#define FT_ERRORDEF(e, v ,s) { e, s },
#define FT_ERROR_END_LIST { 0, NULL } };
const struct error_list {
int code;
const char* msg;
} ft_errors[] =
#include FT_ERRORS_H
const char* FT_GetErrorString(FT_Error error) {
const struct error_list* ptr = ft_errors;
while(ptr->msg) {
if (ptr->code == error)
return ptr->msg;
ptr++;
}
return "Unkown error";
}

View file

@ -0,0 +1,10 @@
#ifndef SPECTRE_GRAPHICS_FONT_FREETYPE_ERROR_H
#define SPECTRE_GRAPHICS_FONT_FREETYPE_ERROR_H
#include <ft2build.h>
#include FT_FREETYPE_H
const char* FT_GetErrorString(FT_Error error);
#endif /* SPECTRE_GRAPHICS_FONT_FREETYPE_ERROR_H */

View file

@ -0,0 +1,12 @@
#include <string>
#include "CheckError.h"
void glCheckError(const char *file, unsigned int line, const char *expr) {
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
std::string msg;
}
}

View file

@ -0,0 +1,11 @@
#ifndef SPECTRE_GRAPHICS_GL_CHECKERROR_H
#define SPECTRE_GRAPHICS_GL_CHECKERROR_H
#include <Spectre/Graphics/OpenGL.h>
#define checkGLError(expr) do { expr; glCheckError(__FILE__, __LINE__, #expr); } while(false)
void glCheckError(const char *file, unsigned int line, const char *expr);
#endif /* SPECTRE_GRAPHICS_GL_CHECKERROR_H */

208
source/Graphics/Image.cpp Normal file
View file

@ -0,0 +1,208 @@
#include "ImageLoader.h"
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/Image.h>
static ImageLoader _loader;
Image::Image() :
m_size (0, 0),
m_format (PF_Unknown)
{
}
void Image::create(unsigned width, unsigned height, const Color& color)
{
m_size.x = width;
m_size.y = height;
m_format = PixelFormat::PF_RGBA;
m_pixels.resize(m_size.x * m_size.y * (getBpp() / 8));
for(int i = 0; i < m_pixels.size(); i += 4) {
m_pixels[i+0] = color.r;
m_pixels[i+1] = color.g;
m_pixels[i+2] = color.b;
m_pixels[i+3] = color.a;
}
}
void Image::create(unsigned width, unsigned height, const void* pixels)
{
create(PixelFormat::PF_RGBA, width, height, pixels);
}
void Image::create(PixelFormat format, unsigned width, unsigned height, const Color& color)
{
m_size.x = width;
m_size.y = height;
m_format = format;
m_pixels.resize(m_size.x * m_size.y * (getBpp() / 8));
if (getBpp() == 32) {
for(int i = 0; i < m_pixels.size(); i += 4) {
m_pixels[i+0] = color.r;
m_pixels[i+1] = color.g;
m_pixels[i+2] = color.b;
m_pixels[i+3] = color.a;
}
} else if (getBpp() == 24) {
for(int i = 0; i < m_pixels.size(); i += 3) {
m_pixels[i+0] = color.r;
m_pixels[i+1] = color.g;
m_pixels[i+2] = color.b;
}
} else {
for(int i = 0; i < m_pixels.size(); i += 1) {
m_pixels[i] = color.a;
}
}
}
void Image::create(PixelFormat format, unsigned width, unsigned height, const void* pixels)
{
m_size.x = width;
m_size.y = height;
m_format = format;
setPixels(pixels);
}
const Vector2u& Image::getSize() const
{
return m_size;
}
unsigned int Image::getWidth() const
{
return m_size.x;
}
unsigned int Image::getHeight() const
{
return m_size.y;
}
unsigned int Image::getBpp() const
{
switch(m_format) {
case PixelFormat::PF_RGBA : return 32;
case PixelFormat::PF_RGB : return 24;
case PixelFormat::PF_Alpha : return 8;
case PixelFormat::PF_Unknown :
default : break;
}
return 0;
}
unsigned int Image::getStride() const
{
return m_size.x * (getBpp() / 8);
}
PixelFormat Image::getFormat() const
{
return m_format;
}
bool Image::hasAlpha() const
{
return m_format == PixelFormat::PF_RGBA || m_format == PixelFormat::PF_Alpha;
}
bool Image::loadFromFile(const std::string& filename)
{
m_pixels.clear();
return _loader.loadFromFile(filename.c_str(), *this);
}
bool Image::loadFromMemory(const void *data, unsigned int size)
{
m_pixels.clear();
return _loader.loadFromMemory(data, size, *this);
}
void Image::saveToFile(const std::string& filename) const
{
_loader.saveToFile(*this, filename.c_str());
}
void Image::setPixel(unsigned x, unsigned y, const Color& c)
{
unsigned char *base = m_pixels.data() + ((getBpp() / 8) * ((y * m_size.x) + x));
if (m_format == PixelFormat::PF_RGB || m_format == PixelFormat::PF_RGBA) {
base[0] = c.r;
base[1] = c.g;
base[2] = c.b;
if (m_format == PixelFormat::PF_RGBA) {
base[3] = c.a;
}
}
else if (m_format == PixelFormat::PF_Alpha) {
base[0] = c.a;
}
}
Color Image::getPixel(unsigned x, unsigned y) const
{
Color c;
const unsigned char *base = m_pixels.data() + ((getBpp() / 8) * ((y * m_size.x) + x));
// RGB / RGBA formats.
if (m_format == PixelFormat::PF_RGB || m_format == PixelFormat::PF_RGBA) {
c.r = base[0];
c.g = base[1];
c.b = base[2];
if (m_format == PixelFormat::PF_RGBA) {
c.a = base[3];
} else {
c.a = 1.0f;
}
}
// Alpha, single channel format.
else if (m_format == PixelFormat::PF_Alpha) {
c = Color(0, 0, 0, base[0]);
}
return c;
}
void Image::flipY()
{
unsigned int stride = getStride();
// The quick and dirty way :)
for(int y = 0; y < m_size.y / 2; y++) {
int row0 = y * stride;
int row1 = (m_size.y - y - 1) * stride;
for(int x = 0; x < stride; x++) {
unsigned char tmp = m_pixels[row0 + x];
m_pixels[row0 + x] = m_pixels[row1 + x];
m_pixels[row1 + x] = tmp;
}
}
}
void Image::setPixels(const void *pixels)
{
unsigned int size = m_size.y * getStride();
m_pixels.resize(size);
std::memcpy(&m_pixels[0], pixels, m_pixels.size());
}
const unsigned char* Image::getPixels() const
{
if (m_pixels.size()) {
return &m_pixels[0];
}
return NULL;
}

View file

@ -0,0 +1,130 @@
#include <Spectre/System/File.h>
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/Image.h>
#include "ImageLoader.h"
// Disable some file formats that we don't use.
#define STBI_NO_PSD
#define STBI_NO_PIC
#define STBI_NO_GIF
#define STBI_NO_HDR
#define STBI_NO_PNM
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include <string.h>
#include <stdio.h>
#include <vector>
bool ImageLoader::loadFromFile(const char *filename, Image& img)
{
FILE *fd = fopen(filename, "rb");
if (fd) {
std::vector<unsigned char> buf;
fseek(fd, 0, SEEK_END);
buf.resize(ftell(fd));
rewind(fd);
fread(&buf[0], 1, buf.size(), fd);
fclose(fd);
// loaded into memory. now decode.
if (decode((const char*)&buf[0], buf.size(), img) == false) {
log("ImageLoader: could not load file '%s'. Reason: %s",
filename, m_error);
return false;
}
return true;
}
log("ImageLoader: could not open file '%s'. Reason: %s",
filename, std::strerror(errno));
return false;
}
bool ImageLoader::loadFromMemory(const void *data, unsigned size, Image& img)
{
//std::vector<unsigned char> buf;
//buf.assign(((unsigned char*) data), ((unsigned char*) data) + size);
return decode((const char*) data, size, img);
}
// TODO: Support more formats.
bool ImageLoader::saveToFile(const Image& img, const char *filename)
{
std::string ext = File::getExtension(filename);
std::vector<unsigned char> encoded_data;
if (ext == "png") {
if (!encodePNG(img, encoded_data)) {
log("ImageLoader: failed to save file '%s'. Reason: \n",
filename, m_error);
}
} else {
log("ImageLoader: Invalid file format\n");
return false;
}
if (encoded_data.size() > 0) {
FILE *fd = fopen(filename, "wb");
if (fd) {
fwrite(&encoded_data[0], 1, encoded_data.size(), fd);
fclose(fd);
}
return true;
}
return false;
}
bool ImageLoader::decode(const char *data, unsigned int size, Image& img)
{
// width, height, num components.
int w, h, n_comp;
const stbi_uc *ptr = (const stbi_uc *) data;
unsigned char *pixels = stbi_load_from_memory(ptr, size, &w, &h, &n_comp, 4);
if (pixels) {
unsigned int len = w * h * 4;
img.create(w, h, pixels);
stbi_image_free(pixels);
return true;
}
m_error = stbi_failure_reason();
return false;
}
bool ImageLoader::encodePNG(const Image& img, std::vector<unsigned char>& data)
{
int buf_len;
unsigned char *raw = (unsigned char*) img.getPixels();
unsigned char *buf;
buf = stbi_write_png_to_mem(raw, img.getStride(), img.getWidth(), img.getHeight(), img.getBpp() / 8, &buf_len);
if (buf && buf_len > 0) {
data.resize(buf_len);
std::memcpy(&data[0], buf, buf_len);
STBIW_FREE(buf);
return true;
}
m_error = stbi_failure_reason();
return false;
}

View file

@ -0,0 +1,33 @@
#ifndef SPECTRE_GRAPHICS_IMAGE_LOADER_H
#define SPECTRE_GRAPHICS_IMAGE_LOADER_H
#include <Spectre/Graphics/Image.h>
#include <Spectre/Math/Vector2.h>
#include <vector>
class ImageLoader
{
public :
bool loadFromFile(const char *filename, Image& img);
bool loadFromMemory(const void *data, unsigned size, Image& img);
bool saveToFile(const Image& img, const char *filename);
protected :
bool decode(const char* data, unsigned int len, Image& img);
bool encode(Image& img, std::vector<unsigned char>& data);
bool encodeJPEG(const Image& img, std::vector<unsigned char>& data);
bool encodePNG(const Image& img, std::vector<unsigned char>& data);
protected :
std::string m_error;
};
#endif /* SPECTRE_GRAPHICS_IMAGE_LOADER_H */

View file

@ -0,0 +1,48 @@
#include <Spectre/Graphics/ShaderProgram.h>
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Graphics/RenderState.h>
RenderState::RenderState() :
m_texture (0),
m_shader (0)
{
}
RenderState::~RenderState()
{
cleanup();
}
void RenderState::enableTexture(const Texture *texture)
{
// Enable the new texture.
if (texture) {
texture->enable();
}
// No texture selected.
// Must unbind cached texture if set.
else if (m_texture) {
m_texture->disable();
}
m_texture = texture;
}
void RenderState::enableShader(const ShaderProgram *program)
{
m_shader = program;
m_shader->enable();
}
void RenderState::cleanup()
{
// Disable current texture if set.
if (m_texture) {
m_texture->disable();
}
if (m_shader) {
m_shader->disable();
}
}

View file

@ -0,0 +1,15 @@
#include <Spectre/Graphics/Renderable.h>
Renderable2D::Renderable2D()
{
}
Renderable2D::Renderable2D(const Vector2f& position) :
Transformable (position)
{
}
Renderable2D::~Renderable2D()
{
}

View file

@ -0,0 +1,15 @@
#include <Spectre/Graphics/Renderer2D.h>
Renderer2D::Renderer2D() :
m_camera (NULL)
{
}
Renderer2D::~Renderer2D()
{
}
void Renderer2D::setCamera(const Camera2D& camera)
{
m_camera = &camera;
}

100
source/Graphics/Shader.cpp Normal file
View file

@ -0,0 +1,100 @@
#include <fstream>
#include <Spectre/System/File.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/Shader.h>
Shader::Shader(Type type, const std::string& name) :
m_name (name)
{
GLenum internal_type = type == Vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER;
m_handle = glCreateShader(internal_type);
}
Shader::~Shader()
{
if (m_handle) {
glDeleteShader(m_handle);
}
}
unsigned int Shader::getHandle() const
{
return m_handle;
}
const std::string& Shader::getName() const
{
return m_name;
}
bool Shader::loadFromFile(const std::string& file)
{
std::string src;
std::ifstream strm;
// If this shader does not have a name, pick the filename.
if (m_name.length() < 1) {
m_name = File::getBasename(file);
}
// Load file into memory.
strm.open(file.c_str(), std::fstream::in);
if (!strm.is_open()) {
m_error = "Can't open file: " + file;
return false;
}
src.assign(std::istreambuf_iterator<char>(strm), std::istreambuf_iterator<char>());
strm.close();
return loadFromMemory(src);
}
bool Shader::loadFromMemory(const std::string& source)
{
const char *s = source.c_str();
glShaderSource(m_handle, 1, &s, NULL);
return compile();
}
const std::string& Shader::getError() const
{
return m_error;
}
bool Shader::isCompiled() const
{
// A shader without handle is not compiled.
if (m_handle) {
// Query OpenGL for status.
GLint status;
glGetShaderiv(m_handle, GL_COMPILE_STATUS, &status);
return status == GL_TRUE;
}
return false;
}
bool Shader::compile()
{
glCompileShader(m_handle);
if (!isCompiled()) {
m_error = fetchErrorLog();
return false;
}
return true;
}
std::string Shader::fetchErrorLog()
{
GLchar buf[4096] = { '\0 ' };
glGetShaderInfoLog(m_handle, sizeof(buf), NULL, buf);
return std::string(buf);
}

View file

@ -0,0 +1,193 @@
#include <Spectre/Math/Color.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/ShaderProgram.h>
#include <Spectre/System/File.h>
ShaderProgram::ShaderProgram() :
m_id (0)
{
}
ShaderProgram::~ShaderProgram()
{
destroy();
}
void ShaderProgram::create()
{
destroy();
m_id = glCreateProgram();
}
void ShaderProgram::destroy()
{
if (m_id > 0) {
glDeleteProgram(m_id);
m_id = 0;
}
}
void ShaderProgram::addShader(const Shader& shader)
{
glAttachShader(m_id, shader.getHandle());
}
bool ShaderProgram::loadFromFile(const std::string& filename)
{
std::string extension = File::getExtension(filename);
// Meta file. load real shaders.
if (extension == "shader.glsl") {
// FIXME: This is ugly :)
std::string base_name = filename.substr(0, filename.length() - extension.length());
// vert and frag are not optional. they must exist.
return loadFromFile(base_name + "vert.glsl", Shader::Type::Vertex) &&
loadFromFile(base_name + "frag.glsl", Shader::Type::Fragment);
} else if (extension == "vert.glsl") {
return loadFromFile(filename, Shader::Type::Vertex);
} else if (extension == "frag.glsl") {
return loadFromFile(filename, Shader::Type::Fragment);
}
m_error = "Invalid file extension: " + extension;
return false;
}
bool ShaderProgram::loadFromFile(const std::string& filename, Shader::Type type)
{
Shader shader(type);
if (!shader.loadFromFile(filename)) {
m_error = shader.getName() + ": " + shader.getError();
return false;
}
addShader(shader);
return true;
}
bool ShaderProgram::loadFromMemory(const std::string& source, Shader::Type type)
{
Shader shader(type);
if (!shader.loadFromMemory(source)) {
m_error = shader.getError();
return false;
}
addShader(shader);
return true;
}
bool ShaderProgram::link()
{
glLinkProgram(m_id);
if (!isLinked()) {
m_error = fetchErrorLog();
return false;
}
return true;
}
bool ShaderProgram::isLinked() const
{
// Make sure we have a id first.
if (m_id) {
// Query OpenGL for link status.
GLint status;
glGetProgramiv(m_id, GL_LINK_STATUS, &status);
return status == GL_TRUE;
}
return false;
}
void ShaderProgram::enable() const
{
glUseProgram(m_id);
}
void ShaderProgram::disable() const
{
glUseProgram(0);
}
std::string ShaderProgram::getLastError() const
{
return m_error;
}
bool ShaderProgram::setMVPMatrix(const Matrix4f& matrix)
{
return setUniform("u_MVP", matrix);
}
bool ShaderProgram::setUniform(const std::string& name, const Matrix4f& matrix) const
{
int loc;
if (getUniformLoc(name, loc)) {
glUniformMatrix4fv(loc, 1, GL_FALSE, matrix.e);
return true;
}
return false;
}
bool ShaderProgram::setAttribute(const std::string& name, const Matrix4f& matrix) const
{
int loc;
if (getAttribLoc(name, loc)) {
glVertexAttrib4fv(loc, matrix.e);
return true;
}
return false;
}
bool ShaderProgram::setUniform(const std::string& name, const Color& color) const
{
int loc;
if (getUniformLoc(name, loc)) {
Vector4f c = color.toRGBAf();
glUniform4f(loc, c.x, c.y, c.z, c.w);
return true;
}
return false;
}
bool ShaderProgram::getAttribLoc(const std::string& name, int& loc) const
{
loc = glGetAttribLocation(m_id, name.c_str());
if (loc < 0) {
m_error = "Attribute variable '" + name + "' was not found in shader.";
return false;
}
return true;
}
bool ShaderProgram::getUniformLoc(const std::string& name, int& loc) const
{
loc = glGetUniformLocation(m_id, name.c_str());
if (loc < 0) {
m_error = "Uniform variable '" + name + "' was not found in shader.";
return false;
}
return true;
}
std::string ShaderProgram::fetchErrorLog()
{
GLchar buf[4096] = { '\0' };
glGetProgramInfoLog(m_id, sizeof(buf), NULL, buf);
return std::string(buf);
}

111
source/Graphics/Sprite.cpp Normal file
View file

@ -0,0 +1,111 @@
#include <Spectre/Graphics/Texture.h>
#include <Spectre/Graphics/Sprite.h>
Sprite::Sprite() :
m_texture (NULL)
{
unsigned short indices[6] = {
0, 1, 2, 2, 3, 0
};
m_indicies.assign(indices, indices + 6);
m_vertices.resize(4);
setSize(vec2f(1.0f, 1.0f));
setColor(Color(255, 255, 255));
// Texcords
m_vertices[0].uv = Vector2f( 0.0f, 0.0f);
m_vertices[1].uv = Vector2f( 0.0f, 1.0f);
m_vertices[2].uv = Vector2f( 1.0f, 1.0f);
m_vertices[3].uv = Vector2f( 1.0f, 0.0f);
}
Sprite::Sprite(const vec2f& pos, const vec2f& size) :
m_texture (NULL)
{
unsigned short indices[6] = {
0, 1, 2, 2, 3, 0
};
m_indicies.assign(indices, indices + 6);
m_vertices.resize(4);
setPosition(pos);
setSize(size);
setColor(Color(255, 255, 255));
m_vertices[0].uv = Vector2f( 0.0f, 1.0f);
m_vertices[1].uv = Vector2f( 0.0f, 0.0f);
m_vertices[2].uv = Vector2f( 1.0f, 0.0f);
m_vertices[3].uv = Vector2f( 1.0f, 1.0f);
}
void Sprite::init()
{
}
void Sprite::setSize(vec2f size)
{
if (size < vec2f(0.0, 0.0f)) {
size = vec2f(0.0, 0.0f);
}
m_vertices[0].position = vec2f(0.0f, 0.0f);
m_vertices[1].position = vec2f(0.0f, size.y);
m_vertices[2].position = vec2f(size.x, size.y);
m_vertices[3].position = vec2f(size.x, 0.0f);
}
void Sprite::setColor(const Color& color)
{
m_vertices[0].color = color.toRGBf();
m_vertices[1].color = m_vertices[0].color;
m_vertices[2].color = m_vertices[0].color;
m_vertices[3].color = m_vertices[0].color;
}
void Sprite::setTexture(const Texture& texture)
{
m_texture = &texture;
}
void Sprite::setTextureCoords(const vec2u& pos, const vec2u& size)
{
// No texture, nothing to do.
if (!m_texture) {
return;
}
Vector2f tex_size = Vector2f(m_texture->getSize());
float left = pos.x / tex_size.x;
float right = left + (size.x / tex_size.x);
float top = pos.y / tex_size.y;
float bottom = top + (size.y / tex_size.y);
m_vertices[0].uv = Vector2f(left , top);
m_vertices[1].uv = Vector2f(left , bottom);
m_vertices[2].uv = Vector2f(right, bottom);
m_vertices[3].uv = Vector2f(right, top);
}
const Texture* Sprite::getTexture() const
{
return m_texture;
}
const std::vector<Vertex2D>& Sprite::getVertices() const
{
return m_vertices;
}
const std::vector<unsigned short>& Sprite::getIndices() const
{
return m_indicies;
}
void Sprite::updateGeometry()
{
}

131
source/Graphics/Text.cpp Normal file
View file

@ -0,0 +1,131 @@
#include <Spectre/Graphics/Text.h>
Text::Text() :
m_font (NULL),
m_color (255, 255, 255, 255)
{
}
Text::Text(const std::string text, const Font& font) :
m_font (&font),
m_color (255, 255, 255, 255),
m_geometryNeedsUpdate (true)
{
}
void Text::setString(const std::string& string)
{
m_string = string;
m_geometryNeedsUpdate = true;
}
const std::string& Text::getString() const
{
return m_string;
}
void Text::setFont(const Font& font)
{
m_font = &font;
m_geometryNeedsUpdate = true;
}
const Font* Text::getFont() const
{
return m_font;
}
void Text::setColor(const Color& color)
{
m_color = color;
m_geometryNeedsUpdate = true;
}
const Color& Text::getColor() const
{
return m_color;
}
Vector2f Text::getSize() const
{
Vector2f size;
for(int i = 0; i < m_string.size(); i++) {
Font::Glyph glyph = m_font->getGlyph(m_string[i]);
float h = glyph.size.y;
float w = glyph.advance;
if (h > size.y) {
size.y = h;
}
size.x += w;
}
return size;
}
const Texture* Text::getTexture() const
{
if (m_geometryNeedsUpdate) {
updateGeometry();
m_geometryNeedsUpdate = false;
}
return m_font->getTexture();
}
const std::vector<unsigned short>& Text::getIndices() const
{
return m_indicies;
}
const std::vector<Vertex2D>& Text::getVertices() const
{
if (m_geometryNeedsUpdate) {
updateGeometry();
m_geometryNeedsUpdate = false;
}
return m_vertices;
}
void Text::updateGeometry() const
{
Vector2f origin;
Vector2f size = getSize();
Vector3f color = getColor().toRGBf();
m_vertices.clear();
for(int i = 0; i < m_string.length(); i++) {
Vertex2D v1, v2, v3, v4;
Font::Glyph glyph = m_font->getGlyph(m_string[i]);
if (glyph.texture) {
Vector2f vpos = origin + vec2f(glyph.offset.x, size.y - glyph.offset.y);
Vertex2D v1 = Vertex2D(vpos + vec2f( 0.0f, 0.0f), vec2f(glyph.texture_origin.x, glyph.texture_origin.y));
Vertex2D v2 = Vertex2D(vpos + vec2f( glyph.size.x, 0.0f), vec2f(glyph.texture_origin.x + glyph.size.x, glyph.texture_origin.y));
Vertex2D v3 = Vertex2D(vpos + vec2f( glyph.size.x, glyph.size.y), vec2f(glyph.texture_origin.x + glyph.size.x, glyph.texture_origin.y + glyph.size.y));
Vertex2D v4 = Vertex2D(vpos + vec2f( 0.0f, glyph.size.y), vec2f(glyph.texture_origin.x, glyph.texture_origin.y + glyph.size.y));
v1.color = color;
v2.color = color;
v3.color = color;
v4.color = color;
m_vertices.push_back(v1);
m_vertices.push_back(v2);
m_vertices.push_back(v3);
m_vertices.push_back(v4);
}
origin.x += glyph.advance;
}
int x = 0;
}

250
source/Graphics/Texture.cpp Normal file
View file

@ -0,0 +1,250 @@
#include <Spectre/Graphics/Image.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/Texture.h>
namespace {
GLint pixelFormatToInternal(enum PixelFormat format) {
switch(format) {
case PixelFormat::PF_RGBA : return GL_RGBA8;
case PixelFormat::PF_RGB : return GL_RGB8;
case PixelFormat::PF_Alpha :
default : return GL_R8;
}
}
GLint pixelFormatToGL(enum PixelFormat format) {
switch(format) {
case PixelFormat::PF_RGBA : return GL_RGBA;
case PixelFormat::PF_RGB : return GL_RGB;
case PixelFormat::PF_Alpha :
default : return GL_RED;
}
}
}
Texture::Texture() :
m_id (0),
m_size (0, 0)
{
}
Texture::~Texture()
{
destroy();
}
void Texture::create(unsigned width, unsigned heigth, PixelFormat format)
{
std::vector<unsigned char> empty_pixels(width * heigth);
if (!m_id) {
glGenTextures(1, &m_id);
}
enable();
m_size = vec2u(width, heigth);
m_format = format;
glTexImage2D(GL_TEXTURE_2D, 0,
pixelFormatToInternal(format), width, heigth, 0,
GL_RED, GL_UNSIGNED_BYTE, &empty_pixels[0]);
setSmooth(true);
setRepeat(false);
disable();
}
void Texture::create(const Vector2u& size, PixelFormat format)
{
create(size.x, size.y, format);
}
void Texture::create(const Image& image)
{
GLint srcFormat;
GLint glFormat;
if (!m_id) {
glGenTextures(1, &m_id);
}
m_size = image.getSize();
m_format = image.getFormat();
enable();
if (image.getFormat() == PixelFormat::PF_Alpha) {
glFormat = GL_R8;
srcFormat = GL_RED;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
} else {
glFormat = GL_RGBA;
srcFormat = GL_RGBA;
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
glTexImage2D(GL_TEXTURE_2D, 0, glFormat, m_size.x, m_size.y,
0, srcFormat, GL_UNSIGNED_BYTE, image.getPixels());
setSmooth(true);
setRepeat(false);
disable();
}
void Texture::create(const std::string& filename, bool isTopDown)
{
Image img;
if (img.loadFromFile(filename)) {
// OpenGL expects bottom-up images, flip.
if (isTopDown) {
img.flipY();
}
create(img);
}
}
void Texture::destroy()
{
if (m_id) {
glDeleteTextures(1, &m_id);
m_id = 0;
}
m_size = vec2u(0, 0);
m_format = PixelFormat::PF_Unknown;
}
bool Texture::isEmpty() const
{
return m_id == 0 || m_size == vec2u(0, 0);
}
const Vector2u& Texture::getSize() const
{
return m_size;
}
void Texture::update(vec2u pos, const Image& image)
{
GLuint format;
enable();
if (image.getFormat() == PixelFormat::PF_Alpha) {
format = GL_RED;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
} else {
format = GL_RGBA;
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
glTexSubImage2D(GL_TEXTURE_2D, 0, pos.x, pos.y,
image.getWidth(), image.getHeight(),
format, GL_UNSIGNED_BYTE, image.getPixels());
disable();
}
void Texture::update(const Image& image)
{
update(Vector2u(0, 0), image);
}
Image Texture::copyToImage() const
{
Image img;
if (!isEmpty()) {
std::vector<unsigned char> pixels(m_size.x * m_size.y * 4);
enable();
//glPixelStorei(GL_PACK_ALIGNMENT, 1);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGetTexImage(GL_TEXTURE_2D, 0,
pixelFormatToGL(m_format),
GL_UNSIGNED_BYTE,
&pixels[0]);
img.create(m_format, m_size.x, m_size.y, &pixels[0]);
disable();
}
return img;
}
void Texture::setMinFilter(enum Filter filter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
}
void Texture::setMagFilter(enum Filter filter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
}
void Texture::setSmooth(bool value)
{
Filter filter = value ? Filter::Linear : Filter::Nearest;
setMinFilter(filter);
setMagFilter(filter);
}
void Texture::setWrapMode(enum WrapMode mode)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode);
}
void Texture::setRepeat(bool value)
{
setWrapMode(value ? WrapMode::Repeat : WrapMode::ClampToEdge);
}
void Texture::enable() const
{
glBindTexture(GL_TEXTURE_2D, m_id);
}
void Texture::disable() const
{
glBindTexture(GL_TEXTURE_2D, 0);
}
static unsigned int _getMaxSize() {
GLint size;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
return static_cast<unsigned int>(size);
}
unsigned int Texture::getMaxSize()
{
static unsigned maxSize = _getMaxSize();
return maxSize;
}
bool Texture::operator<(const Texture* other) const
{
return m_id < other->m_id;
}
bool Texture::operator!=(const Texture* other) const
{
return m_id != other->m_id;
}

View file

@ -0,0 +1,94 @@
#include <Spectre/Graphics/Transformable.h>
Transformable::Transformable() :
m_position (0.0f, 0.0f),
m_scale (1.0f, 1.0f),
m_rotation (0.0f),
m_transformNeedsUpdate (false)
{
}
Transformable::Transformable(const Vector2f& position) :
m_position (position),
m_scale (1.0f, 1.0f),
m_rotation (0.0f),
m_transformNeedsUpdate (false)
{
}
Transformable::~Transformable()
{
}
void Transformable::setPosition(const Vector2f& position)
{
m_position = position;
m_transformNeedsUpdate = true;
}
void Transformable::setPosition(float x, float y)
{
setPosition(Vector2f(x, y));
}
void Transformable::move(const Vector2f& offset)
{
setPosition(m_position + offset);
}
const Vector2f& Transformable::getPosition() const
{
return m_position;
}
void Transformable::setRotation(float angle)
{
m_rotation = angle;
m_transformNeedsUpdate = true;
}
void Transformable::rotate(float angle)
{
setRotation(m_rotation + angle);
}
float Transformable::getRotation() const
{
return m_rotation;
}
void Transformable::setScale(const Vector2f& scale)
{
m_scale = scale;
m_transformNeedsUpdate = true;
}
void Transformable::setScale(float scale)
{
setScale(Vector2f(scale));
}
void Transformable::scale(const Vector2f& offset)
{
m_scale += offset;
}
void Transformable::scale(float offset)
{
scale(Vector2f(offset));
}
const Vector2f Transformable::getScale() const
{
return m_scale;
}
const Transform& Transformable::getTransform() const
{
if (m_transformNeedsUpdate) {
//m_transform.reset();
m_transform.set(m_position, m_rotation, m_scale);
m_transformNeedsUpdate = false;
}
return m_transform;
}

View file

@ -0,0 +1,30 @@
#include <Spectre/Graphics/Vertex2D.h>
Vertex2D::Vertex2D() :
position (0.0f),
color (1.0f),
uv (0.0f)
{
}
Vertex2D::Vertex2D(Vector2f _pos) :
position (_pos),
color (1.0f),
uv (0.0f)
{
}
Vertex2D::Vertex2D(Vector2f _pos, Vector2f _uv) :
position (_pos),
color (1.0f),
uv (_uv)
{
}
Vertex2D::Vertex2D(Vector2f _pos, Vector3f _color, Vector2f _uv) :
position (_pos),
color (_color),
uv (_uv)
{
}

66
source/GraphicsOpenGL.cpp Normal file
View file

@ -0,0 +1,66 @@
#include <Spectre/Graphics.h>
#include <Spectre/Graphics/OpenGL.h>
Graphics::Graphics(PlatformApplication *platform)
{
m_width = 800;
m_height = 600;
m_display = new Display();
}
Graphics::~Graphics()
{
shutdown();
delete m_display;
}
bool Graphics::init()
{
DisplayMode mode(m_width, m_height);
DisplayDescription desc(mode);
desc.decoration = DisplayDecorate::Menu | DisplayDecorate::Close | DisplayDecorate::Resize;
m_display->create(desc);
setClearColor(0.0f, 0.0f, 0.0f);
return true;
}
void Graphics::shutdown()
{
m_display->destroy();
}
void Graphics::setDisplayMode(Display::Mode mode)
{
m_display->setVideoMode(mode);
}
void Graphics::setSize(int width, int height)
{
m_display->setSize(width, height);
}
void Graphics::setViewport(int x, int y, int width, int height)
{
glViewport(x, y, width, height);
}
void Graphics::setClearColor(float r, float g, float b)
{
glClearColor(r, g, b, 1.0f);
}
void Graphics::clearBuffer()
{
glClear(GL_COLOR_BUFFER_BIT);
}
void Graphics::swapBuffers()
{
m_display->swapBuffers();
}

View file

@ -0,0 +1,10 @@
#include <Spectre/Input/InputDevice.h>
InputDevice::~InputDevice()
{
}
void InputDevice::init()
{
}

View file

@ -0,0 +1,19 @@
#include <Spectre/Input/Mouse.h>
#include <Spectre/Input/Keyboard.h>
#include <Spectre/Input/InputEvent.h>
InputEvent::InputEvent(Type type) :
type (type)
{
}
std::string InputEvent::KeyEvent::getKeyName() const
{
return Keyboard::getKeyName(code);
}
std::string InputEvent::MouseButtonEvent::getName() const
{
return Mouse::getButtonName(button);
}

View file

@ -0,0 +1,6 @@
#include <Spectre/Input/Inputlistener.h>
void InputListener::onInputEvent(const InputEvent& event)
{
}

View file

@ -0,0 +1,96 @@
#include <Platform/PlatformInput.h>
#include <Spectre/Input/Keyboard.h>
#include <Spectre/Input/Mouse.h>
#include <Spectre/Input/InputEvent.h>
#include <Spectre/Input/InputDevice.h>
#include <Spectre/Input/InputModule.h>
InputModule::InputModule(PlatformInput *platform) :
m_platform (platform)
{
// Let user "install" devices?
m_mouse = m_platform->createMouse();
m_keyboard = m_platform->createKeyboard();
addInputDevice(m_mouse);
addInputDevice(m_keyboard);
}
InputModule::~InputModule()
{
InputDeviceVec::iterator it;
for(it = m_devices.begin(); it != m_devices.end(); it++) {
delete (*it);
}
}
void InputModule::addInputDevice(InputDevice *device)
{
device->init();
m_devices.push_back(device);
}
void InputModule::registerListener(InputListener* listener)
{
m_listeners.push_back(listener);
}
void InputModule::removeListener(InputListener* listener)
{
}
Mouse* InputModule::getMouse()
{
return m_mouse;
}
Keyboard* InputModule::getKeyboard()
{
return m_keyboard;
}
void InputModule::postInputEvent(const InputEvent& event)
{
if (m_buffer.size() < 128) {
m_buffer.push_back(event);
}
}
void InputModule::update()
{
InputDeviceVec::iterator it;
m_platform->update();
// Update all devices.
for(it = m_devices.begin(); it != m_devices.end(); it++) {
(*it)->update(this);
}
// Dispatch all events to listeners.
dispatch();
}
void InputModule::dispatch()
{
std::deque<InputEvent>::iterator it;
for(it = m_buffer.begin(); it != m_buffer.end(); it++) {
const InputEvent& event = *it;
// Call listeners.
std::vector<InputListener*>::iterator it;
for(it = m_listeners.begin(); it != m_listeners.end(); it++) {
(*it)->onInputEvent(event);
}
}
m_buffer.clear();
}

112
source/Input/Keyboard.cpp Normal file
View file

@ -0,0 +1,112 @@
#include <Spectre/Input/Keyboard.h>
struct keyentry
{
Key::Type type;
const char *name;
};
#define MapSym(key, name) { key, name }
struct keyentry table[] = {
MapSym(Key::Unknown, "Unknown"),
MapSym(Key::A, "A"),
MapSym(Key::B, "B"),
MapSym(Key::C, "C"),
MapSym(Key::D, "D"),
MapSym(Key::E, "E"),
MapSym(Key::F, "F"),
MapSym(Key::G, "G"),
MapSym(Key::H, "H"),
MapSym(Key::I, "I"),
MapSym(Key::J, "J"),
MapSym(Key::K, "K"),
MapSym(Key::L, "L"),
MapSym(Key::M, "M"),
MapSym(Key::N, "N"),
MapSym(Key::O, "O"),
MapSym(Key::P, "P"),
MapSym(Key::Q, "Q"),
MapSym(Key::R, "R"),
MapSym(Key::S, "S"),
MapSym(Key::T, "T"),
MapSym(Key::U, "U"),
MapSym(Key::V, "V"),
MapSym(Key::W, "W"),
MapSym(Key::X, "X"),
MapSym(Key::Y, "Y"),
MapSym(Key::Z, "Z"),
MapSym(Key::One, "1"),
MapSym(Key::Two, "2"),
MapSym(Key::Three, "3"),
MapSym(Key::Four, "4"),
MapSym(Key::Five, "5"),
MapSym(Key::Six, "6"),
MapSym(Key::Seven, "7"),
MapSym(Key::Eight, "8"),
MapSym(Key::Nine, "9"),
MapSym(Key::Zero, "0"),
MapSym(Key::Period, "Period"),
MapSym(Key::Comma, "Comma"),
MapSym(Key::Enter, "Enter"),
MapSym(Key::Backspace, "Backspace"),
MapSym(Key::Escape, "Escape"),
MapSym(Key::Space, "Space"),
MapSym(Key::Capslock, "Capslock"),
MapSym(Key::Up, "Up"),
MapSym(Key::Down, "Down"),
MapSym(Key::Left, "Left"),
MapSym(Key::Right, "Right"),
// Numpad
MapSym(Key::NUMPAD_1, "Numpad 1"),
MapSym(Key::NUMPAD_2, "Numpad 2"),
MapSym(Key::NUMPAD_3, "Numpad 3"),
MapSym(Key::NUMPAD_4, "Numpad 4"),
MapSym(Key::NUMPAD_5, "Numpad 5"),
MapSym(Key::NUMPAD_6, "Numpad 6"),
MapSym(Key::NUMPAD_7, "Numpad 7"),
MapSym(Key::NUMPAD_8, "Numpad 8"),
MapSym(Key::NUMPAD_9, "Numpad 9"),
MapSym(Key::NUMPAD_0, "Numpad 0"),
MapSym(Key::NUMPAD_Enter, "Numpad Enter"),
MapSym(Key::Home, "Home"),
MapSym(Key::End, "End"),
MapSym(Key::Insert, "Insert"),
MapSym(Key::Delete, "Delete"),
MapSym(Key::PageUp, "Page up"),
MapSym(Key::PageDown, "Page down"),
MapSym(Key::Pause, "Pause"),
// Function keys.
MapSym(Key::F1, "F1"),
MapSym(Key::F2, "F2"),
MapSym(Key::F3, "F3"),
MapSym(Key::F4, "F4"),
MapSym(Key::F5, "F5"),
MapSym(Key::F6, "F6"),
MapSym(Key::F7, "F7"),
MapSym(Key::F8, "F8"),
MapSym(Key::F9, "F9"),
MapSym(Key::F10, "F10"),
MapSym(Key::F11, "F11"),
MapSym(Key::F12, "F12"),
MapSym(Key::Tab, "Tab"),
MapSym(Key::LShift, "Left Shift"),
MapSym(Key::RShift, "Right Shift"),
MapSym(Key::LCtrl, "Left Control"),
MapSym(Key::RCtrl, "Right Control"),
MapSym(Key::LAlt, "Left Alt"),
MapSym(Key::RAlt, "Right Alt"),
};
std::string Keyboard::getKeyName(Key::Type key)
{
if (key >= Key::NUM_KEYS) {
key = Key::Unknown;
}
return table[key].name;
}

20
source/Input/Mouse.cpp Normal file
View file

@ -0,0 +1,20 @@
#include <Spectre/Input/Mouse.h>
Mouse::~Mouse()
{
}
std::string Mouse::getButtonName(MouseButton::Type button)
{
switch(button) {
case MouseButton::Button1 : return "Button1";
case MouseButton::Button2 : return "Button2";
case MouseButton::Left : return "Left";
case MouseButton::Right : return "Right";
case MouseButton::Middle : return "Middle";
case MouseButton::Unknown :
default:
return "Unknown";
}
}

128
source/Math/Color.cpp Normal file
View file

@ -0,0 +1,128 @@
#include <Spectre/Math/Color.h>
const Color Color::Black (0 , 0 , 0 , 255);
const Color Color::White (255, 255, 255, 255);
const Color Color::Red (255, 0 , 0 , 255);
const Color Color::Green (0 , 255, 0 , 255);
const Color Color::Blue (0 , 0 , 255, 255);
const Color Color::Transparant (0 , 0 , 0 , 0 );
Color::Color(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
{
r = red; g = green; b = blue; a = alpha;
}
Color::Color(const Color& color)
{
r = color.r; g = color.g; b = color.b; a = color.a;
}
Color& Color::operator=(const Color& color)
{
if (*this != color) {
r = color.r;
g = color.g;
b = color.b;
a = color.a;
}
return *this;
}
Vector3f Color::toRGBf() const
{
Vector3f v(r, g, b);
return v / 255.0f;
}
Vector4f Color::toRGBAf() const
{
Vector4f v(r, g, b, a);
return v / 255.0f;
}
// ---------
// Compare
// ---------
bool operator ==(const Color& c1, const Color& c2)
{
return c1.r == c2.r && c1.g == c2.g && c1.b == c2.b && c1.a == c2.b;
}
bool operator !=(const Color& c1, const Color& c2)
{
return !(c1.r == c2.r && c1.g == c2.g && c1.b == c2.b && c1.a == c2.b);
}
// ------------
// Arithmetic
// ------------
Color operator +(const Color& c1, const Color& c2)
{
return Color(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b, c1.a + c2.a);
}
Color operator -(const Color& c1, const Color& c2)
{
return Color(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b, c1.a - c2.a);
}
Color operator /(const Color& c1, const Color& c2)
{
return Color(c1.r / c2.r, c1.g / c2.g, c1.b / c2.b, c1.a / c2.a);
}
Color operator *(const Color& c1, const Color& c2)
{
return Color(c1.r * c2.r, c1.g * c2.g, c1.b * c2.b, c1.a * c2.a);
}
Color& operator +=(Color& c1, const Color& c2)
{
c1.r += c2.r; c1.g += c2.g; c1.b += c2.b; c1.a += c2.a;
return c1;
}
Color& operator -=(Color& c1, const Color& c2)
{
c1.r -= c2.r; c1.g -= c2.g; c1.b -= c2.b; c1.a -= c2.a;
return c1;
}
Color& operator /=(Color& c1, const Color& c2)
{
c1.r /= c2.r; c1.g /= c2.g; c1.b /= c2.b; c1.a /= c2.a;
return c1;
}
Color& operator *=(Color& c1, const Color& c2)
{
c1.r *= c2.r; c1.g *= c2.g; c1.b *= c2.b; c1.a *= c2.a;
return c1;
}
// -------------------
// Scalar arithmetic
// -------------------
Color operator +(const Color& c, unsigned int s)
{
return Color(c.r + s, c.g + s, c.b + s, c.a + s);
}
Color operator -(const Color& c, unsigned int s)
{
return Color(c.r - s, c.g - s, c.b - s, c.a - s);
}
Color operator /(const Color& c, unsigned int s)
{
return Color(c.r / s, c.g / s, c.b / s, c.a / s);
}
Color operator *(const Color& c, unsigned int s)
{
return Color(c.r * s, c.g * s, c.b * s, c.a * s);
}

20
source/Math/Logarithm.cpp Normal file
View file

@ -0,0 +1,20 @@
// Logarithmic functions.
#include <cstdlib>
#include <Spectre/Math/Math.h>
namespace math {
#define LOG2INBASE10 0.30102999566f
double log(double base, double value) {
return log10(value) / log10(base);
}
double log2(double value) {
return log10(value) / LOG2INBASE10;
}
}; // namespace math

99
source/Math/Math.cpp Normal file
View file

@ -0,0 +1,99 @@
#include <cstdlib>
#include <Spectre/Math/Math.h>
namespace math {
float rand(float min, float max) {
float r = ((float) ::rand()) / RAND_MAX;
return ((max - min) * r) + min;
}
float deg2rad(float deg) {
return deg * 3.141592654f / 180.0f;
}
unsigned int nextPowerOfTwo(unsigned int value) {
if (value == 0) {
return 1;
}
unsigned int exp = static_cast<unsigned int>(::ceil(log2(value)));
return ::pow(2.0f, exp);
}
// left, right, bottom, top, near, far.
Matrix4f orthoProjection(float left, float right,
float bottom, float top,
float zNear, float zFar) {
float rl = (right - left),
tb = (top - bottom),
fn = (zFar - zNear),
rl2 = 2.0f / rl,
tb2 = 2.0f / tb,
fn2 = 2.0f / fn,
x = (right + left) / rl,
y = (top + bottom) / tb,
z = (zFar + zNear) / fn;
return Matrix4f(
rl2 , 0.0f, 0.0f, -x,
0.0f, tb2 , 0.0f, -y,
0.0f, 0.0f, -fn2, -z,
0.0f, 0.0f, 0.0f, 1.0f
);
}
Matrix4f rotation(float theta) {
float r = deg2rad(theta);
float s = std::sin(r);
float c = std::cos(r);
return Matrix4f(
c, -s, 0.0f, 0.0f,
s, c, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
Matrix4f translate(const Vector2f& v) {
return Matrix4f(
1.0f, 0.0f, 0.0f, v.x,
0.0f, 1.0f, 0.0f, v.y,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
Matrix4f scale(const Vector2f& f) {
return Matrix4f(
f.x , 0.0f, 0.0f, 0.0f,
0.0f, f.y , 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
Vector3f getTranslate(const Matrix4f matrix) {
return Vector3f(matrix.e[12], matrix.e[13], matrix.e[14]);
}
Vector3f getUpVector(const Matrix4f matrix) {
return Vector3f(matrix.e[4], matrix.e[5], matrix.e[6]);
}
Vector3f getForwardVector(const Matrix4f matrix) {
return Vector3f(matrix.e[8], matrix.e[9], matrix.e[10]);
}
};

158
source/Math/Transform.cpp Normal file
View file

@ -0,0 +1,158 @@
#include <Spectre/Math/Math.h>
#include <Spectre/Math/Transform.h>
Transform::Transform() :
m_matrix (Matrix4f::Identity)
{
}
Transform::Transform( float a00, float a01, float a02,
float a10, float a11, float a12,
float a20, float a21, float a22) :
m_matrix (a00, a01, 0.0f, a02,
a10, a11, 0.0f, a12,
0.0f, 0.0f, 1.0f, 0.0f,
a20, a21, 0.0f, a22)
{
}
Transform::Transform(const Matrix4f& matrix) :
m_matrix (matrix)
{
}
void Transform::set(Vector2f _translate, float _rotate, Vector2f _scale)
{
reset();
translate(_translate).rotate(_rotate).scale(_scale);
}
void Transform::setMatrix(const Matrix4f& matrix)
{
m_matrix = matrix;
}
void Transform::reset()
{
m_matrix = Matrix4f::Identity;
}
Vector2f Transform::getUpVector() const
{
return Vector2f(m_matrix.e[4], m_matrix.e[5]).normalize();
}
Vector2f Transform::getRightVector() const
{
return Vector2f(m_matrix.e[0], m_matrix.e[1]).normalize();
}
Transform& Transform::translate(float x, float y)
{
Transform t( 1, 0, x,
0, 1, y,
0, 0, 1);
return multiply(t);
}
Transform& Transform::translate(Vector2f vec)
{
return translate(vec.x, vec.y);
}
Transform& Transform::rotate(float theta)
{
float r = math::deg2rad(theta);
float c = std::cos(r);
float s = std::sin(r);
// Always rotate along z-axis in 2D.
Transform rot( c, -s, 0,
s, c, 0,
0, 0, 1);
return multiply(rot);
}
Transform& Transform::scale(float x, float y)
{
Transform s( x, 0, 0,
0, y, 0,
0, 0, 1);
return multiply(s);
}
Transform& Transform::scale(Vector2f vec)
{
return scale(vec.x, vec.y);
}
Transform& Transform::scale(float s)
{
return scale(s, s);
}
Transform& Transform::multiply(const Transform& other)
{
m_matrix *= other.m_matrix;
return *this;
}
Vector2f Transform::transformPoint(float x, float y) const
{
return Vector2f(m_matrix.e[0] * x + m_matrix.e[4] * y + m_matrix.e[12],
m_matrix.e[1] * x + m_matrix.e[5] * y + m_matrix.e[13]);
}
Vector2f Transform::transformPoint(const Vector2f& vec) const
{
return transformPoint(vec.x, vec.y);
}
Matrix4f& Transform::getMatrix()
{
return m_matrix;
}
const Matrix4f& Transform::getMatrix() const
{
return m_matrix;
}
float* Transform::getRawMatrix()
{
return m_matrix.e;
}
const float* Transform::getRawMatrix() const
{
return m_matrix.e;
}
Matrix4f Transform::getRotationMatrix() const
{
return Matrix4f(
m_matrix.e[0], m_matrix.e[4], 0.0f, 0.0f,
m_matrix.e[1], m_matrix.e[5], 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
Transform operator*(const Transform& a, const Transform& b)
{
return Transform(a.getMatrix() * b.getMatrix());
}
Transform& operator*=(Transform& a, const Transform& other)
{
a.multiply(other);
return a;
}
Vector2f operator*(const Transform& transform, const Vector2f& vec)
{
return transform.transformPoint(vec);
}

View file

@ -0,0 +1,25 @@
#ifndef SPECTRE_PLATFORM_H
#define SPECTRE_PLATFORM_H
class PlatformInput;
class PlatformDisplay;
class MessageQueue;
class PlatformApplication
{
public :
virtual void init() = 0;
virtual void shutdown() = 0;
//virtual PlatformDisplay& getDisplay() = 0;
virtual PlatformInput& getInput() = 0;
virtual MessageQueue& getMessageQueue() = 0;
virtual void update() = 0;
};
#endif /* SPECTRE_PLATFORM_H */

View file

@ -0,0 +1,32 @@
#include <Spectre/Display/Display.h>
#include "PlatformDisplay.h"
#ifdef _WIN32
#include <Platform/Win32/Win32Display.h>
typedef Win32Display DisplayType;
#else
#error "No Display implementation exists"
#endif
PlatformDisplay* PlatformDisplay::make(Display* parent)
{
DisplayType* disp = new DisplayType();
disp->m_parent = parent;
return disp;
}
PlatformDisplay::PlatformDisplay()
{
}
PlatformDisplay::~PlatformDisplay()
{
// Nothing to do.
}
void PlatformDisplay::onReshape(int width, int height)
{
// Forward to parent.
m_parent->onReshape(width, height);
}

View file

@ -0,0 +1,52 @@
#ifndef SPECTRE_PLATFORM_DISPLAY_H
#define SPECTRE_PLATFORM_DISPLAY_H
#include <Spectre/Math/Vector2.h>
#include <Spectre/Display/DisplayDescription.h>
// Low-level platform dependant API.
#include <string>
class Display;
class PlatformDisplay
{
public :
// Factory method.
static PlatformDisplay* make(Display* parent);
virtual ~PlatformDisplay();
virtual bool create(DisplayDescription description) = 0;
virtual void destroy() = 0;
virtual void* getHandle() const = 0;
virtual bool isValid() = 0;
virtual void setSize(unsigned int width, unsigned int height) = 0;
virtual Vector2u getSize() const = 0;
virtual void setPosition(unsigned int x, unsigned int y) = 0;
virtual void setCaption(const std::string& caption) = 0;
virtual void setIcon(const std::string& icon) = 0;
virtual void showCursor(bool value) = 0;
protected :
PlatformDisplay();
void onReshape(int width, int height);
private :
Display* m_parent;
};
#endif /* SPECTRE_PLATFORM_DISPLAY_H */

View file

@ -0,0 +1,18 @@
#ifndef PLATFORM_INPUT_H
#define PLATFORM_INPUT_H
class Keyboard;
class Mouse;
class PlatformInput
{
public :
virtual Keyboard* createKeyboard() = 0;
virtual Mouse* createMouse() = 0;
virtual void update() = 0;
};
#endif /* PLATFORM_INPUT_H */

View file

@ -0,0 +1,19 @@
#ifndef PLATFORM_MISC_H
#define PLATFORM_MISC_H
#include <Spectre/Display/DisplayMode.h>
#include <vector>
class DisplayMode;
class PlatformMisc
{
public:
static void GetDisplayModes(std::vector<DisplayMode>& modes);
static DisplayMode GetDesktopMode();
};
#endif /* PLATFORM_MISC_H */

View file

@ -0,0 +1,96 @@
#include <windows.h>
#include "Win32Keyboard.h"
#include "Win32Mouse.h"
#include "Win32Application.h"
void Win32Application::init()
{
}
void Win32Application::shutdown()
{
}
/*
PlatformDisplay& Win32Application::getDisplay()
{
return m_display;
} */
PlatformInput& Win32Application::getInput()
{
return m_input;
}
MessageQueue& Win32Application::getMessageQueue()
{
return m_messageQueue;
}
void Win32Application::update()
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
processMessage(msg);
}
}
LRESULT Win32Application::processMessage(MSG msg)
{
switch(msg.message) {
case WM_QUIT :
m_messageQueue.postEvent(SysEvent(SysEvent::Quit));
return 0;
// Input, Forward to devices.
case WM_KEYDOWN :
case WM_KEYUP :
OutputDebugString("WM_KEYDOWN\n");
//SetCapture(msg.hwnd);
if (Win32Keyboard::handleMessage(msg)) {
// Keyboard did handle the message.
return 0;
}
break;
case WM_MOUSEMOVE :
case WM_MOUSELEAVE :
if (Win32Mouse::handleMessage(msg)) {
// Mouse did handle the message.
return 0;
}
break;
case WM_LBUTTONDOWN :
case WM_RBUTTONDOWN :
case WM_MBUTTONDOWN :
case WM_XBUTTONDOWN :
SetCapture(msg.hwnd);
if (Win32Mouse::handleMessage(msg)) {
// Mouse did handle the message.
return 0;
}
break;
case WM_LBUTTONUP :
case WM_RBUTTONUP :
case WM_MBUTTONUP :
case WM_XBUTTONUP :
ReleaseCapture();
if (Win32Mouse::handleMessage(msg)) {
// Mouse did handle the message.
return 0;
}
break;
default :
break;
}
// Message was not intercepted. Pass down to window.
return DispatchMessage(&msg);
}

View file

@ -0,0 +1,38 @@
#ifndef WIN32_PLATFORM_H
#define WIN32_PLATFORM_H
#include <Windows.h>
#include "Win32Display.h"
#include "Win32Input.h"
#include <Spectre/System/MessageQueue.h>
#include <Platform/PlatformApplication.h>
class Win32Application : public PlatformApplication
{
public :
virtual void init();
virtual void shutdown();
//virtual PlatformDisplay& getDisplay();
virtual PlatformInput& getInput();
virtual MessageQueue& getMessageQueue();
virtual void update();
protected :
LRESULT processMessage(MSG msg);
protected :
//Win32Display m_display;
Win32Input m_input;
MessageQueue m_messageQueue;
};
#endif /* WIN32_PLATFORM_H */

View file

@ -0,0 +1,260 @@
#include <Windows.h>
#include <Spectre/Display/Display.h>
#include <Spectre/System/SystemEvent.h>
#include <Spectre/System/Log.h>
#include "Win32Application.h"
#include "Win32Internal.h"
#include "Win32Display.h"
#define WND_CLASSNAME "SPECTRE_WIN32_WNDCLASS"
static bool firstTime = true;
Win32Display::Win32Display() :
m_handle (NULL),
m_icon (0),
m_cursor (0),
m_inResizeModalLoop (false),
m_minSize (200, 200)
{
}
Win32Display::~Win32Display()
{
if (m_icon) {
DestroyIcon(m_icon);
}
if (m_handle) {
DestroyWindow(m_handle);
}
}
bool Win32Display::create(DisplayDescription description)
{
DWORD flags = getWin32Flags(description.decoration);
int x, y;
if (firstTime) {
registerClass();
firstTime = false;
}
centerWindow(x, y, description.mode.width, description.mode.height);
// Create window.
m_handle = CreateWindowExA(0, WND_CLASSNAME, "", flags,
x, y, description.mode.width, description.mode.height,
NULL, NULL, GetModuleHandle(NULL), (LPVOID) this);
if (!m_handle) {
log("Win32 - Could not create window: %s", Win32GetMessage(GetLastError()));
return false;
}
setSize(description.mode.width, description.mode.height);
// Store the size for use later.
m_size = getSize();
return true;
}
void Win32Display::destroy()
{
if (m_handle) {
DestroyWindow(m_handle);
m_handle = NULL;
}
}
void* Win32Display::getHandle() const
{
return m_handle;
}
bool Win32Display::isValid()
{
return m_handle != NULL;
}
void Win32Display::setSize(unsigned int width, unsigned int height)
{
int w, h;
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, GetWindowLong(m_handle, GWL_STYLE), false);
w = rect.right - rect.left;
h = rect.bottom - rect.top;
::SetWindowPos(m_handle, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER);
}
Vector2u Win32Display::getSize() const
{
RECT rect;
Vector2u size;
if (GetClientRect(m_handle, &rect)) {
size.x = rect.right - rect.left;
size.y = rect.bottom - rect.top;
}
return size;
}
void Win32Display::setPosition(unsigned int x, unsigned int y)
{
::SetWindowPos(m_handle, NULL, x, y, 0, 0, SWP_NOSIZE);
}
void Win32Display::setCaption(const std::string& caption)
{
::SetWindowText(m_handle, caption.c_str());
}
void Win32Display::showCursor(bool value)
{
if (value) {
m_cursor = ::LoadCursor(NULL, IDC_ARROW);
} else {
m_cursor = 0;
}
::SetCursor(m_cursor);
}
void Win32Display::setIcon(const std::string& icon)
{
HICON hIcon = (HICON) ::LoadImage(0, icon.c_str(), IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
if (hIcon) {
if (m_icon) {
DestroyIcon(m_icon);
}
m_icon = hIcon;
::SendMessage(m_handle, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
::SendMessage(m_handle, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
}
}
void Win32Display::registerClass()
{
WNDCLASSA wndcl;
ZeroMemory(&wndcl, sizeof(wndcl));
wndcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wndcl.lpfnWndProc = Win32Display::staticWndProc;
wndcl.hInstance = ::GetModuleHandle(NULL);
wndcl.lpszClassName = WND_CLASSNAME;
::RegisterClass(&wndcl);
}
DWORD Win32Display::getWin32Flags(unsigned int flags)
{
DWORD win32_flags = WS_VISIBLE;
if (flags == DisplayDecorate::None) {
win32_flags |= WS_POPUP;
} else {
if (flags & DisplayDecorate::Menu) {
win32_flags |= WS_CAPTION | WS_MINIMIZEBOX;
}
if (flags & DisplayDecorate::Resize) {
win32_flags |= WS_THICKFRAME | WS_MAXIMIZEBOX;
}
if (flags & DisplayDecorate::Close) {
win32_flags |= WS_SYSMENU;
}
}
return win32_flags;
}
void Win32Display::centerWindow(int &x, int &y, int width, int height)
{
x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;
}
void Win32Display::processResizeMessage(const Vector2u& new_size)
{
// Check if the size has actually changed.
if (m_size != new_size) {
// Update the size and notify the higher layer.
m_size = new_size;
onReshape(m_size.x, m_size.y);
}
}
void Win32Display::processMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_SETCURSOR :
if (LOWORD(lParam) == HTCLIENT) {
::SetCursor(m_cursor);
}
break;
case WM_DESTROY :
destroy();
PostQuitMessage(0);
break;
case WM_SETFOCUS :
OutputDebugString("WM_SETFOCUS\n");
break;
case WM_KILLFOCUS :
OutputDebugString("WM_KILLFOCUS\n");
break;
case WM_SIZE :
if (!m_inResizeModalLoop && (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) {
processResizeMessage(getSize());
}
break;
case WM_GETMINMAXINFO :
{
MINMAXINFO* info = (MINMAXINFO*)lParam;
info->ptMinTrackSize.x = m_minSize.x;
info->ptMinTrackSize.y = m_minSize.y;
info->ptMaxTrackSize.x = 99999;
info->ptMaxTrackSize.y = 99999;
break;
}
case WM_ENTERSIZEMOVE :
m_inResizeModalLoop = true;
break;
case WM_EXITSIZEMOVE :
m_inResizeModalLoop = false;
processResizeMessage(getSize());
break;
}
}
LRESULT CALLBACK Win32Display::staticWndProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
Win32Display *display;
if (message == WM_NCCREATE) {
LONG_PTR ptr = (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams;
::SetWindowLong(handle, GWL_USERDATA, ptr);
display = (Win32Display*) ptr;
} else {
display = (Win32Display*) ::GetWindowLong(handle, GWL_USERDATA);
}
if (display) {
display->processMessage(message, wParam, lParam);
}
return DefWindowProc(handle, message, wParam, lParam);
}

View file

@ -0,0 +1,66 @@
#ifndef PLATFORM_WIN32_DISPLAY_H
#define PLATFORM_WIN32_DISPLAY_H
#include "Win32GLContext.h"
#include <Platform/PlatformDisplay.h>
#include <Windows.h>
class Win32Display : public PlatformDisplay
{
public :
Win32Display();
virtual ~Win32Display();
virtual bool create(DisplayDescription description);
virtual void destroy();
virtual bool isValid();
virtual void* getHandle() const;
virtual void setSize(unsigned int width, unsigned int height);
virtual Vector2u getSize() const;
virtual void setPosition(unsigned int x, unsigned int y);
virtual void setCaption(const std::string& caption);
virtual void setIcon(const std::string& icon);
virtual void showCursor(bool value);
protected :
void registerClass();
DWORD getWin32Flags(unsigned int flags);
void centerWindow(int &x, int &y, int width, int height);
void processMessage(UINT message, WPARAM wParam, LPARAM lParam);
void processResizeMessage(const Vector2u& new_size);
static LRESULT CALLBACK staticWndProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);
protected :
HWND m_handle;
HCURSOR m_cursor;
HICON m_icon;
// True if this window is in a resize loop.
bool m_inResizeModalLoop;
// Client area size. cached here to check if a resize has been made.
Vector2u m_size;
Vector2u m_minSize;
};
#endif /* PLATFORM_WIN32_DISPLAY_H */

View file

@ -0,0 +1,156 @@
#include <GL/glew.h>
#include <GL/wglew.h>
#include <Platform/PlatformDisplay.h>
#include <Spectre/System/Log.h>
#include "Win32Internal.h"
#include "Win32GLContext.h"
// Ensure that OpenGL extensions are loaded.
static void ensureExtensionsLoaded()
{
static bool glewInitOK = false;
if (!glewInitOK) {
GLenum ret = glewInit();
if (ret != GLEW_OK) {
log("Win32: Could not initialize GLEW %s\n",
glewGetErrorString(ret));
return;
}
glewInitOK = true;
}
}
Win32GLContext::Win32GLContext() :
m_wnd (NULL),
m_deviceContext (NULL),
m_renderContext (NULL)
{
}
Win32GLContext::~Win32GLContext()
{
destroy();
}
bool Win32GLContext::create(const PlatformDisplay* display, unsigned int bpp)
{
// If created. destroy old handles.
destroy();
m_wnd = (HWND) display->getHandle();
// Should have a valid handle here. trigger error.
if (!m_wnd) {
log("Win32 - Could not create GL context: Invalid display handle\n");
return false;
}
m_deviceContext = ::GetDC(m_wnd);
createGLContext(bpp);
if (!m_deviceContext || !m_renderContext) {
// Make sure we release all handles.
destroy();
log("Win32 - Could not create GL context: %s", Win32GetMessage(GetLastError()));
return false;
}
return true;
}
void Win32GLContext::destroy()
{
if (m_wnd && m_deviceContext) {
::ReleaseDC(m_wnd, m_deviceContext);
m_deviceContext = NULL;
m_wnd = NULL;
}
if (m_renderContext) {
::wglDeleteContext(m_renderContext);
m_renderContext = NULL;
}
}
void Win32GLContext::createGLContext(unsigned int bpp)
{
// First set pixel format.
if (!setPixelFormat(bpp)) {
return;
}
m_renderContext = ::wglCreateContext(m_deviceContext);
}
bool Win32GLContext::activate()
{
// Make sure we have dc and rc before calling MakeCurrent.
if (m_deviceContext && m_renderContext) {
return ::wglMakeCurrent(m_deviceContext, m_renderContext);
}
return false;
}
bool Win32GLContext::deactivate()
{
return ::wglMakeCurrent(NULL, NULL);
}
bool Win32GLContext::isActive() const
{
return ::wglGetCurrentContext() == m_renderContext;
}
bool Win32GLContext::setSwapInterval(int interval)
{
ensureExtensionsLoaded();
if (WGLEW_EXT_swap_control) {
return wglSwapIntervalEXT(interval);
}
log("wglSwapInterval: function is not supported\n");
return false;
}
void Win32GLContext::setSize(unsigned int width, unsigned int height)
{
if (activate()) {
glViewport(0, 0, width, height);
}
}
void Win32GLContext::swapBuffers()
{
if (m_deviceContext) {
::SwapBuffers(m_deviceContext);
}
}
bool Win32GLContext::setPixelFormat(unsigned int bpp)
{
PIXELFORMATDESCRIPTOR pfd;
int format;
// For now, always create a RGBA pixel format with double buffer.
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = bpp;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ::ChoosePixelFormat(m_deviceContext, &pfd);
if (format) {
return ::SetPixelFormat(m_deviceContext, format, &pfd);
}
return false;
}

View file

@ -0,0 +1,48 @@
#ifndef PLATFORM_WIN32_GLCONTEXT_H
#define PLATFORM_WIN32_GLCONTEXT_H
// Win32 OpenGL Context (wgl)
#include <Windows.h>
#include <Spectre/Display/GLContext.h>
class Win32GLContext : public GLContext
{
public :
Win32GLContext();
~Win32GLContext();
// Create a context associated with a display.
bool create(const PlatformDisplay* display, unsigned int bpp);
void destroy();
bool activate();
bool deactivate();
bool isActive() const;
bool setSwapInterval(int interval);
void setSize(unsigned int width, unsigned int height);
void setSize(const Vector2u size);
void swapBuffers();
private :
void createGLContext(unsigned int bpp);
bool setPixelFormat(unsigned int bpp);
private :
HWND m_wnd;
HDC m_deviceContext;
HGLRC m_renderContext;
};
#endif /* PLATFORM_WIN32_GLCONTEXT_H */

View file

@ -0,0 +1,27 @@
#include "Win32Keyboard.h"
#include "Win32Mouse.h"
#include "Win32Input.h"
Win32InputMsgBuffer Win32Input::inputMsgBuffer;
Win32InputMsgBuffer::Win32InputMsgBuffer() :
index (0),
enabled (false)
{
}
Keyboard* Win32Input::createKeyboard()
{
return new Win32Keyboard();
}
Mouse* Win32Input::createMouse()
{
return new Win32Mouse();
}
void Win32Input::update()
{
}

View file

@ -0,0 +1,32 @@
#ifndef PLATFORM_WIN32_INPUT_H
#define PLATFORM_WIN32_INPUT_H
#include <Windows.h>
#include <Platform/PlatformInput.h>
#define WIN32_INPUT_BUFFER_QUEUE_MAX_SIZE 64
struct Win32InputMsgBuffer {
int index;
MSG messages[WIN32_INPUT_BUFFER_QUEUE_MAX_SIZE];
bool enabled;
Win32InputMsgBuffer();
bool postMessage(MSG msg);
};
class Win32Input : public PlatformInput
{
public :
virtual Keyboard* createKeyboard();
virtual Mouse* createMouse();
virtual void update();
static Win32InputMsgBuffer inputMsgBuffer;
};
#endif /* PLATFORM_WIN32_INPUT_H */

View file

@ -0,0 +1,20 @@
#include <string.h>
#include "Win32Internal.h"
const char* Win32GetMessage(DWORD messageId) {
static char buf[1024] = { '\0' };
DWORD rc = FormatMessage(
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, messageId,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, 1024, NULL);
if (!rc) {
strcpy_s(buf, "Unkown error!\n");
}
return buf;
}

View file

@ -0,0 +1,10 @@
#ifndef PLATFORM_WIN32_INTERNAL_H
#define PLATFORM_WIN32_INTERNAL_H
#include <Windows.h>
#include <string>
const char* Win32GetMessage(DWORD messageId);
#endif /* PLATFORM_WIN32_INTERNAL_H */

View file

@ -0,0 +1,119 @@
#include <Windows.h>
#include <Spectre/Input/InputEvent.h>
#include <Spectre/Input/InputModule.h>
#include "Win32Input.h"
#include "Win32Keyboard.h"
#include "Win32MsgBuffer.h"
static Win32MsgBuffer msg_buf;
static const Key::Type deviceToKey[256] = {
/* 0 1 2 3 4 5 6 7 */
/* 8 9 A B C D E F */
// 00-0F
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Backspace, Key::Tab, Key::Unknown, Key::Unknown, Key::Unknown, Key::Enter, Key::Unknown, Key::Unknown,
// 10-1F
Key::Unknown, Key::Unknown, Key::Unknown, Key::Pause, Key::Capslock, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Escape, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 20-2F
Key::Space, Key::PageUp, Key::PageDown, Key::End, Key::Home, Key::Left, Key::Up, Key::Right,
Key::Down, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Insert, Key::Delete, Key::Unknown,
// 30-3F
Key::Zero, Key::One, Key::Two, Key::Three, Key::Four, Key::Five, Key::Six, Key::Seven,
Key::Eight, Key::Nine, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 40-4F
Key::Unknown, Key::A, Key::B, Key::C, Key::D, Key::E, Key::F, Key::G,
Key::H, Key::I, Key::J, Key::K, Key::L, Key::M, Key::N, Key::O,
// 50-5F
Key::P, Key::Q, Key::R, Key::S, Key::T, Key::U, Key::V, Key::W,
Key::X, Key::Y, Key::Z, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 60-6F
Key::NUMPAD_0, Key::NUMPAD_1, Key::NUMPAD_2, Key::NUMPAD_3, Key::NUMPAD_4, Key::NUMPAD_5, Key::NUMPAD_6, Key::NUMPAD_7,
Key::NUMPAD_8, Key::NUMPAD_9, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 70-7F
Key::F1, Key::F2, Key::F3, Key::F4, Key::F5, Key::F6, Key::F7, Key::F8,
Key::F9, Key::F10, Key::F11, Key::F12, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 80-8F
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// 90-9F
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// A0-AF
Key::LShift, Key::RShift, Key::LCtrl, Key::RCtrl, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// B0-BF
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Comma, Key::Unknown, Key::Period, Key::Unknown,
// C0-CF
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// E0-EF
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
// F0-FF
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown, Key::Unknown,
};
void Win32Keyboard::init()
{
Win32Input::inputMsgBuffer.enabled = true;
memset(m_btnState, 0, sizeof(m_btnState) / sizeof(m_btnState[0]));
}
bool Win32Keyboard::isKeyDown(Key::Type key)
{
return m_btnState[key];
}
void Win32Keyboard::update(InputModule *input)
{
for(int i = 0; i < msg_buf.index; i++) {
MSG msg = msg_buf.messages[i];
if (msg.message == WM_KILLFOCUS) {
for(int i = 0; i < Key::NUM_KEYS; i++) {
if (m_btnState[i]) {
InputEvent event(InputEvent::Key);
event.key.code = (Key::Type) i;
event.key.pressed = msg.message == WM_KEYDOWN;
m_btnState[i] = false;
input->postInputEvent(event);
}
}
continue;
}
if (msg.message != WM_KEYDOWN && msg.message != WM_KEYUP) {
continue;
}
Key::Type key = deviceToKey[msg.wParam % 0xFF];
if (key != Key::Unknown) {
InputEvent event(InputEvent::Key);
event.key.code = key;
event.key.pressed = msg.message == WM_KEYDOWN;
m_btnState[key] = event.key.pressed;
input->postInputEvent(event);
}
}
msg_buf.index = 0;
}
bool Win32Keyboard::handleMessage(MSG message)
{
return msg_buf.postMessage(message);
}

View file

@ -0,0 +1,28 @@
#ifndef PLATFORM_WIN32_KEYBOARD_H
#define PLATFORM_WIN32_KEYBOARD_H
#include <windows.h>
#include <Spectre/Input/Keyboard.h>
class Win32Keyboard : public Keyboard
{
public :
void init();
bool isKeyDown(Key::Type key);
static bool handleMessage(MSG message);
protected :
void update(InputModule *input);
protected :
bool m_btnState[Key::NUM_KEYS];
bool m_hasFocus;
};
#endif /* PLATFORM_WIN32_KEYBOARD_H */

View file

@ -0,0 +1,22 @@
#include <Windows.h>
#include <Platform/PlatformMisc.h>
void PlatformMisc::GetDisplayModes(std::vector<DisplayMode>& modes)
{
DEVMODE dev;
for(int i = 0; EnumDisplaySettings(NULL, i, &dev); i++) {
DisplayMode mode(dev.dmPelsWidth, dev.dmPelsHeight, dev.dmBitsPerPel);
modes.push_back(mode);
}
}
DisplayMode PlatformMisc::GetDesktopMode()
{
DEVMODE dev;
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev)) {
return DisplayMode(dev.dmPelsWidth, dev.dmPelsHeight, dev.dmBitsPerPel);
}
return DisplayMode();
}

View file

@ -0,0 +1,115 @@
#include <Windows.h>
#include <Spectre/System/Log.h>
#include <Spectre/Input/InputModule.h>
#include "Win32MsgBuffer.h"
#include "Win32Input.h"
#include "Win32Mouse.h"
static Win32MsgBuffer msg_buf;
static Vector2f _normalizePos(int x, int y, RECT area)
{
Vector2f out;
out.x = x / ((float) (area.right - area.left));
out.y = y / ((float) (area.bottom - area.top));
return out;
}
static RECT GetClientArea(HWND hwnd) {
RECT rect;
GetClientRect(hwnd, &rect);
return rect;
}
void Win32Mouse::init()
{
memset(m_state, 0, MouseButton::NUM_MBUTTONS);
m_tracked = false;
}
Vector2f Win32Mouse::getPosition() const
{
return m_position;
}
bool Win32Mouse::isButtonDown(MouseButton::Type button) const
{
return m_state[button];
}
void Win32Mouse::update(InputModule *input)
{
// TODO: Clean this.
for(int i = 0; i < msg_buf.index; i++) {
MSG msg = msg_buf.messages[i];
if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONUP) {
InputEvent event(InputEvent::MouseButton);
event.mouseButton.button = MouseButton::Left;
event.mouseButton.pressed = msg.message == WM_LBUTTONDOWN;
m_state[MouseButton::Left] = event.mouseButton.pressed;
input->postInputEvent(event);
} else if (msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP) {
InputEvent event(InputEvent::MouseButton);
event.mouseButton.button = MouseButton::Right;
event.mouseButton.pressed = msg.message == WM_RBUTTONDOWN;
m_state[MouseButton::Right] = event.mouseButton.pressed;
input->postInputEvent(event);
} else if (msg.message == WM_MBUTTONDOWN || msg.message == WM_MBUTTONUP) {
InputEvent event(InputEvent::MouseButton);
event.mouseButton.button = MouseButton::Middle;
event.mouseButton.pressed = msg.message == WM_MBUTTONDOWN;
m_state[MouseButton::Middle] = event.mouseButton.pressed;
input->postInputEvent(event);
} else if (msg.message == WM_XBUTTONDOWN || msg.message == WM_XBUTTONUP) {
int btn = GET_XBUTTON_WPARAM(msg.wParam);
InputEvent event(InputEvent::MouseButton);
event.mouseButton.button = btn == XBUTTON1 ? MouseButton::Button1 : MouseButton::Button2;
event.mouseButton.pressed = msg.message == WM_XBUTTONDOWN;
m_state[MouseButton::Button1] = event.mouseButton.pressed;
input->postInputEvent(event);
} else if (msg.message == WM_MOUSEMOVE) {
InputEvent event(InputEvent::MousePosition);
RECT area = GetClientArea(msg.hwnd);
int x = LOWORD(msg.lParam);
int y = HIWORD(msg.lParam);
// Do not forward the message if mouse is outside client area.
if ((x < area.left) || (x > area.right) || (y < area.top) || (y > area.bottom)) {
continue;
}
event.mouse.x = x;
event.mouse.y = y;
input->postInputEvent(event);
m_position = _normalizePos(x, y, area);
}
}
msg_buf.index = 0;
}
bool Win32Mouse::handleMessage(MSG message)
{
return msg_buf.postMessage(message);
}

View file

@ -0,0 +1,34 @@
#ifndef PLATFORM_WIN32_MOUSE_H
#define PLATFORM_WIN32_MOUSE_H
#include <Windows.h>
#include <Spectre/Input/Mouse.h>
class Win32Mouse : public Mouse
{
public :
~Win32Mouse() {}
virtual void init();
// Get mouse position
virtual Vector2f getPosition() const;
virtual bool isButtonDown(MouseButton::Type button) const;
static bool handleMessage(MSG message);
protected :
virtual void update(InputModule *input);
protected :
Vector2f m_position;
bool m_state[MouseButton::NUM_MBUTTONS];
bool m_tracked;
};
#endif /* PLATFORM_WIN32_MOUSE_H */

View file

@ -0,0 +1,18 @@
#include <Spectre/System/Log.h>
#include "Win32MsgBuffer.h"
Win32MsgBuffer::Win32MsgBuffer() :
index (0)
{
}
bool Win32MsgBuffer::postMessage(MSG msg)
{
if (index < WIN32_MSG_BUFFER_MAX_SIZE) {
messages[index++] = msg;
return true;
}
log("Win32MsgBuffer: Queue overflow\n");
return false;
}

View file

@ -0,0 +1,18 @@
#ifndef PLATFORM_WIN32_MSG_BUFFER_H
#define PLATFORM_WIN32_MSG_BUFFER_H
#include <Windows.h>
#define WIN32_MSG_BUFFER_MAX_SIZE 64
struct Win32MsgBuffer {
int index;
MSG messages[WIN32_MSG_BUFFER_MAX_SIZE];
Win32MsgBuffer();
bool postMessage(MSG msg);
};
#endif /* PLATFORM_WIN32_MSG_BUFFER_H */

View file

@ -0,0 +1,28 @@
#include <Windows.h>
#include <Spectre/System/System.h>
static LARGE_INTEGER getFrequency() {
LARGE_INTEGER freq;
::QueryPerformanceFrequency(&freq);
return freq;
}
unsigned long System::getMilliseconds()
{
static LARGE_INTEGER freq = getFrequency();
LARGE_INTEGER cnt;
::QueryPerformanceCounter(&cnt);
cnt.QuadPart *= 1000;
cnt.QuadPart /= freq.QuadPart;
return (unsigned long) cnt.QuadPart;
}
void System::sleep(int milliseconds)
{
::Sleep(milliseconds);
}

158
source/Scene/Camera2D.cpp Normal file
View file

@ -0,0 +1,158 @@
#include <Spectre/Math/Math.h>
#include <Spectre/Scene/Camera2D.h>
Camera2D::Camera2D() :
m_position (0.0f, 0.0f),
m_rotation (0.0f),
m_zoom (1.0f),
m_size (0, 0),
m_viewNeedsUpdate (false),
m_projNeedsUpdate (false),
m_view (Matrix4f::Identity),
m_proj (Matrix4f::Identity)
{
reset(Vector2f(0, 0), Vector2f(800, 600));
}
Camera2D::Camera2D(const Vector2f& position, const Vector2f& size) :
m_position (position),
m_rotation (0.0f),
m_zoom (1.0f),
m_size (size),
m_viewNeedsUpdate (true),
m_projNeedsUpdate (true),
m_view (Matrix4f::Identity),
m_proj (Matrix4f::Identity)
{
}
void Camera2D::reset(const Vector2f& position, const Vector2f& size)
{
m_position = size / 2.0f;
m_size = size;
m_projNeedsUpdate = true;
m_viewNeedsUpdate = true;
}
void Camera2D::setPosition(float x, float y)
{
m_position.x = x;
m_position.y = y;
m_viewNeedsUpdate = true;
}
void Camera2D::setPosition(const Vector2f& position)
{
setPosition(position.x, position.y);
}
const Vector2f& Camera2D::getPosition() const
{
return m_position;
}
void Camera2D::move(float x, float y)
{
setPosition(m_position.x + x, m_position.y + y);
}
void Camera2D::move(const Vector2f& vec)
{
setPosition(m_position + vec);
}
void Camera2D::moveUp(float delta)
{
vec2f dir = m_view.getUpVector() * vec2f(1.0f, -1.0f);
move(dir * delta);
}
void Camera2D::moveRight(float delta)
{
vec2f dir = m_view.getRightVector() * vec2f(1.0f, -1.0f);
move(dir * delta);
}
void Camera2D::setSize(const Vector2u& size)
{
if (m_size != size) {
m_size = size;
m_viewNeedsUpdate = true;
m_projNeedsUpdate = true;
}
}
void Camera2D::setSize(unsigned int w, unsigned int h)
{
setSize(Vector2u(w, h));
}
const Vector2u& Camera2D::getSize() const
{
return m_size;
}
void Camera2D::setZoom(float factor)
{
if (factor < 0.0f) {
factor = 0.0f;
}
m_zoom = factor;
m_viewNeedsUpdate = true;
}
void Camera2D::zoom(float factor)
{
setZoom(m_zoom + factor);
}
void Camera2D::setRotation(float angle)
{
m_rotation = angle;
m_viewNeedsUpdate = true;
}
float Camera2D::getRotation() const
{
return m_rotation;
}
void Camera2D::rotate(float delta)
{
setRotation(m_rotation + delta);
}
const Matrix4f& Camera2D::getViewMatrix() const
{
return getTransform().getMatrix();
}
const Matrix4f& Camera2D::getProjectionMatrix() const
{
if (m_projNeedsUpdate) {
float w = static_cast<float>(m_size.x);
float h = static_cast<float>(m_size.y);
m_proj = math::orthoProjection(0.0f, w, h, 0.0f);
m_projNeedsUpdate = false;
}
return m_proj;
}
const Transform& Camera2D::getTransform() const
{
if (m_viewNeedsUpdate) {
Vector2f half_size = Vector2f(m_size) / 2.0f;
m_view.reset();
m_view.translate(half_size);
m_view.scale(m_zoom);
m_view.rotate(m_rotation);
m_view.translate(-m_position);
m_viewNeedsUpdate = false;
}
return m_view;
}

40
source/System/File.cpp Normal file
View file

@ -0,0 +1,40 @@
#include <string.h>
#include <stdio.h>
#include <Spectre/System/File.h>
namespace File
{
std::string getBasename(const std::string& path) {
size_t p = path.find_last_of('/');
if (p == std::string::npos)
return path;
return path.substr(p + 1);
}
std::string getExtension(const std::string& path) {
std::string base_name = getBasename(path);
size_t p = base_name.find_first_of('.');
if (p == std::string::npos)
return "";
return base_name.substr(p + 1);
}
std::vector<unsigned char> read(const std::string& path) {
std::vector<unsigned char> buf;
FILE *fd = fopen(path.c_str(), "rb");
if (fd) {
fseek(fd, 0, SEEK_END);
buf.resize(ftell(fd));
rewind(fd);
fread(&buf[0], 1, buf.size(), fd);
fclose(fd);
}
return buf;
}
};

13
source/System/Log.cpp Normal file
View file

@ -0,0 +1,13 @@
#include <stdarg.h>
#include <stdio.h>
#include <Spectre/System/Log.h>
void log(const char *fmt, ...) {
va_list vl;
va_start(vl, fmt);
vfprintf(stderr, fmt, vl);
va_end(vl);
}

View file

@ -0,0 +1,7 @@
#include <Spectre/Display/Display.h>
#include <Spectre/System/MessageHandler.h>
void MessageHandler::onSizeChanged(Display* display, int width, int height)
{
}

View file

@ -0,0 +1,22 @@
#include <Spectre/System/MessageQueue.h>
void MessageQueue::postEvent(SysEvent& event)
{
m_queue.push_back(event);
}
bool MessageQueue::pollEvent(SysEvent& event)
{
if (!isEmpty()) {
event = m_queue.front();
m_queue.pop_front();
return true;
}
return false;
}
bool MessageQueue::isEmpty() const
{
return m_queue.empty();
}

View file

@ -0,0 +1,16 @@
#include <Spectre/System/SystemEvent.h>
SysEvent::SysEvent(Type type) :
type (type)
{
}
SysEvent SysEvent::sizeEvent(Display *display, int width, int height)
{
SysEvent event(Size);
event.size.display = display;
event.size.width = width;
event.size.height = height;
return event;
}