ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
images_load.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *----------------------------------------------------------------------------
16 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
17 * (la "Licenza"); è proibito usare questo file se non in conformità alla
18 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
23 * il software distribuito nei termini della Licenza è distribuito
24 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
25 * implicite. Consultare la Licenza per il testo specifico che regola le
26 * autorizzazioni e le limitazioni previste dalla medesima.
27 ****************************************************************************/
28
29/****************************************************************************
30 * INCLUDE SECTION
31 ****************************************************************************/
32
33#include "../../ugbc.h"
35#include "../../libs/msc1.h"
36
37/****************************************************************************
38 * CODE SECTION
39 ****************************************************************************/
40
48
49/* <usermanual>
50@keyword LOAD ATLAS
51
52@english
53
54The ''LOAD IMAGE'' command allows you to load an set of images and to convert each one
55into an ''ATLAS''. An Atlas is a set of images, numbered by 0 to frame count, which
56can be used individually with the PUT IMAGE command, referring to the corresponding frame.
57The frames are cut out of the original image, using the size provided in the
58''FRAME SIZE (w, h)''. It should be noted that, for this reason, ''ATLAS'' images
59must have a total of a size equal to an entire multiple of the size of the individual frame.
60It is also possible to indicate an offset from which you will have to start cutting the image
61(parameter ''ORIGIN(zx,zy)'') and one related to each individual cutout (''OFFSET (dx, dy)'').
62
63So, the first parameter is the filename to parse. The command support a set of modern image
64format, like JPEG baseline & progressive,
65PNG 1/2/4/8/16-bit-per-channel, TGA, BMP (non-1bpp, non-RLE), PSD
66(composited view only, no extra channels, 8/16 bit-per-channel),
67GIF, HDR (radiance rgbE format), PIC (Softimage PIC) and PNM (PPM and PGM
68binary only) The image will be converted into a way that can be
69efficiently drawn on the screen.
70
71The second parameter is the mode to use to convert the given data (by default, it is
72equal to current mode)
73
74Since it is possible to load only one file of the same
75type at a time, it is necessary to be able to indicate an "alias" with
76which to exceed this limit. In this regard, there is also
77the ''AS'' syntax, which allows you to load the same file several
78times but with different names.
79
80A series of flags, separated by spaces, can be added at loading time
81to modify the behavior of ugBASIC.
82
83The ''FLIP X'' flag allows you to flip the (entire) image horizontally,
84before cutting and translating it into the native format. The same is true for the
85''FLIP Y'' command, which instead inverts the (entire) image vertically.
86There is also the ''FLIP XY'' (or ''FLIP YX'') parameter to act,
87simultaneously, on both directions.
88
89The ''ROLL X'' flag allows you to SHIFT the (entire) image horizontally,
90for the entire size of a frame, in order to generate intermediate
91frames. The very same for ''ROLL Y'' command, which does the same
92vertically. There is also the ''ROLL XY'' (or ''ROLL YX'') parameter to act,
93simultaneously, on both directions.
94
95The ''COMPRESSED'' flag allows you to compress the image, if
96possible. Compression is a space-saving mechanism, in which the
97native data of the image is represented in a more compact form,
98which ugBASIC will be able to quickly convert into graphics at
99the appropriate time.
100
101The ''OVERLAYED'' flag can be used on systems with a palette
102of few colors, to indicate which of them must be preserved
103during the drawing phase, to have the transparency effect.
104
105The ''EXACT'' flag allows you to bypass the automatic detection
106of the palette, opting for the representation of the colors
107according to what is contained in it.
108
109The (entire) image can be loaded as a transparent image (if the original
110image has no transparency) using the keyword ''TRANSPARENCY'',
111followe by an optional parameter that represent the color
112to consider as transparent.
113
114The (entire) image can be loaded as a transparent image (if the original
115image has no transparency) using the keyword ''OPACITY'',
116followe by an optional parameter that represent the color
117to consider as pavement,.
118
119The resulting ''ATLAS'' can be loaded directly into the expansion
120memory using the ''BANKED'' keyword. The number represent
121the shared resident to use as target for this image.
122For some targets this is the default. If you want,
123you can move the image onto the resident memory by
124using the ''UNBANKED'' keyword.
125
126Finally, if the image is not expected to change during gameplay, it can be marked
127with the ''READONLY'' attribute: in this case, the image will be stored
128in read-only memory, if available.
129
130@italian
131
132Il comando ''LOAD ATLAS'' consente di caricare un set di immagini come ''ATLAS''.
133Un ''ATLAS'' è un set di immagini, numerata per il conteggio di 0 a frame, che
134può essere utilizzato individualmente con il comando PUT IMAGE, facendo riferimento
135al frame corrispondente. I frame vengono ritagliati dall'immagine originale,
136utilizzando le dimensioni fornite in ''FRAME SIZE (w, h) ''. Va notato che,
137per questo motivo, l'immagine intera originale deve avere un totale di una
138dimensione pari a un intero multiplo della dimensione del singolo frame.
139È anche possibile indicare un offset da cui si dovrà iniziare a tagliare l'immagine
140(parametro ''ORIGIN(zx,zy)'') e uno relativo a ogni singolo ritaglio (''OFFSET(dx,dy) '').
141
142Quindi, il primo parametro è il nome file da analizzare. Il comando supporta
143un set formati moderni, come JPEG Baseline & Progressive,
144PNG 1/2/4/8/16-bit-per-channel, TGA, BMP (non-1bpp, non-rle), PSD
145(Vista composita solo, nessun canale extra, 8/16 bit-per-channel),
146GIF, HDR (formato radiante RGBE), foto (softimage pic) e PNM (PPM e PGM
147Solo binario) l'immagine verrà convertita in un modo che può essere
148disegnato in modo efficiente sullo schermo.
149
150Il secondo parametro è la modalità da utilizzare per convertire i dati forniti
151(per impostazione predefinita, è uguale alla modalità corrente)
152
153Poiché è possibile caricare solo un file dello stesso nome alla volta, è necessario
154essere in grado di indicare un "alias" con che per superare questo limite.
155A questo proposito, c'è anche La sintassi ''AS'', che consente di caricare lo
156stesso file diverse volte ma con nomi diversi.
157
158Una serie di flag, separate da spazi, può essere aggiunta al momento del caricamento
159Per modificare il comportamento di ugBASIC.
160
161Il flag ''FLIP X '' consente di capovolgere l'intera immagine in orizzontale, prima
162di tagliarla e tradurla nel formato nativo. Lo stesso vale per il flag ''FLIP Y'',
163che invece inverte l'intera immagine in verticale. Vi è anche il flag ''FLIP XY''
164(o ''FLIP XY'') per agire, contemporaneamente, su entrambe le direzioni.
165
166Il flag ''ROLL X'' consente di spostare l'intera immagine in orizzontale,
167per l'intera dimensione di un frame, per generare i fotogrammi intercalari.
168Lo stesso per il flag ''ROLL Y'', che fa lo stesso verticalmente, e
169''ROLL XY '' (o ''ROLL YX'') per agire, contemporaneamente, su entrambe le
170 direzioni.
171
172Il flag "COMPRESSED" consente di comprimere l'immagine, se possibile. La
173compressione è un meccanismo di risparmio spaziale, in cui i dati nativi
174dell'immagine sono rappresentati in una forma più compatta, così che
175ugBASIC sia in grado di convertirsi rapidamente al momento appropriato.
176
177La flag "ORVERLAYED" può essere utilizzata sui sistemi con una tavolozza
178di pochi colori, per indicare quale di essi deve essere preservato,
179durante la fase di disegno, per avere l'effetto di trasparenza.
180
181Il flag "EXACT" consente di bypassare il rilevamento automatico
182della tavolozza, optando per la rappresentazione dei colori precisa.
183
184L'immagine (intera) può essere caricata come un'immagine trasparente (se l'originale
185L'immagine non ha trasparenza) usando la parola chiave ''TRANSPARENCY'',
186seguire da un parametro opzionale che rappresenta il colore
187considerare trasparente.
188
189L'immagine (intera) può essere caricata come un'immagine trasparente (se l'originale
190L'immagine non ha trasparenza) usando la parola chiave ''OPACITY'',
191seguire da un parametro opzionale che rappresenta il colore
192considerare come pavimentazione,.
193
194L' ''ATLAS'' risultante può essere caricata direttamente nell'espansione
195Memoria utilizzando la parola chiave ''BANK''. Il numero rappresenta
196il blocco residente condiviso, da utilizzare come target per questa
197immagine. Per alcuni target questo è il flag predefinito. Si può cambiare
198tale impostazione usando la parola chiave ''UNBANKED''.
199
200Infine, se l'immagine non dovesse cambiare durante il gameplay, può
201essere contrassegnata con l'attributo "READONLY": in questo caso,
202l'immagine verrà memorizzata Nella memoria di sola lettura, se disponibile.
203
204@syntax = LOAD ATLAS( filename [AS alias][,mode] ) frame [ORIGIN(dx,dy)] [fl] [tr] [op] [bg] [bk] [READONLY] [str]
205@syntax = LOAD ATLAS( filename [AS alias][,mode] ) frame [fl] [tr] [op] [bg] [bk] [READONLY] [str]
206@syntax frame : [ FRAME SIZE(w, h) [OFFSET(dx,dy)] [ORIGIN(zx, zy)] | FRAME AUTO]
207@syntax fl : [FLIP X] [FLIP Y] [FLIP XY] [FLIP YX]
208@syntax [COMPRESSED] [OVERLAYED] [EXACT]
209@syntax [ROLL X] [ROLL Y] [ROLL XY] [ROLL YX]
210@syntax tr : [TRANSPARENCY | TRANSPARENCY color]
211@syntax op : [OPACITY | OPACITY color]
212@syntax bg : [BACKGROUND color]
213@syntax bk : [UNBANKED | BANKED | BANKED(number)]
214@syntax str : "[" STRIP [ID id] (f0,f1,...) [, STRIP [ID id] (f2,f3,...)] "]"
215
216@example starship = LOAD ATLAS("starship.png") FRAME SIZE (16, 16)
217@example starship2 = LOAD ATLAS("starship.png" AS "starship2") FRAME SIZE (32, 32) OFFSET(2,2)
218@example alienAt11 = LOAD ATLAS("alien.jpg",11) FRAME SIZE AUTO
219@example alien2 = LOAD ATLAS("alien.jpg" AS "alien2",11) FRAME SIZE(8,8) TRANSPARENCY
220
221@alias LOAD IMAGES
222@alias IMAGES LOAD
223@alias ATLAS LOAD
224
225@target all
226@ntarget gb
227</usermanual> */
228
229/* <usermanual>
230@keyword ATLAS LOAD
231@alias LOAD ATLAS
232@alias LOAD IMAGES
233@alias IMAGES LOAD
234@target all
235@ntarget gb
236</usermanual> */
237
238/* <usermanual>
239@keyword LOAD IMAGES
240@alias LOAD ATLAS
241@alias ATLAS LOAD
242@alias IMAGES LOAD
243@target all
244@ntarget gb
245</usermanual> */
246
247/* <usermanual>
248@keyword IMAGES LOAD
249@alias LOAD ATLAS
250@alias ATLAS LOAD
251@alias LOAD IMAGES
252@target all
253@ntarget gb
254</usermanual> */
255
256Variable * images_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 ) {
257
258 Variable * final = variable_temporary( _environment, VT_IMAGES, 0 );
259
260 if ( _environment->emptyProcedure ) {
261 return final;
262 }
263
264#if defined(__gb__)
265 final->valueBuffer = malloc( 3 );
266 return final;
267#endif
268
269 if ( _environment->tenLinerRulesEnforced ) {
270 CRITICAL_10_LINE_RULES_ENFORCED( "LOAD IMAGES");
271 }
272
273 if ( _environment->sandbox ) {
274 CRITICAL_SANDBOX_ENFORCED( "LOAD IMAGES");
275 }
276
277 LoadedFile * first = _environment->loadedFiles;
278 char *lookfor = _filename;
279 if ( _alias ) {
280 lookfor = _alias;
281 }
282 while( first ) {
283 if ( strcmp(lookfor, first->fileName ) == 0 ) {
284 return first->variable;
285 }
286 first = first->next;
287 }
288
289 AtlasDescriptor * atlasDescriptor = atlas_descriptor_create( _environment, _filename, _flags, _origin_x, _origin_y, _frame_width, _frame_height, _offset_x, _offset_y );
290
291 adiline3("BMP:%4.4x:%4.4x:%2.2x", _frame_width, _frame_height, BITMAP_MODE_STANDARD );
292
293 _environment->disableMemoryAreas = 1;
294
295 int bufferSize = 0;
296 Variable * firstImage = NULL;
297 Variable * lastImage = NULL;
298
299 Variable * partial;
300 ImageDescriptor * frame = atlasDescriptor->frames;
301 for(int i=0; i<atlasDescriptor->count; ++i ) {
302 partial = image_converter( _environment, frame->data, frame->width, frame->height, frame->depth, 0, 0, frame->width, frame->height, _mode, _transparent_color, _flags );
303 if ( !firstImage && !lastImage ) {
304 firstImage = partial;
305 lastImage = firstImage;
306 } else {
307 lastImage->next = partial;
308 lastImage = lastImage->next;
309 }
310 bufferSize += partial->size;
311 frame = frame->next;
312 }
313
314 bufferSize += 3;
315
316 adiline1("LIS2:%x", bufferSize );
317
318 char * buffer = malloc( bufferSize );
319 char * ptr = buffer;
320 ptr[0] = atlasDescriptor->count;
321 ptr[1] = ( _frame_width & 0xff );
322 ptr[2] = ( _frame_width >> 8 ) & 0xff;
323
324 if ( ( firstImage->size * atlasDescriptor->count ) > 0xffff ) {
326 }
327
328 final->offsettingFrames = offsetting_size_count( _environment, firstImage->size, atlasDescriptor->count );
329 offsetting_add_variable_reference( _environment, final->offsettingFrames, final, 0 );
330
331 ptr += 3;
332 lastImage = firstImage;
333 for(int i=0; i<atlasDescriptor->count; ++i ) {
334 memcpy( ptr, lastImage->valueBuffer, lastImage->size );
335 ptr += lastImage->size;
336 lastImage = lastImage->next;
337 }
338
339 variable_store_buffer( _environment, final->name, buffer, bufferSize, 0 );
340 final->originalBitmap = atlasDescriptor->image->data;
341 final->originalWidth = atlasDescriptor->image->width;
342 final->originalHeight = atlasDescriptor->image->height;
343 final->originalDepth = atlasDescriptor->image->depth;
344 final->originalColors = atlasDescriptor->image->colorsCount;
345 memcpy( final->originalPalette, atlasDescriptor->image->colors, MAX_PALETTE * sizeof( RGBi ) );
346 final->frameWidth = _frame_width;
347 final->frameHeight = _frame_height;
348 final->frameSize = firstImage->size;
349 final->frameCount = atlasDescriptor->count;
350
351 lastImage = firstImage;
352 for(int i=0; i<atlasDescriptor->count; ++i ) {
353 variable_temporary_remove( _environment, lastImage->name );
354 lastImage = lastImage->next;
355 }
356
357 _environment->disableMemoryAreas = 0;
358
359 // stbi_image_free(source);
360
361 if ( _bank_expansion && _environment->expansionBanks ) {
362
363 if ( ! banks_store( _environment, final, _bank_expansion ) ) {
365 }
366
367 } else if ( ( _flags & FLAG_COMPRESSED ) && !_environment->compressionForbidden ) {
368
369 // Try to compress the result of image conversion.
370 // This means that the buffer will be compressed using MSC1
371 // algorithm, up to 32 frequent sequences. The original size of
372 // the buffer will be considered as "uncompressed" size.
373 MSC1Compressor * compressor = msc1_create( 32 );
374 final->uncompressedSize = final->size;
375 MemoryBlock * output = msc1_compress( compressor, final->valueBuffer, final->uncompressedSize, &final->size );
376
377 int temporary;
378 MemoryBlock * outputCheck = msc1_uncompress( compressor, output, final->size, &temporary );
379 if ( memcmp( outputCheck, final->valueBuffer, final->uncompressedSize ) != 0 ) {
381 }
382 msc1_free( compressor );
383
384 // If the compressed memory is greater than the original
385 // size, we discard the compression and we will continue as
386 // usual.
387 // If the compressed memory is greater than the original
388 // size, we discard the compression and we will continue as
389 // usual.
390 if ( final->uncompressedSize < final->size ) {
391 final->size = final->uncompressedSize;
392 final->uncompressedSize = 0;
393 free( output );
394 }
395 // Otherwise, we can safely replace the original data
396 // buffer with the compressed one.
397 else {
398 final->valueBuffer = output;
399 if ( ! banks_store( _environment, final, 1 ) ) {
401 };
402 free( final->valueBuffer );
403 final->valueBuffer = NULL;
404 }
405
406 }
407
408 LoadedFile * loaded = malloc( sizeof( LoadedFile ) );
409 loaded->next = first;
410 loaded->variable = final;
411 loaded->fileName = lookfor;
412 _environment->loadedFiles = loaded;
413
414 if ( _alias ) {
415 const_define_numeric( _environment, _alias, UNIQUE_RESOURCE_ID );
416 }
417
418 final->readonly = 1;
419
420 return final;
421
422}
#define BITMAP_MODE_STANDARD
Definition 6847.h:96
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
Variable * images_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(...).
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
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.
#define CRITICAL_IMAGES_LOAD_IMAGE_TOO_BIG(v)
Definition ugbc.h:3662
@ VT_IMAGES
Definition ugbc.h:495
#define adiline3(s, a, b, c)
Definition ugbc.h:4197
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
struct _LoadedFile LoadedFile
#define CRITICAL_COMPRESSION_FAILED(v)
Definition ugbc.h:3768