-
Notifications
You must be signed in to change notification settings - Fork 0
/
graphics.js
182 lines (145 loc) · 6.75 KB
/
graphics.js
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
const GRAPHICS_DEBUG = false;
// NOTE: These must match in graphics/mod.rs
const MAX_DRAW_ARRAY_SIZE = 500;
const MAX_STRING_ARRAY_SIZE = 1000;
// NOTE: These must match in graphics/drawables.rs
const DRAW_RECT_SIZE = 5;
const DRAW_ACTION_COLOR_SIZE = 5;
const STRING_PROPERTIES_SIZE = 4;
const DRAW_ROTATION_SIZE = 2;
let rectMemory;
let stringMemory;
let stringPropertyMemory;
let colorMemory;
const initGraphics = (graphics, wasm) => {
rectMemory = new Float32Array(wasm.memory.buffer, graphics.draw_rects_ptr(), MAX_DRAW_ARRAY_SIZE * DRAW_RECT_SIZE);
stringMemory = new Uint8Array(wasm.memory.buffer, graphics.strings_ptr(), MAX_STRING_ARRAY_SIZE);
stringPropertyMemory = new Float32Array(wasm.memory.buffer, graphics.string_properties_ptr(), MAX_DRAW_ARRAY_SIZE * STRING_PROPERTIES_SIZE);
colorMemory = new Uint8Array(wasm.memory.buffer, graphics.draw_action_colors_ptr(), MAX_DRAW_ARRAY_SIZE * DRAW_ACTION_COLOR_SIZE);
rotationsMemory = new Float32Array(wasm.memory.buffer, graphics.rotations_ptr(), MAX_DRAW_ARRAY_SIZE * DRAW_ROTATION_SIZE);
}
const drawGraphics = (ctx, canvas, graphics) => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
// Right now we only support text that is center aligned
ctx.textAlign = 'center';
let rectArrayLength = graphics.draw_rects_len();
let stringArrayLength = graphics.string_properties_len();
let colorArrayLength = graphics.draw_action_colors_len();
if (GRAPHICS_DEBUG) { console.log("rectArrayLength: %O | stringArrayLength: %O | colorArrayLength: %O", rectArrayLength, stringArrayLength, colorArrayLength) }
let rectIndex = 0;
let stringPropertyIndex = 0;
let stringIndex = 0;
let colorIndex = 0;
let rotationIndex = 0;
let endOrdering = rectArrayLength + stringArrayLength;
for (let ordering = 1; ordering <= endOrdering; ordering++) {
// check if we need to change the fillStyle first
if (colorIndex < colorArrayLength) {
let colorStartIndex = colorIndex * DRAW_ACTION_COLOR_SIZE;
let color_ordering = colorMemory[colorStartIndex];
if (color_ordering == ordering) {
let alpha = colorMemory[colorStartIndex + 4] / 255;
ctx.fillStyle = 'rgba(' +
colorMemory[colorStartIndex + 1] + ',' +
colorMemory[colorStartIndex + 2] + ',' +
colorMemory[colorStartIndex + 3] + ',' +
alpha +
')';
colorIndex++;
}
}
let angle = 0.0;
let set_angle = false;
let rotationStartIndex = rotationIndex * DRAW_ROTATION_SIZE;
let rotationOrdering = rotationsMemory[rotationStartIndex];
if (rotationOrdering == ordering) {
angle = rotationsMemory[rotationStartIndex + 1];
set_angle = true;
rotationIndex++;
}
let stringPropertyStartIndex = stringPropertyIndex * STRING_PROPERTIES_SIZE;
let rectStartIndex = rectIndex * DRAW_RECT_SIZE;
// truncate float to int
let rectOrdering = rectMemory[rectStartIndex] | 0;
let stringPropertyOrdering = stringPropertyMemory[stringPropertyStartIndex] | 0;
if (GRAPHICS_DEBUG) { console.log("Looking for ordering: " + ordering + " | stringPropertyIndex: " + stringPropertyIndex + " | rectIndex: " + rectIndex + " | rectMemory[rectStartIndex]: " + rectMemory[rectStartIndex] + " | stringPropertyMemory[stringPropertyStartIndex]: " + stringPropertyMemory[stringPropertyStartIndex]); }
if (rectIndex < rectArrayLength && rectOrdering == ordering) {
let pos_x = rectMemory[rectStartIndex + 1];
let pos_y = rectMemory[rectStartIndex + 2];
let width = rectMemory[rectStartIndex + 3];
let height = rectMemory[rectStartIndex + 4];
// The native canvas renders from top-left as (0, 0)
// Let's flip the y axis so that it renders from bottom-left (sanely)
pos_y = canvas.height - pos_y - height;
if (GRAPHICS_DEBUG) { console.log("DrawRect (ordering: " + ordering + ") " + "| pos_x: " + pos_x + "| pos_y: " + pos_y + "| width: " + width + "| height: " + height); }
let half_width = (width / 2.0);
let half_height = (height / 2.0);
let center_x = pos_x + half_width;
let center_y = pos_y + half_height;
ctx.translate(center_x, center_y);
if (set_angle) { ctx.rotate(angle * Math.PI / 180); }
ctx.fillRect(-half_width, -half_height, width, height);
rectIndex++;
} else if (stringPropertyIndex < stringArrayLength && stringPropertyOrdering == ordering) {
let pos_x = stringPropertyMemory[stringPropertyStartIndex + 1];
let pos_y = stringPropertyMemory[stringPropertyStartIndex + 2];
let fontSize = stringPropertyMemory[stringPropertyStartIndex + 3];
// The native canvas renders from top-left as (0, 0)
// Let's flip the y axis so that it renders from bottom-left (sanely)
pos_y = canvas.height - pos_y;
// Consume the current string in stringMemory, incrementing the stringIndex
let lastIndex;
for (lastIndex = stringIndex; stringMemory[lastIndex] != 0; lastIndex++);
let data = stringMemory.slice(stringIndex, lastIndex);
stringIndex = lastIndex + 1;
let string = stringFromUTF8Array(data);
if (string == null) {
console.log("Failed to parse string from raw data! Investigate this.");
}
if (GRAPHICS_DEBUG) { console.log("DrawString (ordering: " + ordering + ") | string: " + string + " | pos_x: " + pos_x + " | pos_y: " + pos_y + " | fontSize: " + fontSize); }
let fontText = fontSize.toFixed(2) + 'px sans-serif';
if (ctx.font != fontText) {
ctx.font = fontText;
}
// TODO (darren): rotation does not work perfectly for strings
// ctx.translate(pos_x, pos_y);
// if (set_angle) { ctx.rotate(angle * Math.PI / 180); }
ctx.fillText(string, pos_x, pos_y);
stringPropertyIndex++;
} else {
// Incident Report (05/14/2018): One possibility is that the WASM memory
// reached its limit and reallocated? Reducing buffer size fixed this.
throw new Error("Failed to find ordering in rect / string arrays! This is not good, investigate!");
}
// reset current transformation matrix to the identity matrix
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
ctx.stroke();
graphics.reset();
};
function stringFromUTF8Array(data) {
const extraByteMap = [ 1, 1, 1, 1, 2, 2, 3, 0 ];
var count = data.length;
var str = "";
for (var index = 0;index < count;)
{
var ch = data[index++];
if (ch & 0x80)
{
var extra = extraByteMap[(ch >> 3) & 0x07];
if (!(ch & 0x40) || !extra || ((index + extra) > count))
return null;
ch = ch & (0x3F >> extra);
for (;extra > 0;extra -= 1)
{
var chx = data[index++];
if ((chx & 0xC0) != 0x80)
return null;
ch = (ch << 6) | (chx & 0x3F);
}
}
str += String.fromCharCode(ch);
}
return str;
}