added event system a-la FUSE (because i'm going to steal FUSE FDC emulation code)
[zymosis.git] / src / ZXEmuT / emuevents.c
blob460de07d6e671fe89a6a16de936421163d3d28cd
1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #include "emuevents.h"
23 typedef struct {
24 char *name;
25 uint32_t type;
26 } KnownEvent;
28 static KnownEvent *knownEvTypes = NULL;
29 static uint32_t knownEvAlloted = 0;
30 static uint32_t knownEvUsed = 0;
32 static EmuEvent *evList = NULL;
33 static uint32_t evListAlloted = 0;
34 static uint32_t evListUsed = 0;
36 static EmuEvHandlerCB *evHandlers = NULL;
37 static uint32_t evHandlersAlloted = 0;
38 static uint32_t evHandlersUsed = 0;
41 uint32_t emuEvLastFrameCallTS = 0;
44 //==========================================================================
46 // emuEvRegisterHandler
48 // register new event handler
50 //==========================================================================
51 void emuEvRegisterHandler (EmuEvHandlerCB cb) {
52 if (!cb) return;
53 for (uint32_t f = 0; f < evHandlersUsed; ++f) {
54 if (evHandlers[f] == cb) return;
56 if (evHandlersUsed == evHandlersAlloted) {
57 evHandlersAlloted += 128;
58 evHandlers = realloc(evHandlers, sizeof(EmuEvHandlerCB)*evHandlersAlloted);
59 if (!evHandlers) {
60 fprintf(stderr, "FATAL: out of memory for event handlers!\n");
61 __builtin_trap();
64 evHandlers[evHandlersUsed++] = cb;
69 //==========================================================================
71 // emuEvRegister
73 // register new event; never returns 0
75 //==========================================================================
76 uint32_t emuEvRegister (const char *name) {
77 if (!name || !name[0]) {
78 name = "<anonymous>";
79 } else {
80 for (uint32_t f = 0; f < knownEvUsed; ++f) {
81 if (strcmp(knownEvTypes[f].name, name) == 0) {
82 fprintf(stderr, "FATAL: duplicate event name '%s'!\n", name);
83 __builtin_trap();
88 if (knownEvUsed == knownEvAlloted) {
89 knownEvAlloted += 1024;
90 knownEvTypes = realloc(knownEvTypes, sizeof(KnownEvent)*knownEvAlloted);
91 if (!knownEvTypes) {
92 fprintf(stderr, "FATAL: out of memory for event types!\n");
93 __builtin_trap();
97 if (!(knownEvTypes[knownEvUsed].name = strdup(name))) {
98 fprintf(stderr, "FATAL: out of memory for event types!\n");
99 __builtin_trap();
102 knownEvTypes[knownEvUsed].type = knownEvUsed+1;
104 return ++knownEvUsed;
108 //==========================================================================
110 // emuEvNameByType
112 // get event name by its type
114 //==========================================================================
115 const char *emuEvNameByType (uint32_t type) {
116 if (type == 0) return "<null event>";
117 if (type > knownEvUsed) return "<invalid event>";
118 return knownEvTypes[knownEvUsed-1].name;
122 //==========================================================================
124 // emuEvClear
126 // clear all events
128 //==========================================================================
129 void emuEvClear (void) {
130 evListUsed = 0;
134 //==========================================================================
136 // emuEvForceTimePassed
138 // called when one frame passed
139 // fixes tstates for all events, drops out unprocessed frame events
141 //==========================================================================
143 void emuEvForceTimePassed (uint32_t tskip) {
144 if (!tskip) return;
145 uint32_t evnext = 0;
146 while (evnext < evListUsed && evList[evnext].tstates < tskip) ++evnext;
147 if (evnext >= evListUsed) {
148 evListUsed = 0;
149 } else {
150 memcpy(&evList[0], &evList[evnext], (evListUsed-evnext)*sizeof(EmuEvent));
151 evListUsed -= evnext;
152 for (uint32_t f = 0; f < evListUsed; ++f) evList[f].tstates -= tskip;
158 //==========================================================================
160 // emuTimePassed
162 // pass time, call event handlers
163 // it is ok to add new events from handlers
165 //==========================================================================
166 void emuTimePassed (uint32_t tskip) {
167 while (evListUsed && evList[0].tstates <= tskip) {
168 EmuEvent ev = evList[0];
169 if (--evListUsed) {
170 memcpy(&evList[0], &evList[1], evListUsed*sizeof(EmuEvent));
171 for (uint32_t f = 0; f < evListUsed; ++f) {
172 evList[f].tstates -= ev.tstates;
175 tskip -= ev.tstates;
176 for (uint32_t f = 0; f < evHandlersUsed; ++f) evHandlers[f](&ev);
182 //==========================================================================
184 // emuEvRemoveAllWithType
186 // remove all events with the given type
188 //==========================================================================
189 void emuEvRemoveAllWithType (uint32_t type) {
190 uint32_t ev = 0;
191 while (ev < evListUsed) {
192 if (evList[ev].type == type) {
193 if (ev != evListUsed-1U) memcpy(&evList[ev], &evList[ev+1], (evListUsed-1U)*sizeof(EmuEvent));
194 --evListUsed;
195 } else {
196 ++ev;
202 //==========================================================================
204 // emuEvAdd
206 // append new event
207 // tstates is tstates from the current event time
209 //==========================================================================
210 void emuEvAdd (uint32_t tstates, uint32_t type, void *udata) {
211 if (evListUsed == evListAlloted) {
212 evListAlloted += 1024;
213 evList = realloc(evList, evListAlloted*sizeof(EmuEvent));
214 if (!evList) {
215 fprintf(stderr, "FATAL: out of memory for emulator event queue!\n");
216 __builtin_trap();
220 // find where we should put our event
221 uint32_t evidx = 0;
222 if (evListUsed) {
223 while (evidx < evListUsed && evList[evidx].tstates <= tstates) ++evidx;
224 // insert AFTER evidx
225 if (evidx != evListUsed) {
226 // make room
227 memmove(&evList[evidx+1], &evList[evidx], (evListUsed-evidx-1)*sizeof(EmuEvent));
230 ++evListUsed;
232 evList[evidx].tstates = tstates;
233 evList[evidx].type = type;
234 evList[evidx].udata = udata;
238 //==========================================================================
240 // emuEvNextTime
242 // peek next event time; returns `EMU_EV_NONE` if there are no events
244 //==========================================================================
245 uint32_t emuEvNextTime (void) {
246 return (evListUsed ? evList[0].tstates : EMU_EV_NONE);
250 //==========================================================================
252 // emuEvGet
254 // get next event
255 // returns zero if there are no more event
257 //==========================================================================
258 int emuEvGet (EmuEvent *ev) {
259 if (evListUsed == 0) {
260 if (ev) memset(ev, 0, sizeof(EmuEvent));
261 return 0;
264 if (ev) memcpy(ev, &evList[0], sizeof(EmuEvent));
266 --evListUsed;
267 if (evListUsed != 0) memcpy(&evList[0], &evList[1], sizeof(EmuEvent)*evListUsed);
269 return 1;