ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
animation.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31/****************************************************************************
32 * INCLUDE SECTION
33 ****************************************************************************/
34
35#include "../../ugbc.h"
36
37/****************************************************************************
38 * CODE SECTION
39 ****************************************************************************/
40
47/* <usermanual>
48@keyword ANIMATION
49
50@english
51
52The ''ANIMATION'' command allows you to define an animation starting from a given
53''ATLAS''. The animation can be characterized by a type and parameters, which
54describe its operation. Once defined, the animation can then be used at any time.
55
56In order for this to work, you need to indicate a variable prefix that will be
57associated with the object that will have this animation. This can be indicated with
58the ''USING'' keyword.
59
60If the ''prefix'' is a variable of type ''SPRITE'', ''CSPRITE'' or ''MSPRITE'',
61this movement will be bounded to that object. Otherwise, the following logic
62will be applied.
63
64This statement will generate a series of variables:
65''prefixFrame'', which will contain the next frame to be displayed for the animation;
66''prefixFrameDirection'', which will be 1 if the animation proceeds from the smallest frame to the largest frame and -1 vice versa;
67''prefixX'' and ''prefixY'', which will contain the position where the animation will be displayed;
68''prefixOX'' and ''prefixOY'' will contain the previous coordinates;
69''prefixNext'', to signal / receive a synchonization event (see below);
70''prefixAnimation'' that mantains the thread handle for this animation.
71
72It is possible to indicate that a certain number of frames at the beginning of the
73''ATLAS'' should be used as "ease in". This is done with the keyword ''EASEIN'',
74followed by the number of frames and any delay to be applied between each frame.
75
76It is also possible to indicate a certain number of frames from the end as belonging
77to an "end of sequence" (also called "ease out"). With the keyword ''EASEOUT'' it will
78be possible to indicate the number of frames, and the delay between each of them.
79
80If the animation needs to preserve the background, you need to add the ''PRESERVE BACKGROUND''
81keywords. This option will create an additional variable called ''prefixBackground'' with
82the image that is in the background of the animation before the animation is drawn.
83On each redraw, the background will be restored before drawing the next frame.
84
85If you need to synchronize with vertical blank, i.e. avoid flickering while drawing the
86frame, you need to add the ''WAIT VBL'' option.
87
88Finally, you can indicate the name of an animation that will be executed at the end
89of the current one, where the animation ends naturally or the signal to move to the
90next one is sent. The animation is indicated with the keyword ''NEXT'' and must already
91be defined. If you need to use the ease in sequence, you need to use the
92NEXT WITH EASEIN syntax.
93
94The var ''prefixNext'' deserves a special note. This variable acts as a bidirectional
95data bus. By writing to this variable, you can send signals to the animation thread.
96On the other hand, this variable is also written, and therefore you can get
97information about the progress of the animation. In particular, bit 0, if active,
98indicates that the "ease in" part of the animation has been executed; bit 1,
99if active, indicates that the loop has been completed; bit 2, if active, indicates
100that the "ease out" part of the animation has been executed; bit 3, if set externally
101as active, indicates the request to exit an animation loop.
102
103@italian
104
105Il comando ''ANIMATION'' permette di definire una animazione a partire da un ''ATLAS''
106dato. L'animazione potrà essere caratterizzata da un tipo e da parametri, che ne
107descrivono il funzionamento. Una volta definita, l'animazione potrà poi essere usata
108in qualsiasi momento.
109
110Se il ''prefisso'' è una variabile di tipo ''SPRITE'', ''CSPRITE'' o ''MSPRITE'',
111questo movimento sarà vincolato a quell'oggetto. In caso contrario, verrà applicata
112la seguente logica.
113
114Per poter funzionare, è necessario indicare un prefisso di variabile che sarà associato
115all'oggetto che avrà questa animazione. Questo è possibile indicarlo con la parola
116chiave ''USING''. Questa istruzione genererà una serie di variabili: ''prefixFrame'',
117che conterrà il prossimo fotogramma da visualizzare per l'animazione; ''prefixFrameDirection'',
118che sarà 1 se l'animazione procede dal fotogramma più piccolo a quello più grande e -1 viceversa;
119''prefixX'' e ''prefixY'', che conterrà la posizione dove l'animazione sarà visualizzata, mentre
120''prefixOX'' e ''prefixOY'' conterranno le coordinate precedenti;
121''prefixNext'' per segnalare un evento ''NEXT''; ''prefixAnimation'' che mantiene l'handle per
122il thread per l'animazione attuale.
123
124È possibile indicare che un certo numero di frame all'inizio di ''ATLAS'' debba essere
125utilizzato come "ease in". Questo si fa con la parola chiave ''EASEIN'',
126seguita dal numero di frame e da qualsiasi ritardo da applicare tra ogni frame.
127
128E' possibile, inoltre, indicare un certo numero di fotogrammi dalla fine come
129appartenenti a un "fine sequenza" (chiamato anche "ease out"). Con la parola chiave
130''EASEOUT'' sarà possibile indicare il numero di fotogrammi, e il ritardo tra ognuno di essi.
131
132Se l'animazione deve preservare lo sfondo, è necessario aggiungere le parole chiavi
133''PRESERVE BACKGROUND''. Questa opzione creerà una variabile aggiuntiva chiamata
134''prefixBackground'' con l'immagina presente sullo sfondo dell'animazione prima che la
135stessa sia disegnata. Ad ogni ridisegno, lo sfondo sarà ripristinato prima di disegnare
136il fotogramma successivo.
137
138Se fosse necessario sincronizzarsi con il vertical blank, cioè evitare il flickering durante
139il disegno del fotogramma, è necessario aggiungere l'opzione ''WAIT VBL''.
140
141Infine, si può indicare il nome di una animazione che sarà eseguita al termine di quella
142attuale, laddove la stessa termini in modo naturale o sia inviato il segnale di passare alla
143successiva. L'animazione viene indicata con la parola chiave NEXT e deve essere già definita.
144
145Una nota particolare merita la varable ''prefixNext''. Questa variabile si comporta come un
146bus dati bidirezionale. Scrivendo in questa variabile, si possono inviare segnali al thread
147dell'animazione. D'altra parte, questa variabile viene anche scritta, e quindi si possono
148ottenere informazioni sull'andamento dell'animazione. In particolare il bit 0, se attivo,
149indica che la parte "ease in" dell'animazione è stata eseguita; il bit 1, se attivo, indica
150che il loop è stato completato; il bit 2, se attivo, indica che la parte "ease out"
151dell'animazione è stata eseguita; il bit 3, se impostato dall'esterno come attivo, indica
152la richiesta di uscire da un loop di animazione.
153
154@syntax [DEFINE] ANIMATION type name WITH atlas [od] [in] [out] USING prefix [nx] [vbl] [bg]
155@syntax type: SIMPLE | LOOP | BOUNCE
156@syntax od: DELAY delay
157@syntax in: EASEIN upframe [DELAY delay]
158@syntax out: EASEOUT ofrom [DELAY delay]
159@syntax nx: NEXT [WITH EASIN] anim
160@syntax vbl: WAIT VBL
161@syntax bg: PRESERVE BACKGROUND
162
163@example flyingAirplane := LOAD ATLAS("airplane.png") FRAME SIZE (16, 16)
164@example ANIMATION BOUNCE anim WITH flyingAirplane USING airplane
165
166@target all
167</usermanual> */
168
169/* <usermanual>
170@keyword DEFINE ANIMATION
171
172@english
173
174@italian
175
176@alias ANIMATION
177
178@target all
179</usermanual> */
180void animation( Environment * _environment, char * _identifier, char * _atlas, char * _prefix, char * _next ) {
181
182 if ( _environment->procedureName ) {
184 }
185
186#if defined(__gb__)
187 return;
188#endif
189
190 Variable * atlas = variable_retrieve( _environment, _atlas );
191
192 if ( atlas->type != VT_IMAGES ) {
194 }
195
196 if ( atlas->frameCount <= ( _environment->animationEaseInFrames + _environment->animationEaseOutFrames ) ) {
198 }
199
200 Variable * prefix;
201
202 int spriteLogic = 0;
203
204 if ( variable_exists( _environment, _prefix ) ) {
205 prefix = variable_retrieve( _environment, _prefix );
206 if ( prefix->type == VT_SPRITE || prefix->type == VT_MSPRITE ) {
207 spriteLogic = 1;
208 }
209 }
210
211 // DIM [prefix]Animation AS THREAD
212 char prefixAnimation[MAX_TEMPORARY_STORAGE]; sprintf( prefixAnimation, "%sAnimation", _prefix );
213 Variable * prefixAnimationVar = variable_define( _environment, prefixAnimation, VT_THREAD, 0xff );
214
215 // DIM [prefix]AllowedEaseIn AS SIGNED BYTE
216 char prefixAllowedEaseIn[MAX_TEMPORARY_STORAGE]; sprintf( prefixAllowedEaseIn, "%sAllowedEaseIn", _prefix );
217 Variable * prefixAllowedEaseInVar = variable_define( _environment, prefixAllowedEaseIn, VT_SBYTE, 0 );
218
219 // DIM [prefix]frame AS SIGNED BYTE
220 char prefixFrame[MAX_TEMPORARY_STORAGE]; sprintf( prefixFrame, "%sFrame", _prefix );
221 Variable * prefixFrameVar = variable_define( _environment, prefixFrame, VT_SBYTE, 0 );
222
223 // DIM [prefix]frameDirection AS SIGNED BYTE
224 char prefixFrameDirection[MAX_TEMPORARY_STORAGE]; sprintf( prefixFrameDirection, "%sFrameDirection", _prefix );
225 Variable * prefixFrameDirectionVar = variable_define( _environment, prefixFrameDirection, VT_SBYTE, 0 );
226
227 // DIM [prefix]X AS POSITION
228 char prefixX[MAX_TEMPORARY_STORAGE]; sprintf( prefixX, "%sX", _prefix );
229 Variable * prefixXVar = variable_define( _environment, prefixX, VT_POSITION, 0 );
230
231 // DIM [prefix]Y AS POSITION
232 char prefixY[MAX_TEMPORARY_STORAGE]; sprintf( prefixY, "%sY", _prefix );
233 Variable * prefixYVar = variable_define( _environment, prefixY, VT_POSITION, 0 );
234
235 // DIM [prefix]Next AS SIGNED BYTE
236 char prefixNext[MAX_TEMPORARY_STORAGE]; sprintf( prefixNext, "%sNext", _prefix );
237 Variable * prefixNextVar = variable_define( _environment, prefixNext, VT_BYTE, 0 );
238
239 char prefixDummy[MAX_TEMPORARY_STORAGE]; sprintf( prefixDummy, "%sDummy", _prefix );
240
241 // DIM [prefix]Background AS IMAGE
242 Variable * prefixBackgroundVar = NULL;
243 Variable * prefixOXVar = NULL;
244 Variable * prefixOYVar = NULL;
245 Variable * prefixDummyVar = NULL;
246
247 char prefixBackground[MAX_TEMPORARY_STORAGE]; sprintf( prefixBackground, "%sBackground", _prefix );
248 char prefixBackground2[MAX_TEMPORARY_STORAGE]; sprintf( prefixBackground2, "_%sBackground", _prefix );
249 char prefixOX[MAX_TEMPORARY_STORAGE]; sprintf( prefixOX, "%sOX", _prefix );
250 char prefixOY[MAX_TEMPORARY_STORAGE]; sprintf( prefixOY, "%sOY", _prefix );
251
252 if ( !spriteLogic && _environment->animationPreserveBackground ) {
253 if ( ! variable_exists( _environment, prefixDummy ) ) {
254
255 // DIM [prefix]Background AS IMAGE
256 prefixBackgroundVar = new_image( _environment, atlas->frameWidth, atlas->frameHeight, ((struct _Environment *)_environment)->currentMode );
257 prefixBackgroundVar->name = strdup( prefixBackground );
258 prefixBackgroundVar->realName = strdup( prefixBackground2 );
259
260 // DIM [prefix]OX AS POSITION
261 prefixOXVar = variable_define( _environment, prefixOX, VT_POSITION, 0 );
262
263 // DIM [prefix]OY AS POSITION
264 prefixOYVar = variable_define( _environment, prefixOY, VT_POSITION, 0 );
265
266 } else {
267 prefixBackgroundVar = variable_retrieve( _environment, prefixBackground );
268 prefixOXVar = variable_retrieve( _environment, prefixOX );
269 prefixOYVar = variable_retrieve( _environment, prefixOY );
270 }
271 }
272
273 // PARALLEL PROCEDURE [identifier]
274
275 ((struct _Environment *)_environment)->parameters = 0;
276 ((struct _Environment *)_environment)->protothread = 1;
277 ((struct _Environment *)_environment)->emptyProcedure = 0;
278 begin_procedure( _environment, _identifier );
279
280 // SHARED [prefix]Animation
281 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixAnimation );
282 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_THREAD;
283 ++((struct _Environment *)_environment)->parameters;
284
285 // SHARED [atlas]
286 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( _atlas );
287 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_IMAGES;
288 ++((struct _Environment *)_environment)->parameters;
289
290 // SHARED [prefix]frame
291 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixFrame );
292 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_SBYTE;
293 ++((struct _Environment *)_environment)->parameters;
294
295 // SHARED [prefix]frameDirection
296 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixFrameDirection );
297 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_SBYTE;
298 ++((struct _Environment *)_environment)->parameters;
299
300 // SHARED [prefix]AllowedEaseIn
301 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixAllowedEaseIn );
302 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_BYTE;
303 ++((struct _Environment *)_environment)->parameters;
304
305 // SHARED [prefix]X
306 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixX );
307 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_POSITION;
308 ++((struct _Environment *)_environment)->parameters;
309
310 // SHARED [prefix]Y
311 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixY );
312 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_POSITION;
313 ++((struct _Environment *)_environment)->parameters;
314
315 if ( !spriteLogic && _environment->animationPreserveBackground ) {
316
317 // SHARED [prefix]Background
318 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixBackground );
319 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_IMAGE;
320 ++((struct _Environment *)_environment)->parameters;
321
322 // SHARED [prefix]OX
323 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixOX );
324 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_POSITION;
325 ++((struct _Environment *)_environment)->parameters;
326
327 // SHARED [prefix]OY
328 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixOY );
329 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_POSITION;
330 ++((struct _Environment *)_environment)->parameters;
331
332 // SHARED [prefix]Dummy
333 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixDummy );
334 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_BYTE;
335 ++((struct _Environment *)_environment)->parameters;
336
337 }
338
339 if ( spriteLogic ) {
340 // SHARED [prefix]
341 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefix->name );
342 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = prefix->type;
343 ++((struct _Environment *)_environment)->parameters;
344 }
345
346 // SHARED [prefix]Next
347 ((struct _Environment *)_environment)->parametersEach[((struct _Environment *)_environment)->parameters] = strdup( prefixNext );
348 ((struct _Environment *)_environment)->parametersTypeEach[((struct _Environment *)_environment)->parameters] = VT_SBYTE;
349 ++((struct _Environment *)_environment)->parameters;
350
351 shared( _environment );
352
353 char skipToRealCodeStart[MAX_TEMPORARY_STORAGE]; sprintf( skipToRealCodeStart, "%scodestart", _identifier );
354 char updateIfPositionChanged[MAX_TEMPORARY_STORAGE]; sprintf( updateIfPositionChanged, "%supdate", _prefix );
355 char updateSpriteDataWithImage[MAX_TEMPORARY_STORAGE]; sprintf( updateSpriteDataWithImage, "%supdatesprite", _prefix );
356 char updateSpriteDataWithImageDone[MAX_TEMPORARY_STORAGE]; sprintf( updateSpriteDataWithImageDone, "%supdatespritedone", _prefix );
357
358 if ( !spriteLogic && _environment->animationPreserveBackground && ! variable_exists( _environment, prefixDummy ) ) {
359
360 prefixDummyVar = variable_define( _environment, prefixDummy, VT_BYTE, 0 );
361
362 cpu_jump( _environment, skipToRealCodeStart );
363
364 cpu_label( _environment, updateIfPositionChanged );
365 char skipIfSamePositionLabel[MAX_TEMPORARY_STORAGE]; sprintf( skipIfSamePositionLabel, "%sskip0same", _prefix );
366 char skipIfSamePositionLabel2[MAX_TEMPORARY_STORAGE]; sprintf( skipIfSamePositionLabel2, "%sskip0same2", _prefix );
367 cpu_compare_and_branch_8bit_const( _environment, prefixDummyVar->realName, 0x00, skipIfSamePositionLabel2, 1 );
368 cpu_compare_and_branch_8bit_const( _environment, variable_xor( _environment, variable_xor( _environment, prefixXVar->name, prefixOXVar->name )->name, variable_xor( _environment, prefixYVar->name, prefixOYVar->name )->name )->realName, 0x00, skipIfSamePositionLabel, 1 );
369 put_image( _environment, prefixBackgroundVar->name, prefixOXVar->name, prefixOYVar->name, NULL, NULL, NULL, NULL, 0 );
370 cpu_label( _environment, skipIfSamePositionLabel2 );
371 get_image( _environment, prefixBackgroundVar->name, prefixXVar->name, prefixYVar->name, NULL, NULL, NULL, NULL, 0 );
372 variable_move( _environment, prefixXVar->name, prefixOXVar->name );
373 variable_move( _environment, prefixYVar->name, prefixOYVar->name );
374 cpu_label( _environment, skipIfSamePositionLabel );
375 variable_store( _environment, prefixDummyVar->name, 0xff );
376 cpu_return( _environment );
377 cpu_label( _environment, skipToRealCodeStart );
378
379 }
380
381 if ( spriteLogic ) {
382
383 cpu_jump( _environment, skipToRealCodeStart );
384
385 cpu_label( _environment, updateSpriteDataWithImage );
386 cpu_prepare_for_compare_and_branch_8bit( _environment, prefixFrameVar->realName );
387 for( int i=0; i<atlas->frameCount; ++i ) {
388 char assignFrameLabelSkip[MAX_TEMPORARY_STORAGE]; sprintf( assignFrameLabelSkip, "%sassign%dframeskip", _prefix, i );
389 cpu_execute_compare_and_branch_8bit_const( _environment, i, assignFrameLabelSkip, 0 );
390 Variable * extraction = image_extract( _environment, atlas->name, i, NULL );
391 if ( prefix->type == VT_SPRITE ) {
392 sprite_init( _environment, extraction->name, prefix->name, 0 );
393 } else {
394 msprite_init( _environment, extraction->name, prefix->name, 0 );
395 }
396 cpu_jump( _environment, updateSpriteDataWithImageDone );
397 cpu_label( _environment, assignFrameLabelSkip );
398 }
399 cpu_label( _environment, updateSpriteDataWithImageDone );
400 cpu_return( _environment );
401 cpu_label( _environment, skipToRealCodeStart );
402
403 }
404
405 // [prefix]Frame = 0 / last (it depends on reverse)
406 variable_store( _environment, prefixFrameVar->name, _environment->animationReverse ? ( atlas->frameCount - 1 ) : 0 );
407
408 // [prefix]FrameDirection = 1 / -1 (it depends on reverse)
409 variable_store( _environment, prefixFrameDirectionVar->name, _environment->animationReverse ? -1 : 1 );
410
411 // [prefix]Next = 0
412 variable_store( _environment, prefixNextVar->name, 0 );
413
414 if ( _environment->animationReverse ) {
415
416 if ( _environment->animationEaseOutFrames ) {
417
418 char easeOutLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeOutLabel, "%seaseout", _identifier );
419 char easeOutDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeOutDoneLabel, "%seaseoutdone", _identifier );
420
421 cpu_label( _environment, easeOutLabel );
422
423 wait_milliseconds( _environment, _environment->animationEaseOutDelay );
424
425 if ( _environment->animationWaitVbl ) {
426 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
427 }
428
429 if ( !spriteLogic && _environment->animationPreserveBackground ) {
430 cpu_call( _environment, updateIfPositionChanged );
431 }
432
433 if ( spriteLogic ) {
434 cpu_call( _environment, updateSpriteDataWithImage );
435 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
436 } else {
437 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
438 }
439
440 cpu_dec( _environment, prefixFrameVar->realName );
441
442 cpu_compare_and_branch_8bit_const( _environment, prefixFrameVar->realName, ( atlas->frameCount - _environment->animationEaseOutFrames - 1 ), easeOutDoneLabel, 1 );
443
444 cpu_jump( _environment, easeOutLabel );
445
446 cpu_label( _environment, easeOutDoneLabel );
447 }
448
449 } else {
450
451 if ( _environment->animationEaseInFrames ) {
452
453 char easeInLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeInLabel, "%seasein", _identifier );
454 char easeInDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeInDoneLabel, "%seaseindone", _identifier );
455
456 cpu_compare_and_branch_8bit_const( _environment, prefixAllowedEaseInVar->realName, 0xff, easeInDoneLabel, 1 );
457
458 // DO
459 cpu_label( _environment, easeInLabel );
460
461 // WAIT [idelay] MS
462 wait_milliseconds( _environment, _environment->animationEaseInDelay );
463
464 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
465 if ( _environment->animationWaitVbl ) {
466 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
467 }
468
469 if ( !spriteLogic && _environment->animationPreserveBackground ) {
470 cpu_call( _environment, updateIfPositionChanged );
471 }
472
473 // PUT IMAGE playerIdle FRAME framePlayer AT playerX, playerY
474 if ( spriteLogic ) {
475 cpu_call( _environment, updateSpriteDataWithImage );
476 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
477 } else {
478 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
479 }
480
481 // INC [prefix]Frame
482 cpu_inc( _environment, prefixFrameVar->realName );
483
484 // EXIT IF [prefix]Frame = ito
485 cpu_compare_and_branch_8bit_const( _environment, prefixFrameVar->realName, _environment->animationEaseInFrames, easeInDoneLabel, 1 );
486
487 // LOOP
488 cpu_jump( _environment, easeInLabel );
489
490 cpu_label( _environment, easeInDoneLabel );
491
492 variable_store( _environment, prefixAllowedEaseInVar->name, 0x0 );
493 variable_store( _environment, prefixFrameVar->name, _environment->animationEaseInFrames );
494
495 }
496
497 }
498
499 // Ease in finished!
500 cpu_or_8bit_const( _environment, prefixNextVar->realName, 0x01, prefixNextVar->realName );
501 yield( _environment );
502
503 switch( _environment->animationType ) {
504 case AT_SIMPLE: {
505
506 char simpleLabel[MAX_TEMPORARY_STORAGE]; sprintf( simpleLabel, "%ssimple", _identifier );
507 char simpleDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( simpleDoneLabel, "%ssimpledone", _identifier );
508
509 // DO
510 cpu_label( _environment, simpleLabel );
511
512 // WAIT [delay] MS
513 wait_milliseconds( _environment, _environment->animationDelay );
514
515 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
516 if ( _environment->animationWaitVbl ) {
517 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
518 }
519
520 if ( !spriteLogic && _environment->animationPreserveBackground ) {
521 cpu_call( _environment, updateIfPositionChanged );
522 }
523
524 // PUT IMAGE [atlas] FRAME [prefix]Frame AT [prefix]X, [prefix]Y
525 if ( spriteLogic ) {
526 cpu_call( _environment, updateSpriteDataWithImage );
527 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
528 } else {
529 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
530 }
531
532 if ( _environment->animationReverse ) {
533 // INC [prefix]Frame
534 cpu_dec( _environment, prefixFrameVar->realName );
535 } else {
536 // INC [prefix]Frame
537 cpu_inc( _environment, prefixFrameVar->realName );
538 }
539
540 int lastFrame = 0;
541
542 if ( _environment->animationReverse ) {
543 lastFrame = _environment->animationEaseInFrames - 1 ;
544 } else {
545 lastFrame = _environment->animationEaseOutFrames ? ( atlas->frameCount - _environment->animationEaseOutFrames ) : atlas->frameCount;
546 }
547
548 // EXIT IF [prefix]Frame = ofrom / last frame
549 cpu_compare_and_branch_8bit_const( _environment, prefixFrameVar->realName, lastFrame, simpleDoneLabel, 1 );
550
551 // EXIT if NEXT signal
552 cpu_compare_and_branch_8bit_const( _environment, variable_and_const( _environment, prefixNextVar->name, 0x80 )->realName, 0x80, simpleDoneLabel, 1 );
553
554 // LOOP
555 cpu_jump( _environment, simpleLabel );
556
557 cpu_label( _environment, simpleDoneLabel );
558
559 }
560 break;
561 case AT_BOUNCE: {
562
563 char bounceLabel[MAX_TEMPORARY_STORAGE]; sprintf( bounceLabel, "%sbounce", _identifier );
564 char bounceDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( bounceDoneLabel, "%sbouncedone", _identifier );
565
566 // DO
567 cpu_label( _environment, bounceLabel );
568
569 // WAIT [delay] MS
570 wait_milliseconds( _environment, _environment->animationDelay );
571
572 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
573 if ( _environment->animationWaitVbl ) {
574 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
575 }
576
577 if ( !spriteLogic && _environment->animationPreserveBackground ) {
578 cpu_call( _environment, updateIfPositionChanged );
579 }
580
581 // PUT IMAGE [atlas] FRAME [prefix]Frame AT [prefix]X, [prefix]Y
582 if ( spriteLogic ) {
583 cpu_call( _environment, updateSpriteDataWithImage );
584 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
585 } else {
586 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
587 }
588
589 // ADD [prefix]Frame, [prefix]FrameDirection
590 variable_add_inplace_vars( _environment, prefixFrameVar->name, prefixFrameDirectionVar->name );
591
592 int lastFrame = _environment->animationEaseOutFrames ? ( atlas->frameCount - _environment->animationEaseOutFrames ) : ( atlas->frameCount );
593 int firstFrame = _environment->animationEaseInFrames ? _environment->animationEaseInFrames : 0;
594
595 // IF framePlayer = FRAMES( playerIdle ) - 1 THEN
596 if_then( _environment, variable_compare_const( _environment, prefixFrameVar->name, lastFrame )->name );
597
598 // framePlayerDirection = -1
599 variable_store( _environment, prefixFrameDirectionVar->name, -1 );
600
601 // ELSEIF framePlayer = 3 THEN
602 else_if_then_label( _environment );
603 else_if_then( _environment, variable_compare_const( _environment, prefixFrameVar->name, firstFrame )->name );
604
605 // framePlayerDirection = 1
606 variable_store( _environment, prefixFrameDirectionVar->name, 1 );
607
608 end_if_then( _environment );
609 // ENDIF
610
611 // EXIT if NEXT signal
612 cpu_compare_and_branch_8bit_const( _environment, variable_and_const( _environment, prefixNextVar->name, 0x80 )->realName, 0x80, bounceDoneLabel, 1 );
613
614 // LOOP
615 cpu_jump( _environment, bounceLabel );
616
617 cpu_label( _environment, bounceDoneLabel );
618
619 }
620
621 break;
622 case AT_LOOP: {
623
624 char loopLabel[MAX_TEMPORARY_STORAGE]; sprintf( loopLabel, "%sloop", _identifier );
625 char loopDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( loopDoneLabel, "%sloopdone", _identifier );
626
627 // DO
628 cpu_label( _environment, loopLabel );
629
630 // WAIT [delay] MS
631 wait_milliseconds( _environment, _environment->animationDelay );
632
633
634 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
635 if ( _environment->animationWaitVbl ) {
636 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
637 }
638
639 if ( !spriteLogic && _environment->animationPreserveBackground ) {
640 cpu_call( _environment, updateIfPositionChanged );
641 }
642
643 // PUT IMAGE [atlas] FRAME [prefix]Frame AT [prefix]X, [prefix]Y
644 if ( spriteLogic ) {
645 cpu_call( _environment, updateSpriteDataWithImage );
646 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
647 } else {
648 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
649 }
650
651 // ADD [prefix]Frame, [prefix]FrameDirection
652 variable_add_inplace( _environment, prefixFrameVar->name, _environment->animationReverse ? -1 : 1 );
653
654 int lastFrame = 0;
655 int firstFrame = 0;
656 if ( _environment->animationReverse ) {
657 lastFrame = _environment->animationEaseInFrames ? _environment->animationEaseInFrames : 0 ;
658 firstFrame = _environment->animationEaseOutFrames ? ( atlas->frameCount - _environment->animationEaseOutFrames ) : ( atlas->frameCount );
659 } else {
660 firstFrame = _environment->animationEaseInFrames ? _environment->animationEaseInFrames : 0 ;
661 lastFrame = _environment->animationEaseOutFrames ? ( atlas->frameCount - _environment->animationEaseOutFrames ) : ( atlas->frameCount );
662 }
663
664 // IF [prefix]Frame = FRAMES( [atlas] ) THEN
665 if_then( _environment, variable_compare_const( _environment, prefixFrameVar->name, lastFrame )->name );
666
667 // [prefix]Frame = 0
668 variable_store( _environment, prefixFrameVar->name, firstFrame );
669
670 // ELSEIF framePlayer = 3 THEN
671 end_if_then( _environment );
672 // ENDIF
673
674 // EXIT if NEXT signal
675 cpu_compare_and_branch_8bit_const( _environment, variable_and_const( _environment, prefixNextVar->name, 0x80 )->realName, 0x80, loopDoneLabel, 1 );
676
677 // LOOP
678 cpu_jump( _environment, loopLabel );
679
680 cpu_label( _environment, loopDoneLabel );
681
682 }
683
684 break;
685 }
686
687 // Loop finished!
688 cpu_or_8bit_const( _environment, prefixNextVar->realName, 0x02, prefixNextVar->realName );
689 yield( _environment );
690
691 if ( _environment->animationReverse ) {
692
693 if ( _environment->animationEaseInFrames ) {
694
695 char easeInLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeInLabel, "%seasein", _identifier );
696 char easeInDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeInDoneLabel, "%seaseindone", _identifier );
697
698 cpu_compare_and_branch_8bit_const( _environment, prefixAllowedEaseInVar->realName, 0xff, easeInDoneLabel, 1 );
699
700 // DO
701 cpu_label( _environment, easeInLabel );
702
703 // WAIT [idelay] MS
704 wait_milliseconds( _environment, _environment->animationEaseInDelay );
705
706 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
707 if ( _environment->animationWaitVbl ) {
708 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
709 }
710
711 if ( !spriteLogic && _environment->animationPreserveBackground ) {
712 cpu_call( _environment, updateIfPositionChanged );
713 }
714
715 // PUT IMAGE playerIdle FRAME framePlayer AT playerX, playerY
716 if ( spriteLogic ) {
717 cpu_call( _environment, updateSpriteDataWithImage );
718 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
719 } else {
720 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
721 }
722
723 // INC [prefix]Frame
724 cpu_dec( _environment, prefixFrameVar->realName );
725
726 // EXIT IF [prefix]Frame = ito
727 cpu_compare_and_branch_8bit_const( _environment, prefixFrameVar->realName, 0xff, easeInDoneLabel, 1 );
728
729 // LOOP
730 cpu_jump( _environment, easeInLabel );
731
732 cpu_label( _environment, easeInDoneLabel );
733
734 variable_store( _environment, prefixAllowedEaseInVar->name, 0x0 );
735 variable_store( _environment, prefixFrameVar->name, _environment->animationEaseInFrames );
736
737 }
738
739 } else {
740
741 if ( _environment->animationEaseOutFrames ) {
742
743 char easeOutLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeOutLabel, "%seaseout", _identifier );
744 char easeOutDoneLabel[MAX_TEMPORARY_STORAGE]; sprintf( easeOutDoneLabel, "%seaseoutdone", _identifier );
745
746 // DO
747 cpu_label( _environment, easeOutLabel );
748
749 // WAIT [odelay] MS
750 wait_milliseconds( _environment, _environment->animationEaseOutDelay );
751
752 // WAIT VBL [prefix]Y + IMAGE HEIGHT( [atlas] )
753 if ( _environment->animationWaitVbl ) {
754 wait_vbl( _environment, variable_add_const( _environment, prefixYVar->name, atlas->frameHeight )->name );
755 }
756
757 if ( !spriteLogic && _environment->animationPreserveBackground ) {
758 cpu_call( _environment, updateIfPositionChanged );
759 }
760
761 // PUT IMAGE playerIdle FRAME framePlayer AT playerX, playerY
762 if ( spriteLogic ) {
763 cpu_call( _environment, updateSpriteDataWithImage );
764 sprite_at_vars( _environment, prefix->name, prefixXVar->name, prefixYVar->name );
765 } else {
766 put_image( _environment, atlas->name, prefixXVar->name, prefixYVar->name, NULL, NULL, prefixFrameVar->name, NULL, FLAG_WITH_PALETTE );
767 }
768
769 // INC [prefix]Frame
770 cpu_inc( _environment, prefixFrameVar->realName );
771
772 // EXIT IF [prefix]Frame = last frame
773 cpu_compare_and_branch_8bit_const( _environment, prefixFrameVar->realName, atlas->frameCount, easeOutDoneLabel, 1 );
774
775 // LOOP
776 cpu_jump( _environment, easeOutLabel );
777
778 cpu_label( _environment, easeOutDoneLabel );
779 }
780
781 }
782
783 // Ease out finished!
784 cpu_or_8bit_const( _environment, prefixNextVar->realName, 0x04, prefixNextVar->realName );
785 yield( _environment );
786
787 if ( _next ) {
788 ((struct _Environment *)_environment)->parameters = 0;
789 Variable * temporary = variable_temporary( _environment, VT_THREAD, "(temp)");
790 variable_move( _environment, spawn_procedure( _environment, _next, 0 )->name, temporary->name );
791 kill_procedure( _environment, prefixAnimationVar->name );
792 variable_move( _environment, temporary->name, prefixAnimationVar->name );
793 variable_store( _environment, prefixAllowedEaseInVar->name, _environment->animationNextWithEaseIn ? 0x00 : 0xff );
794 }
795
796 end_procedure( _environment, NULL );
797
798}
799
void cpu_inc(Environment *_environment, char *_variable)
Definition 6309.c:4555
void cpu_label(Environment *_environment, char *_label)
Definition 6309.c:356
void cpu_dec(Environment *_environment, char *_variable)
Definition 6309.c:4630
void cpu_or_8bit_const(Environment *_environment, char *_left, int _right, char *_result)
Definition 6309.c:4306
void cpu_call(Environment *_environment, char *_label)
Definition 6309.c:3755
void cpu_jump(Environment *_environment, char *_label)
Definition 6309.c:3739
void cpu_prepare_for_compare_and_branch_8bit(Environment *_environment, char *_source)
Definition 6309.c:841
void cpu_return(Environment *_environment)
Definition 6309.c:4030
void cpu_execute_compare_and_branch_8bit_const(Environment *_environment, int _destination, char *_label, int _positive)
CPU 6309: emit code to compare two 8 bit values and jump if they are equal/different
Definition 6309.c:901
void cpu_compare_and_branch_8bit_const(Environment *_environment, char *_source, int _destination, char *_label, int _positive)
CPU 6309: emit code to compare two 8 bit values and jump if they are equal/different
Definition 6309.c:876
Variable * variable_retrieve(Environment *_environment, char *_name)
void variable_add_inplace(Environment *_environment, char *_source, int _destination)
int variable_exists(Environment *_environment, char *_name)
Variable * variable_move(Environment *_environment, char *_source, char *_destination)
Store the value of a variable inside another variable by converting it.
Variable * variable_and_const(Environment *_environment, char *_destination, int _mask)
Calculate "and" mask for a variable and it as the result.
Variable * variable_add_const(Environment *_environment, char *_source, int _destination)
Add a variable with a constant, and return the sum of them.
Variable * variable_xor(Environment *_environment, char *_left, char *_right)
Calculate logical "xor" and return it as the result.
Variable * variable_define(Environment *_environment, char *_name, VariableType _type, int _value)
Define a variable for the program.
void variable_add_inplace_vars(Environment *_environment, char *_source, char *_destination)
Add two variable and return the sum of them on the first.
Variable * variable_temporary(Environment *_environment, VariableType _type, char *_meaning)
Define a temporary variable.
Variable * variable_store(Environment *_environment, char *_destination, unsigned int _value)
Store a direct value to a variable.
Variable * variable_compare_const(Environment *_environment, char *_source, int _destination)
Compare two variable and return the result of comparation.
void animation(Environment *_environment, char *_identifier, char *_atlas, char *_prefix, char *_next)
Emit code for ANIMATION ....
Definition animation.c:180
char * name
Definition _optimizer.c:672
void get_image(Environment *_environment, char *_image, char *_x1, char *_y1, char *_x2, char *_y2, char *_frame, char *_sequence, int _palette)
Emit ASM code for GET IMAGE [image] AT [int],[int].
Definition get_image.c:57
Variable * new_image(Environment *_environment, int _width, int _height, int _mode)
Emit code for NEW IMAGE(...).
Definition new_image.c:49
void wait_vbl(Environment *_environment, char *_raster_line)
Emit ASM code for WAIT VBL/b>.
Definition wait_vbl.c:53
void begin_procedure(Environment *_environment, char *_name)
Emit code for PROCEDURE ... END PROC.
Variable * msprite_init(Environment *_environment, char *_image, char *_sprite, int _flags)
Emit code for SPRITE(...).
void sprite_at_vars(Environment *_environment, char *_sprite, char *_x, char *_y)
Emit ASM code for SPRITE [expression] AT ([expression],[expression]).
Definition sprite_at.c:71
Variable * sprite_init(Environment *_environment, char *_image, char *_sprite, int _flags)
Emit code for SPRITE(...).
Definition sprite_init.c:47
void put_image(Environment *_environment, char *_image, char *_x1, char *_y1, char *_x2, char *_y2, char *_frame, char *_sequence, int _flags)
Emit ASM code for PUT IMAGE [image] AT [int],[int].
Definition put_image.c:53
void else_if_then_label(Environment *_environment)
Emit ASM code for ... ELSE [IF] ....
void else_if_then(Environment *_environment, char *_expression)
Emit ASM code for ... ELSE [IF] ....
void end_if_then(Environment *_environment)
Emit ASM code for ENDIF.
Definition end_if_then.c:50
void end_procedure(Environment *_environment, char *_value)
Emit code for END PROC.
Definition end_proc.c:72
void if_then(Environment *_environment, char *_expression)
Emit ASM code for IF ... THEN ....
Definition if_then.c:123
Variable * image_extract(Environment *_environment, char *_images, int _frame, int *_sequence)
Emit code for IMAGE(... FRAME ... STRIP ...).
void kill_procedure(Environment *_environment, char *_handle)
Emit code for KILL ....
Definition kill.c:77
void shared(Environment *_environment)
Manage variable as "global".
Definition shared.c:88
Variable * spawn_procedure(Environment *_environment, char *_name, int _halted)
Emit code for SPAWN ....
Definition spawn.c:68
Structure of compilation environment.
Definition ugbc.h:2269
int animationEaseInFrames
Definition ugbc.h:3199
char * parametersEach[MAX_PARAMETERS]
Definition ugbc.h:2790
int animationNextWithEaseIn
Definition ugbc.h:3205
int animationEaseOutFrames
Definition ugbc.h:3202
int protothread
Definition ugbc.h:2830
int animationReverse
Definition ugbc.h:3211
int animationWaitVbl
Definition ugbc.h:3207
VariableType parametersTypeEach[MAX_PARAMETERS]
Definition ugbc.h:2800
int parameters
Definition ugbc.h:2785
int animationEaseOutDelay
Definition ugbc.h:3203
int animationPreserveBackground
Definition ugbc.h:3209
int animationDelay
Definition ugbc.h:3197
char * procedureName
Definition ugbc.h:2775
int emptyProcedure
Definition ugbc.h:2932
int animationEaseInDelay
Definition ugbc.h:3200
AnimationType animationType
Definition ugbc.h:3196
char * name
Definition ugbc.h:979
VariableType type
Definition ugbc.h:988
int frameCount
Definition ugbc.h:1137
int frameWidth
Definition ugbc.h:1162
int frameHeight
Definition ugbc.h:1164
char * realName
Definition ugbc.h:982
#define CRITICAL_NOT_ENOUGH_FRAMES_FOR_ANIMATION(n)
Definition ugbc.h:3800
#define MAX_TEMPORARY_STORAGE
Definition ugbc.h:563
struct _Variable Variable
Structure of a single variable.
@ AT_BOUNCE
Definition ugbc.h:287
@ AT_LOOP
Definition ugbc.h:288
@ AT_SIMPLE
Definition ugbc.h:286
struct _Environment Environment
Structure of compilation environment.
@ VT_THREAD
Definition ugbc.h:492
@ VT_POSITION
Definition ugbc.h:468
@ VT_MSPRITE
Definition ugbc.h:531
@ VT_BYTE
Definition ugbc.h:450
@ VT_SPRITE
Definition ugbc.h:501
@ VT_SBYTE
Definition ugbc.h:452
@ VT_IMAGES
Definition ugbc.h:495
@ VT_IMAGE
Definition ugbc.h:489
#define FLAG_WITH_PALETTE
Definition ugbc.h:4571
#define CRITICAL_cANNOT_DEFINE_ANIMATION_WITHOUT_ATLAS(n)
Definition ugbc.h:3770
#define CRITICAL_cANNOT_DEFINE_ANIMATION_INSIDE_A_PROCEDURE(n)
Definition ugbc.h:3769
void wait_milliseconds(Environment *_environment, int _timing)
Emit ASM code for WAIT # [integer] MS.
void yield(Environment *_environment)
Emit code for YIELD.
Definition yield.c:63