1 /*
2 *
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
7 *
8 * See LICENSING which should be included
9 * along with this file for more details
10 *
11 */
12
13 #include <cstdarg>
14 #include <memory>
15
16 #include "png.h"
17
18 #include "allocate.h"
19 #include "rawbit.h"
20 #include "bitmap.h"
21 #include "save.h"
22 #include "femath.h"
23
MaskedBlit(bitmap * Bitmap,packcol16 * Color) const24 void rawbitmap::MaskedBlit(bitmap* Bitmap, packcol16* Color) const { MaskedBlit(Bitmap, ZERO_V2, ZERO_V2, Size, Color); }
25
rawbitmap(cfestring & FileName)26 rawbitmap::rawbitmap(cfestring& FileName)
27 {
28 std::shared_ptr<FILE> File(fopen(FileName.CStr(), "rb"), fclose);
29
30 if(!File)
31 ABORT("Bitmap %s not found!", FileName.CStr());
32
33 png_structp PNGStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
34
35 if(!PNGStruct)
36 ABORT("Couldn't read PNG file %s!", FileName.CStr());
37
38 png_infop PNGInfo = png_create_info_struct(PNGStruct);
39
40 if(!PNGInfo)
41 abort();
42
43 if(setjmp(png_jmpbuf(PNGStruct)) != 0)
44 abort();
45
46 png_init_io(PNGStruct, File.get());
47 png_read_info(PNGStruct, PNGInfo);
48
49 Size.X = png_get_image_width(PNGStruct, PNGInfo);
50 Size.Y = png_get_image_height(PNGStruct, PNGInfo);
51
52 if(png_get_bit_depth(PNGStruct, PNGInfo) != 8)
53 ABORT("%s has wrong bit depth %d, should be 8!", FileName.CStr(),
54 int(png_get_bit_depth(PNGStruct, PNGInfo)));
55
56 png_colorp PNGPalette;
57 int PaletteSize;
58
59 if(!png_get_PLTE(PNGStruct, PNGInfo, &PNGPalette, &PaletteSize))
60 ABORT("%s is not in indexed color mode!", FileName.CStr());
61
62 if(PaletteSize != 256)
63 ABORT("%s has wrong palette size %d, should be 256!", FileName.CStr(), PaletteSize);
64
65 Palette = new uchar[768];
66
67 for(int i = 0; i < PaletteSize; ++i)
68 {
69 Palette[i * 3 + 0] = PNGPalette[255 - i].red;
70 Palette[i * 3 + 1] = PNGPalette[255 - i].green;
71 Palette[i * 3 + 2] = PNGPalette[255 - i].blue;
72 }
73
74 Alloc2D(PaletteBuffer, Size.Y, Size.X);
75 png_read_image(PNGStruct, PaletteBuffer);
76 paletteindex* Buffer = PaletteBuffer[0];
77 paletteindex* End = &PaletteBuffer[Size.Y - 1][Size.X];
78
79 for(; Buffer != End; ++Buffer)
80 *Buffer = 255 - *Buffer;
81
82 png_destroy_read_struct(&PNGStruct, &PNGInfo, nullptr);
83 }
84
rawbitmap(v2 Size)85 rawbitmap::rawbitmap(v2 Size) : Size(Size)
86 {
87 Palette = new uchar[768];
88 Alloc2D(PaletteBuffer, Size.Y, Size.X);
89 }
90
~rawbitmap()91 rawbitmap::~rawbitmap()
92 {
93 delete [] Palette;
94 delete [] PaletteBuffer;
95
96 for(fontcache::value_type& p : FontCache)
97 {
98 delete p.second.first;
99 delete p.second.second;
100 }
101 }
102
Save(cfestring & FileName)103 void rawbitmap::Save(cfestring& FileName)
104 {
105 std::shared_ptr<FILE> File(fopen(FileName.CStr(), "wb"), fclose);
106 png_structp PNGStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
107 png_infop PNGInfo = png_create_info_struct(PNGStruct);
108 png_init_io(PNGStruct, File.get());
109
110 png_color PNGPalette[256];
111
112 for(int i = 0; i < 256; ++i)
113 {
114 PNGPalette[255 - i].red = Palette[i * 3 + 0];
115 PNGPalette[255 - i].green = Palette[i * 3 + 1];
116 PNGPalette[255 - i].blue = Palette[i * 3 + 2];
117 }
118
119 png_set_IHDR(PNGStruct, PNGInfo, Size.X, Size.Y, 8, PNG_COLOR_TYPE_PALETTE,
120 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
121 png_set_PLTE(PNGStruct, PNGInfo, PNGPalette, 256);
122 png_write_info(PNGStruct, PNGInfo);
123
124 paletteindex* Buffer = PaletteBuffer[0];
125 paletteindex* End = &PaletteBuffer[Size.Y - 1][Size.X];
126
127 for(; Buffer != End; ++Buffer)
128 *Buffer = 255 - *Buffer;
129
130 png_write_image(PNGStruct, PaletteBuffer);
131 png_write_end(PNGStruct, PNGInfo);
132 png_destroy_write_struct(&PNGStruct, &PNGInfo);
133
134 Buffer = PaletteBuffer[0];
135
136 for(; Buffer != End; ++Buffer)
137 *Buffer = 255 - *Buffer;
138 }
139
MaskedBlit(bitmap * Bitmap,v2 Src,v2 Dest,v2 Border,packcol16 * Color) const140 void rawbitmap::MaskedBlit(bitmap* Bitmap, v2 Src, v2 Dest, v2 Border, packcol16* Color) const
141 {
142 if(!femath::Clip(Src.X, Src.Y, Dest.X, Dest.Y, Border.X, Border.Y,
143 Size.X, Size.Y, Bitmap->GetSize().X, Bitmap->GetSize().Y))
144 return;
145
146 paletteindex* Buffer = &PaletteBuffer[Src.Y][Src.X];
147 packcol16* DestBuffer = &Bitmap->GetImage()[Dest.Y][Dest.X];
148 int BitmapXSize = Bitmap->GetSize().X;
149 uchar* Palette = this->Palette; // eliminate the efficiency cost of dereferencing
150
151 for(int y = 0; y < Border.Y; ++y)
152 {
153 for(int x = 0; x < Border.X; ++x)
154 {
155 int PaletteElement = Buffer[x];
156
157 if(PaletteElement >= 192)
158 {
159 int ThisColor = Color[(PaletteElement - 192) >> 4];
160 int Index = PaletteElement & 15;
161 int Red = (ThisColor >> 8 & 0xF8) * Index;
162 int Green = (ThisColor >> 3 & 0xFC) * Index;
163 int Blue = (ThisColor << 3 & 0xF8) * Index;
164
165 if(Red > 0x7FF)
166 Red = 0x7FF;
167
168 if(Green > 0x7FF)
169 Green = 0x7FF;
170
171 if(Blue > 0x7FF)
172 Blue = 0x7FF;
173
174 DestBuffer[x] = (Red << 5 & 0xF800) | (Green & 0x7E0) | (Blue >> 6 & 0x1F);
175 }
176 else
177 {
178 int PaletteIndex = PaletteElement + (PaletteElement << 1);
179 int ThisColor = ((Palette[PaletteIndex] & 0xFFF8) << 8)
180 | ((Palette[PaletteIndex + 1] & 0xFFFC) << 3)
181 | (Palette[PaletteIndex + 2] >> 3);
182
183 if(ThisColor != TRANSPARENT_COLOR)
184 DestBuffer[x] = ThisColor;
185 }
186 }
187
188 DestBuffer += BitmapXSize;
189 Buffer += Size.X;
190 }
191 }
192
Colorize(cpackcol16 * Color,alpha BaseAlpha,cpackalpha * Alpha) const193 cachedfont* rawbitmap::Colorize(cpackcol16* Color, alpha BaseAlpha, cpackalpha* Alpha) const
194 {
195 cachedfont* Bitmap = new cachedfont(Size);
196 paletteindex* Buffer = PaletteBuffer[0];
197 packcol16* DestBuffer = Bitmap->GetImage()[0];
198 uchar* Palette = this->Palette; // eliminate the efficiency cost of dereferencing
199 packalpha* AlphaMap;
200 truth UseAlpha;
201
202 if(BaseAlpha != 255 || (Alpha && (Alpha[0] != 255 || Alpha[1] != 255 || Alpha[2] != 255 || Alpha[3] != 255)))
203 {
204 Bitmap->CreateAlphaMap(BaseAlpha);
205 AlphaMap = Bitmap->GetAlphaMap()[0];
206 UseAlpha = true;
207 }
208 else
209 {
210 AlphaMap = 0;
211 UseAlpha = false;
212 }
213
214 int BitmapXSize = Bitmap->GetSize().X;
215
216 for(int y = 0; y < Size.Y; ++y)
217 {
218 for(int x = 0; x < Size.X; ++x)
219 {
220 int PaletteElement = Buffer[x];
221
222 if(PaletteElement >= 192)
223 {
224 int ColorIndex = (PaletteElement - 192) >> 4;
225 int ThisColor = Color[ColorIndex];
226
227 if(ThisColor != TRANSPARENT_COLOR)
228 {
229 int Index = PaletteElement & 15;
230 int Red = (ThisColor >> 8 & 0xF8) * Index;
231 int Green = (ThisColor >> 3 & 0xFC) * Index;
232 int Blue = (ThisColor << 3 & 0xF8) * Index;
233
234 if(Red > 0x7FF)
235 Red = 0x7FF;
236
237 if(Green > 0x7FF)
238 Green = 0x7FF;
239
240 if(Blue > 0x7FF)
241 Blue = 0x7FF;
242
243 DestBuffer[x] = (Red << 5 & 0xF800)
244 | (Green & 0x7E0)
245 | (Blue >> 6 & 0x1F);
246
247 if(UseAlpha)
248 AlphaMap[x] = Alpha[ColorIndex];
249 }
250 else
251 DestBuffer[x] = TRANSPARENT_COLOR;
252 }
253 else
254 {
255 int PaletteIndex = PaletteElement + (PaletteElement << 1);
256 DestBuffer[x] = ((Palette[PaletteIndex] & 0xFFF8) << 8)
257 | ((Palette[PaletteIndex + 1] & 0xFFFC) << 3)
258 | (Palette[PaletteIndex + 2] >> 3);
259 }
260 }
261
262 DestBuffer += BitmapXSize;
263 AlphaMap += BitmapXSize;
264 Buffer += Size.X;
265 }
266
267 return Bitmap;
268 }
269
Colorize(v2 Pos,v2 Border,v2 Move,cpackcol16 * Color,alpha BaseAlpha,cpackalpha * Alpha,cuchar * RustData,cuchar * BurnData,truth AllowReguralColors) const270 bitmap* rawbitmap::Colorize(v2 Pos, v2 Border, v2 Move, cpackcol16* Color, alpha BaseAlpha, cpackalpha* Alpha,
271 cuchar* RustData, cuchar* BurnData, truth AllowReguralColors) const
272 {
273 bitmap* Bitmap = new bitmap(Border);
274 v2 TargetPos(0, 0);
275
276 if(Move.X || Move.Y)
277 {
278 Bitmap->ClearToColor(TRANSPARENT_COLOR);
279
280 if(Move.X < 0)
281 {
282 Pos.X -= Move.X;
283 Border.X += Move.X;
284 }
285 else if(Move.X > 0)
286 {
287 TargetPos.X = Move.X;
288 Border.X -= Move.X;
289 }
290
291 if(Move.Y < 0)
292 {
293 Pos.Y -= Move.Y;
294 Border.Y += Move.Y;
295 }
296 else if(Move.Y > 0)
297 {
298 TargetPos.Y = Move.Y;
299 Border.Y -= Move.Y;
300 }
301 }
302
303 paletteindex* Buffer = &PaletteBuffer[Pos.Y][Pos.X];
304 packcol16* DestBuffer = &Bitmap->GetImage()[TargetPos.Y][TargetPos.X];
305 int BitmapXSize = Bitmap->GetSize().X;
306 uchar* Palette = this->Palette; // eliminate the efficiency cost of dereferencing
307 packalpha* AlphaMap;
308 truth UseAlpha;
309
310 if(BaseAlpha != 255 || (Alpha && (Alpha[0] != 255 || Alpha[1] != 255 || Alpha[2] != 255 || Alpha[3] != 255)))
311 {
312 Bitmap->CreateAlphaMap(BaseAlpha);
313 AlphaMap = &Bitmap->GetAlphaMap()[TargetPos.Y][TargetPos.X];
314 UseAlpha = true;
315 }
316 else
317 {
318 AlphaMap = 0;
319 UseAlpha = false;
320 }
321
322 truth Rusted = RustData && (RustData[0] || RustData[1] || RustData[2] || RustData[3]);
323 ulong RustSeed[4];
324
325 if(Rusted)
326 {
327 RustSeed[0] = (RustData[0] & 0xFC) >> 2;
328 RustSeed[1] = (RustData[1] & 0xFC) >> 2;
329 RustSeed[2] = (RustData[2] & 0xFC) >> 2;
330 RustSeed[3] = (RustData[3] & 0xFC) >> 2;
331 }
332
333 truth Burnt = BurnData && (BurnData[0] || BurnData[1] || BurnData[2] || BurnData[3]);
334 ulong BurnSeed[4];
335
336 if(Burnt)
337 {
338 BurnSeed[0] = (BurnData[0] & 0xFC) >> 2;
339 BurnSeed[1] = (BurnData[1] & 0xFC) >> 2;
340 BurnSeed[2] = (BurnData[2] & 0xFC) >> 2;
341 BurnSeed[3] = (BurnData[3] & 0xFC) >> 2;
342 }
343
344 for(int y = 0; y < Border.Y; ++y)
345 {
346 for(int x = 0; x < Border.X; ++x)
347 {
348 int PaletteElement = Buffer[x];
349
350 if(PaletteElement >= 192)
351 {
352 int ColorIndex = (PaletteElement - 192) >> 4;
353 int ThisColor = Color[ColorIndex];
354
355 if(ThisColor != TRANSPARENT_COLOR)
356 {
357 int Index = PaletteElement & 15;
358 int Red = (ThisColor >> 8 & 0xF8) * Index;
359 int Green = (ThisColor >> 3 & 0xFC) * Index;
360 int Blue = (ThisColor << 3 & 0xF8) * Index;
361 int Max = (Red > Green ? Red : Green);
362 Max = (Max > Blue ? Max : Blue);
363
364 if(Rusted && RustData[ColorIndex]
365 && (RustData[ColorIndex] & 3UL)
366 > (RustSeed[ColorIndex] = RustSeed[ColorIndex] * 1103515245 + 12345) >> 30)
367 {
368 Green = ((Green << 1) + Green) >> 2;
369 Blue >>= 1;
370 }
371
372 if(Burnt && BurnData[ColorIndex]
373 && (BurnData[ColorIndex] & 3UL)
374 > (BurnSeed[ColorIndex] = BurnSeed[ColorIndex] * 1103515245 + 12345) >> 30)
375 {
376 Max >>= 2;
377 Red = Max + (Red >> 3);
378 Green = Max + (Green >> 3);
379 Blue = Max + (Blue >> 3);
380 }
381
382 if(Red > 0x7FF)
383 Red = 0x7FF;
384
385 if(Green > 0x7FF)
386 Green = 0x7FF;
387
388 if(Blue > 0x7FF)
389 Blue = 0x7FF;
390
391 DestBuffer[x] = (Red << 5 & 0xF800)
392 | (Green & 0x7E0)
393 | (Blue >> 6 & 0x1F);
394
395 if(UseAlpha)
396 AlphaMap[x] = Alpha[ColorIndex];
397 }
398 else
399 DestBuffer[x] = TRANSPARENT_COLOR;
400 }
401 else if(AllowReguralColors)
402 {
403 int PaletteIndex = PaletteElement + (PaletteElement << 1);
404 DestBuffer[x] = ((Palette[PaletteIndex] & 0xFFF8) << 8)
405 | ((Palette[PaletteIndex + 1] & 0xFFFC) << 3)
406 | (Palette[PaletteIndex + 2] >> 3);
407 }
408 else
409 DestBuffer[x] = TRANSPARENT_COLOR;
410 }
411
412 DestBuffer += BitmapXSize;
413 AlphaMap += BitmapXSize;
414 Buffer += Size.X;
415 }
416
417 return Bitmap;
418 }
419
Printf(bitmap * Bitmap,v2 Pos,packcol16 Color,cchar * Format,...) const420 void rawbitmap::Printf(bitmap* Bitmap, v2 Pos, packcol16 Color, cchar* Format, ...) const
421 {
422 char Buffer[256];
423
424 va_list AP;
425 va_start(AP, Format);
426 vsprintf(Buffer, Format, AP);
427 va_end(AP);
428
429 fontcache::const_iterator Iterator = FontCache.find(Color);
430
431 if(Iterator == FontCache.end())
432 {
433 packcol16 ShadeCol = MakeShadeColor(Color);
434
435 for(int c = 0; Buffer[c]; ++c)
436 {
437 v2 F(((Buffer[c] - 0x20) & 0xF) << 4, (Buffer[c] - 0x20) & 0xF0);
438 //printf("X=%4d -- Y=%d\n", F.X, F.Y);
439 MaskedBlit(Bitmap, F, v2(Pos.X + (c << 3) + 1, Pos.Y + 1), v2(8, 8), &ShadeCol);
440 MaskedBlit(Bitmap, F, v2(Pos.X + (c << 3), Pos.Y), v2(8, 8), &Color);
441 }
442 }
443 else
444 {
445 const cachedfont* Font = Iterator->second.first;
446 blitdata B = { Bitmap,
447 { 0, 0 },
448 { Pos.X, Pos.Y },
449 { 9, 9 },
450 { 0 },
451 TRANSPARENT_COLOR,
452 0 };
453
454 for(int c = 0; Buffer[c]; ++c, B.Dest.X += 8)
455 {
456 B.Src.X = ((Buffer[c] - 0x20) & 0xF) << 4;
457 B.Src.Y = (Buffer[c] - 0x20) & 0xF0;
458 //printf("'%c' -> X=%5d -- Y=%5d\n", Buffer[c], B.Src.X, B.Src.Y);
459 Font->PrintCharacter(B);
460 }
461 }
462 }
463
PrintfUnshaded(bitmap * Bitmap,v2 Pos,packcol16 Color,cchar * Format,...) const464 void rawbitmap::PrintfUnshaded(bitmap* Bitmap, v2 Pos, packcol16 Color, cchar* Format, ...) const
465 {
466 char Buffer[256];
467
468 va_list AP;
469 va_start(AP, Format);
470 vsprintf(Buffer, Format, AP);
471 va_end(AP);
472
473 fontcache::const_iterator Iterator = FontCache.find(Color);
474
475 if(Iterator == FontCache.end())
476 {
477 for(int c = 0; Buffer[c]; ++c)
478 {
479 v2 F(((Buffer[c] - 0x20) & 0xF) << 4, (Buffer[c] - 0x20) & 0xF0);
480 MaskedBlit(Bitmap, F, v2(Pos.X + (c << 3), Pos.Y), v2(8, 8), &Color);
481 }
482 }
483 else
484 {
485 const cachedfont* Font = Iterator->second.second;
486 blitdata B = { Bitmap,
487 { 0, 0 },
488 { Pos.X, Pos.Y },
489 { 9, 9 },
490 { 0 },
491 TRANSPARENT_COLOR,
492 0 };
493
494 for(int c = 0; Buffer[c]; ++c, B.Dest.X += 8)
495 {
496 B.Src.X = ((Buffer[c] - 0x20) & 0xF) << 4;
497 B.Src.Y = (Buffer[c] - 0x20) & 0xF0;
498 Font->PrintCharacter(B);
499 }
500 }
501 }
502
AlterGradient(v2 Pos,v2 Border,int MColor,int Amount,truth Clip)503 void rawbitmap::AlterGradient(v2 Pos, v2 Border, int MColor, int Amount, truth Clip)
504 {
505 int ColorMin = 192 + (MColor << 4);
506 int ColorMax = 207 + (MColor << 4);
507
508 if(Clip)
509 {
510 for(int x = Pos.X; x < Pos.X + Border.X; ++x)
511 for(int y = Pos.Y; y < Pos.Y + Border.Y; ++y)
512 {
513 int Pixel = PaletteBuffer[y][x];
514
515 if(Pixel >= ColorMin && Pixel <= ColorMax)
516 {
517 int NewPixel = Pixel + Amount;
518
519 if(NewPixel < ColorMin)
520 NewPixel = ColorMin;
521
522 if(NewPixel > ColorMax)
523 NewPixel = ColorMax;
524
525 PaletteBuffer[y][x] = NewPixel;
526 }
527 }
528 }
529 else
530 {
531 int x;
532
533 for(x = Pos.X; x < Pos.X + Border.X; ++x)
534 for(int y = Pos.Y; y < Pos.Y + Border.Y; ++y)
535 {
536 int Pixel = PaletteBuffer[y][x];
537
538 if(Pixel >= ColorMin && Pixel <= ColorMax)
539 {
540 int NewPixel = Pixel + Amount;
541
542 if(NewPixel < ColorMin)
543 return;
544
545 if(NewPixel > ColorMax)
546 return;
547 }
548 }
549
550 for(x = Pos.X; x < Pos.X + Border.X; ++x)
551 for(int y = Pos.Y; y < Pos.Y + Border.Y; ++y)
552 {
553 int Pixel = PaletteBuffer[y][x];
554
555 if(Pixel >= ColorMin && Pixel <= ColorMax)
556 PaletteBuffer[y][x] = Pixel + Amount;
557 }
558 }
559 }
560
SwapColors(v2 Pos,v2 Border,int Color1,int Color2)561 void rawbitmap::SwapColors(v2 Pos, v2 Border, int Color1, int Color2)
562 {
563 if(Color1 > 3 || Color2 > 3)
564 ABORT("Illegal col swap!");
565
566 for(int x = Pos.X; x < Pos.X + Border.X; ++x)
567 for(int y = Pos.Y; y < Pos.Y + Border.Y; ++y)
568 {
569 paletteindex& Pixel = PaletteBuffer[y][x];
570
571 if(Pixel >= 192 + (Color1 << 4) && Pixel <= 207 + (Color1 << 4))
572 Pixel += (Color2 - Color1) << 4;
573 else if(Pixel >= 192 + (Color2 << 4) && Pixel <= 207 + (Color2 << 4))
574 Pixel += (Color1 - Color2) << 4;
575 }
576 }
577
578 /* TempBuffer must be an array of Border.X * Border.Y paletteindices */
579
Roll(v2 Pos,v2 Border,v2 Move,paletteindex * TempBuffer)580 void rawbitmap::Roll(v2 Pos, v2 Border, v2 Move, paletteindex* TempBuffer)
581 {
582 int x, y;
583
584 for(x = Pos.X; x < Pos.X + Border.X; ++x)
585 for(y = Pos.Y; y < Pos.Y + Border.Y; ++y)
586 {
587 int XPos = x + Move.X, YPos = y + Move.Y;
588
589 if(XPos < Pos.X)
590 XPos += Border.X;
591
592 if(YPos < Pos.Y)
593 YPos += Border.Y;
594
595 if(XPos >= Pos.X + Border.X)
596 XPos -= Border.X;
597
598 if(YPos >= Pos.Y + Border.Y)
599 YPos -= Border.Y;
600
601 TempBuffer[(YPos - Pos.Y) * Border.X + XPos - Pos.X] = PaletteBuffer[y][x];
602 }
603
604 for(x = Pos.X; x < Pos.X + Border.X; ++x)
605 for(y = Pos.Y; y < Pos.Y + Border.Y; ++y)
606 PaletteBuffer[y][x] = TempBuffer[(y - Pos.Y) * Border.X + x - Pos.X];
607 }
608
CreateFontCache(packcol16 Color)609 void rawbitmap::CreateFontCache(packcol16 Color)
610 {
611 if(FontCache.find(Color) != FontCache.end())
612 return;
613
614 packcol16 ShadeColor = MakeShadeColor(Color);
615 cachedfont* Font = new cachedfont(Size, TRANSPARENT_COLOR);
616 MaskedBlit(Font, ZERO_V2, v2(1, 1), v2(Size.X - 1, Size.Y - 1), &ShadeColor);
617 cachedfont* UnshadedFont = Colorize(&Color);
618
619 blitdata B = { Font,
620 { 0, 0 },
621 { 0, 0 },
622 { Size.X, Size.Y },
623 { 0 },
624 TRANSPARENT_COLOR,
625 0 };
626
627 UnshadedFont->NormalMaskedBlit(B);
628 Font->CreateMaskMap();
629 UnshadedFont->CreateMaskMap();
630 FontCache[Color] = std::make_pair(Font, UnshadedFont);
631 }
632
633 /* returns ERROR_V2 if fails find Pos else returns pos */
634
RandomizeSparklePos(cv2 * ValidityArray,v2 * PossibleBuffer,v2 Pos,v2 Border,int ValidityArraySize,int SparkleFlags) const635 v2 rawbitmap::RandomizeSparklePos(cv2* ValidityArray, v2* PossibleBuffer, v2 Pos, v2 Border,
636 int ValidityArraySize, int SparkleFlags) const
637 {
638 if(!SparkleFlags)
639 return ERROR_V2;
640
641 /* Don't use { } to initialize, or GCC optimizations will produce code that crashes! */
642
643 v2* BadPossible[4];
644 BadPossible[0] = PossibleBuffer;
645 BadPossible[1] = BadPossible[0] + ((Border.X + Border.Y) << 1) - 4;
646 BadPossible[2] = BadPossible[1] + ((Border.X + Border.Y) << 1) - 12;
647 BadPossible[3] = BadPossible[2] + ((Border.X + Border.Y) << 1) - 20;
648 v2* PreferredPossible = BadPossible[3] + ((Border.X + Border.Y) << 1) - 28;
649 int Preferred = 0;
650 int Bad[4] = { 0, 0, 0, 0 };
651 int XMax = Pos.X + Border.X;
652 int YMax = Pos.Y + Border.Y;
653
654 for(int c = 0; c < ValidityArraySize; ++c)
655 {
656 v2 V = ValidityArray[c] + Pos;
657 int Entry = PaletteBuffer[V.Y][V.X];
658
659 if(IsMaterialColor(Entry) && 1 << GetMaterialColorIndex(Entry) & SparkleFlags)
660 {
661 int MinDist = 0x7FFF;
662
663 if(V.X < Pos.X + 4)
664 MinDist = Min(V.X - Pos.X, MinDist);
665
666 if(V.X >= XMax - 4)
667 MinDist = Min(XMax - V.X - 1, MinDist);
668
669 if(V.Y < Pos.Y + 4)
670 MinDist = Min(V.Y - Pos.Y, MinDist);
671
672 if(V.Y >= YMax - 4)
673 MinDist = Min(YMax - V.Y - 1, MinDist);
674
675 if(MinDist >= 4)
676 PreferredPossible[Preferred++] = V;
677 else
678 BadPossible[MinDist][Bad[MinDist]++] = V;
679 }
680 }
681
682 v2 Return;
683
684 if(Preferred)
685 Return = PreferredPossible[RAND() % Preferred] - Pos;
686 else if(Bad[3])
687 Return = BadPossible[3][RAND() % Bad[3]] - Pos;
688 else if(Bad[2])
689 Return = BadPossible[2][RAND() % Bad[2]] - Pos;
690 else if(Bad[1])
691 Return = BadPossible[1][RAND() % Bad[1]] - Pos;
692 else if(Bad[0])
693 Return = BadPossible[0][RAND() % Bad[0]] - Pos;
694 else
695 Return = ERROR_V2;
696
697 return Return;
698 }
699
IsTransparent(v2 Pos) const700 truth rawbitmap::IsTransparent(v2 Pos) const
701 {
702 return PaletteBuffer[Pos.Y][Pos.X] == TRANSPARENT_PALETTE_INDEX;
703 }
704
IsMaterialColor1(v2 Pos) const705 truth rawbitmap::IsMaterialColor1(v2 Pos) const
706 {
707 int P = PaletteBuffer[Pos.Y][Pos.X];
708 return P >= 192 && P < 208;
709 }
710
CopyPaletteFrom(rawbitmap * Bitmap)711 void rawbitmap::CopyPaletteFrom(rawbitmap* Bitmap)
712 {
713 memcpy(Palette, Bitmap->Palette, 768);
714 }
715
Clear()716 void rawbitmap::Clear()
717 {
718 memset(PaletteBuffer[0], TRANSPARENT_PALETTE_INDEX, Size.X * Size.Y * sizeof(paletteindex));
719 }
720
NormalBlit(rawbitmap * Bitmap,v2 Src,v2 Dest,v2 Border,int Flags) const721 void rawbitmap::NormalBlit(rawbitmap* Bitmap, v2 Src, v2 Dest, v2 Border, int Flags) const
722 {
723 paletteindex** SrcBuffer = PaletteBuffer;
724 paletteindex** DestBuffer = Bitmap->PaletteBuffer;
725
726 switch(Flags & 7)
727 {
728 case NONE:
729 {
730 if(Size.X == Bitmap->Size.X && Size.Y == Bitmap->Size.Y)
731 memcpy(DestBuffer[0], SrcBuffer[0], Size.X * Size.Y * sizeof(paletteindex));
732 else
733 {
734 cint Bytes = Border.X * sizeof(paletteindex);
735
736 for(int y = 0; y < Border.Y; ++y)
737 memcpy(&DestBuffer[Dest.Y + y][Dest.X], &SrcBuffer[Src.Y + y][Src.X], Bytes);
738 }
739
740 break;
741 }
742
743 case MIRROR:
744 {
745 Dest.X += Border.X - 1;
746
747 for(int y = 0; y < Border.Y; ++y)
748 {
749 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
750 cpaletteindex* EndPtr = SrcPtr + Border.X;
751 paletteindex* DestPtr = &DestBuffer[Dest.Y + y][Dest.X];
752
753 for(; SrcPtr != EndPtr; ++SrcPtr, --DestPtr)
754 *DestPtr = *SrcPtr;
755 }
756
757 break;
758 }
759
760 case FLIP:
761 {
762 Dest.Y += Border.Y - 1;
763 cint Bytes = Border.X * sizeof(paletteindex);
764
765 for(int y = 0; y < Border.Y; ++y)
766 memcpy(&DestBuffer[Dest.Y - y][Dest.X], &SrcBuffer[Src.Y + y][Src.X], Bytes);
767
768 break;
769 }
770
771 case (MIRROR | FLIP):
772 {
773 Dest.X += Border.X - 1;
774 Dest.Y += Border.Y - 1;
775
776 for(int y = 0; y < Border.Y; ++y)
777 {
778 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
779 cpaletteindex* EndPtr = SrcPtr + Border.X;
780 paletteindex* DestPtr = &DestBuffer[Dest.Y - y][Dest.X];
781
782 for(; SrcPtr != EndPtr; ++SrcPtr, --DestPtr)
783 *DestPtr = *SrcPtr;
784 }
785
786 break;
787 }
788
789 case ROTATE:
790 {
791 Dest.X += Border.X - 1;
792 int TrueDestXMove = Bitmap->Size.X;
793 paletteindex* DestBase = &DestBuffer[Dest.Y][Dest.X];
794
795 for(int y = 0; y < Border.Y; ++y)
796 {
797 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
798 cpaletteindex* EndPtr = SrcPtr + Border.X;
799 paletteindex* DestPtr = DestBase - y;
800
801 for(; SrcPtr != EndPtr; ++SrcPtr, DestPtr += TrueDestXMove)
802 *DestPtr = *SrcPtr;
803 }
804
805 break;
806 }
807
808 case (MIRROR | ROTATE):
809 {
810 int TrueDestXMove = Bitmap->Size.X;
811 paletteindex* DestBase = &DestBuffer[Dest.Y][Dest.X];
812
813 for(int y = 0; y < Border.Y; ++y)
814 {
815 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
816 cpaletteindex* EndPtr = SrcPtr + Border.X;
817 paletteindex* DestPtr = DestBase + y;
818
819 for(; SrcPtr != EndPtr; ++SrcPtr, DestPtr += TrueDestXMove)
820 *DestPtr = *SrcPtr;
821 }
822
823 break;
824 }
825
826 case (FLIP | ROTATE):
827 {
828 Dest.X += Border.X - 1;
829 Dest.Y += Border.Y - 1;
830 int TrueDestXMove = Bitmap->Size.X;
831 paletteindex* DestBase = &DestBuffer[Dest.Y][Dest.X];
832
833 for(int y = 0; y < Border.Y; ++y)
834 {
835 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
836 cpaletteindex* EndPtr = SrcPtr + Border.X;
837 paletteindex* DestPtr = DestBase - y;
838
839 for(; SrcPtr != EndPtr; ++SrcPtr, DestPtr -= TrueDestXMove)
840 *DestPtr = *SrcPtr;
841 }
842
843 break;
844 }
845
846 case (MIRROR | FLIP | ROTATE):
847 {
848 Dest.Y += Border.Y - 1;
849 int TrueDestXMove = Bitmap->Size.X;
850 paletteindex* DestBase = &DestBuffer[Dest.Y][Dest.X];
851
852 for(int y = 0; y < Border.Y; ++y)
853 {
854 cpaletteindex* SrcPtr = &SrcBuffer[Src.Y + y][Src.X];
855 cpaletteindex* EndPtr = SrcPtr + Border.X;
856 paletteindex* DestPtr = DestBase + y;
857
858 for(; SrcPtr != EndPtr; ++SrcPtr, DestPtr -= TrueDestXMove)
859 *DestPtr = *SrcPtr;
860 }
861
862 break;
863 }
864 }
865 }
866