ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
image_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#include "../../libs/rle.h"
39
40/****************************************************************************
41 * CODE SECTION
42 ****************************************************************************/
43
51/* <usermanual>
52@keyword LOAD IMAGE
53
54@english
55
56The ''LOAD IMAGE'' command allows you to load an image and to convert it into
57an ''IMAGE''. The second parameter is the mode to use to convert
58the given data (by default, it is equal to current mode)
59
60The command support a set of modern image format, like JPEG baseline & progressive,
61PNG 1/2/4/8/16-bit-per-channel, TGA, BMP (non-1bpp, non-RLE), PSD
62(composited view only, no extra channels, 8/16 bit-per-channel),
63GIF, HDR (radiance rgbE format), PIC (Softimage PIC) and PNM (PPM and PGM
64binary only) The image will be converted into a way that can be
65efficiently drawn on the screen.
66
67Since it is possible to load only one file of the same
68type at a time, it is necessary to be able to indicate an "alias" with
69which to exceed this limit. In this regard, there is also
70the ''AS'' syntax, which allows you to load the same file several
71times but with different names.
72
73A series of flags, separated by spaces, can be added at loading time
74to modify the behavior of ugBASIC.
75
76The ''FLIP X'' flag allows you to flip the image horizontally,
77before translating it into the native format. The same is true for the
78''FLIP Y'' command, which instead inverts the image vertically.
79There is also the ''FLIP XY'' (or ''FLIP YX'') parameter to act,
80simultaneously, on both directions.
81
82The ''COMPRESSED'' flag allows you to compress the image, if
83possible. Compression is a space-saving mechanism, in which the
84native data of the image is represented in a more compact form,
85which ugBASIC will be able to quickly convert into graphics at
86the appropriate time.
87
88The ''OVERLAYED'' flag can be used on systems with a palette
89of few colors, to indicate which of them must be preserved
90during the drawing phase, to have the transparency effect.
91
92The ''EXACT'' flag allows you to bypass the automatic detection
93of the palette, opting for the representation of the colors
94according to what is contained in it.
95
96The image can be loaded as a transparent image (if the original
97image has no transparency) using the keyword ''TRANSPARENCY'',
98followe by an optional parameter that represent the color
99to consider as transparent.
100
101The image can be loaded as a transparent image (if the original
102image has no transparency) using the keyword ''OPACITY'',
103followe by an optional parameter that represent the color
104to consider as pavement,.
105
106The image can be loaded directly into the expansion
107memory using the BANKED keyword. The number represent
108the shared resident to use as target for this image.
109For some targets this is the default. If you want,
110you can move the image onto the resident memory by
111using the ''UNBANKED'' keyword.
112
113Finally, if the image is not expected to change during gameplay, it can be marked
114with the ''READONLY'' attribute: in this case, the image will be stored
115in read-only memory, if available.
116
117@italian
118
119Il comando ''LOAD IMAGE'' consente di caricare un'immagine e convertirla in
120una ''IMAGE''. Il secondo parametro è la modalità da utilizzare per convertire
121i dati forniti (per impostazione predefinita, è uguale alla modalità corrente)
122
123Il comando supporta un set di formati immagine moderni, come JPEG baseline e progressivo,
124PNG 1/2/4/8/16 bit per canale, TGA, BMP (non 1bpp, non RLE), PSD
125(solo vista composita, nessun canale extra, 8/16 bit per canale),
126GIF, HDR (formato radiance rgbE), PIC (Softimage PIC) e PNM (solo PPM e PGM
127binary). L'immagine verrà convertita in un modo che può essere
128disegnata in modo efficiente sullo schermo.
129
130Poiché è possibile caricare un solo file dello stesso
131tipo alla volta, è necessario poter indicare un "alias" con
132il quale superare questo limite. A questo proposito, esiste anche
133la sintassi ''AS'', che consente di caricare più volte lo stesso
134file ma con nomi diversi.
135
136Una serie di flag, separati da spazi, possono essere aggiunti in fase di caricamento
137per modificare il comportamento di ugBASIC.
138
139Il flag ''FLIP X'' consente di capovolgere l'immagine orizzontalmente,
140prima di tradurla nel formato nativo. Lo stesso vale per il
141comando ''FLIP Y'', che invece inverte l'immagine verticalmente.
142Esiste anche il parametro ''FLIP XY'' (o ''FLIP YX'') per agire,
143contemporaneamente, su entrambe le direzioni.
144
145Il flag ''COMPRESSED'' consente di comprimere l'immagine, se
146possibile. La compressione è un meccanismo di risparmio di spazio, in cui i dati nativi dell'immagine sono rappresentati in una forma più compatta, che
147ugBASIC sarà in grado di convertire rapidamente in grafica al momento opportuno.
148
149Il flag ''OVERLAYED'' può essere utilizzato su sistemi con una tavolozza
150di pochi colori, per indicare quali di essi devono essere conservati
151durante la fase di disegno, per avere l'effetto trasparenza.
152
153Il flag ''EXACT'' consente di bypassare il rilevamento automatico
154della tavolozza, optando per la rappresentazione dei colori
155in base a ciò che è contenuto in essa.
156
157L'immagine può essere caricata come immagine trasparente (se l'immagine originale
158non ha trasparenza) utilizzando la parola chiave ''TRANSPARENCY'',
159seguita da un parametro opzionale che rappresenta il colore
160da considerare come trasparente.
161
162L'immagine può essere caricata come immagine trasparente (se l'immagine originale non ha trasparenza) usando la parola chiave ''OPACITY'',
163seguita da un parametro opzionale che rappresenta il colore
164da considerare come pavimentazione.
165
166L'immagine può essere caricata direttamente nella memoria di espansione
167usando la parola chiave BANKED. Il numero rappresenta
168il residente condiviso da usare come target per questa immagine.
169Per alcuni target questa è l'impostazione predefinita. Se vuoi,
170puoi spostare l'immagine nella memoria residente
171usando la parola chiave ''UNBANKED''.
172
173Infine, se non è previsto che l'immagine cambi durante il gioco, può essere contrassegnata
174con l'attributo ''READONLY'': in questo caso, l'immagine verrà archiviata
175nella memoria di sola lettura, se disponibile.
176
177@syntax = LOAD IMAGE( filename [AS alias][,mode] ) [fl] [tr] [op] [bg] [bk] [READONLY]
178@syntax fl : [FLIP X] [FLIP Y] [FLIPXY] [FLIPYX]
179@syntax [COMPRESSED] [OVERLAYED] [EXACT]
180@syntax tr : [TRANSPARENCY | TRANSPARENCY color]
181@syntax op : [OPACITY | OPACITY color]
182@syntax bg : [BACKGROUND color]
183@syntax bk : [UNBANKED | BANKED | BANKED(number)]
184
185@example starship = LOAD IMAGE("starship.png")
186@example starship2 = LOAD IMAGE("starship.png" AS "starship2")
187@example alienAt11 = LOAD IMAGE("alien.jpg",11)
188@example alien2 = LOAD IMAGE("alien.jpg" AS "alien2",11)
189
190@usedInExample image_loading_01.bas
191
192@alias IMAGE LOAD
193</usermanual> */
194
195/* <usermanual>
196@keyword IMAGE LOAD
197@alias LOAD IMAGE
198</usermanual> */
199
200Variable * image_load( Environment * _environment, char * _filename, char * _alias, int _mode, int _flags, int _transparent_color, int _background_color, int _bank_expansion ) {
201
202 // First of all, we create a variable to store the image.
203 Variable * result = variable_temporary( _environment, VT_IMAGE, 0 );
204
205 // If the LOAD IMAGE is inside an ignored procedure,
206 // we must avoid to do anything.
207 if ( _environment->emptyProcedure ) {
208 return result;
209 }
210
211 // LOAD IMAGE cannot be used on 10 liner competition.
212 if ( _environment->tenLinerRulesEnforced ) {
213 CRITICAL_10_LINE_RULES_ENFORCED( "LOAD IMAGE");
214 }
215
216 // LOAD IMAGE cannot be used inside sandbox.
217 if ( _environment->sandbox ) {
218 CRITICAL_SANDBOX_ENFORCED( "LOAD IMAGE");
219 }
220
221 // If the image loaded has been already loaded previously,
222 // we must avoid to go ahead and return the very same
223 // variable. Note that this works also if the image
224 // has to be loaded from a mass storage.
225 LoadedFile * first = _environment->loadedFiles;
226 char *lookfor = _filename;
227 if ( _alias ) {
228 lookfor = _alias;
229 }
230 while( first ) {
231 if ( strcmp(lookfor, first->fileName ) == 0 ) {
232 return first->variable;
233 }
234 first = first->next;
235 }
236
237 // No we are going to load the image from the PC.
238 // Those variables will maintain the data of the original image.
239 ImageDescriptor * imageDescriptor = image_descriptor_create( _environment, _filename, _flags );
240
241 // This is a workaround. In a previous release of ugBASIC, we must give
242 // the color index to be used as transparency. If given, we active the
243 // "FLAG TRANSPARENCY" during the conversion.
244 if ( _transparent_color != -1 ) {
245 _flags |= FLAG_TRANSPARENCY;
246 }
247
248 // Now we are able to convert the image from the original format to the
249 // custom format of the target. This is a time efficient mode to store
250 // the image, but not a space efficient (no compression is done).
251 // Space efficiency can be applied after, if a bank is present.
252 result = image_converter( _environment, imageDescriptor->data, imageDescriptor->width, imageDescriptor->height, imageDescriptor->depth, 0, 0, 0, 0, _mode, _transparent_color, _flags );
253
254 // ADI INFO
255 adiline1("LI2:%x", result->size );
256
257 // We can now store the data of the image directly into the variable.
258 result->originalBitmap = imageDescriptor->data;
259 result->originalWidth = imageDescriptor->width;
260 result->originalHeight = imageDescriptor->height;
261 result->originalDepth = imageDescriptor->depth;
262
263#ifdef __c128__
264
265 if (!_environment->compressionForbidden&&_environment->enableRle) {
266
267 // Try to compress the result of image conversion.
268 // This means that the buffer will be compressed using RLE
269 // algorithm. The original size of the buffer will be considered
270 // as "uncompressed" size.
271 RLECompressor * compressor = rle_create( );
272 result->uncompressedSize = result->size;
273 MemoryBlock * output = rle_compress( compressor, result->valueBuffer, result->uncompressedSize, &result->size );
274
275 int temporary;
276 MemoryBlock * outputCheck = rle_uncompress( compressor, output, result->size, &temporary );
277
278 if ( memcmp( outputCheck, result->valueBuffer, result->uncompressedSize ) != 0 ) {
280 }
281 rle_free( compressor );
282
283 // If the compressed memory is greater than the original
284 // size, we discard the compression and we will continue as
285 // usual.
286 if ( result->uncompressedSize < result->size ) {
287 result->size = result->uncompressedSize;
288 result->uncompressedSize = 0;
289 free( output );
290 }
291 // Otherwise, we can safely replace the original data
292 // buffer with the compressed one.
293 else {
294 free( result->valueBuffer );
295 result->valueBuffer = output;
296 result->compression = CMP_RLE;
297 }
298
299 }
300
301#endif
302 // If a bank expasion has been requested, and there is at least one bank...
303 if ( _bank_expansion && _environment->expansionBanks ) {
304
305 if ( !_environment->compressionForbidden ) {
306
307 // Try to compress the result of image conversion.
308 // This means that the buffer will be compressed using MSC1
309 // algorithm, up to 32 frequent sequences. The original size of
310 // the buffer will be considered as "uncompressed" size.
311 MSC1Compressor * compressor = msc1_create( 32 );
312 result->uncompressedSize = result->size;
313 MemoryBlock * output = msc1_compress( compressor, result->valueBuffer, result->uncompressedSize, &result->size );
314
315 int temporary;
316 MemoryBlock * outputCheck = msc1_uncompress( compressor, output, result->size, &temporary );
317
318 if ( memcmp( outputCheck, result->valueBuffer, result->uncompressedSize ) != 0 ) {
320 }
321 msc1_free( compressor );
322
323 // If the compressed memory is greater than the original
324 // size, we discard the compression and we will continue as
325 // usual.
326 if ( result->uncompressedSize < result->size ) {
327 result->size = result->uncompressedSize;
328 result->uncompressedSize = 0;
329 free( output );
330 }
331 // Otherwise, we can safely replace the original data
332 // buffer with the compressed one.
333 else {
334 free( result->valueBuffer );
335 result->valueBuffer = output;
336 }
337
338 }
339
340 if ( ! banks_store( _environment, result, _bank_expansion ) ) {
342 }
343
344 // We can compress also if COMPRESSED flag is used.
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 result->uncompressedSize = result->size;
353 MemoryBlock * output = msc1_compress( compressor, result->valueBuffer, result->uncompressedSize, &result->size );
354
355 int temporary;
356 MemoryBlock * outputCheck = msc1_uncompress( compressor, output, result->size, &temporary );
357 if ( memcmp( outputCheck, result->valueBuffer, result->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 ( result->uncompressedSize < result->size ) {
369 result->size = result->uncompressedSize;
370 result->uncompressedSize = 0;
371 free( output );
372 }
373 // Otherwise, we can safely replace the original data
374 // buffer with the compressed one.
375 else {
376 result->valueBuffer = output;
377 if ( ! banks_store( _environment, result, 1 ) ) {
379 };
380 free( result->valueBuffer );
381 result->valueBuffer = NULL;
382 }
383
384 }
385
386 // Loaded images are ALWAYS readonly!
387 result->readonly = 1;
388
389 // If the original file has been stored into a storage,
390 // then we have to change something. Infact, the image
391 // has not to be deployed directly in the executable
392 // but only the space needed to storage the image.
393 // Moreover, we must avoid to create multiple spaces:
394 // it will be enough to store the maximum size of every
395 // single image.
396
397 // Storage * storage = _environment->storage;
398 // FileStorage * fileStorage = NULL;
399
400 // while( storage ) {
401
402 // fileStorage = storage->files;
403
404 // while( fileStorage ) {
405
406 // if ( strcmp( fileStorage->sourceName, _filename ) == 0 ) {
407 // break;
408 // }
409
410 // fileStorage = fileStorage->next;
411
412 // }
413
414 // if ( fileStorage ) {
415 // break;
416 // }
417
418 // storage = storage->next;
419
420 // }
421
422 // // If the file is stored into any storage memory...
423 // if ( fileStorage ) {
424
425 // if ( ! _environment->storageTransientMemoryArea ) {
426 // _environment->storageTransientMemoryArea = variable_temporary( _environment, VT_BUFFER, "(temporary)" );
427 // variable_resize_buffer( _environment, _environment->storageTransientMemoryArea->name, result->size );
428 // }
429
430 // // If the variable has not been already allocated...
431 // if ( ! fileStorage->variable ) {
432
433 // // Allocate the variable
434 // fileStorage->variable = _environment->storageTransientMemoryArea;
435 // // The image is on the storage, really.
436 // result->onStorage = 1;
437 // // The memory should not be read only.
438 // result->readonly = 0;
439 // } else {
440 // if ( fileStorage->variable->size < result->size ) {
441 // variable_resize_buffer( _environment, _environment->storageTransientMemoryArea->name, result->size );
442 // }
443 // }
444
445 // fileStorage->content = result->valueBuffer;
446 // fileStorage->size = result->size;
447
448 // Variable * filename = variable_temporary( _environment, VT_STRING, "(filename)");
449 // variable_store_string( _environment, filename->name, fileStorage->targetName );
450
451 // // Retrieve the (runtime) address and size of the allocated space.
452 // Variable * address = variable_temporary( _environment, VT_ADDRESS, "(word) ");
453 // Variable * size = variable_temporary( _environment, VT_WORD, "(word) ");
454
455 // cpu_addressof_16bit( _environment, _environment->storageTransientMemoryArea->realName, address->realName );
456 // cpu_store_16bit( _environment, size->realName, fileStorage->size );
457
458 // // Load the resource from the storage.
459 // dload( _environment, filename->name, NULL, address->name, size->name );
460
461 // }
462
463 // stbi_image_free(source);
464
465 // Finally, we store the image as already loaded, in order
466 // to avoid to load again and again and again...
467 LoadedFile * loaded = malloc( sizeof( LoadedFile ) );
468 loaded->next = first;
469 loaded->variable = result;
470 loaded->fileName = lookfor;
471 _environment->loadedFiles = loaded;
472
473 if ( _alias ) {
474 const_define_numeric( _environment, _alias, UNIQUE_RESOURCE_ID );
475 }
476
477 return result;
478
479}
void const_define_numeric(Environment *_environment, char *_name, int _value)
Variable * variable_temporary(Environment *_environment, VariableType _type, char *_meaning)
Define a temporary variable.
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)
int banks_store(Environment *_environment, Variable *_variable, int _resident)
Definition _banks.c:170
ImageDescriptor * image_descriptor_create(Environment *_environment, char *_filename, int _flags)
Variable * image_load(Environment *_environment, char *_filename, char *_alias, int _mode, int _flags, int _transparent_color, int _background_color, int _bank_expansion)
Emit code for LOAD IMAGE(...).
Definition image_load.c:200
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
MemoryBlock * rle_compress(RLECompressor *_rle, MemoryBlock *_input, int _size, int *_output_size)
Definition rle.c:88
RLECompressor * rle_create()
Definition rle.c:41
MemoryBlock * rle_uncompress(RLECompressor *_rle, MemoryBlock *_input, int _size, int *_output_size)
Definition rle.c:230
void rle_free(RLECompressor *_rle)
Definition rle.c:224
struct _RLECompressor RLECompressor
LoadedFile * loadedFiles
Definition ugbc.h:2636
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 enableRle
Definition ugbc.h:2561
int emptyProcedure
Definition ugbc.h:2932
char * data
Definition ugbc.h:911
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
char * originalBitmap
Definition ugbc.h:1142
int size
Definition ugbc.h:1077
int originalHeight
Definition ugbc.h:1148
Compression compression
Definition ugbc.h:1087
int originalDepth
Definition ugbc.h:1151
char * name
Definition ugbc.h:979
int readonly
Definition ugbc.h:1195
int originalWidth
Definition ugbc.h:1145
int uncompressedSize
Definition ugbc.h:1082
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
#define adiline1(s, a)
Definition ugbc.h:4187
#define UNIQUE_RESOURCE_ID
Definition ugbc.h:3350
#define FLAG_TRANSPARENCY
Definition ugbc.h:4567
struct _Variable Variable
Structure of a single variable.
struct _Environment Environment
Structure of compilation environment.
@ VT_IMAGE
Definition ugbc.h:489
@ CMP_RLE
Definition ugbc.h:113
#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