-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtrc.cpp
More file actions
307 lines (278 loc) · 9.38 KB
/
Copy pathtrc.cpp
File metadata and controls
307 lines (278 loc) · 9.38 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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#pragma once
#include <cassert>
#include <cmath>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <vector>
const double PI = 3.14159265358979323846;
class Screen;
class Window;
class ColorUtil;
class Player;
class LocalMiniMap;
class FPV;
class ColorUtil {
public:
static std::vector<uint32_t> colors;
static uint32_t pack_colors(const uint8_t r, const uint8_t g, const uint8_t b,
const uint8_t a = 255) {
return (a << 24) + (b << 16) + (g << 8) + r; // 0xAABBGGRR
}
static void unpack_colors(const uint32_t color, uint8_t &r, uint8_t &g,
uint8_t &b, uint8_t &a) {
r = (color >> 0) & 255;
g = (color >> 8) & 255;
b = (color >> 16) & 255;
a = (color >> 24) & 255;
}
};
std::vector<uint32_t> ColorUtil::colors;
class Screen {
public:
size_t w; // width
size_t h; // height
std::vector<Window *> windows;
std::vector<uint32_t> buffer;
Screen(size_t w = 1024, size_t h = 512)
: w(w), h(h), buffer(w * h), windows() {};
void to_ppm(std::string filename = "./screen.ppm") {
std::ofstream ofs(filename,
std::ios::binary); // binary mode is necessary for PPM
ofs << "P6\n" << w << " " << h << "\n" << 255 << "\n";
for (size_t i = 0; i < w * h; i++) {
uint8_t r, g, b, a;
ColorUtil::unpack_colors(buffer[i], r, g, b, a);
ofs << r << g << b;
}
ofs.close();
}
};
class Window {
public:
Screen *screen;
size_t o_x; // origin
size_t o_y;
size_t w;
size_t h;
Window(const Window & window)
: screen(window.screen), o_x(window.o_x), o_y(window.o_y), w(window.w), h(window.h) {
screen->windows.push_back(this);
};
Window(Screen *screen, size_t o_x = 0, size_t o_y = 0, size_t w = 512,
size_t h = 512)
: screen(screen), o_x(o_x), o_y(o_y), w(w), h(h) {
screen->windows.push_back(this);
};
uint32_t &access_virtual_buffer(size_t x, size_t y, bool &err) {
size_t global_index = (x + o_x) + (y + o_y) * screen->w;
if (global_index >= screen->w * screen->h) {
err = true;
return screen->buffer[0]; // or segmenation fault
}
return screen->buffer[global_index];
}
void
draw_rectangle_global(const size_t x, const size_t y, const size_t rec_w,
const size_t rec_h,
const uint32_t color) { // treat (o_x,o_y) as the origin
for (size_t i = 0; i < rec_w; i++)
for (size_t j = 0; j < rec_h; j++) {
bool err = false;
size_t cx = x + i;
size_t cy = y + j;
// assert(cx < w && cy < h);
if (cx >= w || cy >= h)
continue;
screen->buffer[cx + cy * w] = color;
}
}
void draw_rectangle_in_window(
const size_t x, const size_t y, const size_t rec_w, const size_t rec_h,
const uint32_t color) { // treat (o_x,o_y) as the origin
for (size_t i = 0; i < rec_w; i++)
for (size_t j = 0; j < rec_h; j++) {
bool err = false;
size_t cx = x + i;
size_t cy = y + j;
// assert(cx < w && cy < h);
if (cx >= w || cy >= h)
continue;
uint32_t &virtual_buffer = access_virtual_buffer(cx, cy, err);
if (err)
continue;
virtual_buffer = color;
}
}
void reset_origin(const size_t x,
const size_t y) { // treat (x,y) as the new origin
this->o_x = x; // won't cause chaos?
this->o_y = y;
}
virtual void render(){}; // render here basically means updating the buffer
};
class Player {
public:
Screen *screen;
LocalMiniMap *minimap = nullptr;
FPV *fpv = nullptr;
float x = 3.456; // unit: grid
float y = 2.345;
float a = 1.3; // start angle, the angle between the direction and the x-axis
float fov = PI / 3; // field of view
size_t num_laser = 512;
uint32_t color = 0xFFFFFFFF;
Player(Screen *screen, float x = 3.456, float y = 2.345, float a = 1.3,
float fov = PI / 3, uint32_t color = 0xFFFFFFFF)
: screen(screen), x(x), y(y), a(a), fov(fov), color(color) {};
// void draw_radar(float fov = PI / 3); // draw radar, the lines of sight
// void draw_FPV(float dis, size_t index); // draw first person view
// dis: the distance to the wall
// index: the index of the current laser
// num_laser: the number of lasers
// default: num_laser = window->minimap_w, a laser per pixel
};
class LocalMiniMap : public Window {
public:
Player *player;
const char *matrix;
size_t grid_w = 16;
size_t grid_h = 16;
size_t cell_w;
size_t cell_h;
LocalMiniMap(const Window &window, const char *matrix, size_t grid_w = 16,
size_t grid_h = 16, Player *player = nullptr)
: Window(window), matrix(matrix), grid_w(grid_w), grid_h(grid_h),
player(player) {
cell_w = w / grid_w; // not window's width but the view's width
cell_h = h / grid_h;
init_ground();
init_wall();
};
void init_ground() {
for (size_t i = 0; i < w; i++)
for (size_t j = 0; j < h; j++) {
draw_rectangle_in_window(
i, j, 1, 1,
ColorUtil::pack_colors(255 * i / float(w), 0, 255 * j / float(h)));
}
}
void init_wall() {
for (size_t j = 0; j < grid_h; j++)
for (size_t i = 0; i < grid_w; i++) {
if (matrix[i + j * grid_w] == '0')
continue;
draw_rectangle_in_window(i * cell_w, j * cell_h, cell_w, cell_h,
ColorUtil::colors[matrix[i + j * grid_w] - '0']);
}
}
void draw_player() {
size_t px = player->x * cell_w;
size_t py = player->y * cell_h;
draw_rectangle_in_window(px, py, 5, 5,
ColorUtil::pack_colors(255, 255, 255));
}
float shoot_laser(float angle, const uint32_t color, uint32_t& brick_color, bool draw = true) {
float l = 0;
for (; l < 20; l += 0.01) { //l+=0.05 will cause sawtooth
float cx = player->x + l * cos(angle); // logic coordinates
float cy = player->y + l * sin(angle);
size_t pix_x = int(cx * cell_w); // pixel coordinates
size_t pix_y = int(cy * cell_h);
if (draw)
draw_rectangle_in_window(pix_x, pix_y, 1, 1, color);
if (matrix[int(cx) + int(cy) * grid_w] != '0') {
//draw_rectangle_in_window(pix_x, pix_y, 1, 1, ColorUtil::pack_colors(0, 255, 0));
brick_color = ColorUtil::colors[matrix[int(cx) + int(cy) * grid_w] - '0'];
break;
}
}
return l;
}
void draw_radar() {
float player_ca = player->a;
uint32_t brick_color;
for (size_t i = 0; i < (player->num_laser); i++) {
shoot_laser(player_ca, ColorUtil::pack_colors(255, 255, 255),brick_color, true);
player_ca += player->fov / player->num_laser;
}
}
void render() override {
draw_player();
draw_radar();
}
};
class FPV : public Window {
public:
Player *player;
FPV(Window &window, Player *player)
: Window(window), player(player) {
};
void draw_FPV(size_t i,float dis,uint32_t color = ColorUtil::pack_colors(255, 255, 255)) {
/*draw_rectangle_in_window(i, float(h) / 2.0 * (1.0 - 1.0 / dis), 1, float(h) / dis,
ColorUtil::pack_colors(255, 255, 255));*/
draw_rectangle_in_window(i, float(h) / 2.0 * (1.0 - 1.0 / dis), 1, float(h) / dis,
color);
//printf h/dis
//printf("h/dis: %zu\n", static_cast<size_t>(h / dis));
}
void render() override {
float player_ca = player->a;
for (size_t i = 0; i < w; i++) {
uint32_t brick_color;
float dis = player->minimap->shoot_laser(player_ca, ColorUtil::pack_colors(255, 255, 255),brick_color, false);
//printf("dis: %f\n", dis);
draw_FPV(i,dis,brick_color);
player_ca += player->fov / w;
}
}
};
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 255);
for(int i = 0; i < 256; i++) {
ColorUtil::colors.push_back(ColorUtil::pack_colors(dis(gen), dis(gen), dis(gen)));
}
const char matrix[] = "1111111111111111"
"1000000000000001"
"1000000000000001"
"1000555511000001"
"1000100000000001"
"1000100077711111"
"1000100000000001"
"1000100000000001"
"1000122222200001"
"1000003000900001"
"1000003000866111"
"1000000000800001"
"1000144111800001"
"1000100000000001"
"1000000000000001"
"1111111111111111";
Screen screen(1024, 1024);
Window window1(&screen, 0, 0, 512, 512);
Window window2(&screen, 512, 0, 512, 512);
Player player(&screen, 2.456, 10.345, -0.6, PI / 3, 0xFFFFFFFF);
LocalMiniMap minimap(window1, matrix, 16, 16, &player);
FPV fpv(window2, &player);
player.minimap = &minimap;
player.fpv = &fpv;
minimap.render();
fpv.render();
//add a player with different parameters
Window window3(&screen, 0, 512, 512, 512);
Window window4(&screen, 512, 512, 512, 512);
Player player2(&screen, 12.456, 8.345, 3, PI / 3, 0xFFFFFFFF);
LocalMiniMap minimap2(window3, matrix, 16, 16, &player2);
FPV fpv2(window4, &player2);
player2.minimap = &minimap2;
player2.fpv = &fpv2;
minimap2.render();
fpv2.render();
screen.to_ppm("./screen.ppm");
return 0;
}