Files
Ascent-of-Man/qscenerenderer.cpp
T
2026-11-08 11:22:15 +01:00

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);
}
}
}