This repository was archived by the owner on Dec 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcamera.c
More file actions
137 lines (117 loc) · 3.51 KB
/
camera.c
File metadata and controls
137 lines (117 loc) · 3.51 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
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/* system */
#ifdef __linux__
#include <sys/ioctl.h>
#elif _WIN32
// todo
#endif
#include "camera.h"
#include "map.h"
#include "utils.h"
static const char NIL_CHAR = '`';
static const char ROW_CHAR = '-';
static const char COL_CHAR = '|';
static const char CORNER_CHAR = '+';
static const uint16_t PADDING[2] = {2, 4};
static const uint16_t SLEEP_TIME = 30000; /* us */
struct camera {
/* position */
int16_t posY;
int16_t posX;
/* border */
uint16_t height;
uint16_t width;
/* string content (1d) */
char *view;
};
/* lazy single instance */
static Camera* instance;
/* system: get console char size */
static void getWindowSize(uint16_t *h, uint16_t *w) {
#ifdef __linux__
struct winsize max;
ioctl(0, TIOCGWINSZ, &max);
*h = max.ws_row, *w = max.ws_col;
#elif _WIN32
// todo
#endif
}
static inline uint32_t pos(const Camera *c, const int y, const int x) {
return (PADDING[0] + y) * c->width + PADDING[1] + x;
}
static inline void display() {
/* system("clear"); */
// todo color
printf("%s", instance->view);
usleep(SLEEP_TIME);
}
static void drawBorder(const Camera *c) {
const uint16_t ch = c->height, cw = c->width,
rh = ch - (PADDING[0] << 1), rw = cw - (PADDING[1] << 1);
memset(c->view, ' ', ch * cw);
/* draw char */
for (uint16_t i = 0; i < rw; ++ i)
c->view[pos(c, 0, i)] = c->view[pos(c, rh - 1, i)] = ROW_CHAR;
for (uint16_t i = 0; i < rh ; ++ i)
c->view[pos(c, i, 0)] = c->view[pos(c, i, rw - 1)] = COL_CHAR;
c->view[pos(c, 0, 0)]
= c->view[pos(c, 0, rw - 1)]
= c->view[pos(c, rh - 1, 0)]
= c->view[pos(c, rh - 1, rw - 1)]
= CORNER_CHAR;
/* fix line */
for (uint16_t i = 0; i < ch - 1; ++ i)
c->view[i * cw + cw - 1] = '\n';
/* final end */
c->view[( ch - 1 ) * cw] = 0;
}
static void projectMap2Content(const Camera *c, const Map *m) {
const int16_t y = c->posY, x = c->posX;
const uint16_t rh = c->height - (PADDING[0] << 1) , rw = c->width - (PADDING[1] << 1),
/* content size = border size - 2*/
rch = rh - 2, rcw = rw - 2,
mh = getMapH(m), mw = getMapW(m),
/* cross block position */
py1 = y < 0 ? -y : 0, px1 = x < 0 ? -x : 0,
py2 = MIN(mh, rch + y) - y, px2 = MIN(mw, rcw + x) - x;
char ct[rch][rcw];
/* init unreachable content char */
memset(ct, NIL_CHAR, rch * rcw);
/* cut a map block */
for (uint16_t i = py1; i < py2; ++ i)
for (uint16_t j = px1; j < px2; ++ j)
ct[i][j] = getMapCh(m, i + y, j + x);
/* draw view */
for (uint16_t i = 0; i < rch; ++ i)
for (uint16_t j = 0; j < rcw; ++ j)
c->view[pos(c, i + 1, j + 1)] = ct[i][j];
}
static Camera* initCamera() {
Camera *c = (Camera*)malloc(sizeof(Camera));
getWindowSize(&c->height, &c->width);
c->view = (char*)malloc(c->height * c->width);
drawBorder(c);
return c;
}
Camera* getCamera() {
if (!instance) instance = initCamera();
return instance;
}
void cleanCamera(Camera *c) {
free(c->view), free(c);
}
void updateCamera(Camera *c, const int16_t y, const int16_t x, const Map *m) {
uint16_t h, w;
getWindowSize(&h, &w);
if (h != c->height || w != c->width) {
c->height = h, c->width = w;
drawBorder(c);
}
c->posY = y, c->posX = x;
if (m != NULL) projectMap2Content(c, m);
display();
}