-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFloorRenderer.cpp
More file actions
123 lines (105 loc) · 3.3 KB
/
FloorRenderer.cpp
File metadata and controls
123 lines (105 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "FloorRenderer.h"
#include <math.h>
#include <string.h>
#include "SGF/Color565.h"
namespace FloorRenderer {
namespace {
constexpr int TEX_SIZE = 16;
constexpr int FLOOR_ROW_STRIDE = 2;
constexpr int FLOOR_COL_STRIDE = 2;
uint16_t shadeColor(uint16_t color565, float distance) {
float brightness = 1.0f / (1.0f + distance * 0.16f);
if (brightness < 0.20f) {
brightness = 0.20f;
}
uint8_t r5 = (color565 >> 11) & 0x1F;
uint8_t g6 = (color565 >> 5) & 0x3F;
uint8_t b5 = color565 & 0x1F;
uint8_t r = (r5 * 255.0f / 31.0f) * brightness;
uint8_t g = (g6 * 255.0f / 63.0f) * brightness;
uint8_t b = (b5 * 255.0f / 31.0f) * brightness;
return Color565::rgb(r, g, b);
}
uint16_t floorTexel(int texX, int texY, int cellX, int cellY) {
bool warmTile = ((cellX + cellY) & 1) == 0;
uint16_t base = warmTile ? Color565::rgb(92, 84, 70) : Color565::rgb(78, 72, 60);
uint16_t light = Color565::lighten(base);
uint16_t dark = Color565::darken(base);
uint16_t seam = Color565::rgb(42, 36, 32);
bool edge = texX == 0 || texY == 0 || texX == TEX_SIZE - 1 || texY == TEX_SIZE - 1;
bool grout = (texX == 7) || (texY == 7);
bool speckle = ((texX * 3 + texY * 5 + cellX * 7 + cellY * 11) & 0x3) == 0;
bool crack =
((texX == texY) && texX > 2 && texX < 7) ||
((texX + texY) == 11 && texX > 8 && texY > 2) ||
(texX > 10 && texX < 13 && texY == 4);
if (edge || grout) {
return seam;
}
if (crack) {
return dark;
}
if (speckle) {
return light;
}
if (((texX + texY) & 1) == 0) {
return base;
}
return warmTile ? dark : light;
}
} // namespace
void render(
uint16_t* frameBuffer,
int width,
int height,
float playerX,
float playerY,
float dirX,
float dirY,
float planeX,
float planeY
) {
if (frameBuffer == 0 || width <= 0 || height <= 0) {
return;
}
const int halfH = height / 2;
const float rayDirX0 = dirX - planeX;
const float rayDirY0 = dirY - planeY;
const float rayDirX1 = dirX + planeX;
const float rayDirY1 = dirY + planeY;
const float cameraZ = height * 0.5f;
for (int y = halfH + 1; y < height; y += FLOOR_ROW_STRIDE) {
int rowOffset = y - halfH;
if (rowOffset <= 0) {
continue;
}
float rowDistance = cameraZ / rowOffset;
float floorStepX = rowDistance * (rayDirX1 - rayDirX0) / width;
float floorStepY = rowDistance * (rayDirY1 - rayDirY0) / width;
float floorX = playerX + rowDistance * rayDirX0;
float floorY = playerY + rowDistance * rayDirY0;
uint16_t* row = &frameBuffer[y * width];
uint16_t* nextRow = (y + 1 < height) ? &frameBuffer[(y + 1) * width] : nullptr;
for (int x = 0; x < width; x += FLOOR_COL_STRIDE) {
int cellX = floorf(floorX);
int cellY = floorf(floorY);
float fracX = floorX - cellX;
float fracY = floorY - cellY;
int texX = fracX * TEX_SIZE;
int texY = fracY * TEX_SIZE;
texX &= TEX_SIZE - 1;
texY &= TEX_SIZE - 1;
uint16_t color565 = shadeColor(floorTexel(texX, texY, cellX, cellY), rowDistance);
row[x] = color565;
if (x + 1 < width) {
row[x + 1] = color565;
}
floorX += floorStepX * FLOOR_COL_STRIDE;
floorY += floorStepY * FLOOR_COL_STRIDE;
}
if (nextRow != nullptr) {
memcpy(nextRow, row, width * sizeof(uint16_t));
}
}
}
} // namespace FloorRenderer