]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/pk3man/pixmap.cpp
* added pk3man and fixed it to compile for latest radiant
[xonotic/netradiant.git] / contrib / pk3man / pixmap.cpp
1 // PixMap.cpp: implementation of the CPixMap class.
2 //
3 //////////////////////////////////////////////////////////////////////
4
5 #include "stdafx.h"
6 #include "pixmap.h"
7
8 #ifdef __linux__
9         #include <gdk/gdkx.h>
10 #else
11         #include <gdk/win32/gdkwin32.h>
12         #define NO_UNDERSCORE
13 #endif
14
15
16 //////////////////////////////////////////////////////////////////////
17 // Construction/Destruction
18 //////////////////////////////////////////////////////////////////////
19
20 CPixMap::CPixMap()
21 {
22
23 }
24
25 CPixMap::~CPixMap()
26 {
27
28 }
29
30 unsigned char* CPixMap::load_bitmap_file (const char* filename,guint16* width, guint16* height)
31 {
32   gint32 bmWidth, bmHeight;
33   guint16 bmPlanes, bmBitsPixel;
34   typedef struct {
35     unsigned char rgbBlue;
36     unsigned char rgbGreen;
37     unsigned char rgbRed;
38     unsigned char rgbReserved;
39   } RGBQUAD;
40   unsigned char m1,m2;
41   unsigned long sizeimage;
42   short res1,res2;
43   long filesize, pixoff;
44   long bmisize, compression;
45   long xscale, yscale;
46   long colors, impcol;
47   unsigned long m_bytesRead = 0;
48   unsigned char *imagebits = NULL;
49   FILE *fp;
50
51   *width = *height = 0;
52
53   fp = fopen(filename,"rb");
54   if (fp == NULL)
55     return NULL;
56
57   long rc;
58   rc = fread(&m1, 1, 1, fp);
59   m_bytesRead++;
60   if (rc == -1)
61     {
62       fclose(fp);
63       return NULL;
64     }
65
66   rc = fread(&m2, 1, 1, fp);
67   m_bytesRead++;
68   if ((m1!='B') || (m2!='M'))
69     {
70       fclose(fp);
71       return NULL;
72     }
73
74   rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4;
75   if (rc != 1) { fclose(fp); return NULL; }
76
77   rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2;
78   if (rc != 1) { fclose(fp); return NULL; }
79
80   rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2;
81   if (rc != 1) { fclose(fp); return NULL; }
82
83   rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4;
84   if (rc != 1) { fclose(fp); return NULL; }
85
86   rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4;
87   if (rc != 1) { fclose(fp); return NULL; }
88
89   rc = fread((long*)&(bmWidth),4,1,fp); m_bytesRead+=4;
90   if (rc != 1) { fclose(fp); return NULL; }
91
92   rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4;
93   if (rc != 1) { fclose(fp); return NULL; }
94
95   rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2;
96   if (rc != 1) { fclose(fp); return NULL; }
97
98   rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2;
99   if (rc != 1) { fclose(fp); return NULL; }
100
101   rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4;
102   if (rc != 1) { fclose(fp); return NULL; }
103
104   rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4;
105   if (rc != 1) {fclose(fp); return NULL; }
106
107   rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4;
108   if (rc != 1) { fclose(fp); return NULL; }
109
110   rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4;
111   if (rc != 1) { fclose(fp); return NULL; }
112
113   rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4;
114   if (rc != 1) { fclose(fp); return NULL; }
115
116   rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4;
117   if (rc != 1) { fclose(fp); return NULL; }
118
119   if (colors == 0)
120     colors = 1 << bmBitsPixel;
121
122   RGBQUAD *colormap = NULL;
123
124   if (bmBitsPixel != 24)
125     {
126       colormap = new RGBQUAD[colors];
127       if (colormap == NULL)
128         {
129           fclose(fp);
130           return NULL;
131         }
132
133       int i;
134       for (i = 0; i < colors; i++)
135         {
136           unsigned char r ,g, b, dummy;
137
138           rc = fread(&b, 1, 1, fp);
139           m_bytesRead++;
140           if (rc!=1)
141             {
142               delete [] colormap;
143               fclose(fp);
144               return NULL;
145             }
146
147           rc = fread(&g, 1, 1, fp); 
148           m_bytesRead++;
149           if (rc!=1)
150             {
151               delete [] colormap;
152               fclose(fp);
153               return NULL;
154             }
155
156           rc = fread(&r, 1, 1, fp); 
157           m_bytesRead++;
158           if (rc != 1)
159             {
160               delete [] colormap;
161               fclose(fp);
162               return NULL;
163             }
164
165           rc = fread(&dummy, 1, 1, fp); 
166           m_bytesRead++;
167           if (rc != 1)
168             {
169               delete [] colormap;
170               fclose(fp);
171               return NULL;
172             }
173
174           colormap[i].rgbRed=r;
175           colormap[i].rgbGreen=g;
176           colormap[i].rgbBlue=b;
177         }
178     }
179
180   if ((long)m_bytesRead > pixoff)
181     {
182       delete [] colormap;
183       fclose(fp);
184       return NULL;
185     }
186
187   while ((long)m_bytesRead < pixoff)
188     {
189       char dummy;
190       fread(&dummy,1,1,fp);
191       m_bytesRead++;
192     }
193
194   int w = bmWidth;
195   int h = bmHeight;
196
197   // set the output params
198   imagebits = (unsigned char*)malloc(w*h*3);
199   long row_size = w * 3;
200
201   if (imagebits != NULL) 
202     {
203       *width = w;
204       *height = h;
205       unsigned char* outbuf = imagebits;
206       long row = 0;
207       long rowOffset = 0;
208
209       if (compression == 0) // BI_RGB
210         {
211           // read rows in reverse order
212           for (row=bmHeight-1;row>=0;row--)
213             {
214               // which row are we working on?
215               rowOffset = (long unsigned)row*row_size;                                                
216
217               if (bmBitsPixel == 24)
218                 {
219                   for (int col=0;col<w;col++)
220                     {
221                       long offset = col * 3;
222                       char pixel[3];
223
224                       if (fread((void*)(pixel),1,3,fp)==3)
225                         {
226                           // we swap red and blue here
227                           *(outbuf + rowOffset + offset + 0)=pixel[2];          // r
228                           *(outbuf + rowOffset + offset + 1)=pixel[1];          // g
229                           *(outbuf + rowOffset + offset + 2)=pixel[0];          // b
230                         }
231                     }
232                   m_bytesRead += row_size;
233
234                   // read DWORD padding
235                   while ((m_bytesRead-pixoff)&3)
236                     {
237                       char dummy;
238                       if (fread(&dummy,1,1,fp) != 1)
239                         {
240                           free(imagebits);
241                           fclose(fp);
242                           return NULL;
243                         }
244                       m_bytesRead++;
245                     }
246                 }
247               else
248                 {
249                   // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them
250                   int bit_count = 0;
251                   unsigned long mask = (1 << bmBitsPixel) - 1;
252                   unsigned char inbyte = 0;
253
254                   for (int col=0;col<w;col++)
255                     {
256                       int pix = 0;
257
258                       // if we need another byte
259                       if (bit_count <= 0)
260                         {
261                           bit_count = 8;
262                           if (fread(&inbyte,1,1,fp) != 1)
263                             {
264                               free(imagebits);
265                               delete [] colormap;
266                               fclose(fp);
267                               return NULL;
268                             }
269                           m_bytesRead++;
270                         }
271
272                       // keep track of where we are in the bytes
273                       bit_count -= bmBitsPixel;
274                       pix = ( inbyte >> bit_count) & mask;
275
276                       // lookup the color from the colormap - stuff it in our buffer
277                       // swap red and blue
278                       *(outbuf + rowOffset + col * 3 + 2) = colormap[pix].rgbBlue;
279                       *(outbuf + rowOffset + col * 3 + 1) = colormap[pix].rgbGreen;
280                       *(outbuf + rowOffset + col * 3 + 0) = colormap[pix].rgbRed;
281                     }
282
283                   // read DWORD padding
284                   while ((m_bytesRead-pixoff)&3)
285                     {
286                       char dummy;
287                       if (fread(&dummy,1,1,fp)!=1)
288                         {
289                           free(imagebits);
290                           if (colormap)
291                             delete [] colormap;
292                           fclose(fp);
293                           return NULL;
294                         }
295                       m_bytesRead++;
296                     }
297                 }
298             }
299         }
300       else
301         {
302           int i, x = 0;
303           unsigned char c, c1 = 0, *pp;
304           row = 0;
305           pp = outbuf + (bmHeight-1)*bmWidth*3;
306
307           if (bmBitsPixel == 8)
308             {
309               while (row < bmHeight)
310                 {
311                   c = getc(fp);
312
313                   if (c)
314                     {
315                       // encoded mode
316                       c1 = getc(fp);
317                       for (i = 0; i < c; x++, i++)
318                         {
319                           *pp = colormap[c1].rgbRed; pp++;
320                           *pp = colormap[c1].rgbGreen; pp++;
321                           *pp = colormap[c1].rgbBlue; pp++;
322                         }
323                     }
324                   else
325                     {
326                       // c==0x00,  escape codes
327                       c = getc(fp);
328
329                       if (c == 0x00) // end of line
330                         {
331                           row++;
332                           x = 0;
333                           pp = outbuf + (bmHeight-row-1)*bmWidth*3;
334                         }
335                       else if (c == 0x01)
336                         break; // end of pic
337                       else if (c == 0x02) // delta
338                         {
339                           c = getc(fp);
340                           x += c;
341                           c = getc(fp);
342                           row += c;
343                           pp = outbuf + x*3 + (bmHeight-row-1)*bmWidth*3;
344                         }
345                       else // absolute mode
346                         {
347                           for (i = 0; i < c; x++, i++)
348                             {
349                               c1 = getc(fp);
350                               *pp = colormap[c1].rgbRed; pp++;
351                               *pp = colormap[c1].rgbGreen; pp++;
352                               *pp = colormap[c1].rgbBlue; pp++;
353                             }
354
355                           if (c & 1)
356                             getc(fp); // odd length run: read an extra pad byte
357                         }
358                     }
359                 }
360             }
361           else if (bmBitsPixel == 4)
362             {
363               while (row < bmHeight)
364                 {
365                   c = getc(fp);
366
367                   if (c)
368                     {
369                       // encoded mode
370                       c1 = getc(fp);
371                       for (i = 0; i < c; x++, i++)
372                         {
373                           *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
374                           *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
375                           *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
376                         }
377                     }
378                   else
379                     {
380                       // c==0x00,  escape codes
381                       c = getc(fp);
382
383                       if (c == 0x00) // end of line
384                         {
385                           row++;
386                           x = 0;
387                           pp = outbuf + (bmHeight-row-1)*bmWidth*3;
388                         }
389                       else if (c == 0x01)
390                         break; // end of pic
391                       else if (c == 0x02) // delta
392                         {
393                           c = getc(fp);
394                           x += c;
395                           c = getc(fp);
396                           row += c;
397                           pp = outbuf + x*3 + (bmHeight-row-1)*bmWidth*3;
398                         }
399                       else // absolute mode
400                         {
401                           for (i = 0; i < c; x++, i++)
402                             {
403                               if ((i&1) == 0)
404                                 c1 = getc(fp);
405                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbRed; pp++;
406                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbGreen; pp++;
407                               *pp = colormap[(i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f)].rgbBlue; pp++;
408                             }
409
410                           if (((c&3) == 1) || ((c&3) == 2))
411                             getc(fp); // odd length run: read an extra pad byte
412                         }
413                     }
414                 }
415             }
416         }
417
418       if (colormap)
419         delete [] colormap;
420
421       fclose(fp);
422     }
423
424   return imagebits;
425 }
426
427 void CPixMap::bmp_to_pixmap (const char* filename, GdkPixmap **pixmap, GdkBitmap **mask)
428 {
429   guint16 width, height;
430   unsigned char *buf;
431   GdkWindow *window = GDK_ROOT_PARENT();
432   GdkColormap *colormap;
433   GdkGC* gc = gdk_gc_new (window);
434   int i, j;
435   GdkColor c;
436
437   *pixmap = *mask = NULL;
438   buf = load_bitmap_file (filename, &width, &height);
439   if (!buf)
440     return;
441
442   colormap = gdk_window_get_colormap (window);
443   *pixmap = gdk_pixmap_new (window, width, height, -1);
444
445   typedef struct
446   {
447     GdkColor c;
448     unsigned char *p;
449   } PAL;
450
451   GPtrArray* pal = g_ptr_array_new ();
452   GdkColor** col = (GdkColor**)malloc (sizeof (GdkColor*) * height * width);
453   guint32 k;
454
455   for (i = 0; i < height; i++)
456     for (j = 0; j < width; j++)
457     {
458       unsigned char* p = &buf[(i*width+j)*3];
459
460       for (k = 0; k < pal->len; k++)
461       {
462         PAL *pe = (PAL*)pal->pdata[k];
463         if ((pe->p[0] == p[0]) &&
464             (pe->p[1] == p[1]) &&
465             (pe->p[2] == p[2]))
466         {
467           col[(i*width+j)] = &pe->c;
468           break;
469         }
470       }
471
472       if (k == pal->len)
473       {
474         PAL *pe = (PAL*)malloc (sizeof (PAL));
475
476         pe->c.red = (gushort)(p[0]*0xFF);
477         pe->c.green = (gushort)(p[1]*0xFF);
478         pe->c.blue = (gushort)(p[2]*0xFF);
479         gdk_color_alloc (colormap, &pe->c);
480         col[(i*width+j)] = &pe->c;
481         pe->p = p;
482         g_ptr_array_add (pal, pe);
483       }
484     }
485
486   for (i = 0; i < height; i++)
487     for (j = 0; j < width; j++)
488     {
489       /*
490       c.red = (gushort)(buf[(i*width+j)*3]*0xFF);
491       c.green = (gushort)(buf[(i*width+j)*3+1]*0xFF);
492       c.blue = (gushort)(buf[(i*width+j)*3+2]*0xFF);
493       gdk_color_alloc (colormap, &c);
494       gdk_gc_set_foreground(gc, &c);
495       gdk_draw_point(*pixmap, gc, j, i);
496       */
497       gdk_gc_set_foreground(gc, col[(i*width+j)]);
498       gdk_draw_point(*pixmap, gc, j, i);
499     }
500
501   free (col);
502   for (k = 0; k < pal->len; k++)
503     free (pal->pdata[k]);
504   g_ptr_array_free (pal, TRUE);
505
506   gdk_gc_destroy (gc);
507   *mask = gdk_pixmap_new (window, width, height, 1);
508   gc = gdk_gc_new (*mask);
509
510   for (i = 0; i < height; i++)
511     for (j = 0; j < width; j++)
512     {
513       GdkColor mask_pattern;
514
515       // pink is transparent
516       if ((buf[(i*width+j)*3] == 0xff) &&
517           (buf[(i*width+j)*3+1] == 0x00) &&
518           (buf[(i*width+j)*3+2] == 0xff))
519         mask_pattern.pixel = 0;
520       else
521         mask_pattern.pixel = 1;
522
523       gdk_gc_set_foreground (gc, &mask_pattern);
524       // possible Win32 Gtk bug here
525 //      gdk_draw_point (*mask, gc, j, i);
526       gdk_draw_line (*mask, gc, j, i, j + 1, i);
527     }
528
529   gdk_gc_destroy(gc);
530   free (buf);
531 }
532
533 void CPixMap::load_pixmap (const char* filename, GdkPixmap **gdkpixmap, GdkBitmap **mask)
534 {
535   CString str;
536
537   str = g_strBitmapsPath;
538   str += filename;
539   bmp_to_pixmap (str.GetBuffer (),gdkpixmap, mask);
540
541   if (*gdkpixmap == NULL)
542   {
543     char *dummy[] = { "1 1 1 1", "  c None", " " };
544     *gdkpixmap = gdk_pixmap_create_from_xpm_d (GDK_ROOT_PARENT(), mask, NULL, dummy);
545   }
546 }
547
548 // Load a xpm file and return a pixmap widget.
549 GtkWidget* CPixMap::new_pixmap (GtkWidget* widget, char* filename)
550 {
551   GdkPixmap *gdkpixmap;
552   GdkBitmap *mask;
553   GtkWidget *pixmap;
554
555   load_pixmap (filename, &gdkpixmap, &mask);
556   pixmap = gtk_pixmap_new (gdkpixmap, mask);
557
558   gdk_pixmap_unref (gdkpixmap);
559   gdk_pixmap_unref (mask);
560
561  // g_FuncTable.m_pfnLoadBitmap( filename, &pixmap, &mask )
562
563   return pixmap;
564
565
566 GtkWidget* CPixMap::pixmap_from_char(GtkWidget *window, gchar **xpm_data)
567 {
568         GdkPixmap *pixmap;
569     GdkBitmap *mask;
570         GtkStyle *style;
571     GtkWidget *widget;
572
573         style = gtk_widget_get_style( window );
574     pixmap = gdk_pixmap_create_from_xpm_d( window->window,  &mask,
575                                            &style->bg[GTK_STATE_NORMAL],
576                                            (gchar **)xpm_data );
577
578         widget = gtk_pixmap_new( pixmap, mask );
579
580         return widget;
581 }