@@ -350,143 +350,208 @@ bool CFile::read_lbm(FILE* fp, const boost::filesystem::path& filepath)
350350 /* READ SECOND CHUNK "CMAP" */
351351
352352 // chunk-identifier (4 Bytes)
353- // search for the "CMAP" and skip other chunk-types
354- while (!feof (fp))
353+ // search for the "CMAP" and skip/parse other chunk-types
355354 {
356- CHECK_READ (libendian::read (chunk_identifier.data (), 4 , fp));
355+ // Local collection of CRNG (palette animation) chunks
356+ std::vector<PaletteAnimData> crngData;
357357
358- if (strcmp (chunk_identifier.data (), " CMAP" ) == 0 )
359- break ;
360- else
361- {
358+ // Helper to parse a CRNG chunk (caller already read chunk ID, we read length+data)
359+ auto readCRNG = [&]() -> bool {
362360 Uint32 chunkLen;
363- CHECK_READ (libendian::be_read_ui (&chunkLen, fp));
364- if (chunkLen & 1 )
365- chunkLen++;
366- fseek (fp, chunkLen, SEEK_CUR );
367- }
368- }
369- if (feof (fp))
370- return false ;
371- // length of data block
372- CHECK_READ (libendian::be_read_ui (&length, fp));
373- // must be 768 (RGB = 3 Byte x 256 Colors)
374- if (length != 3u * 256u )
375- return false ;
376- // palette
377- for (auto & color : colors)
378- {
379- CHECK_READ (libendian::read (&color.r , 1 , fp));
380- CHECK_READ (libendian::read (&color.g , 1 , fp));
381- CHECK_READ (libendian::read (&color.b , 1 , fp));
382- }
383-
384- /* READ THIRD CHUNK "BODY" */
361+ if (!libendian::be_read_ui (&chunkLen, fp))
362+ return false ;
363+ if (chunkLen >= 8 )
364+ {
365+ PaletteAnimData anim;
366+ uint16_t padding, rate, flags;
367+ if (!libendian::be_read_us (&padding, fp))
368+ return false ;
369+ if (!libendian::be_read_us (&rate, fp))
370+ return false ;
371+ if (!libendian::be_read_us (&flags, fp))
372+ return false ;
373+ uint8_t firstClr, lastClr;
374+ if (!libendian::read (&firstClr, 1 , fp))
375+ return false ;
376+ if (!libendian::read (&lastClr, 1 , fp))
377+ return false ;
378+ anim.isActive = (flags & 1 ) != 0 ;
379+ anim.moveUp = (flags & 2 ) != 0 ;
380+ if (rate)
381+ anim.isActive = anim.moveUp = true ;
382+ anim.rate = rate;
383+ anim.firstClr = firstClr;
384+ anim.lastClr = lastClr;
385+ anim.currentOffset = 0 ;
386+ anim.lastUpdateTime = SDL_GetTicks ();
387+ crngData.push_back (anim);
388+ if (chunkLen > 8 )
389+ {
390+ uint32_t remaining = chunkLen - 8 ;
391+ if (remaining & 1 )
392+ remaining++;
393+ fseek (fp, remaining, SEEK_CUR );
394+ } else if (chunkLen & 1 )
395+ fseek (fp, 1 , SEEK_CUR );
396+ } else
397+ {
398+ if (chunkLen & 1 )
399+ chunkLen++;
400+ fseek (fp, chunkLen, SEEK_CUR );
401+ }
402+ return true ;
403+ };
385404
386- // chunk-identifier (4 Bytes)
387- // search for the "BODY" and skip other chunk-types
388- while (!feof (fp))
389- {
390- CHECK_READ (libendian::read (chunk_identifier.data (), 4 , fp));
405+ while (!feof (fp))
406+ {
407+ CHECK_READ (libendian::read (chunk_identifier.data (), 4 , fp));
391408
392- if (strcmp (chunk_identifier.data (), " BODY" ) == 0 )
393- break ;
394- else
409+ if (strcmp (chunk_identifier.data (), " CMAP" ) == 0 )
410+ break ;
411+ else if (strcmp (chunk_identifier.data (), " CRNG" ) == 0 )
412+ {
413+ CHECK_READ (readCRNG ());
414+ } else
415+ {
416+ Uint32 chunkLen;
417+ CHECK_READ (libendian::be_read_ui (&chunkLen, fp));
418+ if (chunkLen & 1 )
419+ chunkLen++;
420+ fseek (fp, chunkLen, SEEK_CUR );
421+ }
422+ }
423+ if (feof (fp))
424+ return false ;
425+ // length of data block
426+ CHECK_READ (libendian::be_read_ui (&length, fp));
427+ // must be 768 (RGB = 3 Byte x 256 Colors)
428+ if (length != 3u * 256u )
429+ return false ;
430+ // palette
431+ for (auto & color : colors)
395432 {
396- Uint32 chunkLen;
397- CHECK_READ (libendian::be_read_ui (&chunkLen, fp));
398- if (chunkLen & 1 )
399- chunkLen++;
400- fseek (fp, chunkLen, SEEK_CUR );
433+ CHECK_READ (libendian::read (&color.r , 1 , fp));
434+ CHECK_READ (libendian::read (&color.g , 1 , fp));
435+ CHECK_READ (libendian::read (&color.b , 1 , fp));
401436 }
402- }
403- if (feof (fp))
404- return false ;
405- // length of data block
406- CHECK_READ (libendian::be_read_ui (&length, fp));
407437
408- // now we are ready to read the picture lines and fill the surface, so lets create one
409- if (!(bmpArray->surface = makePalSurface (bmpArray->w , bmpArray->h , colors)))
410- {
411- std::cerr << " Failed to create surface: " << SDL_GetError () << std::endl;
412- return false ;
413- }
438+ /* READ THIRD CHUNK "BODY" */
414439
415- if (compression_flag == 0 )
416- {
417- // picture uncompressed
418- // main loop for reading picture lines
419- for (Position pos{0 , 0 }; pos.y < bmpArray->h ; pos.y ++)
440+ // chunk-identifier (4 Bytes)
441+ // search for the "BODY" and skip/parse other chunk-types
442+ while (!feof (fp))
420443 {
421- // loop for reading pixels of the actual picture line
422- for (pos.x = 0 ; pos.x < bmpArray->w ; pos.x ++)
444+ CHECK_READ (libendian::read (chunk_identifier.data (), 4 , fp));
445+
446+ if (strcmp (chunk_identifier.data (), " BODY" ) == 0 )
447+ break ;
448+ else if (strcmp (chunk_identifier.data (), " CRNG" ) == 0 )
423449 {
424- // read color value (1 Byte)
425- CHECK_READ (libendian::read (&color_value, 1 , fp));
426- // draw
427- CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
450+ CHECK_READ (readCRNG ());
451+ } else
452+ {
453+ Uint32 chunkLen;
454+ CHECK_READ (libendian::be_read_ui (&chunkLen, fp));
455+ if (chunkLen & 1 )
456+ chunkLen++;
457+ fseek (fp, chunkLen, SEEK_CUR );
428458 }
429459 }
460+ if (feof (fp))
461+ return false ;
462+ // length of data block
463+ CHECK_READ (libendian::be_read_ui (&length, fp));
430464
431- } else if (compression_flag == 1 )
432- {
433- // picture compressed
465+ // now we are ready to read the picture lines and fill the surface, so lets create one
466+ if (!(bmpArray->surface = makePalSurface (bmpArray->w , bmpArray->h , colors)))
467+ {
468+ std::cerr << " Failed to create surface: " << SDL_GetError () << std::endl;
469+ return false ;
470+ }
434471
435- // main loop for reading picture lines
436- for (Position pos{0 , 0 }; pos.y < bmpArray->h ; pos.y ++)
472+ if (compression_flag == 0 )
437473 {
438- // loop for reading pixels of the actual picture line
439- // (cause of a kind of RLE-Compression we cannot read the pixels sequentially)
440- // 'x' will be incremented WITHIN the loop
441- for (pos.x = 0 ; pos.x < bmpArray->w ;)
474+ // picture uncompressed
475+ // main loop for reading picture lines
476+ for (Position pos{0 , 0 }; pos.y < bmpArray->h ; pos.y ++)
442477 {
443- // read compression type
444- CHECK_READ (libendian::read (&ctype, 1 , fp));
478+ // loop for reading pixels of the actual picture line
479+ for (pos.x = 0 ; pos.x < bmpArray->w ; pos.x ++)
480+ {
481+ // read color value (1 Byte)
482+ CHECK_READ (libendian::read (&color_value, 1 , fp));
483+ // draw
484+ CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
485+ }
486+ }
445487
446- if (ctype >= 0 )
488+ } else if (compression_flag == 1 )
489+ {
490+ // picture compressed
491+
492+ // main loop for reading picture lines
493+ for (Position pos{0 , 0 }; pos.y < bmpArray->h ; pos.y ++)
494+ {
495+ // loop for reading pixels of the actual picture line
496+ // (cause of a kind of RLE-Compression we cannot read the pixels sequentially)
497+ // 'x' will be incremented WITHIN the loop
498+ for (pos.x = 0 ; pos.x < bmpArray->w ;)
447499 {
448- // following 'ctype + 1' pixels are uncompressed
449- for (int k = 0 ; k < ctype + 1 ; k++, pos.x ++)
500+ // read compression type
501+ CHECK_READ (libendian::read (&ctype, 1 , fp));
502+
503+ if (ctype >= 0 )
450504 {
451- // read color value (1 Byte)
505+ // following 'ctype + 1' pixels are uncompressed
506+ for (int k = 0 ; k < ctype + 1 ; k++, pos.x ++)
507+ {
508+ // read color value (1 Byte)
509+ CHECK_READ (libendian::read (&color_value, 1 , fp));
510+ // draw
511+ CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
512+ }
513+ } else if (ctype >= -127 )
514+ {
515+ // draw the following byte '-ctype + 1' times to the surface
452516 CHECK_READ (libendian::read (&color_value, 1 , fp));
453- // draw
454- CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
455- }
456- } else if (ctype >= -127 )
457- {
458- // draw the following byte '-ctype + 1' times to the surface
459- CHECK_READ (libendian::read (&color_value, 1 , fp));
460517
461- for (int k = 0 ; k < -ctype + 1 ; k++, pos.x ++)
462- CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
463- } else // if (ctype == -128)
464- {
465- // ignore
518+ for (int k = 0 ; k < -ctype + 1 ; k++, pos.x ++)
519+ CSurface::DrawPixel_Color (bmpArray->surface .get (), pos, (Uint32)color_value);
520+ } else // if (ctype == -128)
521+ {
522+ // ignore
523+ }
466524 }
467525 }
468- }
469- } else
470- return false ;
471-
472- // if this is a texture file, we need a secondary 32-bit surface for SGE and we set a color key at both surfaces
473- if (filepath.filename () == " TEX5.LBM" || filepath.filename () == " TEX6.LBM" || filepath.filename () == " TEX7.LBM"
474- || filepath.filename () == " TEXTUR_0.LBM" || filepath.filename () == " TEXTUR_3.LBM" )
475- {
476- SDL_SetColorKey (bmpArray->surface .get (), SDL_TRUE , SDL_MapRGB (bmpArray->surface ->format , 0 , 0 , 0 ));
526+ } else
527+ return false ;
477528
478- bmpArray++;
479- if ((bmpArray->surface = makeRGBSurface ((bmpArray - 1 )->w , (bmpArray - 1 )->h )))
529+ // if this is a texture file, we need a secondary 32-bit surface for SGE and we set a color key at both surfaces
530+ if (filepath.filename () == " TEX5.LBM" || filepath.filename () == " TEX6.LBM" || filepath.filename () == " TEX7.LBM"
531+ || filepath.filename () == " TEXTUR_0.LBM" || filepath.filename () == " TEXTUR_3.LBM" )
480532 {
533+ // Store palette animation data for the 8-bit tileset
534+ // bmpArray currently points to the 8-bit slot
535+ const Uint16 bmpIdx8 = static_cast <Uint16>(bmpArray - global::bmpArray.data ());
536+ if (global::tilesetAnimData.size () <= bmpIdx8)
537+ global::tilesetAnimData.resize (bmpIdx8 + 1 );
538+ global::tilesetAnimData[bmpIdx8] = std::move (crngData);
539+
481540 SDL_SetColorKey (bmpArray->surface .get (), SDL_TRUE , SDL_MapRGB (bmpArray->surface ->format , 0 , 0 , 0 ));
482- CSurface::Draw (bmpArray->surface , (bmpArray - 1 )->surface );
483- } else
484- bmpArray--;
485- }
486541
487- // we are finished, the surface is filled
488- // increment bmpArray for the next picture
489- bmpArray++;
542+ bmpArray++;
543+ if ((bmpArray->surface = makeRGBSurface ((bmpArray - 1 )->w , (bmpArray - 1 )->h )))
544+ {
545+ SDL_SetColorKey (bmpArray->surface .get (), SDL_TRUE , SDL_MapRGB (bmpArray->surface ->format , 0 , 0 , 0 ));
546+ CSurface::Draw (bmpArray->surface , (bmpArray - 1 )->surface );
547+ } else
548+ bmpArray--;
549+ }
550+
551+ // we are finished, the surface is filled
552+ // increment bmpArray for the next picture
553+ bmpArray++;
554+ } // end of scope for crngData
490555
491556 return true ;
492557}
0 commit comments