summaryrefslogtreecommitdiffstats
path: root/examples/embedded/raycasting/raycasting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/embedded/raycasting/raycasting.cpp')
-rw-r--r--examples/embedded/raycasting/raycasting.cpp383
1 files changed, 0 insertions, 383 deletions
diff --git a/examples/embedded/raycasting/raycasting.cpp b/examples/embedded/raycasting/raycasting.cpp
deleted file mode 100644
index 4930dbe9f2..0000000000
--- a/examples/embedded/raycasting/raycasting.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the demonstration applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#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();
-}