-
Notifications
You must be signed in to change notification settings - Fork 0
/
screen.cpp
133 lines (125 loc) · 3.74 KB
/
screen.cpp
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
#include "screen.h"
#include "util.h"
#include "df/enabler.h"
#include "df/graphic.h"
#include "df/renderer.h"
using df::global::enabler;
using df::global::gps;
using namespace DFHack;
using namespace tthread;
using namespace yadc;
static uint8_t old_buffer[256 * 256 * 3];
static struct {
bool tiles;
bool events;
} update;
static float colors[16][3];
void screen::invalidate()
{
memset(&update, 1, sizeof(update));
}
uint32_t screen::serialize_changed (uint8_t* dest, int maxlength)
{
// Serialize all changed tiles
// Each tile is represented by 5 bytes: x, y, ch, fg, bg
static int dimx = -1, dimy = -1;
uint8_t* p = dest;
bool incomplete = false;
for (int y = 0; y < gps->dimy; y++)
{
for (int x = 0; x < gps->dimx; x++)
{
if (p + 5 - dest > maxlength)
{
incomplete = true;
break;
}
const int raw_tile = x * gps->dimy + y;
// old_buffer is a constant size, which ensures that tiles are
// properly updated when the screen dimensions change
uint8_t* old_buffer_tile = old_buffer + ((x * 256 + y) * 3);
uint8_t* screen_tile = (uint8_t*)enabler->renderer->screen + (raw_tile * 4);
uint8_t ch = screen_tile[0];
uint8_t fg = (screen_tile[1] + (8 * screen_tile[3])) % 16;
uint8_t bg = screen_tile[2] % 16;
if (ch == 0 || ch == 32)
{
// characters 0 and 32 should be identical in tilesets, due to
// both being used for blank space in various places
// additionally, their foreground color does not matter
ch = 0;
fg = 0;
}
if (!update.tiles &&
old_buffer_tile[0] == ch &&
old_buffer_tile[1] == fg &&
old_buffer_tile[2] == bg &&
// Send newly-visible tiles, even if the same tiles have been displayed
// in this location previously
x < dimx && y < dimy
)
continue;
*(p++) = x;
*(p++) = y;
*(p++) = ch;
*(p++) = fg;
*(p++) = bg;
old_buffer_tile[0] = ch;
old_buffer_tile[1] = fg;
old_buffer_tile[2] = bg;
}
}
dimx = gps->dimx;
dimy = gps->dimy;
if (!incomplete)
update.tiles = false;
uint32_t len = (uint32_t)(p - dest);
return len;
}
bool update_colors()
{
bool changed = false;
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 3; j++)
{
if (colors[i][j] != enabler->ccolor[i][j])
{
colors[i][j] = enabler->ccolor[i][j];
changed = true;
}
}
}
return changed;
}
uint32_t screen::serialize_events (uint8_t* dest, int maxlength)
{
static int dimx = -1, dimy = -1;
Json::Value events;
if (update.events || dimx != gps->dimx || dimy != gps->dimy)
{
events["dims"]["x"] = gps->dimx;
events["dims"]["y"] = gps->dimy;
dimx = gps->dimx;
dimy = gps->dimy;
}
bool colors_changed = update_colors();
if (update.events || colors_changed)
{
Json::Value all_colors;
for (int i = 0; i < 16; i++)
{
Json::Value cur_color;
for (int j = 0; j < 3; j++)
cur_color.append((int)(255.0 * colors[i][j]));
all_colors.append(cur_color);
}
events["colors"] = all_colors;
}
if (events.empty())
return 0;
std::string json = Json::toSimpleString(events);
strncpy((char*)dest, json.c_str(), maxlength);
update.events = false;
return json.size();
}