mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 23:35:28 +08:00
qt 6.5.1 original
This commit is contained in:
48
examples/embedded/raycasting/CMakeLists.txt
Normal file
48
examples/embedded/raycasting/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(raycasting LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/embedded/raycasting")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(raycasting
|
||||
raycasting.cpp
|
||||
)
|
||||
|
||||
set_target_properties(raycasting PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(raycasting PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(raycasting_resource_files
|
||||
"textures.png"
|
||||
)
|
||||
|
||||
qt_add_resources(raycasting "raycasting"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${raycasting_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS raycasting
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
336
examples/embedded/raycasting/raycasting.cpp
Normal file
336
examples/embedded/raycasting/raycasting.cpp
Normal file
@ -0,0 +1,336 @@
|
||||
// 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();
|
||||
}
|
7
examples/embedded/raycasting/raycasting.pro
Normal file
7
examples/embedded/raycasting/raycasting.pro
Normal file
@ -0,0 +1,7 @@
|
||||
TEMPLATE = app
|
||||
QT += widgets
|
||||
SOURCES = raycasting.cpp
|
||||
RESOURCES += raycasting.qrc
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/embedded/raycasting
|
||||
INSTALLS += target
|
5
examples/embedded/raycasting/raycasting.qrc
Normal file
5
examples/embedded/raycasting/raycasting.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>textures.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
examples/embedded/raycasting/textures.png
Normal file
BIN
examples/embedded/raycasting/textures.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user