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