044f43c734bd7485148f5bd68109f2f4eb10e81b
[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   int bmWidth;
81   int bmHeight;
82   unsigned char bmPlanes;
83   unsigned char bmBitsPixel;
84   unsigned char m1,m2;
85   unsigned long sizeimage;
86   short res1,res2;
87   long filesize, pixoff;
88   long bmisize, compression;
89   long xscale, yscale;
90   long colors, impcol;
91   unsigned long m_bytesRead = 0;
92   unsigned char *image;
93   FILE *fp;
94
95   fp = fopen (gbmp.name, "rb");
96   if (fp == NULL)
97     return NULL;
98
99   long rc;
100   rc = fread(&m1, 1, 1, fp);
101   m_bytesRead++;
102   if (rc == -1)
103   {
104     fclose(fp);
105     return NULL;
106   }
107
108   rc = fread(&m2, 1, 1, fp);
109   m_bytesRead++;
110   if ((m1 != 'B') || (m2 != 'M'))
111   {
112     fclose(fp);
113     return NULL;
114   }
115
116   rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4;
117   if (rc != 1) { fclose(fp); return NULL; }
118
119   rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2;
120   if (rc != 1) { fclose(fp); return NULL; }
121
122   rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2;
123   if (rc != 1) { fclose(fp); return NULL; }
124
125   rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4;
126   if (rc != 1) { fclose(fp); return NULL; }
127
128   rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4;
129   if (rc != 1) { fclose(fp); return NULL; }
130
131   rc = fread((long  *)&(bmWidth),4,1,fp); m_bytesRead+=4;
132   if (rc != 1) { fclose(fp); return NULL; }
133
134   rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4;
135   if (rc != 1) { fclose(fp); return NULL; }
136
137   rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2;
138   if (rc != 1) { fclose(fp); return NULL; }
139
140   rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2;
141   if (rc != 1) { fclose(fp); return NULL; }
142
143   rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4;
144   if (rc != 1) { fclose(fp); return NULL; }
145
146   rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4;
147   if (rc != 1) {fclose(fp); return NULL; }
148
149   rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4;
150   if (rc != 1) { fclose(fp); return NULL; }
151
152   rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4;
153   if (rc != 1) { fclose(fp); return NULL; }
154
155   rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4;
156   if (rc != 1) { fclose(fp); return NULL; }
157
158   rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4;
159   if (rc != 1) { fclose(fp); return NULL; }
160
161   if (bmBitsPixel != 8)
162   {
163     g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.",
164                                  "Bitmap", eMB_OK, eMB_ICONWARNING);
165     fclose(fp);
166     return NULL; 
167   }
168
169   if (colors == 0)
170     colors = 1 << bmBitsPixel;
171
172   if (bmBitsPixel != 24)
173   {
174     int i;
175     for (i = 0; i < colors; i++)
176     {
177       unsigned char r ,g, b, dummy;
178
179       rc = fread(&b, 1, 1, fp);
180       m_bytesRead++;
181       if (rc!=1)
182       {
183         fclose(fp);
184         return NULL;
185       }
186
187       rc = fread(&g, 1, 1, fp); 
188       m_bytesRead++;
189       if (rc!=1)
190       {
191         fclose(fp);
192         return NULL;
193       }
194
195       rc = fread(&r, 1, 1, fp); 
196       m_bytesRead++;
197       if (rc != 1)
198       {
199         fclose(fp);
200         return NULL;
201       }
202
203       rc = fread(&dummy, 1, 1, fp); 
204       m_bytesRead++;
205       if (rc != 1)
206       {
207         fclose(fp);
208         return NULL;
209       }
210     }
211   }
212
213   if ((long)m_bytesRead > pixoff)
214   {
215     fclose(fp);
216     return NULL;
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     gbmp.width = w;
235     gbmp.height = h;
236     unsigned char* outbuf = image;
237     long row = 0;
238     long rowOffset = 0;
239
240     if (compression == 0) // BI_RGB
241     {
242       for (row = 0; row < bmHeight; row++)
243       {
244         // which row are we working on?
245         rowOffset = (long unsigned)row*w;                                                     
246
247         {
248           // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
249           int bit_count = 0;
250           unsigned long mask = (1 << bmBitsPixel) - 1;
251           unsigned char inbyte = 0;
252
253           for (int col=0;col<w;col++)
254           {
255             int pix = 0;
256
257             // if we need another byte
258             if (bit_count <= 0)
259             {
260               bit_count = 8;
261               if (fread(&inbyte,1,1,fp) != 1)
262               {
263                 free(image);
264                 fclose(fp);
265                 return NULL;
266               }
267               m_bytesRead++;
268             }
269
270             // keep track of where we are in the bytes
271             bit_count -= bmBitsPixel;
272             pix = ( inbyte >> bit_count) & mask;
273
274             // lookup the color from the colormap - stuff it in our buffer
275             // swap red and blue
276             *(outbuf + rowOffset + col) = pix;
277           }
278
279           // read DWORD padding
280           while ((m_bytesRead-pixoff)&3)
281           {
282             char dummy;
283             if (fread(&dummy,1,1,fp)!=1)
284             {
285               free(image);
286               fclose(fp);
287               return NULL;
288             }
289             m_bytesRead++;
290           }
291         }
292       }
293     }
294     else    // compression != 0
295     {
296       int i, x = 0;
297       unsigned char c, c1 = 0, *pp;
298       row = 0;
299       pp = outbuf;
300
301       if (bmBitsPixel == 8)
302       {
303         while (row < bmHeight)
304         {
305           c = getc(fp);
306
307           if (c)
308           {
309             // encoded mode
310             c1 = getc(fp);
311             for (i = 0; i < c; x++, i++)
312             {
313               *pp = c1; pp++;
314             }
315           }
316           else
317           {
318             // c==0x00,  escape codes
319             c = getc(fp);
320
321             if (c == 0x00) // end of line
322             {
323               row++;
324               x = 0;
325               pp = outbuf + row*bmWidth;
326             }
327             else if (c == 0x01)
328               break; // end of pic
329             else if (c == 0x02) // delta
330             {
331               c = getc(fp);
332               x += c;
333               c = getc(fp);
334               row += c;
335               pp = outbuf + x + row*bmWidth;
336             }
337             else // absolute mode
338             {
339               for (i = 0; i < c; x++, i++)
340               {
341                 c1 = getc(fp);
342                 *pp = c1; pp++;
343               }
344
345               if (c & 1)
346                 getc(fp); // odd length run: read an extra pad byte
347             }
348           }
349         }
350       }
351       else if (bmBitsPixel == 4)
352       {
353         while (row < bmHeight)
354         {
355           c = getc(fp);
356
357           if (c)
358           {
359             // encoded mode
360             c1 = getc(fp);
361             for (i = 0; i < c; x++, i++)
362             {
363               *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++;
364             }
365           }
366           else
367           {
368             // c==0x00,  escape codes
369             c = getc(fp);
370
371             if (c == 0x00) // end of line
372             {
373               row++;
374               x = 0;
375               pp = outbuf + bmHeight*bmWidth;
376             }
377             else if (c == 0x01)
378               break; // end of pic
379             else if (c == 0x02) // delta
380             {
381               c = getc(fp);
382               x += c;
383               c = getc(fp);
384               row += c;
385               pp = outbuf + x + row*bmWidth;
386             }
387             else // absolute mode
388             {
389               for (i = 0; i < c; x++, i++)
390               {
391                 if ((i&1) == 0)
392                   c1 = getc(fp);
393                 *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++;
394               }
395
396               if (((c&3) == 1) || ((c&3) == 2))
397                 getc(fp); // odd length run: read an extra pad byte
398             }
399           }
400         }
401       }
402     }
403   }
404   fclose(fp);
405   return image;
406 }
407
408 bool OpenBitmap ()
409 {
410   if (gbmp.colors)
411     free (gbmp.colors);
412
413   gbmp.colors = OpenBitmapFile ();
414
415   if (!gbmp.colors)
416   {
417     char Text[256];
418
419     sprintf (Text, "Error opening %s", gbmp.name);
420     g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", eMB_OK, eMB_ICONWARNING);
421     strcpy (gbmp.name, "");
422   }
423
424   if (g_pWnd)
425   {
426     gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name);
427     gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")),
428                               strlen (gbmp.name) ? TRUE : FALSE);
429
430     UpdatePreview (true);
431   }
432
433   return (gbmp.colors != NULL);
434 }