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
16 #if defined(HAVE_IMLIB2)
18 #elif defined(HAVE_LIBPNG)
35 static gzFile
xcreate (const char *fname
) {
36 return gzopen(fname
, "wb1");
39 static gzFile
xopenro (const char *fname
) {
40 return gzopen(fname
, "rb");
43 static void xclose (gzFile fl
) {
47 static bool xread (gzFile fi
, void *buf
, size_t bytes
) {
48 if (!fi
) return false;
49 if (bytes
== 0) return true;
50 return (gzread(fi
, buf
, (int)bytes
) == (int)bytes
);
53 static bool xwrite (gzFile fo
, const void *buf
, size_t bytes
) {
54 if (!fo
|| bytes
== 0) return false;
55 return (gzwrite(fo
, buf
, (int)bytes
) == (int)bytes
);
60 static FILE *xcreate (const char *fname
) {
61 return fopen(fname
, "wb");
64 static FILE *xopenro (const char *fname
) {
65 return fopen(fname
, "rb");
68 static void xclose (FILE *fl
) {
72 static bool inline xread (FILE *fi
, void *buf
, size_t bytes
) {
73 if (!fi
) return false;
74 if (bytes
== 0) return true;
75 return (fread(buf
, bytes
, 1, fi
) == (size_t)bytes
);
78 static bool xwrite (FILE *fo
, const void *buf
, size_t bytes
) {
79 if (!fo
|| bytes
== 0) return false;
80 return (fwrite(fo
, buf
, 1, bytes
) == bytes
);
86 * Blitting must be as fast as possible, even if no optimizations are used;
87 * therefore we can't use inline functions inside loops, since they may be
88 * left unexpanded. These macros will do the job efficiently, even if they
91 #define LOAD_SRC() int SrcCol = *SrcPtr;
92 #define LOAD_DEST() int DestCol = *DestPtr;
93 #define LOAD_ALPHA() int Alpha = *AlphaPtr;
94 #define STORE_COLOR() *DestPtr = Red | Green | Blue;
96 #define NEW_LUMINATE_RED() \
97 int Red = (SrcCol & 0xF800)+NewRedLuminance;\
98 if (Red >= 0) { if(Red > 0xF800) Red = 0xF800; } else Red = 0;
100 #define NEW_LUMINATE_GREEN() \
101 int Green = (SrcCol & 0x7E0)+NewGreenLuminance;\
102 if (Green >= 0) { if(Green > 0x7E0) Green = 0x7E0; } else Green = 0;
104 #define NEW_LUMINATE_BLUE() \
105 int Blue = (SrcCol & 0x1F)+NewBlueLuminance;\
106 if (Blue >= 0) { if(Blue > 0x1F) Blue = 0x1F; } else Blue = 0;
108 #define NEW_APPLY_ALPHA_RED() {\
109 int DestRed = (DestCol & 0xF800);\
110 Red = (((Red - DestRed) * Alpha >> 8) + DestRed) & 0xF800;\
113 #define NEW_APPLY_ALPHA_GREEN() {\
114 int DestGreen = (DestCol & 0x7E0);\
115 Green = (((Green - DestGreen) * Alpha >> 8) + DestGreen) & 0x7E0;\
118 #define NEW_APPLY_ALPHA_BLUE() {\
119 int DestBlue = (DestCol & 0x1F);\
120 Blue = ((Blue - DestBlue) * Alpha >> 8) + DestBlue;\
123 #define NEW_LOAD_AND_APPLY_ALPHA_RED()\
126 int DestRed = DestCol & 0xF800;\
127 Red = ((((SrcCol & 0xF800) - DestRed) * Alpha >> 8) + DestRed) & 0xF800;\
130 #define NEW_LOAD_AND_APPLY_ALPHA_GREEN()\
133 int DestGreen = DestCol & 0x7E0;\
134 Green = ((((SrcCol & 0x7E0) - DestGreen) * Alpha >> 8) + DestGreen) & 0x7E0;\
137 #define NEW_LOAD_AND_APPLY_ALPHA_BLUE()\
140 int DestBlue = DestCol & 0x1F;\
141 Blue = (((SrcCol & 0x1F) - DestBlue) * Alpha >> 8) + DestBlue;\
145 bitmap::bitmap (cfestring
&FileName
) : FastFlag(0), AlphaMap(0), PriorityMap(0), RandMap(0) {
146 auto rawpic
= rawbitmap(FileName
);
147 mSize
= rawpic
.GetSize();
148 const uChar
*Palette
= rawpic
.getPalette();
149 XSizeTimesYSize
= mSize
.X
*mSize
.Y
;
150 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
151 packcol16
*Buffer
= Image
[0];
152 const uChar
*buf
= rawpic
.getBuffer();
153 for (int y
= 0; y
< mSize
.Y
; ++y
) {
154 for (int x
= 0; x
< mSize
.X
; ++x
) {
156 int Char3
= Char1
+ (Char1
<< 1);
157 *Buffer
++ = int(Palette
[Char3
] >> 3) << 11 | int(Palette
[Char3
+ 1] >> 2) << 5 | int(Palette
[Char3
+ 2] >> 3);
163 bitmap::bitmap (cbitmap
*Bitmap
, int Flags
, truth CopyAlpha
) :
164 mSize(Bitmap
->mSize
),
165 XSizeTimesYSize(Bitmap
->XSizeTimesYSize
),
170 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
171 if (CopyAlpha
&& Bitmap
->AlphaMap
) {
172 Alloc2D(AlphaMap
, mSize
.Y
, mSize
.X
);
173 Bitmap
->BlitAndCopyAlpha(this, Flags
);
176 if (!Flags
) Bitmap
->FastBlit(this); else Bitmap
->NormalBlit(this, Flags
);
181 bitmap::bitmap (v2 aSize
) :
183 XSizeTimesYSize(mSize
.X
* mSize
.Y
),
189 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
193 bitmap::bitmap (v2 aSize
, col16 Color
) :
195 XSizeTimesYSize(mSize
.X
*mSize
.Y
),
201 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
209 delete [] PriorityMap
;
214 void bitmap::Save (outputfile
&SaveFile
) const {
215 SaveFile
.Write(reinterpret_cast<char *>(Image
[0]), XSizeTimesYSize
*sizeof(packcol16
));
218 SaveFile
.Write(reinterpret_cast<char *>(AlphaMap
[0]), XSizeTimesYSize
*sizeof(packalpha
));
224 SaveFile
.Write(reinterpret_cast<char *>(PriorityMap
[0]), XSizeTimesYSize
*sizeof(packpriority
));
228 SaveFile
<< uChar(FastFlag
);
232 void bitmap::Load (inputfile
&SaveFile
) {
233 SaveFile
.Read(reinterpret_cast<char *>(Image
[0]), XSizeTimesYSize
*sizeof(packcol16
));
234 if (SaveFile
.Get()) {
235 Alloc2D(AlphaMap
, mSize
.Y
, mSize
.X
);
236 SaveFile
.Read(reinterpret_cast<char *>(AlphaMap
[0]), XSizeTimesYSize
*sizeof(packalpha
));
238 if (SaveFile
.Get()) {
239 Alloc2D(PriorityMap
, mSize
.Y
, mSize
.X
);
240 SaveFile
.Read(reinterpret_cast<char *>(PriorityMap
[0]), XSizeTimesYSize
*sizeof(packpriority
));
242 FastFlag
= ReadType(uChar
, SaveFile
);
246 #if defined(HAVE_LIBPNG) && !defined(HAVE_IMLIB2)
247 static void pngWrite (png_structp png_ptr
, png_bytep data
, png_size_t length
) {
248 FILE *fp
= (FILE *)png_get_io_ptr(png_ptr
);
249 fwrite(data
, length
, 1, fp
);
254 #if defined(HAVE_IMLIB2) || defined(HAVE_LIBPNG)
255 void bitmap::SavePNG (cfestring
&FileName
) const {
256 #if defined(HAVE_IMLIB2)
257 if (mSize
.X
< 1 || mSize
.Y
< 1) return;
258 Imlib_Image img
= imlib_create_image(mSize
.X
, mSize
.Y
);
259 imlib_context_set_image(img
);
260 DATA32
*raw
= imlib_image_get_data(); //brga
261 uChar
*pp
= (uChar
*)raw
;
262 for (int y
= 0; y
< mSize
.Y
; y
++) {
263 for (int x
= 0; x
< mSize
.X
; x
++) {
264 col16 Pixel
= GetPixel(x
, y
);
265 uChar b
= (Pixel
<< 3)&0xff;
266 uChar g
= ((Pixel
>> 5) << 2)&0xff;
267 uChar r
= ((Pixel
>> 11) << 3)&0xff;
274 imlib_image_set_format("png");
275 imlib_save_image(FileName
.CStr());
277 #elif defined(HAVE_LIBPNG)
281 //png_colorp palette;
282 png_byte
**row_pointers
= NULL
;
287 FILE *fp
= fopen(FileName
.CStr(), "wb");
289 row_pointers
= (png_byte
**)malloc(mSize
.Y
*sizeof(png_byte
*));
290 //if (!row_pointers);
291 png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
, NULL
,NULL
,NULL
);
293 info_ptr
= png_create_info_struct(png_ptr
);
295 // setup custom writer function
296 png_set_write_fn(png_ptr
, (voidp
)fp
, pngWrite
, NULL
);
297 if (setjmp(png_jmpbuf(png_ptr
))) {
301 if (compression > Z_BEST_COMPRESSION) compression = Z_BEST_COMPRESSION;
302 if (compression == Z_NO_COMPRESSION) {
304 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
305 png_set_compression_level(png_ptr, Z_NO_COMPRESSION);
306 } else if (compression < 0) {
307 png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
309 png_set_compression_level(png_ptr, compression);
312 png_set_filter(png_ptr
, 0, PNG_FILTER_NONE
);
313 png_set_compression_level(png_ptr
, /*Z_BEST_COMPRESSION*/Z_DEFAULT_COMPRESSION
);
314 //png_set_compression_level(png_ptr, Z_NO_COMPRESSION);
315 png_set_IHDR(png_ptr
, info_ptr
, mSize
.X
, mSize
.Y
, 8, PNG_COLOR_TYPE_RGB
, PNG_INTERLACE_NONE
, PNG_COMPRESSION_TYPE_DEFAULT
, PNG_FILTER_TYPE_DEFAULT
);
316 png_write_info(png_ptr
, info_ptr
);
317 uChar
*tcImg
= (uChar
*)malloc((mSize
.X
*3)*mSize
.Y
), *tc
= tcImg
;
318 for (int y
= 0; y
< mSize
.Y
; y
++) {
319 row_pointers
[y
] = (png_bytep
)tc
;
320 for (int x
= 0; x
< mSize
.X
; x
++) {
321 col16 Pixel
= GetPixel(x
, y
);
322 uChar b
= (Pixel
<< 3)&0xff;
323 uChar g
= ((Pixel
>> 5) << 2)&0xff;
324 uChar r
= ((Pixel
>> 11) << 3)&0xff;
331 png_write_image(png_ptr
, row_pointers
);
332 png_write_end(png_ptr
, NULL
);
335 //savedone: /* clean up and return */
336 png_destroy_write_struct(&png_ptr
, &info_ptr
);
337 if (row_pointers
) free(row_pointers
);
345 void bitmap::SaveBMP (cfestring
&FileName
) const {
346 static char BMPHeader
[] = {
347 char(0x42), char(0x4D), char(0xB6), char(0x4F), char(0x12), char(0x00),
348 char(0x00), char(0x00), char(0x00), char(0x00), char(0x36), char(0x00),
349 char(0x00), char(0x00), char(0x28), char(0x00), char(0x00), char(0x00),
350 char(0x20), char(0x03), char(0x00), char(0x00), char(0xF4), char(0x01),
351 char(0x00), char(0x00), char(0x01), char(0x00), char(0x18), char(0x00),
352 char(0x00), char(0x00), char(0x00), char(0x00), char(0x80), char(0x4F),
353 char(0x12), char(0x00), char(0x33), char(0x0B), char(0x00), char(0x00),
354 char(0x33), char(0x0B), char(0x00), char(0x00), char(0x00), char(0x00),
355 char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00)
357 FILE *fo
= fopen(FileName
.CStr(), "wb");
358 BMPHeader
[0x12] = mSize
.X
& 0xFF;
359 BMPHeader
[0x13] = (mSize
.X
>> 8) & 0xFF;
360 BMPHeader
[0x16] = mSize
.Y
& 0xFF;
361 BMPHeader
[0x17] = (mSize
.Y
>> 8) & 0xFF;
362 fwrite(BMPHeader
, 0x36, 1, fo
);
363 for (int y
= mSize
.Y
- 1; y
>= 0; --y
) {
364 for (int x
= 0; x
< mSize
.X
; ++x
) {
365 col16 Pixel
= GetPixel(x
, y
);
366 char b0
= Pixel
<< 3, b1
= (Pixel
>> 5) << 2, b2
= (Pixel
>> 11) << 3;
367 //SaveFile << char(Pixel << 3) << char((Pixel >> 5) << 2) << char((Pixel >> 11) << 3);
368 fwrite(&b0
, 1, 1, fo
);
369 fwrite(&b1
, 1, 1, fo
);
370 fwrite(&b2
, 1, 1, fo
);
377 uChar
*bitmap::createScaled (double scale
, v2
* size
) const {
378 int newX
= (int)((double)mSize
.X
*scale
);
379 int newY
= (int)((double)mSize
.Y
*scale
);
380 if (newX
< 1 || newY
< 1) return 0;
381 uChar
*unp
= new uChar
[mSize
.X
*mSize
.Y
*3];
384 for (int y
= 0; y
< mSize
.Y
; ++y
) {
385 for (int x
= 0; x
< mSize
.X
; ++x
) {
386 col16 Pixel
= GetPixel(x
, y
);
387 uChar b
= (Pixel
<<3)&0xff;
388 uChar g
= ((Pixel
>>5)<<2)&0xff;
389 uChar r
= ((Pixel
>>11)<<3)&0xff;
396 uChar
*nbx
= new uChar
[newX
*mSize
.Y
*3];
397 uChar
*nb
= new uChar
[newX
*newY
*3];
398 double sx
= (double)mSize
.X
/(double)newX
;
399 double sy
= (double)mSize
.Y
/(double)newY
;
400 #define GETRGB(x, y, r, g, b) \
401 r = unp[((y)*mSize.X+(x))*3+0]; \
402 g = unp[((y)*mSize.X+(x))*3+1]; \
403 b = unp[((y)*mSize.X+(x))*3+2];
408 for (int y
= 0; y
< mSize
.Y
; y
++) {
410 for (int x
= 0; x
< newX
; x
++, cx
+= sx
) {
412 int px
, r0
= 0, g0
= 0, b0
= 0, r1
, g1
, b1
;
415 if (px
>= 0 && px
< mSize
.X
) { GETRGB(px
, y
, r0
, g0
, b0
) }
416 if (px
>= 0 && px
< mSize
.X
-1) {
417 GETRGB(px
+1, y
, r1
, g1
, b1
)
418 r0
= (int)((double)r0
*(1.0-rx
)+(double)r1
*rx
);
419 g0
= (int)((double)g0
*(1.0-rx
)+(double)g1
*rx
);
420 b0
= (int)((double)b0
*(1.0-rx
)+(double)b1
*rx
);
422 if (r0
< 0) r0
= 0; else if (r0
> 255) r0
= 255;
423 if (g0
< 0) g0
= 0; else if (g0
> 255) g0
= 255;
424 if (b0
< 0) b0
= 0; else if (b0
> 255) b0
= 255;
432 #define GETRGB1(x, y, r, g, b) \
433 r = nbx[((y)*newX+(x))*3+0]; \
434 g = nbx[((y)*newX+(x))*3+1]; \
435 b = nbx[((y)*newX+(x))*3+2];
440 for (int y
= 0; y
< newY
; y
++, cy
+= sy
) {
442 for (int x
= 0; x
< newX
; x
++, cx
+= sx
) {
444 int py
, r0
= 0, g0
= 0, b0
= 0, r1
, g1
, b1
;
447 if (py
>= 0 && py
< mSize
.Y
) { GETRGB1(x
, py
, r0
, g0
, b0
) }
448 if (py
>= 0 && py
< mSize
.Y
-1) {
449 GETRGB1(x
, py
+1, r1
, g1
, b1
)
450 r0
= (int)((double)r0
*(1.0-ry
)+(double)r1
*ry
);
451 g0
= (int)((double)g0
*(1.0-ry
)+(double)g1
*ry
);
452 b0
= (int)((double)b0
*(1.0-ry
)+(double)b1
*ry
);
454 if (r0
< 0) r0
= 0; else if (r0
> 255) r0
= 255;
455 if (g0
< 0) g0
= 0; else if (g0
> 255) g0
= 255;
456 if (b0
< 0) b0
= 0; else if (b0
> 255) b0
= 255;
467 if (size
) *size
= v2(newX
, newY
);
472 #if defined(HAVE_IMLIB2) || defined(HAVE_LIBPNG)
473 void bitmap::SaveScaledPNG (cfestring
&fileName
, double scale
) const {
474 #if defined(HAVE_IMLIB2)
475 Imlib_Image img
= imlib_create_image(mSize
.X
, mSize
.Y
);
476 imlib_context_set_image(img
);
477 DATA32
*raw
= imlib_image_get_data(); //bgra
478 uChar
*pp
= (uChar
*)raw
;
479 for (int y
= 0; y
< mSize
.Y
; y
++) {
480 for (int x
= 0; x
< mSize
.X
; x
++) {
481 col16 Pixel
= GetPixel(x
, y
);
482 uChar b
= (Pixel
<< 3)&0xff;
483 uChar g
= ((Pixel
>> 5) << 2)&0xff;
484 uChar r
= ((Pixel
>> 11) << 3)&0xff;
491 int newW
= (int)(scale
*mSize
.X
);
492 int newH
= (int)(scale
*mSize
.Y
);
493 Imlib_Image i2
= imlib_create_cropped_scaled_image(0, 0, mSize
.X
, mSize
.Y
, newW
, newH
);
495 imlib_context_set_image(i2
);
496 imlib_image_set_format("png");
497 imlib_save_image(fileName
.CStr());
499 #elif defined(HAVE_LIBPNG)
501 auto rgb
= createScaled(scale
, &size
);
504 png_byte
**row_pointers
= NULL
;
507 FILE *fp
= fopen(fileName
.CStr(), "wb");
509 row_pointers
= (png_byte
**)malloc(size
.Y
*sizeof(png_byte
*));
510 png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
511 info_ptr
= png_create_info_struct(png_ptr
);
512 // setup custom writer function
513 png_set_write_fn(png_ptr
, (voidp
)fp
, pngWrite
, NULL
);
514 if (setjmp(png_jmpbuf(png_ptr
))) {
518 png_set_filter(png_ptr
, 0, PNG_FILTER_NONE
);
519 png_set_compression_level(png_ptr
, /*Z_BEST_COMPRESSION*/Z_DEFAULT_COMPRESSION
);
520 //png_set_compression_level(png_ptr, Z_NO_COMPRESSION);
521 png_set_IHDR(png_ptr
, info_ptr
, size
.X
, size
.Y
, 8, PNG_COLOR_TYPE_RGB
, PNG_INTERLACE_NONE
, PNG_COMPRESSION_TYPE_DEFAULT
, PNG_FILTER_TYPE_DEFAULT
);
522 png_write_info(png_ptr
, info_ptr
);
523 for (int y
= 0; y
< size
.Y
; ++y
) row_pointers
[y
] = (png_bytep
)(rgb
+y
*(size
.X
*3));
524 png_write_image(png_ptr
, row_pointers
);
525 png_write_end(png_ptr
, NULL
);
527 // clean up and return
528 png_destroy_write_struct(&png_ptr
, &info_ptr
);
529 if (row_pointers
) free(row_pointers
);
536 truth
bitmap::LoadPNG (cfestring
&fileName
) {
537 #if defined(HAVE_IMLIB2)
538 Imlib_Image img
= imlib_load_image(fileName
.CStr());
539 if (!img
) return false;
542 delete [] PriorityMap
;
547 imlib_context_set_image(img
);
548 mSize
.X
= imlib_image_get_width();
549 mSize
.Y
= imlib_image_get_height();
550 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
551 //Alloc2D(AlphaMap, mSize.Y, mSize.X);
552 const DATA32
*raw
= imlib_image_get_data_for_reading_only(); //bgra
553 const uChar
*pp
= (const uChar
*)raw
;
554 for (int y
= 0; y
< mSize
.Y
; y
++) {
555 for (int x
= 0; x
< mSize
.X
; x
++) {
561 PutPixel(x
, y
, MakeRGB16(r
, g
, b
));
566 #elif defined(HAVE_LIBPNG)
567 FILE *fl
= fopen(fileName
.CStr(), "rb");
568 if (!fl
) return false;
571 png_bytep
*rowptrs
= 0;
573 png_structp PNGStruct
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0);
581 png_infop PNGInfo
= png_create_info_struct(PNGStruct
);
584 png_destroy_read_struct(&PNGStruct
, (png_infopp
)nullptr, (png_infopp
)nullptr);
590 if (setjmp(png_jmpbuf(PNGStruct
)) != 0) {
592 png_destroy_read_struct(&PNGStruct
, (png_infopp
)nullptr, (png_infopp
)nullptr);
598 png_init_io(PNGStruct
, fl
);
599 png_read_info(PNGStruct
, PNGInfo
);
601 int sizeX
= png_get_image_width(PNGStruct
, PNGInfo
);
602 int sizeY
= png_get_image_height(PNGStruct
, PNGInfo
);
604 if (sizeX
< 1 || sizeX
> 8192 || sizeY
< 1 || sizeY
> 8192) {
606 png_destroy_read_struct(&PNGStruct
, (png_infopp
)nullptr, (png_infopp
)nullptr);
612 //fprintf(stderr, "size: %dx%d; depth=%d\n", sizeX, sizeY, (int)png_get_bit_depth(PNGStruct, PNGInfo));
614 if (png_get_bit_depth(PNGStruct
, PNGInfo
) != 8 || png_get_color_type(PNGStruct
, PNGInfo
) != PNG_COLOR_TYPE_RGB
) {
616 png_destroy_read_struct(&PNGStruct
, (png_infopp
)nullptr, (png_infopp
)nullptr);
622 rgb
= new uChar
[sizeY
*(sizeX
*3)];
623 rowptrs
= new png_bytep
[sizeY
];
625 for (int y
= 0; y
< sizeY
; ++y
) rowptrs
[y
] = (png_bytep
)(rgb
+y
*(sizeX
*3));
627 png_read_image(PNGStruct
, rowptrs
);
629 png_destroy_read_struct(&PNGStruct
, &PNGInfo
, nullptr);
637 delete [] PriorityMap
;
644 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
645 //Alloc2D(AlphaMap, mSize.Y, mSize.X);
646 const uChar
*pp
= rgb
;
647 for (int y
= 0; y
< sizeY
; ++y
) {
648 for (int x
= 0; x
< sizeX
; ++x
) {
652 PutPixel(x
, y
, MakeRGB16(r
, g
, b
));
663 void bitmap::SaveScaledIPU (cfestring
&fileName
, double scale
) const {
665 uChar
*rgb
= createScaled(scale
, &size
);
668 auto fo
= xcreate(fileName
.CStr());
671 ii
= 0x29a; xwrite(fo
, &ii
, sizeof(ii
));
672 ii
= size
.X
; xwrite(fo
, &ii
, sizeof(ii
));
673 ii
= size
.Y
; xwrite(fo
, &ii
, sizeof(ii
));
674 xwrite(fo
, rgb
, size
.X
*size
.Y
*3);
681 truth
bitmap::LoadIPU (cfestring
&fileName
) {
683 int wdt
= 0, hgt
= 0;
684 auto fi
= xopenro(fileName
.CStr());
685 if (!fi
) return false;
686 if (!xread(fi
, &ii
, sizeof(ii
))) { xclose(fi
); return false; }
687 if (ii
!= 0x29a) { xclose(fi
); return false; }
688 if (!xread(fi
, &ii
, sizeof(ii
))) { xclose(fi
); return false; }
689 if (ii
< 1 || ii
> 4096) { xclose(fi
); return false; }
691 if (!xread(fi
, &ii
, sizeof(ii
))) { xclose(fi
); return false; }
692 if (ii
< 1 || ii
> 4096) { xclose(fi
); return false; }
694 uChar
*nb
= new uChar
[wdt
*hgt
*3];
695 if (!xread(fi
, nb
, wdt
*hgt
*3)) { xclose(fi
); delete [] nb
; xclose(fi
); return false; }
700 delete [] PriorityMap
;
708 Alloc2D(Image
, mSize
.Y
, mSize
.X
);
709 //Alloc2D(AlphaMap, mSize.Y, mSize.X);
711 for (int y
= 0; y
< mSize
.Y
; y
++) {
712 for (int x
= 0; x
< mSize
.X
; x
++) {
716 PutPixel(x
, y
, MakeRGB16(r
, g
, b
));
724 void bitmap::Fill (v2 TopLeft
, int Width
, int Height
, col16 Color
) { Fill(TopLeft
.X
, TopLeft
.Y
, Width
, Height
, Color
); }
725 void bitmap::Fill (int X
, int Y
, v2 FillSize
, col16 Color
) { Fill(X
, Y
, FillSize
.X
, FillSize
.Y
, Color
); }
726 void bitmap::Fill (v2 TopLeft
, v2 FillSize
, col16 Color
) { Fill(TopLeft
.X
, TopLeft
.Y
, FillSize
.X
, FillSize
.Y
, Color
); }
728 void bitmap::Fill (int X
, int Y
, int Width
, int Height
, col16 Color
) {
729 if (X
>= mSize
.X
|| Y
>= mSize
.Y
) return;
730 if (X
+ Width
> mSize
.X
) Width
= mSize
.X
- X
;
731 if (Y
+ Height
> mSize
.Y
) Height
= mSize
.Y
- Y
;
732 if (Color
>> 8 == (Color
& 0xFF)) {
734 for (int y
= 0; y
< Height
; ++y
) memset(&Image
[Y
+ y
][X
], Color
, Width
);
736 for (int y
= 0; y
< Height
; ++y
) {
737 packcol16
*Ptr
= &Image
[Y
+ y
][X
];
738 cpackcol16
*const EndPtr
= Ptr
+ Width
;
739 while (Ptr
!= EndPtr
) *Ptr
++ = Color
;
745 void bitmap::ClearToColor (col16 Color
) {
746 packcol16
*Ptr
= Image
[0];
747 if (Color
>> 8 == (Color
& 0xFF)) {
748 memset(Ptr
, Color
, XSizeTimesYSize
*sizeof(packcol16
));
750 cpackcol16
*const EndPtr
= Ptr
+ XSizeTimesYSize
;
751 while (Ptr
!= EndPtr
) *Ptr
++ = Color
;
756 void bitmap::NormalBlit (cblitdata
&BlitData
) const {
757 blitdata B
= BlitData
;
759 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap blit attempt detected!");
760 if ((B
.Flags
&ROTATE
) && B
.Border
.X
!= B
.Border
.Y
) ABORT("Blit error: FeLib supports only square rotating!");
761 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
763 packcol16
**SrcImage
= Image
;
764 packcol16
**DestImage
= B
.Bitmap
->Image
;
767 if (!B
.Src
.X
&& !B
.Src
.Y
&& !B
.Dest
.X
&& !B
.Dest
.Y
&& B
.Border
.X
== mSize
.X
&& B
.Border
.Y
== mSize
.Y
&&
768 B
.Border
.X
== B
.Bitmap
->mSize
.X
&& B
.Border
.Y
== B
.Bitmap
->mSize
.Y
) {
769 memmove(DestImage
[0], SrcImage
[0], XSizeTimesYSize
* sizeof(packcol16
));
771 cint Bytes
= B
.Border
.X
* sizeof(packcol16
);
772 for (int y
= 0; y
< B
.Border
.Y
; ++y
) memmove(&DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
], &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
], Bytes
);
776 B
.Dest
.X
+= B
.Border
.X
- 1;
777 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
778 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
779 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
780 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
781 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) *DestPtr
= *SrcPtr
;
785 B
.Dest
.Y
+= B
.Border
.Y
- 1;
786 cint Bytes
= B
.Border
.X
* sizeof(packcol16
);
787 for (int y
= 0; y
< B
.Border
.Y
; ++y
) memmove(&DestImage
[B
.Dest
.Y
- y
][B
.Dest
.X
], &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
], Bytes
);
789 case (MIRROR
| FLIP
): {
790 B
.Dest
.X
+= B
.Border
.X
- 1;
791 B
.Dest
.Y
+= B
.Border
.Y
- 1;
792 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
793 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
794 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
795 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
- y
][B
.Dest
.X
];
796 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) *DestPtr
= *SrcPtr
;
800 B
.Dest
.X
+= B
.Border
.X
- 1;
801 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
802 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
803 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
804 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
805 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
806 packcol16
*DestPtr
= DestBase
- y
;
807 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) *DestPtr
= *SrcPtr
;
810 case (MIRROR
| ROTATE
): {
811 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
812 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
813 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
814 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
815 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
816 packcol16
*DestPtr
= DestBase
+ y
;
817 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) *DestPtr
= *SrcPtr
;
820 case (FLIP
| ROTATE
): {
821 B
.Dest
.X
+= B
.Border
.X
- 1;
822 B
.Dest
.Y
+= B
.Border
.Y
- 1;
823 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
824 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
825 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
826 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
827 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
828 packcol16
*DestPtr
= DestBase
- y
;
829 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) *DestPtr
= *SrcPtr
;
832 case (MIRROR
| FLIP
| ROTATE
): {
833 B
.Dest
.Y
+= B
.Border
.Y
- 1;
834 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
835 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
836 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
837 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
838 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
839 packcol16
*DestPtr
= DestBase
+ y
;
840 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) *DestPtr
= *SrcPtr
;
847 void bitmap::LuminanceBlit (cblitdata
&BlitData
) const {
848 blitdata B
= BlitData
;
849 if (B
.Luminance
== NORMAL_LUMINANCE
) {
855 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap blit attempt detected!");
856 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
858 packcol16
**SrcImage
= Image
;
859 packcol16
**DestImage
= B
.Bitmap
->Image
;
860 int NewRedLuminance
= (B
.Luminance
>> 7 & 0x1F800) - 0x10000;
861 int NewGreenLuminance
= (B
.Luminance
>> 4 & 0xFE0) - 0x800;
862 int NewBlueLuminance
= (B
.Luminance
>> 2 & 0x3F) - 0x20;
863 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
864 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
865 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
866 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
867 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
) {
870 NEW_LUMINATE_GREEN();
878 void bitmap::NormalMaskedBlit (cblitdata
&BlitData
) const {
879 blitdata B
= BlitData
;
881 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap masked blit attempt detected!");
882 if ((B
.Flags
&ROTATE
) && B
.Border
.X
!= B
.Border
.Y
) ABORT("MaskedBlit error: FeLib supports only square rotating!");
883 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
885 packcol16
**SrcImage
= Image
;
886 packcol16
**DestImage
= B
.Bitmap
->Image
;
887 packcol16 PackedMaskColor
= B
.MaskColor
;
890 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
891 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
892 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
893 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
894 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
898 B
.Dest
.X
+= B
.Border
.X
- 1;
899 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
900 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
901 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
902 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
903 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
907 B
.Dest
.Y
+= B
.Border
.Y
- 1;
908 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
909 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
910 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
911 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
- y
][B
.Dest
.X
];
912 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
915 case (MIRROR
| FLIP
): {
916 B
.Dest
.X
+= B
.Border
.X
- 1;
917 B
.Dest
.Y
+= B
.Border
.Y
- 1;
918 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
919 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
920 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
921 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
- y
][B
.Dest
.X
];
922 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
926 B
.Dest
.X
+= B
.Border
.X
- 1;
927 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
928 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
929 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
930 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
931 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
932 packcol16
*DestPtr
= DestBase
- y
;
933 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
936 case (MIRROR
| ROTATE
): {
937 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
938 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
939 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
940 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
941 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
942 packcol16
*DestPtr
= DestBase
+ y
;
943 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= TrueDestXMove
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
946 case (FLIP
| ROTATE
): {
947 B
.Dest
.X
+= B
.Border
.X
- 1;
948 B
.Dest
.Y
+= B
.Border
.Y
- 1;
949 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
950 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
951 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
952 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
953 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
954 packcol16
*DestPtr
= DestBase
- y
;
955 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
958 case (MIRROR
| FLIP
| ROTATE
): {
959 B
.Dest
.Y
+= B
.Border
.Y
- 1;
960 int TrueDestXMove
= B
.Bitmap
->mSize
.X
;
961 packcol16
*DestBase
= &DestImage
[B
.Dest
.Y
][B
.Dest
.X
];
962 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
963 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
964 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
965 packcol16
*DestPtr
= DestBase
+ y
;
966 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= TrueDestXMove
) if (*SrcPtr
!= PackedMaskColor
) *DestPtr
= *SrcPtr
;
973 void bitmap::LuminanceMaskedBlit (cblitdata
&BlitData
) const {
974 blitdata B
= BlitData
;
975 if (B
.Luminance
== NORMAL_LUMINANCE
) {
981 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap masked blit attempt detected!");
982 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
984 packcol16
**SrcImage
= Image
;
985 packcol16
**DestImage
= B
.Bitmap
->Image
;
986 int NewRedLuminance
= (B
.Luminance
>> 7 & 0x1F800) - 0x10000;
987 int NewGreenLuminance
= (B
.Luminance
>> 4 & 0xFE0) - 0x800;
988 int NewBlueLuminance
= (B
.Luminance
>> 2 & 0x3F) - 0x20;
989 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
990 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
991 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
992 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
993 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
) {
995 if (SrcCol
!= B
.MaskColor
) {
997 NEW_LUMINATE_GREEN();
1006 void bitmap::SimpleAlphaBlit (bitmap
*Bitmap
, alpha Alpha
, col16 MaskColor
) const {
1012 { mSize
.X
, mSize
.Y
},
1017 NormalMaskedBlit(B
);
1020 if (!FastFlag
&& (mSize
.X
!= Bitmap
->mSize
.X
|| mSize
.Y
!= Bitmap
->mSize
.Y
)) ABORT("Fast simple alpha blit attempt of noncongruent bitmaps detected!");
1021 cpackcol16
*SrcPtr
= Image
[0];
1022 cpackcol16
*EndPtr
= SrcPtr
+ XSizeTimesYSize
;
1023 packcol16
*DestPtr
= Bitmap
->Image
[0];
1024 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
) {
1026 if (SrcCol
!= MaskColor
) {
1028 NEW_LOAD_AND_APPLY_ALPHA_RED();
1029 NEW_LOAD_AND_APPLY_ALPHA_GREEN();
1030 NEW_LOAD_AND_APPLY_ALPHA_BLUE();
1037 void bitmap::AlphaMaskedBlit (cblitdata
&BlitData
) const {
1038 blitdata B
= BlitData
;
1041 NormalMaskedBlit(B
);
1045 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap alpha blit attempt detected!");
1046 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1049 packcol16
**SrcImage
= Image
;
1050 packalpha
**SrcAlphaMap
= AlphaMap
;
1051 packcol16
**DestImage
= B
.Bitmap
->Image
;
1053 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
1054 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
1055 cpackalpha
*AlphaPtr
= &SrcAlphaMap
[B
.Src
.Y
+ y
][B
.Src
.X
];
1056 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
1057 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1058 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
, ++AlphaPtr
) {
1060 if (SrcCol
!= B
.MaskColor
) {
1063 NEW_LOAD_AND_APPLY_ALPHA_RED();
1064 NEW_LOAD_AND_APPLY_ALPHA_GREEN();
1065 NEW_LOAD_AND_APPLY_ALPHA_BLUE();
1073 void bitmap::DrawLine (v2 From
, int ToX
, int ToY
, col16 Color
, truth Wide
) { DrawLine(From
.X
, From
.Y
, ToX
, ToY
, Color
, Wide
); }
1074 void bitmap::DrawLine (int FromX
, int FromY
, v2 To
, col16 Color
, truth Wide
) { DrawLine(FromX
, FromY
, To
.X
, To
.Y
, Color
, Wide
); }
1075 void bitmap::DrawLine (v2 From
, v2 To
, col16 Color
, truth Wide
) { DrawLine(From
.X
, From
.Y
, To
.X
, To
.Y
, Color
, Wide
); }
1077 void bitmap::DrawLine (int OrigFromX
, int OrigFromY
, int OrigToX
, int OrigToY
, col16 Color
, truth Wide
) {
1078 if (OrigFromY
== OrigToY
) {
1079 DrawHorizontalLine(OrigFromX
, OrigToX
, OrigFromY
, Color
, Wide
);
1082 if (OrigFromX
== OrigToX
) {
1083 DrawVerticalLine(OrigFromX
, OrigFromY
, OrigToY
, Color
, Wide
);
1087 static cint PointX
[] = { 0, 0, -1, 1, 0 };
1088 static cint PointY
[] = { 0, -1, 0, 0, 1 };
1089 cint Times
= Wide
? 5 : 1;
1091 for (int c1
= 0; c1
< Times
; ++c1
) {
1092 cint X1
= OrigFromX
+ PointX
[c1
];
1093 cint Y1
= OrigFromY
+ PointY
[c1
];
1094 cint X2
= OrigToX
+ PointX
[c1
];
1095 cint Y2
= OrigToY
+ PointY
[c1
];
1096 cint DeltaX
= abs(X2
- X1
);
1097 cint DeltaY
= abs(Y2
- Y1
);
1099 int XChange
, PtrXChange
, PtrYChange
;
1100 int DoubleDeltaX
, DoubleDeltaY
, End
;
1101 if (DeltaX
>= DeltaY
) {
1104 PtrXChange
= XChange
= X1
< X2
? 1 : -1;
1105 PtrYChange
= Y1
< Y2
? mSize
.X
: -mSize
.X
;
1106 DoubleDeltaX
= DeltaX
<< 1;
1107 DoubleDeltaY
= DeltaY
<< 1;
1112 XChange
= Y1
< Y2
? 1 : -1;
1113 PtrXChange
= Y1
< Y2
? mSize
.X
: -mSize
.X
;
1114 PtrYChange
= X1
< X2
? 1 : -1;
1115 DoubleDeltaX
= DeltaY
<< 1;
1116 DoubleDeltaY
= DeltaX
<< 1;
1119 packcol16
*Ptr
= &Image
[Y1
][X1
];
1125 if (c2
>= DoubleDeltaX
) {
1135 void bitmap::DrawVerticalLine (int OrigX
, int OrigFromY
, int OrigToY
, col16 Color
, truth Wide
) {
1136 static cint PointX
[] = { 0, -1, 1 };
1137 cint Times
= Wide
? 3 : 1;
1138 for (int c
= 0; c
< Times
; ++c
) {
1139 int X
= OrigX
+ PointX
[c
];
1140 int FromY
= OrigFromY
;
1142 if (FromY
> ToY
) Swap(FromY
, ToY
);
1147 if (X
< 0 || X
>= mSize
.X
|| ToY
< 0 || FromY
>= mSize
.Y
) continue;
1148 FromY
= Max(FromY
, 0);
1149 ToY
= Min(ToY
, mSize
.Y
-1);
1150 packcol16
*Ptr
= &Image
[FromY
][X
];
1151 for (int y
= FromY
; y
<= ToY
; ++y
, Ptr
+= mSize
.X
) *Ptr
= Color
;
1156 void bitmap::DrawHorizontalLine(int OrigFromX
, int OrigToX
, int OrigY
, col16 Color
, truth Wide
) {
1157 static cint PointY
[] = { 0, -1, 1 };
1158 cint Times
= Wide
? 3 : 1;
1159 for (int c
= 0; c
< Times
; ++c
) {
1160 int Y
= OrigY
+ PointY
[c
];
1161 int FromX
= OrigFromX
;
1163 if (FromX
> ToX
) Swap(FromX
, ToX
);
1168 if (Y
< 0 || Y
>= mSize
.Y
|| ToX
< 0 || FromX
>= mSize
.X
) continue;
1169 FromX
= Max(FromX
, 0);
1170 ToX
= Min(ToX
, mSize
.X
-1);
1171 packcol16
*Ptr
= &Image
[Y
][FromX
];
1172 for (int x
= FromX
; x
<= ToX
; ++x
, ++Ptr
) *Ptr
= Color
;
1177 void bitmap::DrawPolygon (int CenterX
, int CenterY
, int Radius
, int NumberOfSides
, col16 Color
, truth DrawSides
, truth DrawDiameters
, double Rotation
) {
1178 if (!DrawSides
&& !DrawDiameters
) return;
1179 v2
*Point
= new v2
[NumberOfSides
];
1180 double AngleDelta
= 2 * FPI
/ NumberOfSides
;
1182 for (c
= 0; c
< NumberOfSides
; ++c
) {
1183 Point
[c
].X
= CenterX
+ int(sin(AngleDelta
* c
+ Rotation
) * Radius
);
1184 Point
[c
].Y
= CenterY
+ int(cos(AngleDelta
* c
+ Rotation
) * Radius
);
1186 if (DrawDiameters
) {
1188 for (c
= 0; c
< NumberOfSides
; ++c
)
1189 for (int a
= 0; a
< NumberOfSides
; ++a
)
1190 if (c
!= a
) DrawLine(Point
[c
].X
, Point
[c
].Y
, Point
[a
].X
, Point
[a
].Y
, Color
, true);
1192 for (c
= 0; c
< NumberOfSides
; ++c
)
1193 for (int a
= 0; a
< NumberOfSides
; ++a
)
1194 if ((int(c
- a
) > 1 || int(a
- c
) > 1) && (a
|| c
!= NumberOfSides
- 1) && (c
|| a
!= NumberOfSides
- 1))
1195 DrawLine(Point
[c
].X
, Point
[c
].Y
, Point
[a
].X
, Point
[a
].Y
, Color
, true);
1198 for (c
= 0; c
< NumberOfSides
- 1; ++c
)
1199 DrawLine(Point
[c
].X
, Point
[c
].Y
, Point
[c
+ 1].X
, Point
[c
+ 1].Y
, Color
, true);
1200 DrawLine(Point
[NumberOfSides
- 1].X
, Point
[NumberOfSides
- 1].Y
, Point
[0].X
, Point
[0].Y
, Color
, true);
1206 void bitmap::CreateAlphaMap (alpha InitialValue
) {
1207 if (AlphaMap
) ABORT("Alpha leak detected!");
1208 Alloc2D(AlphaMap
, mSize
.Y
, mSize
.X
);
1209 memset(AlphaMap
[0], InitialValue
, XSizeTimesYSize
);
1213 truth
bitmap::Fade (sLong
&AlphaSum
, packalpha
& AlphaAverage
, int Amount
) {
1214 if (!AlphaMap
) ABORT("No alpha map to fade.");
1215 truth Changes
= false;
1217 sLong NewAlphaSum
= 0;
1218 sLong Size
= XSizeTimesYSize
;
1219 for (sLong c
= 0; c
< Size
; ++c
) {
1220 packalpha
*AlphaPtr
= &AlphaMap
[0][c
];
1222 if (*AlphaPtr
> Amount
) {
1223 *AlphaPtr
-= Amount
;
1224 NewAlphaSum
+= *AlphaPtr
;
1230 if (RandMap
) UpdateRandMap(c
, false);
1234 AlphaSum
= NewAlphaSum
;
1235 AlphaAverage
= Alphas
? NewAlphaSum
/ Alphas
: 0;
1240 void bitmap::Outline (col16 Color
, alpha Alpha
, priority Priority
) {
1241 if (!AlphaMap
) CreateAlphaMap(255);
1242 col16 LastColor
, NextColor
;
1244 int YMax
= mSize
.Y
- 1;
1245 for (int x
= 0; x
< XMax
; ++x
) {
1246 packcol16
*Buffer
= &Image
[0][x
];
1247 LastColor
= *Buffer
;
1248 for (int y
= 0; y
< YMax
; ++y
) {
1249 NextColor
= *(Buffer
+ XMax
);
1250 if ((LastColor
== TRANSPARENT_COLOR
|| !y
) && NextColor
!= TRANSPARENT_COLOR
) {
1252 SetAlpha(x
, y
, Alpha
);
1253 SafeSetPriority(x
, y
, Priority
);
1256 if (LastColor
!= TRANSPARENT_COLOR
&& (NextColor
== TRANSPARENT_COLOR
|| y
== YMax
- 1)) {
1258 SetAlpha(x
, y
+ 1, Alpha
);
1259 SafeSetPriority(x
, y
+ 1, Priority
);
1261 LastColor
= NextColor
;
1266 for (int y
= 0; y
< YMax
; ++y
) {
1267 packcol16
*Buffer
= Image
[y
];
1268 LastColor
= *Buffer
;
1269 for (int x
= 0; x
< XMax
; ++x
) {
1270 NextColor
= *(Buffer
+ 1);
1271 if ((LastColor
== TRANSPARENT_COLOR
|| !x
) && NextColor
!= TRANSPARENT_COLOR
) {
1273 SetAlpha(x
, y
, Alpha
);
1274 SafeSetPriority(x
, y
, Priority
);
1277 if (LastColor
!= TRANSPARENT_COLOR
&& (NextColor
== TRANSPARENT_COLOR
|| x
== XMax
- 1)) {
1279 SetAlpha(x
+ 1, y
, Alpha
);
1280 SafeSetPriority(x
+ 1, y
, Priority
);
1282 LastColor
= NextColor
;
1288 void bitmap::FadeToScreen (bitmapeditor BitmapEditor
) {
1289 bitmap
Backup(DOUBLE_BUFFER
);
1290 Backup
.ActivateFastFlag();
1300 for (int c
= 0; c
<= 5; ++c
) {
1301 clock_t StartTime
= clock();
1302 int Element
= 127 - c
* 25;
1303 B
.Luminance
= MakeRGB24(Element
, Element
, Element
);
1304 Backup
.LuminanceMaskedBlit(B
);
1305 if (BitmapEditor
) BitmapEditor(this, true);
1306 SimpleAlphaBlit(DOUBLE_BUFFER
, c
* 50, 0);
1307 graphics::BlitDBToScreen();
1308 while(clock() - StartTime
< 0.05 * CLOCKS_PER_SEC
);
1310 DOUBLE_BUFFER
->ClearToColor(0);
1311 if (BitmapEditor
) BitmapEditor(this, true);
1313 NormalMaskedBlit(B
);
1314 graphics::BlitDBToScreen();
1318 void bitmap::StretchBlit (cblitdata
&BlitData
) const {
1319 blitdata B
= BlitData
;
1321 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap stretch blit attempt detected!");
1322 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1324 if (B
.Stretch
> 1) {
1326 for (int x1
= B
.Src
.X
; x1
< B
.Src
.X
+ B
.Border
.X
; ++x1
, tx
+= B
.Stretch
) {
1328 for (int y1
= B
.Src
.Y
; y1
< B
.Src
.Y
+ B
.Border
.Y
; ++y1
, ty
+= B
.Stretch
) {
1329 packcol16 Pixel
= Image
[y1
][x1
];
1330 if (Pixel
!= TRANSPARENT_COLOR
)
1331 for (int x2
= tx
; x2
< tx
+ B
.Stretch
; ++x2
)
1332 for (int y2
= ty
; y2
< ty
+ B
.Stretch
; ++y2
)
1333 B
.Bitmap
->Image
[y2
][x2
] = Pixel
;
1337 } else if (B
.Stretch
< -1) {
1339 for (int x1
= B
.Src
.X
; x1
< B
.Src
.X
+ B
.Border
.X
; x1
-= B
.Stretch
, ++tx
) {
1341 for (int y1
= B
.Src
.Y
; y1
< B
.Src
.Y
+ B
.Border
.Y
; y1
-= B
.Stretch
, ++ty
) {
1342 packcol16 Pixel
= Image
[y1
][x1
];
1343 if (Pixel
!= TRANSPARENT_COLOR
) B
.Bitmap
->Image
[ty
][tx
] = Pixel
;
1349 NormalMaskedBlit(B
);
1355 outputfile
&operator << (outputfile
&SaveFile
, cbitmap
*Bitmap
) {
1358 SaveFile
<< Bitmap
->GetSize();
1359 Bitmap
->Save(SaveFile
);
1367 inputfile
&operator >> (inputfile
&SaveFile
, bitmap
*&Bitmap
) {
1368 if (SaveFile
.Get()) {
1369 Bitmap
= new bitmap(ReadType(v2
, SaveFile
));
1370 Bitmap
->Load(SaveFile
);
1378 void bitmap::DrawRectangle (v2 TopLeft
, int Right
, int Bottom
, col16 Color
, truth Wide
) { DrawRectangle(TopLeft
.X
, TopLeft
.Y
, Right
, Bottom
, Color
, Wide
); }
1379 void bitmap::DrawRectangle (int Left
, int Top
, v2 BottomRight
, col16 Color
, truth Wide
) { DrawRectangle(Left
, Top
, BottomRight
.X
, BottomRight
.Y
, Color
, Wide
); }
1380 void bitmap::DrawRectangle (v2 TopLeft
, v2 BottomRight
, col16 Color
, truth Wide
) { DrawRectangle(TopLeft
.X
, TopLeft
.Y
, BottomRight
.X
, BottomRight
.Y
, Color
, Wide
); }
1382 void bitmap::DrawRectangle (int Left
, int Top
, int Right
, int Bottom
, col16 Color
, truth Wide
) {
1383 DrawHorizontalLine(Left
, Right
, Top
, Color
, Wide
);
1384 DrawHorizontalLine(Left
, Right
, Bottom
, Color
, Wide
);
1385 DrawVerticalLine(Right
, Top
, Bottom
, Color
, Wide
);
1386 DrawVerticalLine(Left
, Top
, Bottom
, Color
, Wide
);
1390 void bitmap::AlphaLuminanceBlit (cblitdata
&BlitData
) const {
1391 if (BlitData
.Luminance
== NORMAL_LUMINANCE
) {
1392 AlphaMaskedBlit(BlitData
);
1396 LuminanceMaskedBlit(BlitData
);
1399 blitdata B
= BlitData
;
1401 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap alpha blit attempt detected!");
1402 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1404 packcol16
**SrcImage
= Image
;
1405 packalpha
**SrcAlphaMap
= AlphaMap
;
1406 packcol16
**DestImage
= B
.Bitmap
->Image
;
1407 int NewRedLuminance
= (B
.Luminance
>> 7 & 0x1F800) - 0x10000;
1408 int NewGreenLuminance
= (B
.Luminance
>> 4 & 0xFE0) - 0x800;
1409 int NewBlueLuminance
= (B
.Luminance
>> 2 & 0x3F) - 0x20;
1410 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
1411 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
1412 cpackalpha
*AlphaPtr
= &SrcAlphaMap
[B
.Src
.Y
+ y
][B
.Src
.X
];
1413 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
1414 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1415 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
, ++AlphaPtr
) {
1417 if (SrcCol
!= B
.MaskColor
) {
1421 NEW_APPLY_ALPHA_RED();
1422 NEW_LUMINATE_GREEN();
1423 NEW_APPLY_ALPHA_GREEN();
1424 NEW_LUMINATE_BLUE();
1425 NEW_APPLY_ALPHA_BLUE();
1433 /* Only works for 16x16 pictures :( */
1434 void bitmap::CreateFlames (rawbitmap
*RawBitmap
, v2 RawPos
, feuLong SeedNFlags
, int Frame
) {
1436 femath::SetSeed(SeedNFlags
);
1437 int FlameTop
[16], FlameBottom
[16], FlamePhase
[16];
1439 for (x
= 0; x
< 16; ++x
) {
1440 FlameBottom
[x
] = NO_FLAME
;
1441 for (y
= 0; y
< 16; ++y
) {
1442 if (GetPixel(x
, y
) != TRANSPARENT_COLOR
) {
1443 if (1 << RawBitmap
->GetMaterialColorIndex(RawPos
.X
+ x
, RawPos
.Y
+ y
) & SeedNFlags
) {
1444 FlamePhase
[x
] = RAND_16
;
1446 FlameBottom
[x
] = y
- 1;
1447 if (y
>= 5) FlameTop
[x
] = (y
- (RAND_32
* y
>> 5)) >> 1; else FlameTop
[x
] = 0;
1457 for (x
= 0; x
< 16; ++x
) {
1458 if (FlameBottom
[x
] != NO_FLAME
) {
1459 int Phase
= (Frame
+ FlamePhase
[x
]) & 15;
1460 int Length
= FlameBottom
[x
] - FlameTop
[x
];
1461 int Top
= FlameBottom
[x
] - Length
+ Phase
* (15 - Phase
) * Length
/ 56;
1462 for (y
= Top
; y
<= FlameBottom
[x
]; ++y
) {
1464 PowerPutPixel(x
, y
, MakeRGB16(255, 255 - (Pos
<< 7) / Length
, 0), 127 + (Pos
<< 6) / Length
, AVERAGE_PRIORITY
);
1472 void bitmap::CreateSparkle (v2 SparklePos
, int Frame
) {
1474 int Size
= (Frame
- 1) * (16 - Frame
) / 10;
1475 PowerPutPixel(SparklePos
.X
, SparklePos
.Y
, WHITE
, 255, SPARKLE_PRIORITY
);
1476 for (int c
= 1; c
< Size
; ++c
) {
1477 int Lightness
= 191 + ((Size
- c
) << 6) / Size
;
1478 col16 RGB
= MakeRGB16(Lightness
, Lightness
, Lightness
);
1479 PowerPutPixel(SparklePos
.X
+ c
, SparklePos
.Y
, RGB
, 255, SPARKLE_PRIORITY
);
1480 PowerPutPixel(SparklePos
.X
- c
, SparklePos
.Y
, RGB
, 255, SPARKLE_PRIORITY
);
1481 PowerPutPixel(SparklePos
.X
, SparklePos
.Y
+ c
, RGB
, 255, SPARKLE_PRIORITY
);
1482 PowerPutPixel(SparklePos
.X
, SparklePos
.Y
- c
, RGB
, 255, SPARKLE_PRIORITY
);
1488 void bitmap::CreateFlies (feuLong Seed
, int Frame
, int FlyAmount
) {
1490 femath::SetSeed(Seed
);
1491 for (int c
= 0; c
< FlyAmount
; ++c
) {
1492 double Constant
= double(RAND() % 10000) / 10000 * FPI
;
1493 v2 StartPos
= v2(5 + RAND() % 6, 5 + RAND() % 6);
1494 double Temp
= (double(16 - Frame
) * FPI
) / 16;
1495 if (RAND() & 1) Temp
= -Temp
;
1497 Where
.X
= int(StartPos
.X
+ sin(Constant
+ Temp
) * 3);
1498 Where
.Y
= int(StartPos
.Y
+ sin(2*(Constant
+ Temp
)) * 3);
1499 PowerPutPixel(Where
.X
, Where
.Y
, MakeRGB16(40, 40, 60), 255, FLY_PRIORITY
);
1505 void bitmap::CreateLightning (feuLong Seed
, col16 Color
) {
1507 femath::SetSeed(Seed
);
1517 StartPos
.X
= mSize
.X
- 1;
1520 StartPos
.Y
= RAND() % mSize
.Y
;
1526 StartPos
.Y
= mSize
.Y
- 1;
1529 StartPos
.X
= RAND() % mSize
.X
;
1531 } while (GetPixel(StartPos
) != TRANSPARENT_COLOR
);
1532 } while (!CreateLightning(StartPos
, Direction
, NO_LIMIT
, Color
));
1537 struct pixelvectorcontroller
{
1538 static truth
Handler (int x
, int y
) {
1539 if (CurrentSprite
->GetPixel(x
, y
) == TRANSPARENT_COLOR
) {
1540 PixelVector
.push_back(v2(x
, y
));
1545 static std::vector
<v2
> PixelVector
;
1546 static bitmap
*CurrentSprite
;
1550 std::vector
<v2
> pixelvectorcontroller::PixelVector
;
1551 bitmap
*pixelvectorcontroller::CurrentSprite
;
1554 truth
bitmap::CreateLightning (v2 StartPos
, v2 Direction
, int MaxLength
, col16 Color
) {
1555 pixelvectorcontroller::CurrentSprite
= this;
1556 std::vector
<v2
> &PixelVector
= pixelvectorcontroller::PixelVector
;
1557 PixelVector
.clear();
1561 v2
Move(1 + (RAND() & 3), 1 + (RAND() & 3));
1562 if (Direction
.X
< 0 || (!Direction
.X
&& RAND() & 1)) Move
.X
= -Move
.X
;
1563 if (Direction
.Y
< 0 || (!Direction
.Y
&& RAND() & 1)) Move
.Y
= -Move
.Y
;
1564 LimitRef(Move
.X
, -StartPos
.X
, mSize
.X
- StartPos
.X
- 1);
1565 LimitRef(Move
.Y
, -StartPos
.Y
, mSize
.X
- StartPos
.Y
- 1);
1566 if (Counter
< 10 && ((!Move
.Y
&& !LastMove
.Y
) || (Move
.Y
&& LastMove
.Y
&& (Move
.X
<< 10) / Move
.Y
== (LastMove
.X
<< 10) / LastMove
.Y
))) {
1571 if (!mapmath
<pixelvectorcontroller
>::DoLine(StartPos
.X
, StartPos
.Y
, StartPos
.X
+ Move
.X
, StartPos
.Y
+ Move
.Y
, LINE_BOTH_DIRS
) || feuLong(MaxLength
) <= PixelVector
.size()) {
1572 int Limit
= Min
<int>(PixelVector
.size(), MaxLength
);
1573 for (int c
= 0; c
< Limit
; ++c
) {
1574 PutPixel(PixelVector
[c
], Color
);
1575 SafeSetPriority(PixelVector
[c
], LIGHTNING_PRIORITY
);
1577 PixelVector
.clear();
1582 if ((Direction
.X
&& (!StartPos
.X
|| StartPos
.X
== mSize
.X
- 1)) || (Direction
.Y
&& (!StartPos
.Y
|| StartPos
.Y
== mSize
.X
- 1))) {
1583 PixelVector
.clear();
1590 void bitmap::BlitAndCopyAlpha (bitmap
*Bitmap
, int Flags
) const {
1592 if (!AlphaMap
|| !Bitmap
->AlphaMap
) ABORT("Attempt to blit and copy alpha without an alpha map detected!");
1593 if ((Flags
&ROTATE
) && mSize
.X
!= mSize
.Y
) ABORT("Blit and copy alpha error: FeLib supports only square rotating!");
1594 if (mSize
.X
!= Bitmap
->mSize
.X
|| mSize
.Y
!= Bitmap
->mSize
.Y
) ABORT("Blit and copy alpha attempt of noncongruent bitmaps detected!");
1596 packcol16
**SrcImage
= Image
;
1597 packalpha
**SrcAlphaMap
= AlphaMap
;
1598 packcol16
**DestImage
= Bitmap
->Image
;
1599 packalpha
**DestAlphaMap
= Bitmap
->AlphaMap
;
1602 memmove(DestImage
[0], SrcImage
[0], XSizeTimesYSize
* sizeof(packcol16
));
1603 memmove(DestAlphaMap
[0], SrcAlphaMap
[0], XSizeTimesYSize
* sizeof(packalpha
));
1606 int Width
= mSize
.X
;
1607 int Height
= mSize
.Y
;
1608 int DestX
= Width
- 1;
1609 cpackcol16
*SrcPtr
= SrcImage
[0];
1610 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1611 for (int y
= 0; y
< Height
; ++y
) {
1612 cpackcol16
*EndPtr
= SrcPtr
+ Width
;
1613 packcol16
*DestPtr
= &DestImage
[y
][DestX
];
1614 packalpha
*DestAlphaPtr
= &DestAlphaMap
[y
][DestX
];
1615 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
, ++SrcAlphaPtr
, --DestAlphaPtr
) {
1617 *DestAlphaPtr
= *SrcAlphaPtr
;
1622 int Height
= mSize
.Y
;
1623 int Width
= mSize
.X
;
1624 int DestY
= Height
- 1;
1625 for (int y
= 0; y
< Height
; ++y
) {
1626 memmove(DestImage
[DestY
- y
], SrcImage
[y
], Width
* sizeof(packcol16
));
1627 memmove(DestAlphaMap
[DestY
- y
], SrcAlphaMap
[y
], Width
* sizeof(packalpha
));
1630 case (MIRROR
| FLIP
): {
1631 cpackcol16
*SrcPtr
= SrcImage
[0];
1632 cpackcol16
*EndPtr
= SrcPtr
+ XSizeTimesYSize
;
1633 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1634 packcol16
*DestPtr
= &DestImage
[mSize
.Y
- 1][mSize
.X
- 1];
1635 packalpha
*DestAlphaPtr
= &DestAlphaMap
[mSize
.Y
- 1][mSize
.X
- 1];
1636 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, --DestPtr
, ++SrcAlphaPtr
, --DestAlphaPtr
) {
1638 *DestAlphaPtr
= *SrcAlphaPtr
;
1642 cint Width
= mSize
.X
;
1643 cpackcol16
*SrcPtr
= SrcImage
[0];
1644 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1645 packcol16
*DestBase
= &DestImage
[0][Width
- 1];
1646 packalpha
*DestAlphaBase
= &DestAlphaMap
[0][Width
- 1];
1647 for (int y
= 0; y
< Width
; ++y
) {
1648 cpackcol16
*EndPtr
= SrcPtr
+ Width
;
1649 packcol16
*DestPtr
= DestBase
- y
;
1650 packalpha
*DestAlphaPtr
= DestAlphaBase
- y
;
1651 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= Width
, ++SrcAlphaPtr
, DestAlphaPtr
+= Width
) {
1653 *DestAlphaPtr
= *SrcAlphaPtr
;
1657 case (MIRROR
| ROTATE
): {
1658 cint Width
= mSize
.X
;
1659 cpackcol16
*SrcPtr
= SrcImage
[0];
1660 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1661 packcol16
*DestBase
= DestImage
[0];
1662 packalpha
*DestAlphaBase
= DestAlphaMap
[0];
1663 for (int y
= 0; y
< Width
; ++y
) {
1664 cpackcol16
*EndPtr
= SrcPtr
+ Width
;
1665 packcol16
*DestPtr
= DestBase
+ y
;
1666 packalpha
*DestAlphaPtr
= DestAlphaBase
+ y
;
1667 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
+= Width
, ++SrcAlphaPtr
, DestAlphaPtr
+= Width
) {
1669 *DestAlphaPtr
= *SrcAlphaPtr
;
1673 case (FLIP
| ROTATE
): {
1674 cint Width
= mSize
.X
;
1675 cpackcol16
*SrcPtr
= SrcImage
[0];
1676 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1677 packcol16
*DestBase
= &DestImage
[Width
- 1][Width
- 1];
1678 packalpha
*DestAlphaBase
= &DestAlphaMap
[Width
- 1][Width
- 1];
1679 for (int y
= 0; y
< Width
; ++y
) {
1680 cpackcol16
*EndPtr
= SrcPtr
+ Width
;
1681 packcol16
*DestPtr
= DestBase
- y
;
1682 packalpha
*DestAlphaPtr
= DestAlphaBase
- y
;
1683 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= Width
, ++SrcAlphaPtr
, DestAlphaPtr
-= Width
) {
1685 *DestAlphaPtr
= *SrcAlphaPtr
;
1689 case (MIRROR
| FLIP
| ROTATE
): {
1690 cint Width
= mSize
.X
;
1691 cpackcol16
*SrcPtr
= SrcImage
[0];
1692 cpackalpha
*SrcAlphaPtr
= SrcAlphaMap
[0];
1693 packcol16
*DestBase
= DestImage
[Width
- 1];
1694 packalpha
*DestAlphaBase
= DestAlphaMap
[Width
- 1];
1695 for (int y
= 0; y
< Width
; ++y
) {
1696 cpackcol16
*EndPtr
= SrcPtr
+ Width
;
1697 packcol16
*DestPtr
= DestBase
+ y
;
1698 packalpha
*DestAlphaPtr
= DestAlphaBase
+ y
;
1699 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, DestPtr
-= Width
, ++SrcAlphaPtr
, DestAlphaPtr
-= Width
) {
1701 *DestAlphaPtr
= *SrcAlphaPtr
;
1709 void bitmap::FillAlpha (alpha Alpha
) {
1710 memset(AlphaMap
[0], Alpha
, XSizeTimesYSize
);
1714 void bitmap::PowerPutPixel (int X
, int Y
, col16 Color
, alpha Alpha
, priority Priority
) {
1715 if (X
>= 0 && Y
>= 0 && X
< mSize
.X
&& Y
< mSize
.Y
) {
1716 Image
[Y
][X
] = Color
;
1718 AlphaMap
[Y
][X
] = Alpha
;
1719 } else if (Alpha
!= 255) {
1720 CreateAlphaMap(255);
1721 AlphaMap
[Y
][X
] = Alpha
;
1723 if (PriorityMap
) PriorityMap
[Y
][X
] = Priority
;
1728 void bitmap::MaskedPriorityBlit (cblitdata
&BlitData
) const {
1729 if (!PriorityMap
|| !BlitData
.Bitmap
->PriorityMap
) {
1730 LuminanceMaskedBlit(BlitData
);
1733 blitdata B
= BlitData
;
1735 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap masked priority blit attempt detected!");
1736 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1738 packcol16
**SrcImage
= Image
;
1739 packpriority
**SrcPriorityMap
= PriorityMap
;
1740 packcol16
**DestImage
= B
.Bitmap
->Image
;
1741 packpriority
**DestPriorityMap
= B
.Bitmap
->PriorityMap
;
1742 int NewRedLuminance
= (B
.Luminance
>> 7 & 0x1F800) - 0x10000;
1743 int NewGreenLuminance
= (B
.Luminance
>> 4 & 0xFE0) - 0x800;
1744 int NewBlueLuminance
= (B
.Luminance
>> 2 & 0x3F) - 0x20;
1746 if (B
.Dest
.X
< 0) B
.Dest
.X
= 0; //FIXME: k8: ???
1748 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
1749 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
1750 cpackpriority
*SrcPriorityPtr
= &SrcPriorityMap
[B
.Src
.Y
+ y
][B
.Src
.X
];
1751 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
1752 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1753 packpriority
*DestPriorityPtr
= &DestPriorityMap
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1754 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
, ++SrcPriorityPtr
, ++DestPriorityPtr
) {
1756 if (SrcCol
!= B
.MaskColor
) {
1757 priority SrcPriority
= *SrcPriorityPtr
;
1758 priority DestPriority
= *DestPriorityPtr
;
1759 if ((SrcPriority
& 0xF) >= (DestPriority
& 0xF) || (SrcPriority
& 0xF0) >= (DestPriority
& 0xF0)) {
1761 NEW_LUMINATE_GREEN();
1762 NEW_LUMINATE_BLUE();
1764 *DestPriorityPtr
= SrcPriority
;
1772 void bitmap::AlphaPriorityBlit (cblitdata
&BlitData
) const {
1774 MaskedPriorityBlit(BlitData
);
1777 if (!PriorityMap
|| !BlitData
.Bitmap
->PriorityMap
) {
1778 AlphaLuminanceBlit(BlitData
);
1781 blitdata B
= BlitData
;
1783 if (!B
.Border
.X
|| !B
.Border
.Y
) ABORT("Zero-sized bitmap alpha priority blit attempt detected!");
1784 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1787 if (!femath::Clip(B
.Src
.X
, B
.Src
.Y
, B
.Dest
.X
, B
.Dest
.Y
, B
.Border
.X
, B
.Border
.Y
, mSize
.X
, mSize
.Y
, B
.Bitmap
->mSize
.X
, B
.Bitmap
->mSize
.Y
)) return;
1789 packcol16
**SrcImage
= Image
;
1790 packalpha
**SrcAlphaMap
= AlphaMap
;
1791 packpriority
**SrcPriorityMap
= PriorityMap
;
1792 packcol16
**DestImage
= B
.Bitmap
->Image
;
1793 packpriority
**DestPriorityMap
= B
.Bitmap
->PriorityMap
;
1794 int NewRedLuminance
= (B
.Luminance
>> 7 & 0x1F800) - 0x10000;
1795 int NewGreenLuminance
= (B
.Luminance
>> 4 & 0xFE0) - 0x800;
1796 int NewBlueLuminance
= (B
.Luminance
>> 2 & 0x3F) - 0x20;
1797 for (int y
= 0; y
< B
.Border
.Y
; ++y
) {
1798 cpackcol16
*SrcPtr
= &SrcImage
[B
.Src
.Y
+ y
][B
.Src
.X
];
1799 cpackalpha
*AlphaPtr
= &SrcAlphaMap
[B
.Src
.Y
+ y
][B
.Src
.X
];
1800 cpackpriority
*SrcPriorityPtr
= &SrcPriorityMap
[B
.Src
.Y
+ y
][B
.Src
.X
];
1801 cpackcol16
*EndPtr
= SrcPtr
+ B
.Border
.X
;
1802 packcol16
*DestPtr
= &DestImage
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1803 packpriority
*DestPriorityPtr
= &DestPriorityMap
[B
.Dest
.Y
+ y
][B
.Dest
.X
];
1804 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++DestPtr
, ++AlphaPtr
, ++SrcPriorityPtr
, ++DestPriorityPtr
) {
1806 if (SrcCol
!= B
.MaskColor
) {
1807 priority SrcPriority
= *SrcPriorityPtr
;
1808 priority DestPriority
= *DestPriorityPtr
;
1809 if ((SrcPriority
& 0xF) >= (DestPriority
& 0xF) || (SrcPriority
& 0xF0) >= (DestPriority
& 0xF0)) {
1813 NEW_APPLY_ALPHA_RED();
1814 NEW_LUMINATE_GREEN();
1815 NEW_APPLY_ALPHA_GREEN();
1816 NEW_LUMINATE_BLUE();
1817 NEW_APPLY_ALPHA_BLUE();
1819 *DestPriorityPtr
= SrcPriority
;
1827 void bitmap::InitPriorityMap (priority InitialValue
) {
1828 if (!PriorityMap
) Alloc2D(PriorityMap
, mSize
.Y
, mSize
.X
);
1829 memset(PriorityMap
[0], InitialValue
, XSizeTimesYSize
);
1833 void bitmap::FillPriority (priority Priority
) {
1834 memset(PriorityMap
[0], Priority
, XSizeTimesYSize
);
1838 void bitmap::FastBlitAndCopyAlpha (bitmap
*Bitmap
) const {
1840 if (!AlphaMap
|| !Bitmap
->AlphaMap
) ABORT("Attempt to fast blit and copy alpha without an alpha map detected!");
1841 if (mSize
.X
!= Bitmap
->mSize
.X
|| mSize
.Y
!= Bitmap
->mSize
.Y
) ABORT("Fast blit and copy alpha attempt of noncongruent bitmaps detected!");
1843 memmove(Bitmap
->Image
[0], Image
[0], XSizeTimesYSize
* sizeof(packcol16
));
1844 memmove(Bitmap
->AlphaMap
[0], AlphaMap
[0], XSizeTimesYSize
* sizeof(packalpha
));
1848 void bitmap::UpdateRandMap (sLong Index
, truth Value
) {
1849 sLong c1
= XSizeTimesYSize
+ Index
;
1850 RandMap
[c1
] = Value
;
1851 for (sLong c2
= c1
>> 1; c2
; c1
= c2
, c2
>>= 1) {
1852 Value
|= RandMap
[c1
^ 1];
1853 if (!RandMap
[c2
] != !Value
) RandMap
[c2
] = Value
; else return;
1858 void bitmap::InitRandMap () {
1859 if (!RandMap
) RandMap
= new truth
[XSizeTimesYSize
<< 1];
1860 memset(RandMap
, 0, (XSizeTimesYSize
<< 1) * sizeof(truth
));
1864 v2
bitmap::RandomizePixel () const {
1865 if (!RandMap
[1]) return ERROR_V2
;
1866 sLong Rand
= RAND();
1867 feuLong c
, RandMask
= 1;
1868 feuLong MapSize
= XSizeTimesYSize
<< 1;
1869 for (c
= 2; c
< MapSize
; c
<<= 1) if (RandMap
[c
+ 1] && (!RandMap
[c
] || Rand
& (RandMask
<<= 1))) ++c
;
1870 c
= (c
- MapSize
) >> 1;
1871 return v2(c
% mSize
.X
, c
/ mSize
.X
);
1875 void bitmap::CalculateRandMap () {
1876 if (!AlphaMap
) ABORT("Alpha map needed to calculate random map.");
1877 feuLong Size
= XSizeTimesYSize
;
1878 for (feuLong c
= 0; c
< Size
; ++c
) UpdateRandMap(c
, AlphaMap
[0][c
]);
1882 void bitmap::AlphaPutPixel (int x
, int y
, col16 SrcCol
, col24 Luminance
, alpha Alpha
) {
1883 if (x
< 0 || y
< 0 || x
>= mSize
.X
|| y
>= mSize
.Y
) return;
1884 int DestCol
= Image
[y
][x
];
1885 int NewRedLuminance
= (Luminance
>> 7 & 0x1F800) - 0x10000;
1886 int NewGreenLuminance
= (Luminance
>> 4 & 0xFE0) - 0x800;
1887 int NewBlueLuminance
= (Luminance
>> 2 & 0x3F) - 0x20;
1889 NEW_APPLY_ALPHA_RED();
1890 NEW_LUMINATE_GREEN();
1891 NEW_APPLY_ALPHA_GREEN();
1892 NEW_LUMINATE_BLUE();
1893 NEW_APPLY_ALPHA_BLUE();
1894 Image
[y
][x
] = Red
|Green
|Blue
;
1898 alpha
bitmap::CalculateAlphaAverage () const {
1899 if (!AlphaMap
) ABORT("Alpha map needed to calculate alpha average!");
1902 feuLong Size
= XSizeTimesYSize
;
1903 for (feuLong c
= 0; c
< Size
; ++c
) {
1904 packalpha
*AlphaPtr
= &AlphaMap
[0][c
];
1906 AlphaSum
+= *AlphaPtr
;
1910 return Alphas
? AlphaSum
/ Alphas
: 0;
1914 cachedfont::cachedfont (v2 aSize
) : bitmap(aSize
) {
1915 Alloc2D(MaskMap
, mSize
.Y
, mSize
.X
);
1919 cachedfont::cachedfont (v2 aSize
, col16 Color
) : bitmap(aSize
, Color
) {
1920 Alloc2D(MaskMap
, mSize
.Y
, mSize
.X
);
1924 void cachedfont::PrintCharacter (cblitdata B
) const {
1925 if (B
.Dest
.X
< 0 || B
.Dest
.Y
< 0 || B
.Dest
.X
+10 >= B
.Bitmap
->mSize
.X
|| B
.Dest
.Y
+9 >= B
.Bitmap
->mSize
.Y
) {
1926 NormalMaskedBlit(B
);
1929 packcol16
**SrcLine
= &Image
[B
.Src
.Y
];
1930 packcol16
**EndLine
= SrcLine
+9;
1931 packcol16
**SrcMaskLine
= &MaskMap
[B
.Src
.Y
];
1932 packcol16
**DestLine
= &B
.Bitmap
->Image
[B
.Dest
.Y
];
1933 for (; SrcLine
!= EndLine
; ++SrcLine
, ++SrcMaskLine
, ++DestLine
) {
1934 culong
*FontPtr
= reinterpret_cast<culong
*>(*SrcLine
+ B
.Src
.X
);
1935 culong
*EndPtr
= FontPtr
+5;
1936 culong
*MaskPtr
= reinterpret_cast<culong
*>(*SrcMaskLine
+ B
.Src
.X
);
1937 feuLong
*DestPtr
= reinterpret_cast<feuLong
*>(*DestLine
+ B
.Dest
.X
);
1938 for (; FontPtr
!= EndPtr
; ++DestPtr
, ++MaskPtr
, ++FontPtr
) *DestPtr
= (*DestPtr
& *MaskPtr
) | *FontPtr
;
1943 void cachedfont::CreateMaskMap () {
1944 packcol16
*SrcPtr
= Image
[0];
1945 packcol16
*EndPtr
= SrcPtr
+XSizeTimesYSize
;
1946 packcol16
*MaskPtr
= MaskMap
[0];
1947 for (; SrcPtr
!= EndPtr
; ++SrcPtr
, ++MaskPtr
) {
1948 if (*SrcPtr
== TRANSPARENT_COLOR
) {
1958 static const cint WaveDelta
[] = { 1, 2, 2, 2, 1, 0, -1, -2, -2, -2, -1 };
1960 void bitmap::Wobble (int Frame
, int SpeedShift
, truth Horizontally
) {
1961 int WavePos
= (Frame
<< SpeedShift
>> 1) - 14;
1963 for (int c
= 0; c
< 11; ++c
) if (WavePos
+ c
>= 0 && WavePos
+ c
< mSize
.Y
) MoveLineHorizontally(WavePos
+ c
, WaveDelta
[c
]);
1965 for (int c
= 0; c
< 11; ++c
) if (WavePos
+ c
>= 0 && WavePos
+ c
< mSize
.X
) MoveLineVertically(WavePos
+ c
, WaveDelta
[c
]);
1970 void bitmap::MoveLineVertically (int X
, int Delta
) {
1973 for (y
= 0; y
< mSize
.Y
+ Delta
; ++y
)
1974 PowerPutPixel(X
, y
, GetPixel(X
, y
- Delta
), AlphaMap
? GetAlpha(X
, y
- Delta
) : 255, AVERAGE_PRIORITY
);
1975 for (int y
= -1; y
>= Delta
; --y
)
1976 PowerPutPixel(X
, mSize
.Y
+ y
, TRANSPARENT_COLOR
, 255, AVERAGE_PRIORITY
);
1977 } else if (Delta
> 0) {
1978 for (y
= mSize
.Y
- 1; y
>= Delta
; --y
)
1979 PowerPutPixel(X
, y
, GetPixel(X
, y
- Delta
), AlphaMap
? GetAlpha(X
, y
- Delta
) : 255, AVERAGE_PRIORITY
);
1980 for (y
= 0; y
< Delta
; ++y
)
1981 PowerPutPixel(X
, y
, TRANSPARENT_COLOR
, 255, AVERAGE_PRIORITY
);
1986 void bitmap::MoveLineHorizontally (int Y
, int Delta
) {
1989 for (x
= 0; x
< mSize
.X
+ Delta
; ++x
)
1990 PowerPutPixel(x
, Y
, GetPixel(x
- Delta
, Y
), AlphaMap
? GetAlpha(x
- Delta
, Y
) : 255, AVERAGE_PRIORITY
);
1991 for (x
= -1; x
>= Delta
; --x
)
1992 PowerPutPixel(mSize
.X
+ x
, Y
, TRANSPARENT_COLOR
, 255, AVERAGE_PRIORITY
);
1993 } else if (Delta
> 0) {
1994 for (x
= mSize
.X
- 1; x
>= Delta
; --x
)
1995 PowerPutPixel(x
, Y
, GetPixel(x
- Delta
, Y
), AlphaMap
? GetAlpha(x
- Delta
, Y
) : 255, AVERAGE_PRIORITY
);
1996 for (x
= 0; x
< Delta
; ++x
)
1997 PowerPutPixel(x
, Y
, TRANSPARENT_COLOR
, 255, AVERAGE_PRIORITY
);
2002 void bitmap::InterLace () {
2003 for (int y
= 0; y
< mSize
.Y
; ++y
) {
2004 if (!(y
% 3)) for (int x
= 0; x
< mSize
.X
; ++x
) if (Image
[y
][x
] != 0) Image
[y
][x
] = 1;