scene.c (5093B)
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <stdbool.h>
5 #include "fixed.h"
6 #include "fb.h"
7 #include "image.h"
8 #include "text.h"
9 #include "shapes.h"
10
11 typedef struct {
12 const uint8_t *data;
13 ta_text *text;
14 uint32_t length;
15 uint32_t x;
16 uint32_t y;
17 uint32_t width;
18 uint32_t height;
19 uint16_t frame;
20 uint32_t shape_type;
21 uint32_t shape_args[6];
22 uint32_t color;
23 uint8_t sprites_after;
24 } ta_scene_op;
25
26 static ta_scene_op *ops[2];
27 static size_t counts[2];
28 static size_t capacities[2];
29 static uint8_t current;
30 static bool valid;
31 static uint16_t last_width;
32 static uint16_t last_height;
33 static uint8_t last_bpp;
34
35 static bool same(const ta_scene_op *a, const ta_scene_op *b) {
36 return a->data == b->data
37 && a->text == b->text
38 && a->length == b->length
39 && a->x == b->x
40 && a->y == b->y
41 && a->width == b->width
42 && a->height == b->height
43 && a->frame == b->frame
44 && a->shape_type == b->shape_type
45 && a->color == b->color
46 && a->shape_args[0] == b->shape_args[0]
47 && a->shape_args[1] == b->shape_args[1]
48 && a->shape_args[2] == b->shape_args[2]
49 && a->shape_args[3] == b->shape_args[3]
50 && a->shape_args[4] == b->shape_args[4]
51 && a->shape_args[5] == b->shape_args[5];
52 }
53
54 static ta_scene_op *push(void) {
55 if (counts[current] == capacities[current]) {
56 size_t new_capacity = capacities[current] + 1;
57 ta_scene_op *grown = (ta_scene_op *)malloc(new_capacity * sizeof(ta_scene_op));
58
59 if (grown == NULL) {
60 return NULL;
61 }
62
63 for (size_t i = 0; i < counts[current]; i++) {
64 grown[i] = ops[current][i];
65 }
66
67 free(ops[current]);
68
69 ops[current] = grown;
70 capacities[current] = new_capacity;
71 }
72
73 ta_scene_op *op = &ops[current][counts[current]++];
74
75 op->data = NULL;
76 op->text = NULL;
77 op->length = 0;
78 op->x = 0;
79 op->y = 0;
80 op->width = 0;
81 op->height = 0;
82 op->frame = 0;
83 op->shape_type = 0;
84
85 for (uint32_t i = 0; i < 6; i++) {
86 op->shape_args[i] = 0;
87 }
88
89 op->color = 0;
90 op->sprites_after = 0;
91
92 return op;
93 }
94
95 static void sprites_trim(uint8_t count) {
96 while (ta_display_sprites && ta_display_sprites->count > count) {
97 ta_display_sprite_free(ta_display_sprites->sprites[ta_display_sprites->count - 1]);
98 }
99 }
100
101 void ta_scene_invalidate(void) {
102 valid = false;
103 }
104
105 void ta_scene_begin(void) {
106 counts[current] = 0;
107
108 if (ta_display->width != last_width || ta_display->height != last_height || ta_display->bpp != last_bpp) {
109 last_width = ta_display->width;
110 last_height = ta_display->height;
111 last_bpp = ta_display->bpp;
112 valid = false;
113 }
114 }
115
116 bool ta_scene_image(const uint8_t *data, uint32_t length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, uint16_t frame) {
117 ta_scene_op *op = push();
118
119 if (op == NULL) {
120 return false;
121 }
122
123 op->data = data;
124 op->length = length;
125 op->x = x;
126 op->y = y;
127 op->width = width;
128 op->height = height;
129 op->frame = frame;
130
131 return true;
132 }
133
134 bool ta_scene_shape(uint32_t type, const uint32_t *args, uint32_t color) {
135 ta_scene_op *op = push();
136
137 if (op == NULL || args == NULL || type < 1 || type > 4) {
138 return false;
139 }
140
141 op->shape_type = type;
142 op->color = color;
143
144 for (uint32_t i = 0; i < 6; i++) {
145 op->shape_args[i] = args[i];
146 }
147
148 return true;
149 }
150
151 bool ta_scene_text(ta_text *text, uint32_t x, uint32_t y) {
152 ta_scene_op *op = push();
153
154 if (op == NULL) {
155 return false;
156 }
157
158 op->text = text;
159 op->color = ((uint32_t)text->red << 16) | ((uint32_t)text->green << 8) | text->blue;
160 op->x = x;
161 op->y = y;
162
163 return true;
164 }
165
166 bool ta_scene_end(void) {
167 ta_scene_op *now = ops[current];
168 ta_scene_op *before = ops[current ^ 1];
169 size_t now_count = counts[current];
170 size_t before_count = counts[current ^ 1];
171 size_t prefix = 0;
172
173 if (valid) {
174 while (prefix < now_count && prefix < before_count && same(&now[prefix], &before[prefix])) {
175 prefix++;
176 }
177
178 if (prefix == now_count && prefix == before_count) {
179 return false;
180 }
181 }
182
183 size_t start = ta_display->sprite_mode ? prefix : 0;
184
185 if (start == 0) {
186 ta_fb_clear(ta_display);
187 } else {
188 sprites_trim(before[start - 1].sprites_after);
189
190 for (size_t i = 0; i < start; i++) {
191 now[i].sprites_after = before[i].sprites_after;
192 }
193 }
194
195 for (size_t i = start; i < now_count; i++) {
196 ta_scene_op *op = &now[i];
197
198 if (op->shape_type != 0) {
199 uint32_t *a = op->shape_args;
200 if (op->shape_type == 1) {
201 ta_shapes_draw_pixel(a[0], a[1], op->color);
202 } else if (op->shape_type == 2) {
203 ta_shapes_draw_rectangle(a[0], a[1], a[2], a[3], op->color);
204 } else if (op->shape_type == 3) {
205 ta_shapes_draw_triangle(a[0], a[1], a[2], a[3], a[4], a[5], op->color);
206 } else {
207 ta_shapes_draw_oval(a[0], a[1], a[2], a[3], op->color);
208 }
209 } else if (op->text != NULL) {
210 op->text->x = op->x;
211 op->text->y = op->y;
212 ta_text_draw(op->text);
213 } else {
214 ta_image_draw(op->data, op->length, op->x, op->y, op->width, op->height, op->frame);
215 }
216
217 op->sprites_after = ta_display_sprites ? ta_display_sprites->count : 0;
218 }
219
220 valid = true;
221 current ^= 1;
222
223 return true;
224 }