246 lines
6.7 KiB
C++
246 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>
|
|
|
|
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();
|
|
}
|