181 lines
5.5 KiB
C++
181 lines
5.5 KiB
C++
#include "qscenerenderer.h"
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
GLuint vertexbuffer;
|
|
GLuint VertexArrayID;
|
|
QSceneRenderer::QSceneRenderer(QWidget* parent): QOpenGLWidget(parent)
|
|
{
|
|
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
|
|
installEventFilter(this);
|
|
QImage img = QImage("/home/bart/project/tiletest/images/heightmap.jpg").convertToFormat(QImage::Format_RGB32);
|
|
m_zoom = 4;
|
|
m_point = new Matrix2D<TerrainPoint>(img.width(),img.height());
|
|
m_numPoints05= img.width()/MAP_WIDTH/1.5/2;
|
|
for (int y = 0; y<img.height(); y++) {
|
|
QRgb *line = (QRgb *) img.scanLine(img.height() - 1 - y);
|
|
TerrainPoint *row = m_point->row(y);
|
|
for (int x = 0; x<img.width(); x++) {
|
|
row[x].height = qRed(line[x]);
|
|
}
|
|
}
|
|
|
|
cameraUpDirection = cameraTransformation * QVector3D(0, 1, 0);
|
|
cameraTransformation.rotate(zRot, 0, 0, 1);
|
|
cameraPosition = cameraTransformation * QVector3D(5, 5, 5);
|
|
/*
|
|
for (int y=0; y<getNumPointsHeight(); y++)
|
|
for (int x=0; x<getNumPointsWidth(); x++){
|
|
|
|
m_point->operator ()(x,y).height = abs((x*10%200)-100);
|
|
}*/
|
|
|
|
tiles=new Matrix2D<Tile>(MAP_WIDTH,MAP_HEIGHT);
|
|
}
|
|
|
|
Tile * QSceneRenderer::getTile(int x, int y)
|
|
{
|
|
return &tiles->operator ()(x,y);
|
|
}
|
|
|
|
void QSceneRenderer::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
lastPos = event->pos();
|
|
}
|
|
|
|
void QSceneRenderer::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
/*int dx = event->x() - lastPos.x();
|
|
int dy = event->y() - lastPos.y();
|
|
|
|
if (event->buttons() & Qt::LeftButton) {
|
|
zRot += 8 * dx;
|
|
} else if (event->buttons() & Qt::RightButton) {
|
|
zRot -= 8 * dx;
|
|
}
|
|
lastPos = event->pos();
|
|
update();*/
|
|
|
|
}
|
|
|
|
void QSceneRenderer::keyPressEvent(QKeyEvent *e)
|
|
{
|
|
if (e->key()== Qt::Key_A) {
|
|
cameraPosition.setX(cameraPosition.x()+ 0.1f*cos(PI*(zRot+90)/180.0f));
|
|
cameraPosition.setY(cameraPosition.y()+ 0.1f*sin(PI*(zRot+90)/180.0f));
|
|
}
|
|
else if (e->key()== Qt::Key_D) {
|
|
cameraPosition.setX(cameraPosition.x()+ 0.1f*cos(PI*(zRot-90)/180.0f));
|
|
cameraPosition.setY(cameraPosition.y()+ 0.1f*sin(PI*(zRot-90)/180.0f));
|
|
}
|
|
|
|
if (e->key()== Qt::Key_W) {
|
|
cameraPosition.setX(cameraPosition.x()+ 0.1f*cos(PI*(zRot+0)/180.0f));
|
|
cameraPosition.setY(cameraPosition.y()+ 0.1f*sin(PI*(zRot+0)/180.0f));
|
|
}
|
|
else if (e->key()== Qt::Key_S) {
|
|
cameraPosition.setX(cameraPosition.x()+ 0.1f*cos(PI*(zRot+180)/180.0f));
|
|
cameraPosition.setY(cameraPosition.y()+ 0.1f*sin(PI*(zRot+180)/180.0f));
|
|
}
|
|
else if (e->key()== Qt::Key_E) {
|
|
zRot --;
|
|
if (zRot<0.0)
|
|
zRot+=360.0;
|
|
}
|
|
else if (e->key()== Qt::Key_Q) {
|
|
zRot ++;
|
|
if (zRot>=360.0)
|
|
zRot-=360.0;
|
|
}
|
|
update();
|
|
}
|
|
|
|
void QSceneRenderer::wheelEvent(QWheelEvent *e)
|
|
{
|
|
m_zoom -= e->delta()/100.0;
|
|
if (m_zoom<2) m_zoom =2;
|
|
if (m_zoom>10)m_zoom =10;
|
|
update();
|
|
}
|
|
|
|
void QSceneRenderer::initializeGL()
|
|
{
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
}
|
|
|
|
void QSceneRenderer::resizeGL(int width, int height)
|
|
{
|
|
Projection= QMatrix4x4();
|
|
Projection.perspective(45, (float) width / (float)height,0.1f,100.0f);
|
|
|
|
|
|
}
|
|
|
|
void QSceneRenderer::paintGL()
|
|
{
|
|
glEnable(GL_DEPTH_TEST);
|
|
QMatrix4x4 cameraTransformation;
|
|
QMatrix4x4 vMatrix;
|
|
|
|
cameraTransformation.rotate(zRot, 0, 0, 1);
|
|
cameraUpDirection = cameraTransformation * QVector3D(0, 0, 1);
|
|
cameraPosition.setZ(m_zoom);
|
|
|
|
QVector3D lookat = QVector3D(cameraPosition.x()+ m_zoom*m_zoom/5.0f*cos(PI*zRot/180.0f)
|
|
, cameraPosition.y()+ m_zoom*m_zoom/5.0f*sin(PI*zRot/180.0f)
|
|
,0);
|
|
vMatrix.lookAt(cameraPosition, lookat, cameraUpDirection);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Bounding box of the visible area in world coordinates
|
|
float minWorldX = std::min(cameraPosition.x(), lookat.x());
|
|
float maxWorldX = std::max(cameraPosition.x(), lookat.x());
|
|
float minWorldY = std::min(cameraPosition.y(), lookat.y());
|
|
float maxWorldY = std::max(cameraPosition.y(), lookat.y());
|
|
|
|
float margin = m_zoom * 2.5f + 8.0f;
|
|
minWorldX -= margin;
|
|
maxWorldX += margin;
|
|
minWorldY -= margin;
|
|
maxWorldY += margin;
|
|
|
|
float tileStepX = LOD_0_SIZE * 0.75f;
|
|
float tileStepY = LOD_0_SIZE_Y * 2.0f;
|
|
|
|
int minTileX = std::max(0, (int)floor(minWorldX / tileStepX));
|
|
int maxTileX = std::min(MAP_WIDTH - 1, (int)ceil(maxWorldX / tileStepX));
|
|
int minTileY = std::max(0, (int)floor(minWorldY / tileStepY));
|
|
int maxTileY = std::min(MAP_HEIGHT - 1, (int)ceil(maxWorldY / tileStepY));
|
|
|
|
// Expand margin by 1 for neighbor normal calculations
|
|
int initMinX = std::max(0, minTileX - 1);
|
|
int initMaxX = std::min(MAP_WIDTH - 1, maxTileX + 1);
|
|
int initMinY = std::max(0, minTileY - 1);
|
|
int initMaxY = std::min(MAP_HEIGHT - 1, maxTileY + 1);
|
|
|
|
// 1. Lazy initialize visible tiles and direct neighbors
|
|
for (int y = initMinY; y <= initMaxY; ++y) {
|
|
for (int x = initMinX; x <= initMaxX; ++x) {
|
|
tiles->operator()(x, y).ensureInitialized(this, x, y);
|
|
}
|
|
}
|
|
|
|
// 2. Ensure normals are built for visible tiles
|
|
for (int y = minTileY; y <= maxTileY; ++y) {
|
|
for (int x = minTileX; x <= maxTileX; ++x) {
|
|
tiles->operator()(x, y).ensureNormalsBuilt();
|
|
}
|
|
}
|
|
|
|
// 3. Render only visible tiles
|
|
for (int y = minTileY; y <= maxTileY; ++y) {
|
|
for (int x = minTileX; x <= maxTileX; ++x) {
|
|
tiles->operator()(x, y).paint(Projection, cameraPosition, cameraUpDirection, vMatrix, zRot);
|
|
}
|
|
}
|
|
|
|
}
|