3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
25 // ////////////////////////////////////////////////////////////////////////// //
26 festring
rawbitmap::curfile
;
29 // ////////////////////////////////////////////////////////////////////////// //
30 unsigned char rawbitmap::getb (FILE* fl
) {
32 if (!fl
) ABORT("Cannot read from nothing!");
33 if (fread(&c
, 1, 1, fl
) != 1) ABORT("Error reading file '%s'!", curfile
.CStr());
38 // ////////////////////////////////////////////////////////////////////////// //
39 void rawbitmap::loadPCX (FILE *fl
) {
40 if (fseek(fl
, 0, SEEK_SET
) == -1) ABORT("Error reading file '%s'!", curfile
.CStr());
42 if (getb(fl
) != 10) ABORT("Invalid bitmap format: %s!", curfile
.CStr());
45 case 4: case 5: break;
46 default: ABORT("Invalid bitmap version: %s!", curfile
.CStr());
50 case 0: packed
= false; break;
52 default: ABORT("Invalid bitmap encoding: %s!", curfile
.CStr());
54 if (getb(fl
) != 8) ABORT("Invalid bitmap BPP: %s!", curfile
.CStr());
68 // calculate dimensions
72 if (wdt
< 1 || wdt
> 32700) ABORT("Invalid bitmap width: %s!", curfile
.CStr());
73 if (hgt
< 1 || hgt
> 32700) ABORT("Invalid bitmap height: %s!", curfile
.CStr());
75 for (int skipcount
= 4; skipcount
> 0; --skipcount
) getb(fl
);
76 // skip 16-color palette and reserved
77 for (int skipcount
= 16*3+1; skipcount
> 0; --skipcount
) getb(fl
);
79 if (getb(fl
) != 1) ABORT("Invalid bitmap colorplanes: %s!", curfile
.CStr());
83 if (bpl
< wdt
) ABORT("Invalid bitmap bytes per line: %s!", curfile
.CStr());
84 int hdrread
= 4+4*2+2*2+16*3+1+1+2;
87 if (getb(fl
) != 1) ABORT("Invalid bitmap palette type: %s!", curfile
.CStr());
88 if (getb(fl
) != 0) ABORT("Invalid bitmap palette type: %s!", curfile
.CStr());
91 // skip rest of the header
92 while (hdrread
< 128) { getb(fl
); ++hdrread
; }
96 Alloc2D(PaletteBuffer
, Size
.Y
, Size
.X
);
97 for (int y
= 0; y
< hgt
; ++y
) {
99 for (int x
= 0; x
< bpl
; ++x
) {
101 b
= (unsigned char)getb(fl
);
102 if (packed
&& b
>= 0xc0) {
105 delete [] PaletteBuffer
;
106 ABORT("Invalid compressed bitmap: %s!", curfile
.CStr());
108 b
= (unsigned char)getb(fl
);
114 paletteindex
*Buffer
= PaletteBuffer
[0];
116 *Buffer
= (paletteindex
)b
;
122 if (fseek(fl
, -769, SEEK_END
) == -1) ABORT("Error reading file '%s'!", curfile
.CStr());
124 if (getb(fl
) != 12) ABORT("Invalid bitmap palette: %s!", curfile
.CStr());
125 Palette
= new uChar
[768];
126 if (fread(reinterpret_cast<char *>(Palette
), 1, 768, fl
) != 768) ABORT("Cannot read bitmap palette: %s!", curfile
.CStr());
130 // ////////////////////////////////////////////////////////////////////////// //
132 void rawbitmap::loadPNG (FILE *fl
) {
133 if (fseek(fl
, 0, SEEK_SET
) == -1) ABORT("Error reading file '%s'!", curfile
.CStr());
135 png_structp PNGStruct
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0);
136 if (!PNGStruct
) ABORT("Couldn't read PNG file %s!", curfile
.CStr());
138 png_infop PNGInfo
= png_create_info_struct(PNGStruct
);
139 if (!PNGInfo
) ABORT("Couldn't read PNG file %s!", curfile
.CStr());
141 if (setjmp(png_jmpbuf(PNGStruct
)) != 0) ABORT("Couldn't read PNG file %s!", curfile
.CStr());
143 png_init_io(PNGStruct
, fl
);
144 png_read_info(PNGStruct
, PNGInfo
);
146 Size
.X
= png_get_image_width(PNGStruct
, PNGInfo
);
147 Size
.Y
= png_get_image_height(PNGStruct
, PNGInfo
);
149 if (Size
.X
< 1 || Size
.X
> 32700) ABORT("Invalid bitmap width: %s!", curfile
.CStr());
150 if (Size
.Y
< 1 || Size
.Y
> 32700) ABORT("Invalid bitmap height: %s!", curfile
.CStr());
152 if (png_get_bit_depth(PNGStruct
, PNGInfo
) != 8) ABORT("%s has wrong bit depth %d, should be 8!", curfile
.CStr(), int(png_get_bit_depth(PNGStruct
, PNGInfo
)));
154 png_colorp PNGPalette
;
157 if (!png_get_PLTE(PNGStruct
, PNGInfo
, &PNGPalette
, &PaletteSize
)) ABORT("%s is not in indexed color mode!", curfile
.CStr());
159 if (PaletteSize
!= 256) ABORT("%s has wrong palette size %d, should be 256!", curfile
.CStr(), PaletteSize
);
161 Palette
= new uChar
[768];
163 for (int i
= 0; i
< PaletteSize
; ++i
) {
164 Palette
[i
*3+0] = PNGPalette
[i
].red
;
165 Palette
[i
*3+1] = PNGPalette
[i
].green
;
166 Palette
[i
*3+2] = PNGPalette
[i
].blue
;
169 Alloc2D(PaletteBuffer
, Size
.Y
, Size
.X
);
170 png_read_image(PNGStruct
, PaletteBuffer
);
173 paletteindex *Buffer = PaletteBuffer[0];
174 paletteindex *End = &PaletteBuffer[Size.Y - 1][Size.X];
175 for (; Buffer != End; ++Buffer) *Buffer = 255-(*Buffer);
178 png_destroy_read_struct(&PNGStruct
, &PNGInfo
, nullptr);
183 // ////////////////////////////////////////////////////////////////////////// //
184 void rawbitmap::loadFromFile (FILE *fl
) {
185 if (getb(fl
) == 0x0a) { loadPCX(fl
); return; }
189 ABORT("Invalid image file: '%s'!", curfile
.CStr());
194 // ////////////////////////////////////////////////////////////////////////// //
195 rawbitmap::rawbitmap (cfestring
&FileName
) {
197 FILE *fl
= fopen(FileName
.CStr(), "rb");
200 //fprintf(stderr, "OLD: <%s>\n", curfile.CStr());
201 if (curfile
.GetSize() > 4 && curfile
.endsWithCI(".pcx")) {
202 curfile
.Erase(curfile
.GetSize()-4, 4);
204 //fprintf(stderr, "NEW: <%s>\n", curfile.CStr());
205 fl
= fopen(curfile
.CStr(), "rb");
206 } else if (curfile
.GetSize() > 4 && curfile
.endsWithCI(".png")) {
207 curfile
.Erase(curfile
.GetSize()-4, 4);
209 //fprintf(stderr, "NEW: <%s>\n", curfile.CStr());
210 fl
= fopen(curfile
.CStr(), "rb");
212 if (!fl
) ABORT("Cannot open file '%s'!", FileName
.CStr());
220 rawbitmap::rawbitmap (v2 Size
) : Size(Size
) {
221 Palette
= new uChar
[768];
222 Alloc2D(PaletteBuffer
, Size
.Y
, Size
.X
);
226 rawbitmap::~rawbitmap () {
228 delete [] PaletteBuffer
;
229 for (fontcache::iterator i
= FontCache
.begin(); i
!= FontCache
.end(); ++i
) {
230 delete i
->second
.first
;
231 delete i
->second
.second
;
236 /* a lousy bitmap saver that uses the pcx format */
237 void rawbitmap::Save (cfestring
&FileName
) {
239 memset(PCXHeader
, 0, 128);
241 PCXHeader
[1] = 0x05; // version
242 PCXHeader
[2] = 1; // RLE-packed
243 PCXHeader
[3] = 8; // bpp
244 PCXHeader
[65] = 0x01;
246 PCXHeader
[66] = Size
.X
&0xFF;
247 PCXHeader
[67] = (Size
.X
>>8)&0xFF;
248 PCXHeader
[0x08] = (Size
.X
-1)&0xFF;
249 PCXHeader
[0x09] = ((Size
.X
-1)>>8)&0xFF;
250 PCXHeader
[0x0A] = (Size
.Y
-1)&0xFF;
251 PCXHeader
[0x0B] = ((Size
.Y
-1)>>8)&0xFF;
253 FILE *fo
= fopen(FileName
.CStr(), "wb");
254 //SaveFile.Write(PCXHeader, 128);
255 fwrite(PCXHeader
, 128, 1, fo
);
257 paletteindex
* Buffer
= PaletteBuffer
[0];
258 paletteindex
* End
= &PaletteBuffer
[Size
.Y
-1][Size
.X
];
261 int count
= 0, accb
= 0;
263 while (Buffer
!= End
) {
264 paletteindex b
= *Buffer
++;
268 } else if (count
== 0x3f || b
!= accb
) {
270 if (count
> 1 || accb
>= 0xc0) fputc((unsigned char)(count
|0xc0), fo
);
271 fputc((unsigned char)accb
, fo
);
277 if (++curx
== Size
.X
) {
280 if (count
> 1 || accb
>= 0xc0) fputc((unsigned char)(count
|0xc0), fo
);
281 fputc((unsigned char)accb
, fo
);
284 curx
= 0; // next line
289 if (count
> 1 || accb
>= 0xc0) fputc((unsigned char)(count
|0xc0), fo
);
290 fputc((unsigned char)accb
, fo
);
293 //SaveFile.Write(reinterpret_cast<char*>(Palette), 768);
294 fputc(12, fo
); // palette signature
295 fwrite(reinterpret_cast<char*>(Palette
), 768, 1, fo
);
300 void rawbitmap::MaskedBlit (bitmap
*Bitmap
, packcol16
*Color
) const {
301 MaskedBlit(Bitmap
, ZERO_V2
, ZERO_V2
, Size
, Color
);
305 void rawbitmap::MaskedBlit (bitmap
*Bitmap
, v2 Src
, v2 Dest
, v2 Border
, packcol16
*Color
) const {
306 if (!femath::Clip(Src
.X
, Src
.Y
, Dest
.X
, Dest
.Y
, Border
.X
, Border
.Y
, Size
.X
, Size
.Y
, Bitmap
->GetSize().X
, Bitmap
->GetSize().Y
)) return;
307 paletteindex
*Buffer
= &PaletteBuffer
[Src
.Y
][Src
.X
];
308 packcol16
*DestBuffer
= &Bitmap
->GetImage()[Dest
.Y
][Dest
.X
];
309 int BitmapXSize
= Bitmap
->GetSize().X
;
310 uChar
*Palette
= this->Palette
; // eliminate the efficiency cost of dereferencing
311 for (int y
= 0; y
< Border
.Y
; ++y
) {
312 for (int x
= 0; x
< Border
.X
; ++x
) {
313 int PaletteElement
= Buffer
[x
];
314 if (PaletteElement
>= 192) {
315 int ThisColor
= Color
[(PaletteElement
-192)>>4];
316 int Index
= PaletteElement
&15;
317 int Red
= (ThisColor
>> 8 & 0xF8)*Index
;
318 int Green
= (ThisColor
>> 3 & 0xFC)*Index
;
319 int Blue
= (ThisColor
<< 3 & 0xF8)*Index
;
320 if (Red
> 0x7FF) Red
= 0x7FF;
321 if (Green
> 0x7FF) Green
= 0x7FF;
322 if (Blue
> 0x7FF) Blue
= 0x7FF;
323 DestBuffer
[x
] = (Red
<< 5 & 0xF800) | (Green
& 0x7E0) | (Blue
>> 6 & 0x1F);
325 int PaletteIndex
= PaletteElement
+(PaletteElement
<< 1);
327 ((Palette
[PaletteIndex
] & 0xFFF8) << 8) |
328 ((Palette
[PaletteIndex
+1] & 0xFFFC) << 3) |
329 (Palette
[PaletteIndex
+2] >> 3);
330 if (ThisColor
!= TRANSPARENT_COLOR
) DestBuffer
[x
] = ThisColor
;
333 DestBuffer
+= BitmapXSize
;
339 cachedfont
*rawbitmap::Colorize (cpackcol16
*Color
, alpha BaseAlpha
, cpackalpha
*Alpha
) const {
340 cachedfont
*Bitmap
= new cachedfont(Size
);
341 paletteindex
*Buffer
= PaletteBuffer
[0];
342 packcol16
*DestBuffer
= Bitmap
->GetImage()[0];
343 uChar
*Palette
= this->Palette
; // eliminate the efficiency cost of dereferencing
346 if (BaseAlpha
!= 255 || (Alpha
&& (Alpha
[0] != 255 || Alpha
[1] != 255 || Alpha
[2] != 255 || Alpha
[3] != 255))) {
347 Bitmap
->CreateAlphaMap(BaseAlpha
);
348 AlphaMap
= Bitmap
->GetAlphaMap()[0];
354 int BitmapXSize
= Bitmap
->GetSize().X
;
355 for (int y
= 0; y
< Size
.Y
; ++y
) {
356 for (int x
= 0; x
< Size
.X
; ++x
) {
357 int PaletteElement
= Buffer
[x
];
358 if (PaletteElement
>= 192) {
359 int ColorIndex
= (PaletteElement
-192)>>4;
360 int ThisColor
= Color
[ColorIndex
];
361 if (ThisColor
!= TRANSPARENT_COLOR
) {
362 int Index
= PaletteElement
& 15;
363 int Red
= (ThisColor
>> 8 & 0xF8)*Index
;
364 int Green
= (ThisColor
>> 3 & 0xFC)*Index
;
365 int Blue
= (ThisColor
<< 3 & 0xF8)*Index
;
366 if(Red
> 0x7FF) Red
= 0x7FF;
367 if(Green
> 0x7FF) Green
= 0x7FF;
368 if(Blue
> 0x7FF) Blue
= 0x7FF;
369 DestBuffer
[x
] = (Red
<< 5 & 0xF800) | (Green
& 0x7E0) | (Blue
>> 6 & 0x1F);
370 if (UseAlpha
) AlphaMap
[x
] = Alpha
[ColorIndex
];
372 DestBuffer
[x
] = TRANSPARENT_COLOR
;
375 int PaletteIndex
= PaletteElement
+(PaletteElement
<<1);
377 ((Palette
[PaletteIndex
] & 0xFFF8) << 8) |
378 ((Palette
[PaletteIndex
+ 1] & 0xFFFC) << 3) |
379 (Palette
[PaletteIndex
+ 2] >> 3);
382 DestBuffer
+= BitmapXSize
;
383 AlphaMap
+= BitmapXSize
;
390 bitmap
*rawbitmap::Colorize (v2 Pos
, v2 Border
, v2 Move
, cpackcol16
*Color
, alpha BaseAlpha
,
391 cpackalpha
*Alpha
, cuchar
*RustData
, truth AllowReguralColors
) const
393 bitmap
*Bitmap
= new bitmap(Border
);
395 if (Move
.X
|| Move
.Y
) {
396 Bitmap
->ClearToColor(TRANSPARENT_COLOR
);
400 } else if (Move
.X
> 0) {
401 TargetPos
.X
= Move
.X
;
407 } else if (Move
.Y
> 0) {
408 TargetPos
.Y
= Move
.Y
;
412 paletteindex
*Buffer
= &PaletteBuffer
[Pos
.Y
][Pos
.X
];
413 packcol16
*DestBuffer
= &Bitmap
->GetImage()[TargetPos
.Y
][TargetPos
.X
];
414 int BitmapXSize
= Bitmap
->GetSize().X
;
415 uChar
*Palette
= this->Palette
; // eliminate the efficiency cost of dereferencing
418 if (BaseAlpha
!= 255 || (Alpha
&& (Alpha
[0] != 255 || Alpha
[1] != 255 || Alpha
[2] != 255 || Alpha
[3] != 255))) {
419 Bitmap
->CreateAlphaMap(BaseAlpha
);
420 AlphaMap
= &Bitmap
->GetAlphaMap()[TargetPos
.Y
][TargetPos
.X
];
426 truth Rusted
= RustData
&& (RustData
[0] || RustData
[1] || RustData
[2] || RustData
[3]);
429 RustSeed
[0] = (RustData
[0]&0xFC)>>2;
430 RustSeed
[1] = (RustData
[1]&0xFC)>>2;
431 RustSeed
[2] = (RustData
[2]&0xFC)>>2;
432 RustSeed
[3] = (RustData
[3]&0xFC)>>2;
434 for (int y
= 0; y
< Border
.Y
; ++y
) {
435 for (int x
= 0; x
< Border
.X
; ++x
) {
436 int PaletteElement
= Buffer
[x
];
437 if (PaletteElement
>= 192) {
438 int ColorIndex
= (PaletteElement
-192)>>4;
439 int ThisColor
= Color
[ColorIndex
];
440 if (ThisColor
!= TRANSPARENT_COLOR
) {
441 int Index
= PaletteElement
& 15;
442 int Red
= (ThisColor
>> 8 & 0xF8)*Index
;
443 int Green
= (ThisColor
>> 3 & 0xFC)*Index
;
444 int Blue
= (ThisColor
<< 3 & 0xF8)*Index
;
445 if (Rusted
&& RustData
[ColorIndex
] &&
446 (RustData
[ColorIndex
] & 3UL) > (RustSeed
[ColorIndex
] = RustSeed
[ColorIndex
] * 1103515245 + 12345) >> 30) {
447 Green
= ((Green
<< 1) + Green
) >> 2;
450 if (Red
> 0x7FF) Red
= 0x7FF;
451 if (Green
> 0x7FF) Green
= 0x7FF;
452 if (Blue
> 0x7FF) Blue
= 0x7FF;
453 DestBuffer
[x
] = (Red
<< 5 & 0xF800) | (Green
& 0x7E0) | (Blue
>> 6 & 0x1F);
454 if (UseAlpha
) AlphaMap
[x
] = Alpha
[ColorIndex
];
456 DestBuffer
[x
] = TRANSPARENT_COLOR
;
458 } else if (AllowReguralColors
) {
459 int PaletteIndex
= PaletteElement
+(PaletteElement
<<1);
461 ((Palette
[PaletteIndex
] & 0xFFF8) << 8) |
462 ((Palette
[PaletteIndex
+ 1] & 0xFFFC) << 3) |
463 (Palette
[PaletteIndex
+ 2] >> 3);
465 DestBuffer
[x
] = TRANSPARENT_COLOR
;
468 DestBuffer
+= BitmapXSize
;
469 AlphaMap
+= BitmapXSize
;
476 truth
rawbitmap::strHasCtlCodes (cchar
*str
) {
478 if (*str
== '\1' || *str
== '\2') return true;
485 void rawbitmap::printstrColored (bitmap
*bmp
, v2 pos
, packcol16 clr
, truth shaded
, cchar
*str
) const {
486 if (!str
|| *str
== 0) return;
487 // has control codes?
488 if (!strHasCtlCodes(str
)) {
489 // no, try cached font
490 fontcache::const_iterator Iterator
= FontCache
.find(clr
);
491 if (Iterator
!= FontCache
.end()) {
493 const cachedfont
*Font
= (shaded
? Iterator
->second
.first
: Iterator
->second
.second
);
504 unsigned char ch
= (unsigned char)*str
++;
505 if (ch
< ' ' || ch
>= 127) ch
= ' '; //FIXME: ignore?
506 B
.Src
.X
= ((ch
-0x20)&0xF) << 4;
507 B
.Src
.Y
= (ch
-0x20)&0xF0;
508 Font
->PrintCharacter(B
);
514 // has control codes, or no cached font
515 packcol16 curcol
= clr
;
516 packcol16 clrshade
= MakeShadeColor(clr
);
521 if (str
[0] == 0) break;
523 case 'R': curcol
= RED
; break;
524 case 'G': curcol
= GREEN
; break;
525 case 'B': curcol
= BLUE
; break;
526 case 'Y': curcol
= YELLOW
; break;
527 case 'W': curcol
= (clr
!= WHITE
? WHITE
: LIGHT_GRAY
); break;
528 case 'C': curcol
= CYAN
; break;
529 case 'P': curcol
= PINK
; break;
530 case 'D': curcol
= DARK_GRAY
; break;
531 case 'S': curcol
= SEL_BLUE
; break;
536 if (*str
== '\2') { curcol
= clr
; ++str
; continue; }
537 // other control chars?
538 if ((unsigned char)*str
< ' ' || (unsigned char)*str
>= 127) { ++str
; continue; }
540 v2
F(((*str
-0x20)&0xF)<<4, (*str
-0x20)&0xF0);
542 if (shaded
) MaskedBlit(bmp
, F
, v2(pos
.X
+1, pos
.Y
+1), v2(8, 8), &clrshade
);
543 MaskedBlit(bmp
, F
, pos
, v2(8, 8), &curcol
);
549 void rawbitmap::printfColoredVA (bitmap
*bmp
, v2 pos
, packcol16 clr
, truth shaded
, cchar
*fmt
, va_list vap
) const {
551 char *bufptr
= buffer
;
552 int bufsz
= (int)sizeof(buffer
)-1;
559 n
= vsnprintf(bufptr
, bufsz
, fmt
, ap
);
561 if (n
> -1 && n
< bufsz
) break;
562 if (n
< -1) n
= bufsz
+4096;
563 np
= (char *)realloc((bufptr
== buffer
? NULL
: bufptr
), n
+1);
564 if (np
== NULL
) return; //FIXME
567 printstrColored(bmp
, pos
, clr
, shaded
, bufptr
);
569 if (bufptr
!= buffer
) free(bufptr
);
573 void rawbitmap::Printf (bitmap
*Bitmap
, v2 Pos
, packcol16 Color
, cchar
*Format
, ...) const {
575 va_start(ap
, Format
);
576 printfColoredVA(Bitmap
, Pos
, Color
, true, Format
, ap
);
581 void rawbitmap::PrintfColored (bitmap
*Bitmap
, v2 Pos
, packcol16 Color
, cchar
*Format
, ...) const {
583 va_start(ap
, Format
);
584 printfColoredVA(Bitmap
, Pos
, Color
, true, Format
, ap
);
589 void rawbitmap::PrintfUnshaded (bitmap
*Bitmap
, v2 Pos
, packcol16 Color
, cchar
*Format
, ...) const {
591 va_start(ap
, Format
);
592 printfColoredVA(Bitmap
, Pos
, Color
, false, Format
, ap
);
597 void rawbitmap::PrintfUnshadedColored (bitmap
*Bitmap
, v2 Pos
, packcol16 Color
, cchar
*Format
, ...) const {
599 va_start(ap
, Format
);
600 printfColoredVA(Bitmap
, Pos
, Color
, false, Format
, ap
);
605 void rawbitmap::AlterGradient (v2 Pos
, v2 Border
, int MColor
, int Amount
, truth Clip
) {
606 int ColorMin
= 192+(MColor
<<4);
607 int ColorMax
= 207+(MColor
<<4);
609 for (int x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
) {
610 for (int y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
) {
611 int Pixel
= PaletteBuffer
[y
][x
];
612 if (Pixel
>= ColorMin
&& Pixel
<= ColorMax
) {
613 int NewPixel
= Pixel
+Amount
;
614 if (NewPixel
< ColorMin
) NewPixel
= ColorMin
;
615 if (NewPixel
> ColorMax
) NewPixel
= ColorMax
;
616 PaletteBuffer
[y
][x
] = NewPixel
;
622 for (x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
) {
623 for (int y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
) {
624 int Pixel
= PaletteBuffer
[y
][x
];
625 if (Pixel
>= ColorMin
&& Pixel
<= ColorMax
) {
626 int NewPixel
= Pixel
+Amount
;
627 if (NewPixel
< ColorMin
) return;
628 if (NewPixel
> ColorMax
) return;
632 for (x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
) {
633 for (int y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
) {
634 int Pixel
= PaletteBuffer
[y
][x
];
635 if (Pixel
>= ColorMin
&& Pixel
<= ColorMax
) PaletteBuffer
[y
][x
] = Pixel
+Amount
;
642 void rawbitmap::SwapColors (v2 Pos
, v2 Border
, int Color1
, int Color2
) {
643 if (Color1
> 3 || Color2
> 3) ABORT("Illgal col swap!");
644 for (int x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
) {
645 for (int y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
) {
646 paletteindex
&Pixel
= PaletteBuffer
[y
][x
];
647 if (Pixel
>= 192+(Color1
<<4) && Pixel
<= 207+(Color1
<<4)) Pixel
+= (Color2
-Color1
)<<4;
648 else if (Pixel
>= 192+(Color2
<<4) && Pixel
<= 207+(Color2
<<4)) Pixel
+= (Color1
-Color2
)<<4;
654 /* TempBuffer must be an array of Border.X * Border.Y paletteindices */
655 void rawbitmap::Roll (v2 Pos
, v2 Border
, v2 Move
, paletteindex
*TempBuffer
) {
657 for (x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
) {
658 for (y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
) {
659 int XPos
= x
+Move
.X
, YPos
= y
+Move
.Y
;
660 if (XPos
< Pos
.X
) XPos
+= Border
.X
;
661 if (YPos
< Pos
.Y
) YPos
+= Border
.Y
;
662 if (XPos
>= Pos
.X
+Border
.X
) XPos
-= Border
.X
;
663 if (YPos
>= Pos
.Y
+Border
.Y
) YPos
-= Border
.Y
;
664 TempBuffer
[(YPos
-Pos
.Y
)*Border
.X
+XPos
-Pos
.X
] = PaletteBuffer
[y
][x
];
667 for (x
= Pos
.X
; x
< Pos
.X
+ Border
.X
; ++x
)
668 for (y
= Pos
.Y
; y
< Pos
.Y
+ Border
.Y
; ++y
)
669 PaletteBuffer
[y
][x
] = TempBuffer
[(y
-Pos
.Y
)*Border
.X
+x
-Pos
.X
];
673 void rawbitmap::CreateFontCache (packcol16 Color
) {
674 if (FontCache
.find(Color
) != FontCache
.end()) return;
675 packcol16 ShadeColor
= MakeShadeColor(Color
);
676 cachedfont
*Font
= new cachedfont(Size
, TRANSPARENT_COLOR
);
677 MaskedBlit(Font
, ZERO_V2
, v2(1, 1), v2(Size
.X
-1, Size
.Y
-1), &ShadeColor
);
678 cachedfont
*UnshadedFont
= Colorize(&Color
);
688 UnshadedFont
->NormalMaskedBlit(B
);
689 Font
->CreateMaskMap();
690 UnshadedFont
->CreateMaskMap();
691 FontCache
[Color
] = std::make_pair(Font
, UnshadedFont
);
695 /* returns ERROR_V2 if fails find Pos else returns pos */
696 v2
rawbitmap::RandomizeSparklePos (cv2
*ValidityArray
, v2
*PossibleBuffer
, v2 Pos
, v2 Border
,
697 int ValidityArraySize
, int SparkleFlags
) const
699 if (!SparkleFlags
) return ERROR_V2
;
700 /* Don't use { } to initialize, or GCC optimizations will produce code that crashes! */
702 BadPossible
[0] = PossibleBuffer
;
703 BadPossible
[1] = BadPossible
[0]+((Border
.X
+Border
.Y
)<<1)-4;
704 BadPossible
[2] = BadPossible
[1]+((Border
.X
+Border
.Y
)<<1)-12;
705 BadPossible
[3] = BadPossible
[2]+((Border
.X
+Border
.Y
)<<1)-20;
706 v2
*PreferredPossible
= BadPossible
[3]+((Border
.X
+Border
.Y
)<<1)-28;
708 int Bad
[4] = { 0, 0, 0, 0 };
709 int XMax
= Pos
.X
+Border
.X
;
710 int YMax
= Pos
.Y
+Border
.Y
;
711 for (int c
= 0; c
< ValidityArraySize
; ++c
) {
712 v2 V
= ValidityArray
[c
]+Pos
;
713 int Entry
= PaletteBuffer
[V
.Y
][V
.X
];
714 if (IsMaterialColor(Entry
) && 1 << GetMaterialColorIndex(Entry
) & SparkleFlags
) {
715 int MinDist
= 0x7FFF;
716 if (V
.X
< Pos
.X
+4) MinDist
= Min(V
.X
-Pos
.X
, MinDist
);
717 if (V
.X
>= XMax
-4) MinDist
= Min(XMax
-V
.X
-1, MinDist
);
718 if (V
.Y
< Pos
.Y
+4) MinDist
= Min(V
.Y
-Pos
.Y
, MinDist
);
719 if (V
.Y
>= YMax
-4) MinDist
= Min(YMax
-V
.Y
-1, MinDist
);
720 if (MinDist
>= 4) PreferredPossible
[Preferred
++] = V
;
721 else BadPossible
[MinDist
][Bad
[MinDist
]++] = V
;
725 if (Preferred
) Return
= PreferredPossible
[RAND()%Preferred
]-Pos
;
726 else if (Bad
[3]) Return
= BadPossible
[3][RAND()%Bad
[3]]-Pos
;
727 else if (Bad
[2]) Return
= BadPossible
[2][RAND()%Bad
[2]]-Pos
;
728 else if (Bad
[1]) Return
= BadPossible
[1][RAND()%Bad
[1]]-Pos
;
729 else if (Bad
[0]) Return
= BadPossible
[0][RAND()%Bad
[0]]-Pos
;
730 else Return
= ERROR_V2
;
735 truth
rawbitmap::IsTransparent (v2 Pos
) const {
736 return PaletteBuffer
[Pos
.Y
][Pos
.X
] == TRANSPARENT_PALETTE_INDEX
;
740 truth
rawbitmap::IsMaterialColor1 (v2 Pos
) const {
741 int P
= PaletteBuffer
[Pos
.Y
][Pos
.X
];
742 return P
>= 192 && P
< 208;
746 void rawbitmap::CopyPaletteFrom (rawbitmap
*Bitmap
) {
747 memmove(Palette
, Bitmap
->Palette
, 768);
751 void rawbitmap::Clear () {
752 memset(PaletteBuffer
[0], TRANSPARENT_PALETTE_INDEX
, Size
.X
*Size
.Y
*sizeof(paletteindex
));
756 void rawbitmap::NormalBlit (rawbitmap
*Bitmap
, v2 Src
, v2 Dest
, v2 Border
, int Flags
) const {
757 paletteindex
**SrcBuffer
= PaletteBuffer
;
758 paletteindex
**DestBuffer
= Bitmap
->PaletteBuffer
;
760 paletteindex
*DestBase
;
763 if (Size
.X
== Bitmap
->Size
.X
&& Size
.Y
== Bitmap
->Size
.Y
) {
764 memmove(DestBuffer
[0], SrcBuffer
[0], Size
.X
*Size
.Y
*sizeof(paletteindex
));
766 cint Bytes
= Border
.X
*sizeof(paletteindex
);
767 for (int y
= 0; y
< Border
.Y
; ++y
) memmove(&DestBuffer
[Dest
.Y
+y
][Dest
.X
], &SrcBuffer
[Src
.Y
+y
][Src
.X
], Bytes
);
771 Dest
.X
+= Border
.X
-1;
772 for (int y
= 0; y
< Border
.Y
; ++y
) {
773 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
774 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
775 paletteindex
*DestPtr
= &DestBuffer
[Dest
.Y
+y
][Dest
.X
];
776 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) *DestPtr
= *SrcPtr
;
780 Dest
.Y
+= Border
.Y
-1;
781 cint Bytes
= Border
.X
*sizeof(paletteindex
);
782 for (int y
= 0; y
< Border
.Y
; ++y
) memmove(&DestBuffer
[Dest
.Y
-y
][Dest
.X
], &SrcBuffer
[Src
.Y
+y
][Src
.X
], Bytes
);
784 case (MIRROR
| FLIP
):
785 Dest
.X
+= Border
.X
-1;
786 Dest
.Y
+= Border
.Y
-1;
787 for (int y
= 0; y
< Border
.Y
; ++y
) {
788 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
789 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
790 paletteindex
*DestPtr
= &DestBuffer
[Dest
.Y
-y
][Dest
.X
];
791 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) *DestPtr
= *SrcPtr
;
795 Dest
.X
+= Border
.X
-1;
796 TrueDestXMove
= Bitmap
->Size
.X
;
797 DestBase
= &DestBuffer
[Dest
.Y
][Dest
.X
];
798 for (int y
= 0; y
< Border
.Y
; ++y
) {
799 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
800 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
801 paletteindex
*DestPtr
= DestBase
-y
;
802 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) *DestPtr
= *SrcPtr
;
805 case (MIRROR
| ROTATE
):
806 TrueDestXMove
= Bitmap
->Size
.X
;
807 DestBase
= &DestBuffer
[Dest
.Y
][Dest
.X
];
808 for (int y
= 0; y
< Border
.Y
; ++y
) {
809 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
810 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
811 paletteindex
*DestPtr
= DestBase
+y
;
812 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) *DestPtr
= *SrcPtr
;
815 case (FLIP
| ROTATE
):
816 Dest
.X
+= Border
.X
-1;
817 Dest
.Y
+= Border
.Y
-1;
818 TrueDestXMove
= Bitmap
->Size
.X
;
819 DestBase
= &DestBuffer
[Dest
.Y
][Dest
.X
];
820 for (int y
= 0; y
< Border
.Y
; ++y
) {
821 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
822 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
823 paletteindex
*DestPtr
= DestBase
-y
;
824 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) *DestPtr
= *SrcPtr
;
827 case (MIRROR
| FLIP
| ROTATE
):
828 Dest
.Y
+= Border
.Y
-1;
829 TrueDestXMove
= Bitmap
->Size
.X
;
830 DestBase
= &DestBuffer
[Dest
.Y
][Dest
.X
];
831 for (int y
= 0; y
< Border
.Y
; ++y
) {
832 cpaletteindex
*SrcPtr
= &SrcBuffer
[Src
.Y
+y
][Src
.X
];
833 cpaletteindex
*EndPtr
= SrcPtr
+Border
.X
;
834 paletteindex
*DestPtr
= DestBase
+y
;
835 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) *DestPtr
= *SrcPtr
;