dfhack/plugins/qtplug/glwidget.cpp

247 lines
6.7 KiB
C++

/*
* Copyright (c) 2010 Petr Mrázek (peterix)
* See LICENSE for details.
*/
#include "glwidget.h"
#include <QtOpenGL>
#include <QGLBuffer>
#include <QGLShaderProgram>
#include <QGLPixelBuffer>
#include <iostream>
#include <GL/gl.h>
struct Vertex
{
float texcoord[2];
float color[3];
float position[3];
};
#define FRS 0.0625
#define FRX FRS/2
// this is crap
const Vertex house_vert[] =
{
// walls
{ { 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { -4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 0.0 }, { -4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 0.0, 1.0, 1.0 }, { 4.0, -4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 0.0 }, { 4.0, -4.0, -4.0 } },
{ { 0.0, 0.0 }, { 1.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { 0.0, FRS }, { 1.0, 1.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 1.0, 1.0 }, { 4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 0.0, 0.0, 1.0 }, { 4.0, 4.0, -4.0 } },
{ { 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { -4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { -4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 0.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 4.0, -4.0, -4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { 4.0, -4.0, 4.0 } },
{ { FRS, FRS }, { 1.0, 0.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 1.0 }, { 4.0, 4.0, -4.0 } },
// roof
{ { 0.0, 0.0 }, { 0.0, 0.0, 1.0 }, { -4.0, 4.0, -4.0 } },
{ { FRS, 0.0 }, { 0.0, 1.0, 1.0 }, { 4.0, 4.0, -4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { FRS, 0.0 }, { 1.0, 0.0, 0.0 }, { 4.0, 4.0, -4.0 } },
{ { FRS, FRS }, { 1.0, 1.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { FRS, FRS }, { 0.0, 1.0, 0.0 }, { 4.0, 4.0, 4.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 1.0 }, { -4.0, 4.0, 4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } },
{ { 0.0, FRS }, { 0.0, 1.0, 0.0 }, { -4.0, 4.0, 4.0 } },
{ { 0.0, 0.0 }, { 1.0, 1.0, 0.0 }, { -4.0, 4.0, -4.0 } },
{ { FRX, FRX }, { 1.0, 1.0, 1.0 }, { 0.0, 9.0, 0.0 } }
};
const unsigned char house_idx[] =
{
// walls
0, 1, 2, 0, 2, 3,
4, 5, 6, 4, 6, 7,
8, 9, 10, 8, 10, 11,
12, 13, 14, 12, 14, 15,
// roof
16, 17, 18,
19, 20, 21,
22, 23, 24,
25, 26, 27
};
class GLWPrivate
{
public:
QGLBuffer *VBO;
QGLBuffer *EBO;
QGLShaderProgram prog;
int positionAttrib;
int colorAttrib;
int texcoordsAttrib;
int mvpUniform;
int textureUniform;
int terrain;
float pz,rx,ry;
QPoint lastMouse;
};
GLWidget::GLWidget()
{
d = new GLWPrivate;
d->pz = -140.0f;
d->rx = d->ry = 0.0f;
d->VBO = d->EBO = 0;
startTimer( 10 );
}
GLWidget::~GLWidget()
{
if(d->VBO) delete d->VBO;
if(d->EBO) delete d->EBO;
delete d;
}
const char * VS_src =
"#version 130\n"
"in vec3 position; in vec3 color; uniform mat4 mvp; out vec3 c;"
"in vec2 tc_in; out vec2 coord;"
"void main()"
"{"
"gl_Position = mvp*vec4(position,1);"
"c = color;"
"coord = tc_in;"
"}";
const char * FS_src =
"#version 130\n"
"in vec3 c;"
//"out vec4 gl_FragColor;"
"in vec2 coord; uniform sampler2D tex;"
"void main()"
"{"
// "gl_FragColor = vec4(c,1);"
// "gl_FragColor = mix( texture(tex, coord), vec4(c,1), 0.5);"
// "gl_FragColor = vec4(c,1) - texture(tex, coord);"
"gl_FragColor = vec4(c,1) * texture(tex, coord);"
"}";
//initialization of OpenGL
void GLWidget::initializeGL()
{
bool test = 1;
test &= d->prog.addShaderFromSourceCode(QGLShader::Vertex,VS_src);
test &= d->prog.addShaderFromSourceCode(QGLShader::Fragment,FS_src);
test &= d->prog.link();
if(!test)
std::cout << "OUCH!" << std::endl;
d->positionAttrib = d->prog.attributeLocation("position");
d->colorAttrib = d->prog.attributeLocation("color");
d->texcoordsAttrib = d->prog.attributeLocation("tc_in");
d->mvpUniform = d->prog.uniformLocation("mvp");
d->textureUniform = d->prog.uniformLocation("tex");
if(d->positionAttrib == -1 || d->colorAttrib == -1 || d->mvpUniform == -1)
std::cout << "Bad attribs!" << std::endl;
QGLBuffer &VBO = *(d->VBO = new QGLBuffer(QGLBuffer::VertexBuffer));
VBO.create();
VBO.bind();
VBO.allocate(sizeof(house_vert));
VBO.write(0,house_vert,sizeof(house_vert));
QGLBuffer &EBO = *(d->EBO = new QGLBuffer(QGLBuffer::IndexBuffer));
EBO.create();
EBO.bind();
EBO.allocate(sizeof(house_idx));
EBO.write(0,house_idx,sizeof(house_idx));
QImage texture;
texture.load("terrain.png");
d->terrain = bindTexture(texture);
glClearColor(0.0f, 0.0f, 0.0f, 0.f);
glShadeModel( GL_SMOOTH );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glEnable( GL_TEXTURE_2D );
glEnable( GL_DEPTH_TEST );
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d->prog.bind();
QMatrix4x4 projection;
QMatrix4x4 mvp;
//projection.ortho(-10,10,-10,10,1,1000);
float aspect = (float)width()/(float)height();
projection.perspective(10,aspect,1,1000);
mvp = projection;
mvp.translate(0,0,d->pz);
mvp.rotate(d->ry,1,0,0);
mvp.rotate(d->rx,0,1,0);
d->prog.setUniformValue(d->mvpUniform,mvp);
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, d->terrain);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
d->prog.setUniformValue(d->textureUniform,0);
d->prog.enableAttributeArray(d->positionAttrib);
d->prog.enableAttributeArray(d->colorAttrib);
d->prog.enableAttributeArray(d->texcoordsAttrib);
d->VBO->bind();
d->prog.setAttributeBuffer(d->texcoordsAttrib, GL_FLOAT, offsetof(Vertex, texcoord), 2, sizeof(Vertex));
d->prog.setAttributeBuffer(d->positionAttrib, GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex));
d->prog.setAttributeBuffer(d->colorAttrib, GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex));
d->EBO->bind();
glDrawElements(GL_TRIANGLES, d->EBO->size(), GL_UNSIGNED_BYTE, NULL);
d->prog.release();
}
void GLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
void GLWidget::mousePressEvent(QMouseEvent *event)
{
d->lastMouse = event->pos();
}
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - d->lastMouse.x();
int dy = event->y() - d->lastMouse.y();
if (event->buttons() & Qt::LeftButton)
{
d->rx = d->rx + dx;
d->ry = d->ry + dy;
}
d->lastMouse = event->pos();
}
void GLWidget::timerEvent(QTimerEvent *event)
{
updateGL();
}