5e267682a705182ce39abd6071a6215228057452
[rocksndiamonds.git] / src / game_sp / BitMapObject.c
1 // ----------------------------------------------------------------------------
2 // BitMapObject.c
3 // ----------------------------------------------------------------------------
4
5 #include "BitMapObject.h"
6
7 // static void ConvertToVBPalette();
8 static long Get_ByteWidth();
9 static long Get_LineLength();
10 static void ReDimArrays();
11
12 // --- VERSION 1.0 CLASS
13 // --- BEGIN
14 // ---   MultiUse = -1  'True  // True
15 // ---   Persistable = 0  'NotPersistable  // NotPersistable
16 // ---   DataBindingBehavior = 0  'vbNone  // vbNone
17 // ---   DataSourceBehavior  = 0  'vbNone  // vbNone
18 // ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
19 // --- END
20
21 // static char *VB_Name = "BitMapObject";
22 // static boolean VB_GlobalNameSpace = False;
23 // static boolean VB_Creatable = True;
24 // static boolean VB_PredeclaredId = False;
25 // static boolean VB_Exposed = False;
26
27 // --- Option Explicit
28
29 // info von http://web.usxchange.net/elmo/bmp.htm
30
31 // A BMP file consists of the four following parts:
32 //
33 //   1.BITMAPFILEHEADER
34 //   2.BITMAPINFOHEADER
35 //   3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
36 //   4.An array of bytes for the actual image data
37
38 // 1.BITMAPFILEHEADER
39 //        1.bfType
40 //               Declared an unsigned integer. But, this is just to reserve space for 2 bytes.
41 //               The 2 bytes must be the 2 characters BM to indicate a BitMap file.
42 //        2.bfSize
43 //               Total size of file in bytes.
44 //        3.bfReserved1
45 //               Always zero (ignore).
46 //        4.bfReserved2
47 //               Always zero (ignore).
48 //        5.bfOffBits
49 //               Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
50 // ::: #ifndef HAS_BitmapFileHeaderType
51 // ::: typedef struct // {    /* bmfh */
52 // ::: {
53 // :::   byte bfTypeB;
54 // :::   byte bfTypeM;
55 // :::   long bfSize;
56 // :::   int bfReserved1;
57 // :::   int bfReserved2;
58 // :::   long bfOffBits;
59 // ::: } BitmapFileHeaderType;
60 // ::: #define HAS_BitmapFileHeaderType
61 // ::: #endif
62
63 //   2.BITMAPINFOHEADER
64 //        1.biSize
65 //               Size of BITMAPINFOHEADER structure (should always be 40).
66 //        2.biWidth
67 //               Width of image in pixels.
68 //        3.biHeight
69 //               Height of image in pixels.
70 //        4.biPlanes
71 //               Always one (ignore).
72 //        5.biBitCount
73 //               Specifies the number of bits per pixel. This value must be 1, 4, 8, or 24.
74 //        6.biCompression
75 //               Specifies the type of compression.
76 //                  1.BI_RGB No compression.
77 //                  2.BI_RLE8 8 bit RLE
78 //                  3.BI_RLE4 4 bit RLE
79 //        7.biSizeImage
80 //               Specifies the size, in bytes, of the image data. May be zero if the bitmap is in the BI_RGB format.
81 //        8.biXPelsPerMeter
82 //               Ignore.
83 //        9.biYPelsPerMeter
84 //               Ignore.
85 //       10.biClrUsed
86 //               Specifies the number of color indices in the color table. Zero indicaes the bitmap uses the maximum number of colors corresponding to the value of the
87 //               biBitCount member e.g. 8 bit -> 256 colors.
88 //
89 //               The maximum number of colors = 2N. Where N = biBitCount. 2N is the same as 1 << N. The same as you can get powers of 10 by shifting the decimal point
90 //               in a decimal number, only it is binary.
91 //       11.biClrImportant
92 //               Ignore.
93 // ::: #ifndef HAS_BitmapInfoHeaderType
94 // ::: typedef struct // {    /* bmih */
95 // ::: {
96 // :::   long biSize;
97 // :::   long biWidth;
98 // :::   long biHeight;
99 // :::   int biPlanes;
100 // :::   int biBitCount;
101 // :::   long biCompression;
102 // :::   long biSizeImage;
103 // :::   long biXPelsPerMeter;
104 // :::   long biYPelsPerMeter;
105 // :::   long biClrUsed;
106 // :::   long biClrImportant;
107 // ::: } BitmapInfoHeaderType;
108 // ::: #define HAS_BitmapInfoHeaderType
109 // ::: #endif
110
111 //   3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
112 //          RGBQUAD structure is self explanatory.
113 // ::: #ifndef HAS_RGBQUADType
114 // ::: typedef struct // {     /* rgbq */
115 // ::: {
116 // :::   byte rgbBlue;
117 // :::   byte rgbGreen;
118 // :::   byte rgbRed;
119 // :::   byte rgbReserved;
120 // ::: } RGBQUADType;
121 // ::: #define HAS_RGBQUADType
122 // ::: #endif
123
124 RGBQUADType *ColorTable;
125 long *VBPalette;
126
127 //   4.An array of bytes for the actual image data
128 //          Bits per pixel & compression determined by biBitCount & biCompression.
129
130 byte *ImageDataBytes;
131
132 // ######################################################################################################
133
134 BitmapFileHeaderType BMFH;
135 BitmapInfoHeaderType BMIH;
136
137 static long Get_LineLength()
138 {
139   static long LineLength;
140
141   LineLength = 4 * (((Get_ByteWidth() - 1) / 4) + 1);
142
143   return LineLength;
144 }
145
146 static long Get_ByteWidth()
147 {
148   static long ByteWidth;
149
150   ByteWidth = BMIH.biWidth * BMIH.biBitCount / 8;
151
152   return ByteWidth;
153 }
154
155 void BitMapObject_CreateAtSize(long XPixels, long YPixels, long BitsPerPixel)
156 {
157   {
158     BMIH.biWidth = XPixels;
159     BMIH.biHeight = YPixels;
160     BMIH.biSize = 40;
161     BMIH.biBitCount = BitsPerPixel;
162     BMIH.biClrUsed = (1 << BMIH.biBitCount);
163     BMIH.biPlanes = 1;
164     BMIH.biClrImportant = BMIH.biClrUsed;
165     BMIH.biCompression = 0;
166   }
167   {
168     BMFH.bfTypeB = 0x42; // B'
169     BMFH.bfTypeM = 0x4D; // M'
170   }
171   ReDimArrays();
172 }
173
174 #if 0
175
176 void BitMapObject_CreateFromFile(char *Path)
177 {
178   long FNum;
179
180   FNum = FreeFile();
181   if (! FileExists(Path))
182     return;
183
184   if (FileLen(Path) < (Len(BMFH) + Len(BMIH)))
185     return;
186
187   FNum = fopen(Path, "rb");
188   FILE_GET(FNum, -1, &BMFH, sizeof(BMFH));
189   FILE_GET(FNum, -1, &BMIH, sizeof(BMIH));
190   ReDimArrays();
191   {
192     if (BMIH.biCompression != 0)
193     {
194       Err.Raise(600, "BitMapObject", "Cannot read compressed BMP files");
195       fclose(FNum);
196       return;
197     }
198
199     if (BMIH.biBitCount < 9)
200     {
201       FILE_GET(FNum, -1, &ColorTable, sizeof(ColorTable));
202     }
203
204   }
205   FILE_GET(FNum, 1 + BMFH.bfOffBits, &ImageDataBytes, sizeof(ImageDataBytes));
206   fclose(FNum);
207   if (BMIH.biBitCount < 9)
208     ConvertToVBPalette();
209 }
210
211 void BitMapObject_SaveToFile(char *Path)
212 {
213   FILE *FNum;
214
215   BMFH.bfOffBits = Len(BMFH) + Len(BMIH);
216   if (BMIH.biBitCount < 9)
217     BMFH.bfOffBits = BMFH.bfOffBits + ((1 << BMIH.biBitCount)) * Len(ColorTable[0]);
218
219   BMIH.biSizeImage = Get_LineLength() * BMIH.biHeight;
220   BMFH.bfSize = BMFH.bfOffBits + BMIH.biSizeImage;
221   // FNum = FreeFile();
222   FNum = fopen(Path, "wb");
223   FILE_PUT(FNum, -1, &BMFH, sizeof(BMFH));
224   FILE_PUT(FNum, -1, &BMIH, sizeof(BMIH));
225   if (BMIH.biBitCount < 9)
226   {
227     FILE_PUT(FNum, -1, &ColorTable, sizeof(ColorTable));
228   }
229
230   FILE_PUT(FNum, -1, &ImageDataBytes, sizeof(ImageDataBytes));
231   fclose(FNum);
232 }
233
234 static void ConvertToVBPalette()
235 {
236   long ColMax, i;
237
238   ColMax = UBound(ColorTable);
239   for (i = 0; i <= ColMax; i++)
240   {
241     {
242       VBPalette[i] = RGB(ColorTable[i].rgbRed, ColorTable[i].rgbGreen, ColorTable[i].rgbBlue);
243     }
244   }
245 }
246
247 #endif
248
249 static void ReDimArrays()
250 {
251   {
252     if (BMIH.biBitCount < 9)
253     {
254       BMIH.biClrUsed = (1 << BMIH.biBitCount);
255       ColorTable = REDIM_1D(sizeof(RGBQUADType), 0, BMIH.biClrUsed - 1);
256       VBPalette = REDIM_1D(sizeof(long), 0, BMIH.biClrUsed - 1);
257     }
258
259     if (0 < Get_LineLength() && 0 < BMIH.biHeight)
260     {
261       ImageDataBytes = REDIM_2D(sizeof(byte), 0, Get_LineLength() - 1, 0, BMIH.biHeight - 1);
262     }
263
264   }
265 }
266
267 long BitMapObject_Get_Palette(long Index)
268 {
269   long Palette;
270
271   Palette = VBPalette[Index];
272
273   return Palette;
274 }
275
276 void BitMapObject_Let_Palette(long Index, long NewVal)
277 {
278   VBPalette[Index] = NewVal & 0xFFFFFF;
279   {
280     ColorTable[Index].rgbRed = (NewVal & 0xFF) / 0x1;
281     ColorTable[Index].rgbGreen = (NewVal & 0xFF00) / 0x100;
282     ColorTable[Index].rgbBlue = (NewVal & 0xFF0000) / 0x10000;
283   }
284 }
285
286 long BitMapObject_Get_ColorsUsed()
287 {
288   long ColorsUsed;
289
290   if (BMIH.biBitCount < 9)
291   {
292     ColorsUsed = (1 << BMIH.biBitCount);
293   }
294   else
295   {
296     ColorsUsed = 0;
297   }
298
299   return ColorsUsed;
300 }
301
302 #if 0
303
304 long BitMapObject_Get_ColorIndex(long X, long Y)
305 {
306   long ColorIndex;
307
308   long ColIndex, NewX, BitPos, nY;
309
310   if (8 < BMIH.biBitCount)
311   {
312     Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
313     ColorIndex = -1;
314     return ColorIndex;
315   }
316
317   nY = BMIH.biHeight - 1 - Y;
318   switch (BMIH.biBitCount)
319   {
320     case 1:
321       ColIndex = ImageDataBytes[X / 8, nY];
322       BitPos = 7 - (X % 8);
323       NewX = (1 << BitPos);
324       if ((NewX && ColIndex) == 0)
325       {
326         ColorIndex = 0;
327       }
328       else
329       {
330         ColorIndex = 1;
331       }
332
333       break;
334
335     case 4:
336       ColIndex = ImageDataBytes[X / 2, nY];
337       if ((X % 2) == 0)
338       {
339         ColorIndex = (ColIndex & 0xF0) / 0x10;
340       }
341       else
342       {
343         ColorIndex = (ColIndex & 0xF);
344       }
345
346       break;
347
348     case 8:
349       ColorIndex = ImageDataBytes[X, nY];
350       break;
351
352     default:
353       Err.Raise(600, "BitmapObject", "Invalid bpx value");
354       break;
355   }
356
357   return ColorIndex;
358 }
359
360 void BitMapObject_Let_ColorIndex(long X, long Y, long ColorIndex)
361 {
362   long ColIndex, ByteVal, NewX, BitPos, nY;
363
364   if (8 < BMIH.biBitCount)
365   {
366     Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
367     return;
368   }
369
370   nY = BMIH.biHeight - 1 - Y;
371   switch (BMIH.biBitCount)
372   {
373     case 1:
374       ByteVal = ImageDataBytes[X / 8, nY];
375       BitPos = 7 - (X % 8);
376       NewX = (1 << BitPos);
377       ColIndex = ColorIndex * NewX;
378       if (ColIndex == 0)
379       {
380         ByteVal = (ByteVal & (! NewX));
381       }
382       else
383       {
384         ByteVal = (ByteVal | NewX);
385       }
386
387       ImageDataBytes[X / 8, nY] = ByteVal;
388       break;
389
390     case 4:
391       ByteVal = ImageDataBytes[X / 2, nY];
392       if ((X % 2) == 0)
393       {
394         ByteVal = (ByteVal & 0xF) + ColorIndex * 0x10;
395       }
396       else
397       {
398         ByteVal = (ByteVal & 0xF0) + ColorIndex;
399       }
400
401       ImageDataBytes[X / 2, nY] = ByteVal;
402       break;
403
404     case 8:
405       ImageDataBytes[X, nY] = ColorIndex;
406       break;
407
408     case 24:
409       Err.Raise(600, "BitmapObject", "Invalid bpx value");
410       break;
411   }
412 }
413
414 long BitMapObject_Get_Point(long X, long Y)
415 {
416   long Point;
417
418   long ColIndex, NewX, BitPos, nY;
419
420   nY = BMIH.biHeight - 1 - Y;
421   switch (BMIH.biBitCount)
422   {
423     case 1:
424       ColIndex = ImageDataBytes[X / 8, nY];
425       BitPos = 7 - (X % 8);
426       NewX = (1 << BitPos);
427       if ((NewX && ColIndex) == 0)
428       {
429         ColIndex = 0;
430       }
431       else
432       {
433         ColIndex = 1;
434       }
435
436       Point = VBPalette[ColIndex];
437       break;
438
439     case 4:
440       ColIndex = ImageDataBytes[X / 2, nY];
441       if ((X % 2) == 0)
442       {
443         ColIndex = (ColIndex & 0xF0) / 0x10;
444       }
445       else
446       {
447         ColIndex = (ColIndex & 0xF);
448       }
449
450       Point = VBPalette[ColIndex];
451       break;
452
453     case 8:
454       ColIndex = ImageDataBytes[X, nY];
455       Point = VBPalette[ColIndex];
456       break;
457
458     case 24:
459       NewX = 3 * X;
460       Point = ImageDataBytes[NewX, nY] * 0x10000;
461       Point = Point + ImageDataBytes[NewX + 1, nY] * 0x100;
462       Point = Point + ImageDataBytes[NewX + 2, nY];
463       break;
464
465     default:
466       Err.Raise(600, "BitmapObject", "Invalid bpx value");
467       break;
468   }
469
470   return Point;
471 }
472
473 void BitMapObject_Let_Point(long X, long Y, long NewColor)
474 {
475   long ColIndex, ByteVal, NewX, BitPos, nY;
476
477   nY = BMIH.biHeight - 1 - Y;
478   switch (BMIH.biBitCount)
479   {
480     case 1:
481       ColIndex = GetPaletteIndex(NewColor);
482       ByteVal = ImageDataBytes[X / 8][nY];
483       BitPos = 7 - (X % 8);
484       NewX = (1 << BitPos);
485       ColIndex = ColIndex * NewX;
486       if (ColIndex == 0)
487       {
488         ByteVal = (ByteVal & (! NewX));
489       }
490       else
491       {
492         ByteVal = (ByteVal | NewX);
493       }
494
495       ImageDataBytes[X / 8][nY] = ByteVal;
496       break;
497
498     case 4:
499       ColIndex = GetPaletteIndex(NewColor);
500       ByteVal = ImageDataBytes[X / 2][nY];
501       if ((X % 2) == 0)
502       {
503         ByteVal = (ByteVal & 0xF) + ColIndex * 0x10;
504       }
505       else
506       {
507         ByteVal = (ByteVal & 0xF0) + ColIndex;
508       }
509
510       ImageDataBytes[X / 2][nY] = ByteVal;
511       break;
512
513     case 8:
514       ImageDataBytes[X][nY] = GetPaletteIndex(NewColor);
515       break;
516
517     case 24:
518       NewX = 3 * X;
519       ImageDataBytes[NewX][nY] = (NewColor & 0xFF0000) / 0x10000;  // B
520       ImageDataBytes[NewX + 1][nY] = (NewColor & 0xFF00) / 0x100;  // G
521       ImageDataBytes[NewX + 2][nY] = (NewColor & 0xFF);  // R
522       break;
523
524     default:
525       Err.Raise(600, "BitmapObject", "Invalid bpx value");
526       break;
527   }
528 }
529
530 int BitMapObject_GetPaletteIndex(long Color)
531 {
532   int GetPaletteIndex;
533
534   long i, ColMax;
535
536   ColMax = UBound(VBPalette);
537   for (i = 0; i <= ColMax; i++)
538   {
539     if (VBPalette[i] == Color)
540       break;
541   }
542
543   if (ColMax < i) // Error - Color not in Palette!
544     i = -1;
545
546   GetPaletteIndex = i;
547
548   return GetPaletteIndex;
549 }
550
551 #endif
552
553 long BitMapObject_Get_Width()
554 {
555   long Width;
556
557   Width = BMIH.biWidth;
558
559   return Width;
560 }
561
562 long BitMapObject_Get_Height()
563 {
564   long Height;
565
566   Height = BMIH.biHeight;
567
568   return Height;
569 }
570
571 #if 0
572
573 BitMapObject BitMapObject_GetStretchCopy(float StretchVal)
574 {
575   BitMapObject GetStretchCopy;
576
577   long nWidth, nHeight, iX, iY;
578
579   // GetStretchCopy = New BitMapObject; // (handle this later, if needed)
580   nWidth = StretchVal * BMIH.biWidth;
581   nHeight = StretchVal * BMIH.biHeight;
582   GetStretchCopy.CreateAtSize(nWidth, nHeight, CLng(BMIH.biBitCount));
583   nWidth = nWidth - 1;
584   nHeight = nHeight - 1;
585   for (iX = 0; iX <= BMIH.biClrUsed - 1; iX++)
586   {
587     GetStretchCopy.Let_Palette(iX, Palette(iX));
588   }
589
590   for (iY = 0; iY <= nHeight; iY++)
591   {
592     for (iX = 0; iX <= nWidth; iX++)
593     {
594       GetStretchCopy.Let_ColorIndex(iX, iY, ColorIndex((int)(iX / StretchVal), (int)(iY / StretchVal)));
595     }
596   }
597
598   return GetStretchCopy;
599 }
600
601 #endif