PixelWars/src/pixelpipeline.cpp
2016-05-18 00:12:10 +02:00

227 lines
6.8 KiB
C++

#include "pixelpipeline.h"
#include <framebuffer.h>
#include <texture.h>
#include <shader.h>
#include <cstring>
#include <glm/vec2.hpp>
#include <qtutils.h>
#include "mapscene.h"
#include <parametricmesh.h>
#include <glm/ext.hpp>
#define SCROLL_SPEED 0.998f
#define HEX_TO_VEC3(hex) glm::vec3(float((hex & 0xFF0000) >> 16)/255, float((hex & 0x00FF00) >> 8)/255, float(hex & 0x0000FF)/255)
inline glm::vec3 getColor(const Pixel &p)
{
switch(p.type){
case Pixel::BEDROCK : return HEX_TO_VEC3(0x101020);
case Pixel::GRASS : return HEX_TO_VEC3(0x719678);
case Pixel::MARK : return HEX_TO_VEC3(0x5D7B62);
case Pixel::ROCK : return HEX_TO_VEC3(0x8C8C8C);
case Pixel::IRON_ORE : return HEX_TO_VEC3(0x917B61);
case Pixel::TREE : return HEX_TO_VEC3(0x003800);
case Pixel::BERRIES : return HEX_TO_VEC3(0x4D6394);
case Pixel::FOOD : return HEX_TO_VEC3(0xFF7A7A);
case Pixel::WOOD : return HEX_TO_VEC3(0x634A22);
case Pixel::STONE : return HEX_TO_VEC3(0x454545);
case Pixel::IRON : return HEX_TO_VEC3(0x4A4036);
case Pixel::DUDE :
// TODO
return HEX_TO_VEC3(0x0000FF);
case Pixel::SPAWN :
// TODO
return HEX_TO_VEC3(0x0000FF);
case Pixel::WALL : return HEX_TO_VEC3(0xE6B2A1);
case Pixel::ROAD : return HEX_TO_VEC3(0xEDB287);
case Pixel::SWORD : return HEX_TO_VEC3(0xEBEBEB);
case Pixel::LIBRARY : return HEX_TO_VEC3(0xA37A50);
case Pixel::DEAD_DUDE : return HEX_TO_VEC3(0xFF0000);
default : return HEX_TO_VEC3(0x0000FF); // bleu absolu = bug
}
}
class ToreillerGenerator : public MeshGenerator
{
public:
virtual glm::vec3 evalUV(float u, float v)
{
const float MAGIC_RATIO = 1;
glm::vec2 relUV = glm::vec2(u-0.5f, v-0.5f);
float clockAngle = atan2(relUV.y, relUV.x);
float depthAngle = glm::length(relUV)*3.1416f*MAGIC_RATIO;
float r = sin(depthAngle);
return glm::vec3(r*cos(clockAngle), r*sin(clockAngle), cos(depthAngle)-1);
}
};
// MESH (2D points)
class PixelMesh
{
private:
GLuint m_vao;
GLuint m_vbo;
public:
struct Pix
{
glm::vec2 pos;
glm::vec3 color;
};
std::vector<Pix> m_pixels;
PixelMesh(int size)
{
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Pix), (void*)(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Pix), (void*)(sizeof(glm::vec2)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
~PixelMesh()
{
if(m_vao != 0)
{
glDeleteBuffers(1, &m_vbo);
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
}
void draw()
{
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_pixels.size() * sizeof(Pix), m_pixels.data(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_POINTS, 0, m_pixels.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_pixels.clear();
}
};
// PIPELINE
PixelPipeline::PixelPipeline(MapScene *map) :
m_mapWidth(map->getWidth()),
m_mapHeight(map->getHeight()),
m_camera(0, 0, 1)
{
m_width = 256;
m_height = 256;
map->setPipeline(this);
m_targetFBO = FrameBuffer::screen;
m_mapFBO = new FrameBuffer();
m_mapTex = new Texture(GL_RGBA, GL_RGBA, m_mapWidth, m_mapHeight, GL_UNSIGNED_BYTE, GL_TEXTURE_RECTANGLE);
m_mapTex->setFiltering(GL_NEAREST);
m_mapTex->setWrap(GL_CLAMP_TO_EDGE);
m_mapFBO->addTexture(m_mapTex, GL_COLOR_ATTACHMENT0);
m_mapFBO->initColorAttachments();
// set up vao
ToreillerGenerator gen;
m_toreiller = gen.generateParametricMesh(NULL, 40, 40, 1.0f);
m_toreiller->computeNormals();
m_toreiller->mergeVertices();
m_toreiller->initGL();
std::string vertSource = QtUtils::fileToString(":shaders/shaders/pixel.vert.glsl").toStdString();
std::string fragSource = QtUtils::fileToString(":shaders/shaders/pixel.frag.glsl").toStdString();
m_texMapShader = new Shader(vertSource, fragSource);
vertSource = QtUtils::fileToString(":shaders/shaders/world.vert.glsl").toStdString();
fragSource = QtUtils::fileToString(":shaders/shaders/world.frag.glsl").toStdString();
m_renderShader = new Shader(vertSource, fragSource);
m_changes = new PixelMesh(map->getWidth() * map->getHeight());
for(int i=0; i<map->getWidth(); ++i)
for(int j=0; j<map->getHeight(); ++j)
pushChange(glm::vec2(i, j), getColor((*map)[i][j]));
updateChanges();
}
PixelPipeline::~PixelPipeline()
{
delete m_mapFBO;
delete m_mapTex;
delete m_texMapShader;
delete m_renderShader;
delete m_changes;
}
void PixelPipeline::pushChange(const glm::vec2 &pos, const glm::vec3 &color)
{
m_changes->m_pixels.push_back({pos, color});
}
void PixelPipeline::updateChanges()
{
if(!m_changes->m_pixels.empty())
{
m_mapFBO->bindFBO();
glViewport(0, 0, m_mapWidth, m_mapHeight);
m_texMapShader->bind();
m_texMapShader->bindVec2(m_texMapShader->getLocation("texRatio"), glm::vec2(2.0f/m_mapWidth, 2.0f/m_mapHeight));
m_changes->draw();
}
}
void PixelPipeline::renderGL(Scene *scene)
{
m_targetFBO->bindFBO();
glViewport(0, 0, m_width, m_height);
glClearColor(0, 0, 0, 1);
glDisable(GL_BLEND);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
m_renderShader->bind();
m_renderShader->bindVec3(m_renderShader->getLocation("camera"), m_camera);
m_renderShader->bindVec2(m_renderShader->getLocation("worldSize"), glm::vec2(m_mapWidth, m_mapHeight));
m_renderShader->bindVec2(m_renderShader->getLocation("screenSize"), glm::vec2(m_width, m_height));
m_mapTex->bind(0);
m_renderShader->bindInteger(m_renderShader->getLocation("colorMap"), 0);
glClearDepth(1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
m_renderShader->bindMat4(m_renderShader->getLocation("mvp"), m_mvp);
m_toreiller->draw(m_renderShader);
}
void PixelPipeline::resizeGL(int w, int h)
{
m_width = w;
m_height = h;
m_mvp = glm::translate(glm::perspectiveFov(70.f, float(w), float(h), 0.1f, 10.f), glm::vec3(0, 0, -3));
}
void PixelPipeline::cameraZoom(int nbScrolls)
{
while(nbScrolls != 0)
{
if(nbScrolls > 0)
{
m_camera.z *= SCROLL_SPEED;
--nbScrolls;
}
else
{
m_camera.z /= SCROLL_SPEED;
++nbScrolls;
}
}
}