screen.c (2575B)
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include <stddef.h>
5 #include "vm.h"
6 #include "scene.h"
7 #include "image.h"
8
9 #define TA_SCREEN_NONE (-1)
10
11 typedef struct {
12 uint32_t init;
13 uint32_t update;
14 uint32_t destroy;
15 bool registered;
16 } ta_screen_entry;
17
18 static ta_screen_entry *screens;
19 static uint32_t screen_count;
20 static int32_t current_screen;
21 static int32_t pending_screen;
22
23 static void screens_clear(void) {
24 if (screens != NULL) {
25 free(screens);
26 }
27
28 screens = NULL;
29 screen_count = 0;
30 }
31
32 static bool screens_grow(uint32_t new_count) {
33 ta_screen_entry *grown = (ta_screen_entry *)malloc((size_t)new_count * sizeof(ta_screen_entry));
34
35 if (grown == NULL) {
36 return false;
37 }
38
39 for (uint32_t i = 0; i < screen_count; i++) {
40 grown[i] = screens[i];
41 }
42
43 for (uint32_t i = screen_count; i < new_count; i++) {
44 grown[i].init = 0;
45 grown[i].update = 0;
46 grown[i].destroy = 0;
47 grown[i].registered = false;
48 }
49
50 if (screens != NULL) {
51 free(screens);
52 }
53
54 screens = grown;
55 screen_count = new_count;
56
57 return true;
58 }
59
60 void ta_screen_init(void) {
61 screens_clear();
62
63 current_screen = TA_SCREEN_NONE;
64 pending_screen = TA_SCREEN_NONE;
65 }
66
67 bool ta_screen_register(uint32_t id, uint32_t init, uint32_t update, uint32_t destroy) {
68 if (id == 0xFFFFFFFFu) {
69 return false;
70 }
71
72 if (id >= screen_count && !screens_grow(id + 1)) {
73 return false;
74 }
75
76 screens[id].init = init;
77 screens[id].update = update;
78 screens[id].destroy = destroy;
79 screens[id].registered = true;
80
81 return true;
82 }
83
84 bool ta_screen_switch(uint32_t id) {
85 if (id >= screen_count || !screens[id].registered) {
86 return false;
87 }
88
89 pending_screen = (int32_t)id;
90
91 return true;
92 }
93
94 bool ta_screen_update(void) {
95 while (pending_screen != TA_SCREEN_NONE) {
96 int32_t next_screen = pending_screen;
97
98 pending_screen = TA_SCREEN_NONE;
99
100 if (current_screen != TA_SCREEN_NONE && screens[current_screen].destroy != 0) {
101 if (!ta_vm_call(screens[current_screen].destroy, 0, 0, 0, NULL)) {
102 return false;
103 }
104 }
105
106 current_screen = next_screen;
107
108 if (screens[current_screen].init != 0) {
109 if (!ta_vm_call(screens[current_screen].init, 0, 0, 0, NULL)) {
110 return false;
111 }
112 }
113 }
114
115 if (current_screen == TA_SCREEN_NONE || screens[current_screen].update == 0) {
116 return false;
117 }
118
119 ta_scene_begin();
120
121 if (!ta_vm_call(screens[current_screen].update, 0, 0, 0, NULL)) {
122 return false;
123 }
124
125 return ta_scene_end();
126 }
127
128 void ta_screen_destroy(void) {
129 current_screen = TA_SCREEN_NONE;
130 pending_screen = TA_SCREEN_NONE;
131 ta_scene_invalidate();
132
133 screens_clear();
134
135 ta_image_release();
136 }