diff options
Diffstat (limited to 'examples/embedded/raycasting/raycasting.cpp')
-rw-r--r-- | examples/embedded/raycasting/raycasting.cpp | 336 |
1 files changed, 0 insertions, 336 deletions
diff --git a/examples/embedded/raycasting/raycasting.cpp b/examples/embedded/raycasting/raycasting.cpp deleted file mode 100644 index 1823974f8c..0000000000 --- a/examples/embedded/raycasting/raycasting.cpp +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include <QtCore> -#include <QtWidgets> -#include <qmath.h> - -#define WORLD_SIZE 8 -int world_map[WORLD_SIZE][WORLD_SIZE] = { - { 1, 1, 1, 1, 6, 1, 1, 1 }, - { 1, 0, 0, 1, 0, 0, 0, 7 }, - { 1, 1, 0, 1, 0, 1, 1, 1 }, - { 6, 0, 0, 0, 0, 0, 0, 3 }, - { 1, 8, 8, 0, 8, 0, 8, 1 }, - { 2, 2, 0, 0, 8, 8, 7, 1 }, - { 3, 0, 0, 0, 0, 0, 0, 5 }, - { 2, 2, 2, 2, 7, 4, 4, 4 }, -}; - -#define TEXTURE_SIZE 64 -#define TEXTURE_BLOCK (TEXTURE_SIZE * TEXTURE_SIZE) - -class Raycasting: public QWidget -{ -public: - Raycasting(QWidget *parent = nullptr) - : QWidget(parent) - , angle(0.5) - , playerPos(1.5, 1.5) - , angleDelta(0) - , moveDelta(0) - , touchDevice(false) { - - // http://www.areyep.com/RIPandMCS-TextureLibrary.html - textureImg.load(":/textures.png"); - textureImg = textureImg.convertToFormat(QImage::Format_ARGB32); - Q_ASSERT(textureImg.width() == TEXTURE_SIZE * 2); - Q_ASSERT(textureImg.bytesPerLine() == 4 * TEXTURE_SIZE * 2); - textureCount = textureImg.height() / TEXTURE_SIZE; - - watch.start(); - ticker.start(25, this); - setAttribute(Qt::WA_OpaquePaintEvent, true); - setMouseTracking(false); - } - - void updatePlayer() { - int interval = qBound(20ll, watch.elapsed(), 250ll); - watch.start(); - angle += angleDelta * interval / 1000; - qreal step = moveDelta * interval / 1000; - qreal dx = cos(angle) * step; - qreal dy = sin(angle) * step; - QPointF pos = playerPos + 3 * QPointF(dx, dy); - int xi = static_cast<int>(pos.x()); - int yi = static_cast<int>(pos.y()); - if (world_map[yi][xi] == 0) - playerPos = playerPos + QPointF(dx, dy); - } - - void showFps() { - static QElapsedTimer frameTick; - static int totalFrame = 0; - if (!(totalFrame & 31)) { - const qint64 elapsed = frameTick.elapsed(); - frameTick.start(); - int fps = 32 * 1000 / (1 + elapsed); - setWindowTitle(QString("Raycasting (%1 FPS)").arg(fps)); - } - totalFrame++; - } - - void render() { - - // setup the screen surface - if (buffer.size() != bufferSize) - buffer = QImage(bufferSize, QImage::Format_ARGB32); - int bufw = buffer.width(); - int bufh = buffer.height(); - if (bufw <= 0 || bufh <= 0) - return; - - // we intentionally cheat here, to avoid detach - const uchar *ptr = buffer.bits(); - QRgb *start = (QRgb*)(ptr); - QRgb stride = buffer.bytesPerLine() / 4; - QRgb *finish = start + stride * bufh; - - // prepare the texture pointer - const uchar *src = textureImg.bits(); - const QRgb *texsrc = reinterpret_cast<const QRgb*>(src); - - // cast all rays here - qreal sina = sin(angle); - qreal cosa = cos(angle); - qreal u = cosa - sina; - qreal v = sina + cosa; - qreal du = 2 * sina / bufw; - qreal dv = -2 * cosa / bufw; - - for (int ray = 0; ray < bufw; ++ray, u += du, v += dv) { - // every time this ray advances 'u' units in x direction, - // it also advanced 'v' units in y direction - qreal uu = (u < 0) ? -u : u; - qreal vv = (v < 0) ? -v : v; - qreal duu = 1 / uu; - qreal dvv = 1 / vv; - int stepx = (u < 0) ? -1 : 1; - int stepy = (v < 0) ? -1 : 1; - - // the cell in the map that we need to check - qreal px = playerPos.x(); - qreal py = playerPos.y(); - int mapx = static_cast<int>(px); - int mapy = static_cast<int>(py); - - // the position and texture for the hit - int texture = 0; - qreal hitdist = 0.1; - qreal texofs = 0; - bool dark = false; - - // first hit at constant x and constant y lines - qreal distx = (u > 0) ? (mapx + 1 - px) * duu : (px - mapx) * duu; - qreal disty = (v > 0) ? (mapy + 1 - py) * dvv : (py - mapy) * dvv; - - // loop until we hit something - while (texture <= 0) { - if (distx > disty) { - // shorter distance to a hit in constant y line - hitdist = disty; - disty += dvv; - mapy += stepy; - texture = world_map[mapy][mapx]; - if (texture > 0) { - dark = true; - if (stepy > 0) { - qreal ofs = px + u * (mapy - py) / v; - texofs = ofs - floor(ofs); - } else { - qreal ofs = px + u * (mapy + 1 - py) / v; - texofs = ofs - floor(ofs); - } - } - } else { - // shorter distance to a hit in constant x line - hitdist = distx; - distx += duu; - mapx += stepx; - texture = world_map[mapy][mapx]; - if (texture > 0) { - if (stepx > 0) { - qreal ofs = py + v * (mapx - px) / u; - texofs = ofs - floor(ofs); - } else { - qreal ofs = py + v * (mapx + 1 - px) / u; - texofs = ceil(ofs) - ofs; - } - } - } - } - - // get the texture, note that the texture image - // has two textures horizontally, "normal" vs "dark" - int col = static_cast<int>(texofs * TEXTURE_SIZE); - col = qBound(0, col, TEXTURE_SIZE - 1); - texture = (texture - 1) % textureCount; - const QRgb *tex = texsrc + TEXTURE_BLOCK * texture * 2 + - (TEXTURE_SIZE * 2 * col); - if (dark) - tex += TEXTURE_SIZE; - - // start from the texture center (horizontally) - int h = static_cast<int>(bufw / hitdist / 2); - int dy = (TEXTURE_SIZE << 12) / h; - int p1 = ((TEXTURE_SIZE / 2) << 12) - dy; - int p2 = p1 + dy; - - // start from the screen center (vertically) - // y1 will go up (decrease), y2 will go down (increase) - int y1 = bufh / 2; - int y2 = y1 + 1; - QRgb *pixel1 = start + y1 * stride + ray; - QRgb *pixel2 = pixel1 + stride; - - // map the texture to the sliver - while (y1 >= 0 && y2 < bufh && p1 >= 0) { - *pixel1 = tex[p1 >> 12]; - *pixel2 = tex[p2 >> 12]; - p1 -= dy; - p2 += dy; - --y1; - ++y2; - pixel1 -= stride; - pixel2 += stride; - } - - // ceiling and floor - for (; pixel1 > start; pixel1 -= stride) - *pixel1 = qRgb(0, 0, 0); - for (; pixel2 < finish; pixel2 += stride) - *pixel2 = qRgb(96, 96, 96); - } - - update(QRect(QPoint(0, 0), bufferSize)); - } - -protected: - - void resizeEvent(QResizeEvent*) { - touchDevice = false; - if (touchDevice) { - if (width() < height()) { - trackPad = QRect(0, height() / 2, width(), height() / 2); - centerPad = QPoint(width() / 2, height() * 3 / 4); - bufferSize = QSize(width(), height() / 2); - } else { - trackPad = QRect(width() / 2, 0, width() / 2, height()); - centerPad = QPoint(width() * 3 / 4, height() / 2); - bufferSize = QSize(width() / 2, height()); - } - } else { - trackPad = QRect(); - bufferSize = size(); - } - update(); - } - - void timerEvent(QTimerEvent*) { - updatePlayer(); - render(); - showFps(); - } - - void paintEvent(QPaintEvent *event) { - QPainter p(this); - p.setCompositionMode(QPainter::CompositionMode_Source); - - p.drawImage(event->rect(), buffer, event->rect()); - - if (touchDevice && event->rect().intersects(trackPad)) { - p.fillRect(trackPad, Qt::white); - p.setPen(QPen(QColor(224, 224, 224), 6)); - int rad = qMin(trackPad.width(), trackPad.height()) * 0.3; - p.drawEllipse(centerPad, rad, rad); - - p.setPen(Qt::NoPen); - p.setBrush(Qt::gray); - - QPolygon poly; - poly << QPoint(-30, 0); - poly << QPoint(0, -40); - poly << QPoint(30, 0); - - p.translate(centerPad); - for (int i = 0; i < 4; ++i) { - p.rotate(90); - p.translate(0, 20 - rad); - p.drawPolygon(poly); - p.translate(0, rad - 20); - } - } - - p.end(); - } - - void keyPressEvent(QKeyEvent *event) { - event->accept(); - if (event->key() == Qt::Key_Left) - angleDelta = 1.3 * M_PI; - if (event->key() == Qt::Key_Right) - angleDelta = -1.3 * M_PI; - if (event->key() == Qt::Key_Up) - moveDelta = 2.5; - if (event->key() == Qt::Key_Down) - moveDelta = -2.5; - } - - void keyReleaseEvent(QKeyEvent *event) { - event->accept(); - if (event->key() == Qt::Key_Left) - angleDelta = (angleDelta > 0) ? 0 : angleDelta; - if (event->key() == Qt::Key_Right) - angleDelta = (angleDelta < 0) ? 0 : angleDelta; - if (event->key() == Qt::Key_Up) - moveDelta = (moveDelta > 0) ? 0 : moveDelta; - if (event->key() == Qt::Key_Down) - moveDelta = (moveDelta < 0) ? 0 : moveDelta; - } - - void mousePressEvent(QMouseEvent *event) { - qreal dx = centerPad.x() - event->position().toPoint().x(); - qreal dy = centerPad.y() - event->position().toPoint().y(); - angleDelta = dx * 2 * M_PI / width(); - moveDelta = dy * 10 / height(); - } - - void mouseMoveEvent(QMouseEvent *event) { - qreal dx = centerPad.x() - event->position().toPoint().x(); - qreal dy = centerPad.y() - event->position().toPoint().y(); - angleDelta = dx * 2 * M_PI / width(); - moveDelta = dy * 10 / height(); - } - - void mouseReleaseEvent(QMouseEvent*) { - angleDelta = 0; - moveDelta = 0; - } - -private: - QElapsedTimer watch; - QBasicTimer ticker; - QImage buffer; - qreal angle; - QPointF playerPos; - qreal angleDelta; - qreal moveDelta; - QImage textureImg; - int textureCount; - bool touchDevice; - QRect trackPad; - QPoint centerPad; - QSize bufferSize; -}; - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - - Raycasting w; - w.setWindowTitle("Raycasting"); - w.resize(640, 480); - w.show(); - - return app.exec(); -} |