Initial commit
This commit is contained in:
commit
edfc5298e1
252 changed files with 93965 additions and 0 deletions
25
source/Core/String.cpp
Normal file
25
source/Core/String.cpp
Normal 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
150
source/Display/Display.cpp
Normal 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);
|
||||
}
|
||||
14
source/Display/DisplayDescription.cpp
Normal file
14
source/Display/DisplayDescription.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
54
source/Display/DisplayMode.cpp
Normal file
54
source/Display/DisplayMode.cpp
Normal 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();
|
||||
}
|
||||
19
source/Display/GLContext.cpp
Normal file
19
source/Display/GLContext.cpp
Normal 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
109
source/Game.cpp
Normal 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;
|
||||
}
|
||||
55
source/Game/FPSCounter.cpp
Normal file
55
source/Game/FPSCounter.cpp
Normal 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
76
source/Game/GameTime.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
259
source/Graphics/BatchRenderer2D.cpp
Normal file
259
source/Graphics/BatchRenderer2D.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
72
source/Graphics/DefaultRenderer2D.cpp
Normal file
72
source/Graphics/DefaultRenderer2D.cpp
Normal 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
127
source/Graphics/Font.cpp
Normal 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;
|
||||
}
|
||||
12
source/Graphics/Font/FontDriver.cpp
Normal file
12
source/Graphics/Font/FontDriver.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
#include "FontDriver.h"
|
||||
|
||||
FontDriver::FontDriver() :
|
||||
m_hinting (true)
|
||||
{
|
||||
}
|
||||
|
||||
void FontDriver::setHinting(bool value)
|
||||
{
|
||||
m_hinting = value;
|
||||
}
|
||||
31
source/Graphics/Font/FontDriver.h
Normal file
31
source/Graphics/Font/FontDriver.h
Normal 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 */
|
||||
131
source/Graphics/Font/FreeTypeDriver.cpp
Normal file
131
source/Graphics/Font/FreeTypeDriver.cpp
Normal 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;
|
||||
}
|
||||
29
source/Graphics/Font/FreeTypeDriver.h
Normal file
29
source/Graphics/Font/FreeTypeDriver.h
Normal 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 */
|
||||
28
source/Graphics/Font/FreeTypeError.cpp
Normal file
28
source/Graphics/Font/FreeTypeError.cpp
Normal 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";
|
||||
}
|
||||
10
source/Graphics/Font/FreeTypeError.h
Normal file
10
source/Graphics/Font/FreeTypeError.h
Normal 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 */
|
||||
12
source/Graphics/GL/CheckError.cpp
Normal file
12
source/Graphics/GL/CheckError.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
11
source/Graphics/GL/CheckError.h
Normal file
11
source/Graphics/GL/CheckError.h
Normal 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
208
source/Graphics/Image.cpp
Normal 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;
|
||||
}
|
||||
130
source/Graphics/ImageLoader.cpp
Normal file
130
source/Graphics/ImageLoader.cpp
Normal 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;
|
||||
}
|
||||
33
source/Graphics/ImageLoader.h
Normal file
33
source/Graphics/ImageLoader.h
Normal 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 */
|
||||
48
source/Graphics/RenderState.cpp
Normal file
48
source/Graphics/RenderState.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
15
source/Graphics/Renderable2D.cpp
Normal file
15
source/Graphics/Renderable2D.cpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
#include <Spectre/Graphics/Renderable.h>
|
||||
|
||||
Renderable2D::Renderable2D()
|
||||
{
|
||||
}
|
||||
|
||||
Renderable2D::Renderable2D(const Vector2f& position) :
|
||||
Transformable (position)
|
||||
{
|
||||
}
|
||||
|
||||
Renderable2D::~Renderable2D()
|
||||
{
|
||||
}
|
||||
15
source/Graphics/Renderer2D.cpp
Normal file
15
source/Graphics/Renderer2D.cpp
Normal 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
100
source/Graphics/Shader.cpp
Normal 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);
|
||||
}
|
||||
193
source/Graphics/ShaderProgram.cpp
Normal file
193
source/Graphics/ShaderProgram.cpp
Normal 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
111
source/Graphics/Sprite.cpp
Normal 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
131
source/Graphics/Text.cpp
Normal 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
250
source/Graphics/Texture.cpp
Normal 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;
|
||||
}
|
||||
94
source/Graphics/Transformable.cpp
Normal file
94
source/Graphics/Transformable.cpp
Normal 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;
|
||||
}
|
||||
30
source/Graphics/Vertex2D.cpp
Normal file
30
source/Graphics/Vertex2D.cpp
Normal 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
66
source/GraphicsOpenGL.cpp
Normal 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();
|
||||
}
|
||||
10
source/Input/InputDevice.cpp
Normal file
10
source/Input/InputDevice.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
#include <Spectre/Input/InputDevice.h>
|
||||
|
||||
InputDevice::~InputDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void InputDevice::init()
|
||||
{
|
||||
}
|
||||
19
source/Input/InputEvent.cpp
Normal file
19
source/Input/InputEvent.cpp
Normal 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);
|
||||
}
|
||||
6
source/Input/InputListener.cpp
Normal file
6
source/Input/InputListener.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include <Spectre/Input/Inputlistener.h>
|
||||
|
||||
void InputListener::onInputEvent(const InputEvent& event)
|
||||
{
|
||||
}
|
||||
96
source/Input/InputModule.cpp
Normal file
96
source/Input/InputModule.cpp
Normal 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
112
source/Input/Keyboard.cpp
Normal 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
20
source/Input/Mouse.cpp
Normal 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
128
source/Math/Color.cpp
Normal 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
20
source/Math/Logarithm.cpp
Normal 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
99
source/Math/Math.cpp
Normal 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
158
source/Math/Transform.cpp
Normal 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);
|
||||
}
|
||||
25
source/Platform/PlatformApplication.h
Normal file
25
source/Platform/PlatformApplication.h
Normal 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 */
|
||||
32
source/Platform/PlatformDisplay.cpp
Normal file
32
source/Platform/PlatformDisplay.cpp
Normal 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);
|
||||
}
|
||||
52
source/Platform/PlatformDisplay.h
Normal file
52
source/Platform/PlatformDisplay.h
Normal 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 */
|
||||
18
source/Platform/PlatformInput.h
Normal file
18
source/Platform/PlatformInput.h
Normal 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 */
|
||||
19
source/Platform/PlatformMisc.h
Normal file
19
source/Platform/PlatformMisc.h
Normal 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 */
|
||||
96
source/Platform/Win32/Win32Application.cpp
Normal file
96
source/Platform/Win32/Win32Application.cpp
Normal 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);
|
||||
}
|
||||
38
source/Platform/Win32/Win32Application.h
Normal file
38
source/Platform/Win32/Win32Application.h
Normal 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 */
|
||||
260
source/Platform/Win32/Win32Display.cpp
Normal file
260
source/Platform/Win32/Win32Display.cpp
Normal 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);
|
||||
}
|
||||
66
source/Platform/Win32/Win32Display.h
Normal file
66
source/Platform/Win32/Win32Display.h
Normal 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 */
|
||||
156
source/Platform/Win32/Win32GLContext.cpp
Normal file
156
source/Platform/Win32/Win32GLContext.cpp
Normal 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;
|
||||
}
|
||||
48
source/Platform/Win32/Win32GLContext.h
Normal file
48
source/Platform/Win32/Win32GLContext.h
Normal 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 */
|
||||
27
source/Platform/Win32/Win32Input.cpp
Normal file
27
source/Platform/Win32/Win32Input.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
32
source/Platform/Win32/Win32Input.h
Normal file
32
source/Platform/Win32/Win32Input.h
Normal 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 */
|
||||
20
source/Platform/Win32/Win32Internal.cpp
Normal file
20
source/Platform/Win32/Win32Internal.cpp
Normal 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;
|
||||
}
|
||||
10
source/Platform/Win32/Win32Internal.h
Normal file
10
source/Platform/Win32/Win32Internal.h
Normal 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 */
|
||||
119
source/Platform/Win32/Win32Keyboard.cpp
Normal file
119
source/Platform/Win32/Win32Keyboard.cpp
Normal 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);
|
||||
}
|
||||
28
source/Platform/Win32/Win32Keyboard.h
Normal file
28
source/Platform/Win32/Win32Keyboard.h
Normal 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 */
|
||||
22
source/Platform/Win32/Win32Misc.cpp
Normal file
22
source/Platform/Win32/Win32Misc.cpp
Normal 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();
|
||||
}
|
||||
115
source/Platform/Win32/Win32Mouse.cpp
Normal file
115
source/Platform/Win32/Win32Mouse.cpp
Normal 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);
|
||||
}
|
||||
34
source/Platform/Win32/Win32Mouse.h
Normal file
34
source/Platform/Win32/Win32Mouse.h
Normal 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 */
|
||||
18
source/Platform/Win32/Win32MsgBuffer.cpp
Normal file
18
source/Platform/Win32/Win32MsgBuffer.cpp
Normal 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;
|
||||
}
|
||||
18
source/Platform/Win32/Win32MsgBuffer.h
Normal file
18
source/Platform/Win32/Win32MsgBuffer.h
Normal 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 */
|
||||
28
source/Platform/Win32/Win32System.cpp
Normal file
28
source/Platform/Win32/Win32System.cpp
Normal 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
158
source/Scene/Camera2D.cpp
Normal 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
40
source/System/File.cpp
Normal 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
13
source/System/Log.cpp
Normal 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);
|
||||
}
|
||||
7
source/System/MessageHandler.cpp
Normal file
7
source/System/MessageHandler.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
#include <Spectre/Display/Display.h>
|
||||
#include <Spectre/System/MessageHandler.h>
|
||||
|
||||
void MessageHandler::onSizeChanged(Display* display, int width, int height)
|
||||
{
|
||||
}
|
||||
22
source/System/MessageQueue.cpp
Normal file
22
source/System/MessageQueue.cpp
Normal 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();
|
||||
}
|
||||
16
source/System/SystemEvent.cpp
Normal file
16
source/System/SystemEvent.cpp
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue