1
0
Fork 0

Initial commit

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

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

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

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

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

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

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

View file

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

View file

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