* patch from Micah Heyer (GtkRadiant Mailinglist)
[xonotic/netradiant.git] / contrib / gtkgensurf / bitmap.cpp
1 /*
2 GenSurf plugin for GtkRadiant
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include "gensurf.h"
24
25 void GenerateBitmapMapping ()
26 {
27   double              value;
28   double              C0, C1;
29   double              x, y;
30   int                 i, j;
31   int                 O00,O01,O10,O11;
32   int                 r0, r1, c0, c1;
33   int                 color;
34   unsigned char       *colors;
35
36   if (!gbmp.colors)
37     return;
38
39   colors = gbmp.colors;
40
41   for (j=0; j<=NV; j++)
42   {
43     y  = (double)(j*(gbmp.height-1))/(double)NV;
44     r0 = (int)floor(y);
45     r1 = (int)ceil(y);
46     for (i=0; i<=NH; i++)
47     {
48       x = (double)(i*(gbmp.width-1))/(double)NH;
49       c0 = (int)floor(x);
50       c1 = (int)ceil(x);
51       O00 = r0*gbmp.width + c0;
52       O01 = r0*gbmp.width + c1;
53       O10 = r1*gbmp.width + c0;
54       O11 = r1*gbmp.width + c1;
55       C0 = (double)colors[O00] + (double)(colors[O01]-colors[O00])*(x-(double)c0);
56       C1 = (double)colors[O10] + (double)(colors[O11]-colors[O10])*(x-(double)c0);
57       color = (int)(C0 + (C1-C0)*(y-r0));
58
59       value = CalculateSnapValue(gbmp.black_value + color*((gbmp.white_value-gbmp.black_value)/255.));
60
61       switch(Plane)
62       {
63       case PLANE_XZ0:
64       case PLANE_XZ1:
65         xyz[i][j].p[1] = value;
66         break;
67       case PLANE_YZ0:
68       case PLANE_YZ1:
69         xyz[i][j].p[0] = value;
70         break;
71       default:
72         xyz[i][j].p[2] = value;
73       }
74     }
75   }
76 }
77
78 static unsigned char* OpenBitmapFile ()
79 {
80 #define INVALID_FORMAT do{\
81   fprintf(stderr,"%s:%d: Error file '%s' is malformed.\n",__FILE__,__LINE__,gbmp.name);\
82   fclose(fp);\
83   return NULL;\
84 }while(0);
85
86   int32_t bmWidth;
87   int32_t bmHeight;
88   uint16_t bmPlanes;
89   uint16_t bmBitsPixel;
90   uint8_t m1,m2;
91   uint32_t sizeimage;
92   int16_t res1,res2;
93   int32_t filesize, pixoff;
94   int32_t bmisize, compression;
95   int32_t xscale, yscale;
96   int32_t colors, impcol;
97   uint32_t m_bytesRead = 0;
98   unsigned char *image;
99   FILE *fp;
100
101   fp = fopen (gbmp.name, "rb");
102   if (fp == NULL)
103   {
104           fprintf(stderr,"Error: Invalid filename '%s'\n",gbmp.name);
105           return NULL;
106   }
107
108   long rc;
109   rc = fread(&m1, 1, 1, fp);
110   m_bytesRead++;
111   if (rc == -1)
112   {
113     fclose(fp);
114     return NULL;
115   }
116
117   rc = fread(&m2, 1, 1, fp);
118   m_bytesRead++;
119   if ((m1 != 'B') || (m2 != 'M'))
120   INVALID_FORMAT;
121
122   rc = fread((uint32_t*)&(filesize),4,1,fp); m_bytesRead+=4;
123   if (rc != 1)  INVALID_FORMAT;
124
125   rc = fread((uint16_t*)&(res1),2,1,fp); m_bytesRead+=2;
126   if (rc != 1) INVALID_FORMAT;
127
128   rc = fread((uint16_t*)&(res2),2,1,fp); m_bytesRead+=2;
129   if (rc != 1) INVALID_FORMAT;
130
131   rc = fread((uint32_t*)&(pixoff),4,1,fp); m_bytesRead+=4;
132   if (rc != 1) INVALID_FORMAT;
133
134   rc = fread((uint32_t*)&(bmisize),4,1,fp); m_bytesRead+=4;
135   if (rc != 1) INVALID_FORMAT;
136
137   rc = fread((uint32_t  *)&(bmWidth),4,1,fp); m_bytesRead+=4;
138   if (rc != 1) INVALID_FORMAT;
139
140   rc = fread((uint32_t*)&(bmHeight),4,1,fp); m_bytesRead+=4;
141   if (rc != 1) INVALID_FORMAT;
142
143   rc = fread((uint16_t*)&(bmPlanes),2,1,fp); m_bytesRead+=2;
144   if (rc != 1) INVALID_FORMAT;
145
146   rc = fread((uint16_t*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2;
147   if (rc != 1)  INVALID_FORMAT;
148
149   rc = fread((uint32_t*)&(compression),4,1,fp); m_bytesRead+=4;
150   if (rc != 1)  INVALID_FORMAT;
151
152   rc = fread((uint32_t*)&(sizeimage),4,1,fp); m_bytesRead+=4;
153   if (rc != 1)  INVALID_FORMAT;
154
155   rc = fread((uint32_t*)&(xscale),4,1,fp); m_bytesRead+=4;
156   if (rc != 1)  INVALID_FORMAT;
157
158   rc = fread((uint32_t*)&(yscale),4,1,fp); m_bytesRead+=4;
159   if (rc != 1)  INVALID_FORMAT;
160
161   rc = fread((uint32_t*)&(colors),4,1,fp); m_bytesRead+=4;
162   if (rc != 1)  INVALID_FORMAT;
163
164   rc = fread((uint32_t*)&(impcol),4,1,fp); m_bytesRead+=4;
165   if (rc != 1)  INVALID_FORMAT;
166
167   if (bmBitsPixel != 8)
168   {
169     g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.",
170                                  "Bitmap", MB_ICONEXCLAMATION, NULL);
171      INVALID_FORMAT;
172   }
173
174   if (colors == 0)
175     colors = 1 << bmBitsPixel;
176
177   if (bmBitsPixel != 24)
178   {
179     int i;
180     for (i = 0; i < colors; i++)
181     {
182       unsigned char r ,g, b, dummy;
183
184       rc = fread(&b, 1, 1, fp);
185       m_bytesRead++;
186       if (rc!=1)
187       {
188                INVALID_FORMAT;
189       }
190
191       rc = fread(&g, 1, 1, fp); 
192       m_bytesRead++;
193       if (rc!=1)
194       {
195                INVALID_FORMAT;
196       }
197
198       rc = fread(&r, 1, 1, fp); 
199       m_bytesRead++;
200       if (rc != 1)
201       {
202                INVALID_FORMAT;
203       }
204
205       rc = fread(&dummy, 1, 1, fp); 
206       m_bytesRead++;
207       if (rc != 1)
208       {
209                INVALID_FORMAT;
210       }
211     }
212   }
213
214   if ((long)m_bytesRead > pixoff)
215   {
216            INVALID_FORMAT;
217   }
218
219   while ((long)m_bytesRead < pixoff)
220   {
221     char dummy;
222     fread(&dummy,1,1,fp);
223     m_bytesRead++;
224   }
225
226   int w = bmWidth;
227   int h = bmHeight;
228
229   // set the output params
230   image = (unsigned char*)malloc(w*h);
231
232   if (image != NULL) 
233   {
234     unsigned char* outbuf = image;
235     long row = 0;
236     long rowOffset = 0;
237
238     if (compression == 0) // BI_RGB
239     {
240       for (row = 0; row < bmHeight; row++)
241       {
242         // which row are we working on?
243         rowOffset = (long unsigned)row*w;                                                     
244
245         {
246           // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
247           int bit_count = 0;
248           unsigned long mask = (1 << bmBitsPixel) - 1;
249           unsigned char inbyte = 0;
250
251           for (int col=0;col<w;col++)
252           {
253             int pix = 0;
254
255             // if we need another byte
256             if (bit_count <= 0)
257             {
258               bit_count = 8;
259               if (fread(&inbyte,1,1,fp) != 1)
260               {
261                 free(image);
262                  INVALID_FORMAT;
263               }
264               m_bytesRead++;
265             }
266
267             // keep track of where we are in the bytes
268             bit_count -= bmBitsPixel;
269             pix = ( inbyte >> bit_count) & mask;
270
271             // lookup the color from the colormap - stuff it in our buffer
272             // swap red and blue
273             *(outbuf + rowOffset + col) = pix;
274           }
275
276           // read DWORD padding
277           while ((m_bytesRead-pixoff)&3)
278           {
279             char dummy;
280             if (fread(&dummy,1,1,fp)!=1)
281             {
282               free(image);
283                INVALID_FORMAT;
284             }
285             m_bytesRead++;
286           }
287         }
288       }
289     }
290     else    // compression != 0
291     {
292       int i, x = 0;
293       unsigned char c, c1 = 0, *pp;
294       row = 0;
295       pp = outbuf;
296
297       if (bmBitsPixel == 8)
298       {
299         while (row < bmHeight)
300         {
301           c = getc(fp);
302
303           if (c)
304           {
305             // encoded mode
306             c1 = getc(fp);
307             for (i = 0; i < c; x++, i++)
308             {
309               *pp = c1; pp++;
310             }
311           }
312           else
313           {
314             // c==0x00,  escape codes
315             c = getc(fp);
316
317             if (c == 0x00) // end of line
318             {
319               row++;
320               x = 0;
321               pp = outbuf + row*bmWidth;
322             }
323             else if (c == 0x01)
324               break; // end of pic
325             else if (c == 0x02) // delta
326             {
327               c = getc(fp);
328               x += c;
329               c = getc(fp);
330               row += c;
331               pp = outbuf + x + row*bmWidth;
332             }
333             else // absolute mode
334             {
335               for (i = 0; i < c; x++, i++)
336               {
337                 c1 = getc(fp);
338                 *pp = c1; pp++;
339               }
340
341               if (c & 1)
342                 getc(fp); // odd length run: read an extra pad byte
343             }
344           }
345         }
346       }
347       else if (bmBitsPixel == 4)
348       {
349         while (row < bmHeight)
350         {
351           c = getc(fp);
352
353           if (c)
354           {
355             // encoded mode
356             c1 = getc(fp);
357             for (i = 0; i < c; x++, i++)
358             {
359               *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++;
360             }
361           }
362           else
363           {
364             // c==0x00,  escape codes
365             c = getc(fp);
366
367             if (c == 0x00) // end of line
368             {
369               row++;
370               x = 0;
371               pp = outbuf + bmHeight*bmWidth;
372             }
373             else if (c == 0x01)
374               break; // end of pic
375             else if (c == 0x02) // delta
376             {
377               c = getc(fp);
378               x += c;
379               c = getc(fp);
380               row += c;
381               pp = outbuf + x + row*bmWidth;
382             }
383             else // absolute mode
384             {
385               for (i = 0; i < c; x++, i++)
386               {
387                 if ((i&1) == 0)
388                   c1 = getc(fp);
389                 *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++;
390               }
391
392               if (((c&3) == 1) || ((c&3) == 2))
393                 getc(fp); // odd length run: read an extra pad byte
394             }
395           }
396         }
397       }
398     }
399   }
400   fclose(fp);
401
402   gbmp.width = w;
403   gbmp.height = h;
404   if(gbmp.colors)
405         free(gbmp.colors);
406   gbmp.colors = image;
407   return image;
408
409
410 }
411
412 bool OpenBitmap ()
413 {
414
415   OpenBitmapFile ();
416
417   if (!gbmp.colors)
418   {
419     g_print("failed to load file gbmp %s\n",gbmp.name);
420     char Text[256];
421
422     sprintf (Text, "Error opening %s", gbmp.name);
423     g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", MB_ICONEXCLAMATION, NULL);
424     strcpy (gbmp.name, "");
425   }
426
427   if (g_pWnd)
428   {
429     gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name);
430     gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")),
431                               strlen (gbmp.name) ? TRUE : FALSE);
432
433     UpdatePreview (true);
434   }
435
436   return (gbmp.colors != NULL);
437 }