ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
sequence_load.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"
37#include "../../libs/msc1.h"
38
39/****************************************************************************
40 * CODE SECTION
41 ****************************************************************************/
42
50
51/* <usermanual>
52@keyword LOAD SEQUENCE
53
54@english
55
56The ''LOAD SEQUENCE'' command allows you to load an set of images and to convert each one
57into a ''SEQUENCE''. A Sequence is a set of set of images, numbered by 0 to sequence
58count (vertically), and from 0 to frame count each (horizontally), which can be used individually with the PUT IMAGE
59command, referring to the corresponding frame and sequence.
60The frames are cut out of the original image, using the size provided in the
61''FRAME SIZE (w, h)''. It should be noted that, for this reason, ''SEQUENCE'' images
62must have a total of a size equal to an entire multiple of the size of the individual frame.
63It is also possible to indicate an offset from which you will have to start cutting the image
64(parameter ''ORIGIN(zx,zy)'') and one related to each individual cutout (''OFFSET (dx, dy)'').
65
66So, the first parameter is the filename to parse. The command support a set of modern image
67format, like JPEG baseline & progressive,
68PNG 1/2/4/8/16-bit-per-channel, TGA, BMP (non-1bpp, non-RLE), PSD
69(composited view only, no extra channels, 8/16 bit-per-channel),
70GIF, HDR (radiance rgbE format), PIC (Softimage PIC) and PNM (PPM and PGM
71binary only) The image will be converted into a way that can be
72efficiently drawn on the screen.
73
74The second parameter is the mode to use to convert the given data (by default, it is
75equal to current mode)
76
77Since it is possible to load only one file of the same
78type at a time, it is necessary to be able to indicate an "alias" with
79which to exceed this limit. In this regard, there is also
80the ''AS'' syntax, which allows you to load the same file several
81times but with different names.
82
83A series of flags, separated by spaces, can be added at loading time
84to modify the behavior of ugBASIC.
85
86The ''FLIP X'' flag allows you to flip the (entire) image horizontally,
87before cutting and translating it into the native format. The same is true for the
88''FLIP Y'' command, which instead inverts the (entire) image vertically.
89There is also the ''FLIP XY'' (or ''FLIP YX'') parameter to act,
90simultaneously, on both directions.
91
92The ''ROLL X'' flag allows you to SHIFT the (entire) image horizontally,
93for the entire size of a frame, in order to generate intermediate
94frames. The very same for ''ROLL Y'' command, which does the same
95vertically. There is also the ''ROLL XY'' (or ''ROLL YX'') parameter to act,
96simultaneously, on both directions.
97
98The ''COMPRESSED'' flag allows you to compress the image, if
99possible. Compression is a space-saving mechanism, in which the
100native data of the image is represented in a more compact form,
101which ugBASIC will be able to quickly convert into graphics at
102the appropriate time.
103
104The ''OVERLAYED'' flag can be used on systems with a palette
105of few colors, to indicate which of them must be preserved
106during the drawing phase, to have the transparency effect.
107
108The ''EXACT'' flag allows you to bypass the automatic detection
109of the palette, opting for the representation of the colors
110according to what is contained in it.
111
112The (entire) image can be loaded as a transparent image (if the original
113image has no transparency) using the keyword ''TRANSPARENCY'',
114followe by an optional parameter that represent the color
115to consider as transparent.
116
117The (entire) image can be loaded as a transparent image (if the original
118image has no transparency) using the keyword ''OPACITY'',
119followe by an optional parameter that represent the color
120to consider as pavement,.
121
122The resulting ''SEQUENCE'' can be loaded directly into the expansion
123memory using the ''BANKED'' keyword. The number represent
124the shared resident to use as target for this image.
125For some targets this is the default. If you want,
126you can move the image onto the resident memory by
127using the ''UNBANKED'' keyword.
128
129Finally, if the image is not expected to change during gameplay, it can be marked
130with the ''READONLY'' attribute: in this case, the image will be stored
131in read-only memory, if available.
132
133@italian
134
135Il comando ''LOAD SEQUENCE'' consente di caricare un set di immagini come ''SEQUENCE''.
136Un ''SEQUENCE'' è un set di immagini, numerata per il conteggio di 0 a frame, che
137può essere utilizzato individualmente con il comando PUT IMAGE, facendo riferimento
138al frame corrispondente. I frame vengono ritagliati dall'immagine originale,
139utilizzando le dimensioni fornite in ''FRAME SIZE (w, h) ''. Va notato che,
140per questo motivo, l'immagine intera originale deve avere un totale di una
141dimensione pari a un intero multiplo della dimensione del singolo frame.
142È anche possibile indicare un offset da cui si dovrà iniziare a tagliare l'immagine
143(parametro ''ORIGIN(zx,zy)'') e uno relativo a ogni singolo ritaglio (''OFFSET(dx,dy) '').
144
145Quindi, il primo parametro è il nome file da analizzare. Il comando supporta
146un set formati moderni, come JPEG Baseline & Progressive,
147PNG 1/2/4/8/16-bit-per-channel, TGA, BMP (non-1bpp, non-rle), PSD
148(Vista composita solo, nessun canale extra, 8/16 bit-per-channel),
149GIF, HDR (formato radiante RGBE), foto (softimage pic) e PNM (PPM e PGM
150Solo binario) l'immagine verrà convertita in un modo che può essere
151disegnato in modo efficiente sullo schermo.
152
153Il secondo parametro è la modalità da utilizzare per convertire i dati forniti
154(per impostazione predefinita, è uguale alla modalità corrente)
155
156Poiché è possibile caricare solo un file dello stesso nome alla volta, è necessario
157essere in grado di indicare un "alias" con che per superare questo limite.
158A questo proposito, c'è anche La sintassi ''AS'', che consente di caricare lo
159stesso file diverse volte ma con nomi diversi.
160
161Una serie di flag, separate da spazi, può essere aggiunta al momento del caricamento
162Per modificare il comportamento di ugBASIC.
163
164Il flag ''FLIP X '' consente di capovolgere l'intera immagine in orizzontale, prima
165di tagliarla e tradurla nel formato nativo. Lo stesso vale per il flag ''FLIP Y'',
166che invece inverte l'intera immagine in verticale. Vi è anche il flag ''FLIP XY''
167(o ''FLIP XY'') per agire, contemporaneamente, su entrambe le direzioni.
168
169Il flag ''ROLL X'' consente di spostare l'intera immagine in orizzontale,
170per l'intera dimensione di un frame, per generare i fotogrammi intercalari.
171Lo stesso per il flag ''ROLL Y'', che fa lo stesso verticalmente, e
172''ROLL XY '' (o ''ROLL YX'') per agire, contemporaneamente, su entrambe le
173 direzioni.
174
175Il flag "COMPRESSED" consente di comprimere l'immagine, se possibile. La
176compressione è un meccanismo di risparmio spaziale, in cui i dati nativi
177dell'immagine sono rappresentati in una forma più compatta, così che
178ugBASIC sia in grado di convertirsi rapidamente al momento appropriato.
179
180La flag "ORVERLAYED" può essere utilizzata sui sistemi con una tavolozza
181di pochi colori, per indicare quale di essi deve essere preservato,
182durante la fase di disegno, per avere l'effetto di trasparenza.
183
184Il flag "EXACT" consente di bypassare il rilevamento automatico
185della tavolozza, optando per la rappresentazione dei colori precisa.
186
187L'immagine (intera) può essere caricata come un'immagine trasparente (se l'originale
188L'immagine non ha trasparenza) usando la parola chiave ''TRANSPARENCY'',
189seguire da un parametro opzionale che rappresenta il colore
190considerare trasparente.
191
192L'immagine (intera) può essere caricata come un'immagine trasparente (se l'originale
193L'immagine non ha trasparenza) usando la parola chiave ''OPACITY'',
194seguire da un parametro opzionale che rappresenta il colore
195considerare come pavimentazione,.
196
197La ''SEQUENCE'' risultante può essere caricata direttamente nell'espansione
198memoria utilizzando la parola chiave ''BANK''. Il numero rappresenta
199il blocco residente condiviso, da utilizzare come target per questa
200immagine. Per alcuni target questo è il flag predefinito. Si può cambiare
201tale impostazione usando la parola chiave ''UNBANKED''.
202
203Infine, se l'immagine non dovesse cambiare durante il gameplay, può
204essere contrassegnata con l'attributo "READONLY": in questo caso,
205l'immagine verrà memorizzata Nella memoria di sola lettura, se disponibile.
206
207@syntax = LOAD SEQUENCE( filename [AS alias][,mode] ) frame [ORIGIN(dx,dy)] [fl] [tr] [op] [bg] [bk] [READONLY]
208@syntax = LOAD SEQUENCE( filename [AS alias][,mode] ) frame [fl] [tr] [op] [bg] [bk] [READONLY]
209@syntax frame : [ FRAME SIZE(w, h) [OFFSET(dx,dy)] [ORIGIN(zx, zy)] | FRAME AUTO]
210@syntax fl : [FLIP X] [FLIP Y] [FLIP XY] [FLIP YX]
211@syntax [COMPRESSED] [OVERLAYED] [EXACT]
212@syntax [ROLL X] [ROLL Y] [ROLL XY] [ROLL YX]
213@syntax tr : [TRANSPARENCY | TRANSPARENCY color]
214@syntax op : [OPACITY | OPACITY color]
215@syntax bg : [BACKGROUND color]
216@syntax bk : [UNBANKED | BANKED | BANKED(number)]
217
218@example starship = LOAD SEQUENCE("starship.png") FRAME SIZE (16, 16)
219@example starship2 = LOAD SEQUENCE("starship.png" AS "starship2") FRAME SIZE (32, 32) OFFSET(2,2)
220@example alienAt11 = LOAD SEQUENCE("alien.jpg",11) FRAME SIZE AUTO
221@example alien2 = LOAD SEQUENCE("alien.jpg" AS "alien2",11) FRAME SIZE(8,8) TRANSPARENCY
222
223@alias STRIP LOAD
224@target all
225@ntarget gb
226</usermanual> */
227
228/* <usermanual>
229@keyword STRIP LOAD
230@alias LOAD SEQUENCE
231@target all
232@ntarget gb
233</usermanual> */
234
235Variable * sequence_load( Environment * _environment, char * _filename, char * _alias, int _mode, int _frame_width, int _frame_height, int _flags, int _transparent_color, int _background_color, int _bank_expansion, int _origin_x, int _origin_y, int _offset_x, int _offset_y ) {
236
237 Variable * final = variable_temporary( _environment, VT_SEQUENCE, 0 );
238
239 if ( _environment->emptyProcedure ) {
240 return final;
241 }
242
243#if defined(__gb__)
244 final->valueBuffer = malloc( 3 );
245 return final;
246#endif
247
248 if ( _environment->tenLinerRulesEnforced ) {
249 CRITICAL_10_LINE_RULES_ENFORCED( "LOAD SEQUENCE");
250 }
251
252 if ( _environment->sandbox ) {
253 CRITICAL_SANDBOX_ENFORCED( "LOAD SEQUENCE");
254 }
255
256 LoadedFile * first = _environment->loadedFiles;
257 char *lookfor = _filename;
258 if ( _alias ) {
259 lookfor = _alias;
260 }
261 while( first ) {
262 if ( strcmp(lookfor, first->fileName ) == 0 ) {
263 return first->variable;
264 }
265 first = first->next;
266 }
267
268 AtlasDescriptor * atlasDescriptor = atlas_descriptor_create( _environment, _filename, _flags, _origin_x, _origin_y, _frame_width, _frame_height, _offset_x, _offset_y );
269
270 int bufferSize = 0;
271 Variable * firstImage = NULL;
272 Variable * lastImage = NULL;
273
274 _environment->disableMemoryAreas = 1;
275
276 ImageDescriptor * frame = atlasDescriptor->frames;
277 for(int i=0; i<atlasDescriptor->count; ++i) {
278 Variable * partial = image_converter( _environment, frame->data, frame->width, frame->height, frame->depth, 0, 0, frame->width, frame->height, _mode, _transparent_color, _flags );
279 if ( ! firstImage && ! lastImage ) {
280 firstImage = partial;
281 lastImage = partial;
282 } else {
283 lastImage->next = partial;
284 lastImage = lastImage->next;
285 }
286 bufferSize += partial->size;
287 frame = frame->next;
288 }
289
290 bufferSize += 3;
291
292 adiline1("LS2:%x", bufferSize );
293
294 char * buffer = malloc( bufferSize );
295 char * ptr = buffer;
296 ptr[0] = atlasDescriptor->horizontal;
297 ptr[1] = _frame_width;
298 ptr[2] = atlasDescriptor->horizontal;
299
300 if ( ( firstImage->size * atlasDescriptor->horizontal ) > 0xffff ) {
302 }
303
304 final->offsettingFrames = offsetting_size_count( _environment, firstImage->size, atlasDescriptor->horizontal );
305 offsetting_add_variable_reference( _environment, final->offsettingFrames, final, 0 );
306
307 final->offsettingSequences = offsetting_size_count( _environment, atlasDescriptor->horizontal*firstImage->size, atlasDescriptor->vertical );
308 offsetting_add_variable_reference( _environment, final->offsettingSequences, final, 1 );
309
310 ptr += 3;
311 lastImage = firstImage;
312 for(int i=0; i<atlasDescriptor->count; ++i ) {
313 memcpy( ptr, lastImage->valueBuffer, lastImage->size );
314 ptr += lastImage->size;
315 lastImage = lastImage->next;
316 }
317 variable_store_buffer( _environment, final->name, buffer, bufferSize, 0 );
318 final->originalBitmap = atlasDescriptor->image->data;
319 final->originalWidth = atlasDescriptor->image->width;
320 final->originalHeight = atlasDescriptor->image->height;
321 final->originalDepth = atlasDescriptor->image->depth;
322 final->originalColors = atlasDescriptor->image->colorsCount;
323 memcpy( final->originalPalette, atlasDescriptor->image->colors, MAX_PALETTE * sizeof( RGBi ) );
324 final->frameSize = firstImage->size;
325 final->frameCount = atlasDescriptor->horizontal;
326 final->frameWidth = atlasDescriptor->frames->width;
327 final->frameHeight = atlasDescriptor->frames->height;
328
329 lastImage = firstImage;
330 for(int i=0; i<atlasDescriptor->count; ++i ) {
331 variable_temporary_remove( _environment, lastImage->name );
332 lastImage = lastImage->next;
333 }
334
335 _environment->disableMemoryAreas = 0;
336
337 // stbi_image_free(source);
338
339 if ( _bank_expansion && _environment->expansionBanks ) {
340
341 if ( ! banks_store( _environment, final, _bank_expansion ) ) {
343 }
344
345 } else if ( ( _flags & FLAG_COMPRESSED ) && !_environment->compressionForbidden ) {
346
347 // Try to compress the result of image conversion.
348 // This means that the buffer will be compressed using MSC1
349 // algorithm, up to 32 frequent sequences. The original size of
350 // the buffer will be considered as "uncompressed" size.
351 MSC1Compressor * compressor = msc1_create( 32 );
352 final->uncompressedSize = final->size;
353 MemoryBlock * output = msc1_compress( compressor, final->valueBuffer, final->uncompressedSize, &final->size );
354
355 int temporary;
356 MemoryBlock * outputCheck = msc1_uncompress( compressor, output, final->size, &temporary );
357 if ( memcmp( outputCheck, final->valueBuffer, final->uncompressedSize ) != 0 ) {
359 }
360 msc1_free( compressor );
361
362 // If the compressed memory is greater than the original
363 // size, we discard the compression and we will continue as
364 // usual.
365 // If the compressed memory is greater than the original
366 // size, we discard the compression and we will continue as
367 // usual.
368 if ( final->uncompressedSize < final->size ) {
369 final->size = final->uncompressedSize;
370 final->uncompressedSize = 0;
371 free( output );
372 }
373 // Otherwise, we can safely replace the original data
374 // buffer with the compressed one.
375 else {
376 final->valueBuffer = output;
377 if ( ! banks_store( _environment, final, 1 ) ) {
379 };
380 free( final->valueBuffer );
381 final->valueBuffer = NULL;
382 }
383
384 }
385
386 LoadedFile * loaded = malloc( sizeof( LoadedFile ) );
387 loaded->next = first;
388 loaded->variable = final;
389 loaded->fileName = lookfor;
390 _environment->loadedFiles = loaded;
391
392 if ( _alias ) {
393 const_define_numeric( _environment, _alias, UNIQUE_RESOURCE_ID );
394 }
395
396 final->readonly = 1;
397
398 return final;
399
400}
void const_define_numeric(Environment *_environment, char *_name, int _value)
void variable_temporary_remove(Environment *_environment, char *_name)
void offsetting_add_variable_reference(Environment *_environment, Offsetting *_first, Variable *_var, int _sequence)
Variable * variable_temporary(Environment *_environment, VariableType _type, char *_meaning)
Define a temporary variable.
Offsetting * offsetting_size_count(Environment *_environment, int _size, int _count)
Variable * variable_store_buffer(Environment *_environment, char *_destination, unsigned char *_buffer, int _size, int _at)
Variable * image_converter(Environment *_environment, char *_data, int _width, int _height, int _depth, int _offset_x, int _offset_y, int _frame_width, int _frame_height, int _mode, int _transparent_color, int _flags)
AtlasDescriptor * atlas_descriptor_create(Environment *_environment, char *_filename, int _flags, int _image_origin_x, int _image_origin_y, int _frame_width, int _frame_height, int _frame_offset_x, int _frame_offset_y)
int banks_store(Environment *_environment, Variable *_variable, int _resident)
Definition _banks.c:170
MSC1Compressor * msc1_create(int _maximum_repeated_sequences)
Definition msc1.c:300
void msc1_free(MSC1Compressor *_msc1)
Definition msc1.c:740
MemoryBlock * msc1_uncompress(MSC1Compressor *_msc1, MemoryBlock *_input, int _size, int *_output_size)
Definition msc1.c:746
MemoryBlock * msc1_compress(MSC1Compressor *_msc1, MemoryBlock *_input, int _size, int *_output_size)
Definition msc1.c:381
unsigned char MemoryBlock
Definition msc1.h:90
struct _MSC1Compressor MSC1Compressor
Variable * sequence_load(Environment *_environment, char *_filename, char *_alias, int _mode, int _frame_width, int _frame_height, int _flags, int _transparent_color, int _background_color, int _bank_expansion, int _origin_x, int _origin_y, int _offset_x, int _offset_y)
Emit code for LOAD IMAGE(...).
struct _ImageDescriptor * frames
Definition ugbc.h:939
struct _ImageDescriptor * image
Definition ugbc.h:925
LoadedFile * loadedFiles
Definition ugbc.h:2636
int disableMemoryAreas
Definition ugbc.h:2691
int compressionForbidden
Definition ugbc.h:3169
int sandbox
Definition ugbc.h:2990
Bank * expansionBanks
Definition ugbc.h:3005
int tenLinerRulesEnforced
Definition ugbc.h:2985
int emptyProcedure
Definition ugbc.h:2932
int colorsCount
Definition ugbc.h:918
RGBi * colors
Definition ugbc.h:917
char * data
Definition ugbc.h:911
struct _ImageDescriptor * next
Definition ugbc.h:919
char * fileName
Definition ugbc.h:1481
struct _LoadedFile * next
Definition ugbc.h:1486
Variable * variable
Definition ugbc.h:1483
unsigned char * valueBuffer
Definition ugbc.h:1061
struct _Variable * next
Definition ugbc.h:1225
int size
Definition ugbc.h:1077
char * name
Definition ugbc.h:979
void * malloc(YYSIZE_T)
void free(void *)
#define FLAG_COMPRESSED
Definition ugbc.h:4570
#define CRITICAL_10_LINE_RULES_ENFORCED(v)
Definition ugbc.h:3550
struct _ImageDescriptor ImageDescriptor
struct _RGBi RGBi
Structure to store color components (red, green and blue).
#define adiline1(s, a)
Definition ugbc.h:4187
#define UNIQUE_RESOURCE_ID
Definition ugbc.h:3350
struct _Variable Variable
Structure of a single variable.
struct _Environment Environment
Structure of compilation environment.
@ VT_SEQUENCE
Definition ugbc.h:513
struct _AtlasDescriptor AtlasDescriptor
#define MAX_PALETTE
Definition ugbc.h:568
#define CRITICAL_EXPANSION_OUT_OF_MEMORY_LOADING(v)
Definition ugbc.h:3568
#define CRITICAL_SANDBOX_ENFORCED(v)
Definition ugbc.h:3687
#define CRITICAL_SEQUENCE_LOAD_IMAGE_TOO_BIG(v)
Definition ugbc.h:3663
struct _LoadedFile LoadedFile
#define CRITICAL_COMPRESSION_FAILED(v)
Definition ugbc.h:3768