moved almost all hardcoded constants to "define.dat"
[k8-i-v-a-n.git] / src / felib / rawbit.cpp
blob7a5a6dbc8454038165cb304295741ac37fe1447e
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #include <cstdarg>
14 #ifdef HAVE_LIBPNG
15 # include <png.h>
16 #endif
18 #include "allocate.h"
19 #include "rawbit.h"
20 #include "bitmap.h"
21 #include "fesave.h"
22 #include "femath.h"
25 // ////////////////////////////////////////////////////////////////////////// //
26 festring rawbitmap::curfile;
29 // ////////////////////////////////////////////////////////////////////////// //
30 unsigned char rawbitmap::getb (FILE* fl) {
31 unsigned char c = 0;
32 if (!fl) ABORT("Cannot read from nothing!");
33 if (fread(&c, 1, 1, fl) != 1) ABORT("Error reading file '%s'!", curfile.CStr());
34 return c;
38 // ////////////////////////////////////////////////////////////////////////// //
39 void rawbitmap::loadPCX (FILE *fl) {
40 if (fseek(fl, 0, SEEK_SET) == -1) ABORT("Error reading file '%s'!", curfile.CStr());
41 // simple checks
42 if (getb(fl) != 10) ABORT("Invalid bitmap format: %s!", curfile.CStr());
43 int ver = getb(fl);
44 switch (ver) {
45 case 4: case 5: break;
46 default: ABORT("Invalid bitmap version: %s!", curfile.CStr());
48 truth packed = true;
49 switch (getb(fl)) {
50 case 0: packed = false; break;
51 case 1: break;
52 default: ABORT("Invalid bitmap encoding: %s!", curfile.CStr());
54 if (getb(fl) != 8) ABORT("Invalid bitmap BPP: %s!", curfile.CStr());
55 // dimensions
56 // x0
57 int x0 = getb(fl);
58 x0 |= getb(fl)<<8;
59 // y0
60 int y0 = getb(fl);
61 y0 |= getb(fl)<<8;
62 // x1
63 int x1 = getb(fl);
64 x1 |= getb(fl)<<8;
65 // y1
66 int y1 = getb(fl);
67 y1 |= getb(fl)<<8;
68 // calculate dimensions
69 int wdt = (x1-x0)+1;
70 int hgt = (y1-y0)+1;
71 // check 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());
74 // skip dpi
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);
78 // check colorplanes
79 if (getb(fl) != 1) ABORT("Invalid bitmap colorplanes: %s!", curfile.CStr());
80 // bytes per line
81 int bpl = getb(fl);
82 bpl |= getb(fl)<<8;
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;
85 // check palette type
86 if (ver == 4) {
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());
89 hdrread += 2;
91 // skip rest of the header
92 while (hdrread < 128) { getb(fl); ++hdrread; }
93 // load bitmap
94 Size.X = wdt;
95 Size.Y = hgt;
96 Alloc2D(PaletteBuffer, Size.Y, Size.X);
97 for (int y = 0; y < hgt; ++y) {
98 int cnt = 0, b = 0;
99 for (int x = 0; x < bpl; ++x) {
100 if (cnt == 0) {
101 b = (unsigned char)getb(fl);
102 if (packed && b >= 0xc0) {
103 cnt = b&0x3f;
104 if (cnt == 0) {
105 delete [] PaletteBuffer;
106 ABORT("Invalid compressed bitmap: %s!", curfile.CStr());
108 b = (unsigned char)getb(fl);
109 } else {
110 cnt = 1;
113 if (x < wdt) {
114 paletteindex *Buffer = PaletteBuffer[0];
115 Buffer += (y*wdt)+x;
116 *Buffer = (paletteindex)b;
118 --cnt;
121 // load palette
122 if (fseek(fl, -769, SEEK_END) == -1) ABORT("Error reading file '%s'!", curfile.CStr());
123 // check signature
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 // ////////////////////////////////////////////////////////////////////////// //
131 #ifdef HAVE_LIBPNG
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;
155 int PaletteSize;
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);
180 #endif
183 // ////////////////////////////////////////////////////////////////////////// //
184 void rawbitmap::loadFromFile (FILE *fl) {
185 if (getb(fl) == 0x0a) { loadPCX(fl); return; }
186 #ifdef HAVE_LIBPNG
187 loadPNG(fl);
188 #else
189 ABORT("Invalid image file: '%s'!", curfile.CStr());
190 #endif
194 // ////////////////////////////////////////////////////////////////////////// //
195 rawbitmap::rawbitmap (cfestring &FileName) {
196 curfile = FileName;
197 FILE *fl = fopen(FileName.CStr(), "rb");
198 if (!fl) {
199 // try to find .png
200 //fprintf(stderr, "OLD: <%s>\n", curfile.CStr());
201 if (curfile.GetSize() > 4 && curfile.endsWithCI(".pcx")) {
202 curfile.Erase(curfile.GetSize()-4, 4);
203 curfile += ".png";
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);
208 curfile += ".pcx";
209 //fprintf(stderr, "NEW: <%s>\n", curfile.CStr());
210 fl = fopen(curfile.CStr(), "rb");
212 if (!fl) ABORT("Cannot open file '%s'!", FileName.CStr());
214 loadFromFile(fl);
215 fclose(fl);
216 curfile.Empty();
220 rawbitmap::rawbitmap (v2 Size) : Size(Size) {
221 Palette = new uChar[768];
222 Alloc2D(PaletteBuffer, Size.Y, Size.X);
226 rawbitmap::~rawbitmap () {
227 delete [] Palette;
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) {
238 char PCXHeader[128];
239 memset(PCXHeader, 0, 128);
240 PCXHeader[0] = 0x0a;
241 PCXHeader[1] = 0x05; // version
242 PCXHeader[2] = 1; // RLE-packed
243 PCXHeader[3] = 8; // bpp
244 PCXHeader[65] = 0x01;
245 // bytes in line
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];
260 int curx = 0;
261 int count = 0, accb = 0;
263 while (Buffer != End) {
264 paletteindex b = *Buffer++;
265 if (count == 0) {
266 count = 1;
267 accb = b;
268 } else if (count == 0x3f || b != accb) {
269 // flush
270 if (count > 1 || accb >= 0xc0) fputc((unsigned char)(count|0xc0), fo);
271 fputc((unsigned char)accb, fo);
272 count = 1;
273 accb = b;
274 } else {
275 ++count;
277 if (++curx == Size.X) {
278 // flush
279 if (count > 0) {
280 if (count > 1 || accb >= 0xc0) fputc((unsigned char)(count|0xc0), fo);
281 fputc((unsigned char)accb, fo);
282 count = 0;
284 curx = 0; // next line
287 // flush
288 if (count > 0) {
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);
296 fclose(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);
324 } else {
325 int PaletteIndex = PaletteElement+(PaletteElement << 1);
326 int ThisColor =
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;
334 Buffer += Size.X;
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
344 packalpha *AlphaMap;
345 truth UseAlpha;
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];
349 UseAlpha = true;
350 } else {
351 AlphaMap = 0;
352 UseAlpha = false;
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];
371 } else {
372 DestBuffer[x] = TRANSPARENT_COLOR;
374 } else {
375 int PaletteIndex = PaletteElement+(PaletteElement<<1);
376 DestBuffer[x] =
377 ((Palette[PaletteIndex] & 0xFFF8) << 8) |
378 ((Palette[PaletteIndex + 1] & 0xFFFC) << 3) |
379 (Palette[PaletteIndex + 2] >> 3);
382 DestBuffer += BitmapXSize;
383 AlphaMap += BitmapXSize;
384 Buffer += Size.X;
386 return Bitmap;
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);
394 v2 TargetPos(0, 0);
395 if (Move.X || Move.Y) {
396 Bitmap->ClearToColor(TRANSPARENT_COLOR);
397 if (Move.X < 0) {
398 Pos.X -= Move.X;
399 Border.X += Move.X;
400 } else if (Move.X > 0) {
401 TargetPos.X = Move.X;
402 Border.X -= Move.X;
404 if (Move.Y < 0) {
405 Pos.Y -= Move.Y;
406 Border.Y += Move.Y;
407 } else if (Move.Y > 0) {
408 TargetPos.Y = Move.Y;
409 Border.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
416 packalpha *AlphaMap;
417 truth UseAlpha;
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];
421 UseAlpha = true;
422 } else {
423 AlphaMap = 0;
424 UseAlpha = false;
426 truth Rusted = RustData && (RustData[0] || RustData[1] || RustData[2] || RustData[3]);
427 feuLong RustSeed[4];
428 if (Rusted) {
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;
448 Blue >>= 1;
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];
455 } else {
456 DestBuffer[x] = TRANSPARENT_COLOR;
458 } else if (AllowReguralColors) {
459 int PaletteIndex = PaletteElement+(PaletteElement<<1);
460 DestBuffer[x] =
461 ((Palette[PaletteIndex] & 0xFFF8) << 8) |
462 ((Palette[PaletteIndex + 1] & 0xFFFC) << 3) |
463 (Palette[PaletteIndex + 2] >> 3);
464 } else {
465 DestBuffer[x] = TRANSPARENT_COLOR;
468 DestBuffer += BitmapXSize;
469 AlphaMap += BitmapXSize;
470 Buffer += Size.X;
472 return Bitmap;
476 truth rawbitmap::strHasCtlCodes (cchar *str) {
477 while (*str) {
478 if (*str == '\1' || *str == '\2') return true;
479 ++str;
481 return false;
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()) {
492 // found cached font
493 const cachedfont *Font = (shaded ? Iterator->second.first : Iterator->second.second);
494 blitdata B = {
495 bmp,
496 { 0, 0 },
497 { pos.X, pos.Y },
498 { 9, 9 },
499 { 0 },
500 TRANSPARENT_COLOR,
503 while (*str) {
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);
509 B.Dest.X += 8;
511 return;
514 // has control codes, or no cached font
515 packcol16 curcol = clr;
516 packcol16 clrshade = MakeShadeColor(clr);
517 while (*str) {
518 // new color
519 if (*str == '\1') {
520 ++str;
521 if (str[0] == 0) break;
522 switch (*str++) {
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;
533 continue;
535 // reset color
536 if (*str == '\2') { curcol = clr; ++str; continue; }
537 // other control chars?
538 if ((unsigned char)*str < ' ' || (unsigned char)*str >= 127) { ++str; continue; }
539 // normal char
540 v2 F(((*str-0x20)&0xF)<<4, (*str-0x20)&0xF0);
541 ++str;
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);
544 pos.X += 8;
549 void rawbitmap::printfColoredVA (bitmap *bmp, v2 pos, packcol16 clr, truth shaded, cchar *fmt, va_list vap) const {
550 char buffer[2048];
551 char *bufptr = buffer;
552 int bufsz = (int)sizeof(buffer)-1;
554 for (;;) {
555 va_list ap;
556 int n;
557 char *np;
558 va_copy(ap, vap);
559 n = vsnprintf(bufptr, bufsz, fmt, ap);
560 va_end(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 {
574 va_list ap;
575 va_start(ap, Format);
576 printfColoredVA(Bitmap, Pos, Color, true, Format, ap);
577 va_end(ap);
581 void rawbitmap::PrintfColored (bitmap *Bitmap, v2 Pos, packcol16 Color, cchar *Format, ...) const {
582 va_list ap;
583 va_start(ap, Format);
584 printfColoredVA(Bitmap, Pos, Color, true, Format, ap);
585 va_end(ap);
589 void rawbitmap::PrintfUnshaded (bitmap *Bitmap, v2 Pos, packcol16 Color, cchar *Format, ...) const {
590 va_list ap;
591 va_start(ap, Format);
592 printfColoredVA(Bitmap, Pos, Color, false, Format, ap);
593 va_end(ap);
597 void rawbitmap::PrintfUnshadedColored (bitmap *Bitmap, v2 Pos, packcol16 Color, cchar *Format, ...) const {
598 va_list ap;
599 va_start(ap, Format);
600 printfColoredVA(Bitmap, Pos, Color, false, Format, ap);
601 va_end(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);
608 if (Clip) {
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;
620 } else {
621 int x;
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) {
656 int x, y;
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);
679 blitdata B = {
680 Font,
681 { 0, 0 },
682 { 0, 0 },
683 { Size.X, Size.Y },
684 { 0 },
685 TRANSPARENT_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! */
701 v2 *BadPossible[4];
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;
707 int Preferred = 0;
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;
724 v2 Return;
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;
731 return Return;
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;
759 int TrueDestXMove;
760 paletteindex *DestBase;
761 switch (Flags & 7) {
762 case NONE:
763 if (Size.X == Bitmap->Size.X && Size.Y == Bitmap->Size.Y) {
764 memmove(DestBuffer[0], SrcBuffer[0], Size.X*Size.Y*sizeof(paletteindex));
765 } else {
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);
769 break;
770 case MIRROR:
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;
778 break;
779 case FLIP: {
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);
783 } break;
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;
793 break;
794 case ROTATE:
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;
804 break;
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;
814 break;
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;
826 break;
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;
837 break;