]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata/images.c
set eol-style
[xonotic/netradiant.git] / tools / quake2 / qdata / images.c
1 #include "qdata.h"
2 #include "inout.h"
3
4 char            mip_prefix[1024];               // directory to dump the textures in
5
6 qboolean        colormap_issued;
7 byte            colormap_palette[768];
8
9 /*
10 ==============
11 RemapZero
12
13 Replaces all 0 bytes in an image with the closest palette entry.
14 This is because NT won't let us change index 0, so any palette
15 animation leaves those pixels untouched.
16 ==============
17 */
18 void RemapZero (byte *pixels, byte *palette, int width, int height)
19 {
20         int             i, c;
21         int             alt_zero;
22         int             value, best;
23
24         alt_zero = 0;
25         best = 9999999;
26         for (i=1 ; i<255 ; i++)
27         {
28                 value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2];
29                 if (value < best)
30                 {
31                         best = value;
32                         alt_zero = i;
33                 }
34         }
35
36         c = width*height;
37         for (i=0 ; i<c ; i++)
38                 if (pixels[i] == 0)
39                         pixels[i] = alt_zero;
40 }
41
42 /*
43 ==============
44 Cmd_Grab
45
46 $grab filename x y width height
47 ==============
48 */
49 void Cmd_Grab (void)
50 {
51         int             xl,yl,w,h,y;
52         byte                    *cropped;
53         char                    savename[1024];
54         char                    dest[1024];
55
56         GetToken (false);
57
58         if (token[0] == '/' || token[0] == '\\')
59                 sprintf (savename, "%s%s.pcx", gamedir, token+1);
60         else
61                 sprintf (savename, "%spics/%s.pcx", gamedir, token);
62
63         if (g_release)
64         {
65                 if (token[0] == '/' || token[0] == '\\')
66                         sprintf (dest, "%s.pcx", token+1);
67                 else
68                         sprintf (dest, "pics/%s.pcx", token);
69
70                 ReleaseFile (dest);
71                 return;
72         }
73
74         GetToken (false);
75         xl = atoi (token);
76         GetToken (false);
77         yl = atoi (token);
78         GetToken (false);
79         w = atoi (token);
80         GetToken (false);
81         h = atoi (token);
82
83         if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
84                 Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
85
86         // crop it to the proper size
87         cropped = malloc (w*h);
88         for (y=0 ; y<h ; y++)
89         {
90                 memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
91         }
92
93         // save off the new image
94         printf ("saving %s\n", savename);
95         CreatePath (savename);
96         WritePCXfile (savename, cropped, w,     h, lbmpalette);
97
98         free (cropped);
99 }
100
101 /*
102 ==============
103 Cmd_Raw
104
105 $grab filename x y width height
106 ==============
107 */
108 void Cmd_Raw (void)
109 {
110         int             xl,yl,w,h,y;
111         byte                    *cropped;
112         char                    savename[1024];
113         char                    dest[1024];
114
115         GetToken (false);
116
117         sprintf (savename, "%s%s.lmp", gamedir, token);
118
119         if (g_release)
120         {
121                 sprintf (dest, "%s.lmp", token);
122                 ReleaseFile (dest);
123                 return;
124         }
125
126         GetToken (false);
127         xl = atoi (token);
128         GetToken (false);
129         yl = atoi (token);
130         GetToken (false);
131         w = atoi (token);
132         GetToken (false);
133         h = atoi (token);
134
135         if (xl<0 || yl<0 || w<0 || h<0 || xl+w>byteimagewidth || yl+h>byteimageheight)
136                 Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h);
137
138         // crop it to the proper size
139         cropped = malloc (w*h);
140         for (y=0 ; y<h ; y++)
141         {
142                 memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w);
143         }
144
145         // save off the new image
146         printf ("saving %s\n", savename);
147         CreatePath (savename);
148
149         SaveFile (savename, cropped, w*h);
150
151         free (cropped);
152 }
153
154 /*
155 =============================================================================
156
157 COLORMAP GRABBING
158
159 =============================================================================
160 */
161
162 /*
163 ===============
164 BestColor
165 ===============
166 */
167 byte BestColor (int r, int g, int b, int start, int stop)
168 {
169         int     i;
170         int     dr, dg, db;
171         int     bestdistortion, distortion;
172         int     bestcolor;
173         byte    *pal;
174
175 //
176 // let any color go to 0 as a last resort
177 //
178         bestdistortion = 256*256*4;
179         bestcolor = 0;
180
181         pal = colormap_palette + start*3;
182         for (i=start ; i<= stop ; i++)
183         {
184                 dr = r - (int)pal[0];
185                 dg = g - (int)pal[1];
186                 db = b - (int)pal[2];
187                 pal += 3;
188                 distortion = dr*dr + dg*dg + db*db;
189                 if (distortion < bestdistortion)
190                 {
191                         if (!distortion)
192                                 return i;               // perfect match
193
194                         bestdistortion = distortion;
195                         bestcolor = i;
196                 }
197         }
198
199         return bestcolor;
200 }
201
202
203 /*
204 ==============
205 Cmd_Colormap
206
207 $colormap filename
208
209   the brightes colormap is first in the table (FIXME: reverse this now?)
210
211   64 rows of 256 : lightmaps
212   256 rows of 256 : translucency table
213 ==============
214 */
215 void Cmd_Colormap (void)
216 {
217         int             levels, brights;
218         int             l, c;
219         float   frac, red, green, blue;
220         float   range;
221         byte    *cropped, *lump_p;
222         char    savename[1024];
223         char    dest[1024];
224
225         colormap_issued = true;
226         if (!g_release)
227                 memcpy (colormap_palette, lbmpalette, 768);
228
229         if (!TokenAvailable ())
230         {       // just setting colormap_issued
231                 return;
232         }
233
234         GetToken (false);
235         sprintf (savename, "%spics/%s.pcx", gamedir, token);
236
237         if (g_release)
238         {
239                 sprintf (dest, "pics/%s.pcx", token);
240                 ReleaseFile (dest);
241                 return;
242         }
243
244         range = 2;
245         levels = 64;
246         brights = 1;    // ignore 255 (transparent)
247
248         cropped = malloc((levels+256)*256);
249         lump_p = cropped;
250
251 // shaded levels
252         for (l=0;l<levels;l++)
253         {
254                 frac = range - range*(float)l/(levels-1);
255                 for (c=0 ; c<256-brights ; c++)
256                 {
257                         red = lbmpalette[c*3];
258                         green = lbmpalette[c*3+1];
259                         blue = lbmpalette[c*3+2];
260
261                         red = (int)(red*frac+0.5);
262                         green = (int)(green*frac+0.5);
263                         blue = (int)(blue*frac+0.5);
264                         
265 //
266 // note: 254 instead of 255 because 255 is the transparent color, and we
267 // don't want anything remapping to that
268 // don't use color 0, because NT can't remap that (or 255)
269 //
270                         *lump_p++ = BestColor(red,green,blue, 1, 254);
271                 }
272
273                 // fullbrights allways stay the same
274                 for ( ; c<256 ; c++)
275                         *lump_p++ = c;
276         }
277         
278 // 66% transparancy table
279         for (l=0;l<255;l++)
280         {
281                 for (c=0 ; c<255 ; c++)
282                 {
283                         red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66;
284                         green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66;
285                         blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66;
286
287                         *lump_p++ = BestColor(red,green,blue, 1, 254);
288                 }
289                 *lump_p++ = 255;
290         }
291         for (c=0 ; c<256 ; c++)
292                 *lump_p++ = 255;
293         
294         // save off the new image
295         printf ("saving %s\n", savename);
296         CreatePath (savename);
297         WritePCXfile (savename, cropped, 256, levels+256, lbmpalette);
298
299         free (cropped);
300 }
301
302 /*
303 =============================================================================
304
305 MIPTEX GRABBING
306
307 =============================================================================
308 */
309
310 byte    pixdata[256];
311
312 int             d_red, d_green, d_blue;
313
314 byte    palmap[32][32][32];
315 qboolean        palmap_built;
316
317 /*
318 =============
319 FindColor
320 =============
321 */
322 int FindColor (int r, int g, int b)
323 {
324         int             bestcolor;
325
326         if (r > 255)
327                 r = 255;
328         if (r < 0)
329                 r = 0;
330         if (g > 255)
331                 g = 255;
332         if (g < 0)
333                 g = 0;
334         if (b > 255)
335                 b = 255;
336         if (b < 0)
337                 b = 0;
338 #ifndef TABLECOLORS
339         bestcolor = BestColor (r, g, b, 0, 254);
340 #else
341         bestcolor = palmap[r>>3][g>>3][b>>3];
342 #endif
343
344         return bestcolor;
345 }
346
347
348 void BuildPalmap (void)
349 {
350 #ifdef TABLECOLORS
351         int             r, g, b;
352         int             bestcolor;
353
354         if (palmap_built)
355                 return;
356         palmap_built = true;
357
358         for (r=4 ; r<256 ; r+=8)
359         {
360                 for (g=4 ; g<256 ; g+=8)
361                 {
362                         for (b=4 ; b<256 ; b+=8)
363                         {
364                                 bestcolor = BestColor (r, g, b, 1, 254);
365                                 palmap[r>>3][g>>3][b>>3] = bestcolor;
366                         }
367                 }
368         }
369 #endif
370
371         if (!colormap_issued)
372                 Error ("You must issue a $colormap command first");
373
374 }
375
376 /*
377 =============
378 AveragePixels
379 =============
380 */
381 byte AveragePixels (int count)
382 {
383         int             r,g,b;
384         int             i;
385         int             vis;
386         int             pix;
387         int             bestcolor;
388         byte    *pal;
389         int             fullbright;
390         
391         vis = 0;
392         r = g = b = 0;
393         fullbright = 0;
394         for (i=0 ; i<count ; i++)
395         {
396                 pix = pixdata[i];
397                 
398                 r += lbmpalette[pix*3];
399                 g += lbmpalette[pix*3+1];
400                 b += lbmpalette[pix*3+2];
401                 vis++;
402         }
403                 
404         r /= vis;
405         g /= vis;
406         b /= vis;
407
408         // error diffusion
409         r += d_red;
410         g += d_green;
411         b += d_blue;
412         
413 //
414 // find the best color
415 //
416         bestcolor = FindColor (r, g, b);
417
418         // error diffusion
419         pal = colormap_palette + bestcolor*3;
420         d_red = r - (int)pal[0];
421         d_green = g - (int)pal[1];
422         d_blue = b - (int)pal[2];
423
424         return bestcolor;
425 }
426
427
428 typedef enum
429 {
430         pt_contents,
431         pt_flags,
432         pt_animvalue,
433         pt_flagvalue
434 } parmtype_t;
435
436 typedef struct
437 {
438         char    *name;
439         int             flags;
440         parmtype_t      type;
441 } mipparm_t;
442
443 mipparm_t       mipparms[] =
444 {
445         // utility content attributes
446         {"water",       CONTENTS_WATER, pt_contents},
447         {"slime",       CONTENTS_SLIME, pt_contents},           // mildly damaging
448         {"lava",        CONTENTS_LAVA, pt_contents},            // very damaging
449         {"window",      CONTENTS_WINDOW, pt_contents},  // solid, but doesn't eat internal textures
450         {"mist",        CONTENTS_MIST, pt_contents},    // non-solid window
451         {"origin",      CONTENTS_ORIGIN, pt_contents},  // center of rotating brushes
452         {"playerclip",  CONTENTS_PLAYERCLIP, pt_contents},
453         {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents},
454
455         // utility surface attributes
456         {"hint",        SURF_HINT, pt_flags},
457         {"skip",        SURF_SKIP, pt_flags},
458         {"light",       SURF_LIGHT, pt_flagvalue},              // value is the light quantity
459
460         // texture chaining
461         {"anim",        0,                      pt_animvalue},          // value is the next animation
462
463         // server attributes
464         {"slick",       SURF_SLICK, pt_flags},
465
466         // drawing attributes
467         {"sky",         SURF_SKY, pt_flags},
468         {"warping",     SURF_WARP, pt_flags},           // only valid with 64x64 textures
469         {"trans33",     SURF_TRANS33, pt_flags},        // translucent should allso set fullbright
470         {"trans66",     SURF_TRANS66, pt_flags},
471         {"flowing",     SURF_FLOWING, pt_flags},        // flow direction towards angle 0
472         {"nodraw",      SURF_NODRAW, pt_flags}, // for clip textures and trigger textures
473
474         {NULL, 0, pt_contents}
475 };
476
477
478
479 /*
480 ==============
481 Cmd_Mip
482
483 $mip filename x y width height <OPTIONS>
484 must be multiples of sixteen
485 SURF_WINDOW
486 ==============
487 */
488 void Cmd_Mip (void)
489 {
490         int             x,y,xl,yl,xh,yh,w,h;
491         byte            *screen_p, *source;
492         int             linedelta;
493         miptex_t                *qtex;
494         int                             miplevel, mipstep;
495         int                             xx, yy, pix;
496         int                             count;
497         int                             flags, value, contents;
498         mipparm_t               *mp;
499         char                    lumpname[64];
500         byte                    *lump_p;
501         char                    filename[1024];
502         char                    animname[64];
503
504         GetToken (false);
505         strcpy (lumpname, token);
506         
507         GetToken (false);
508         xl = atoi (token);
509         GetToken (false);
510         yl = atoi (token);
511         GetToken (false);
512         w = atoi (token);
513         GetToken (false);
514         h = atoi (token);
515
516         if ( (w & 15) || (h & 15) )
517                 Error ("line %i: miptex sizes must be multiples of 16", scriptline);
518
519         flags = 0;
520         contents = 0;
521         value = 0;
522
523         animname[0] = 0;
524
525         // get optional flags and values
526         while (TokenAvailable ())
527         {
528                 GetToken (false);
529         
530                 for (mp=mipparms ; mp->name ; mp++)
531                 {
532                         if (!strcmp(mp->name, token))
533                         {
534                                 switch (mp->type)
535                                 {
536                                 case pt_animvalue:
537                                         GetToken (false);       // specify the next animation frame
538                                         strcpy (animname, token);
539                                         break;
540                                 case pt_flags:
541                                         flags |= mp->flags;
542                                         break;
543                                 case pt_contents:
544                                         contents |= mp->flags;
545                                         break;
546                                 case pt_flagvalue:
547                                         flags |= mp->flags;
548                                         GetToken (false);       // specify the light value
549                                         value = atoi(token);
550                                         break;
551                                 }
552                                 break;
553                         }
554                 }
555                 if (!mp->name)
556                         Error ("line %i: unknown parm %s", scriptline, token);
557         }
558
559         sprintf (filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname);
560         if (g_release)
561                 return; // textures are only released by $maps
562
563         xh = xl+w;
564         yh = yl+h;
565
566         qtex = malloc (sizeof(miptex_t) + w*h*2);
567         memset (qtex, 0, sizeof(miptex_t));
568
569         qtex->width = LittleLong(w);
570         qtex->height = LittleLong(h);
571         qtex->flags = LittleLong(flags);
572         qtex->contents = LittleLong(contents);
573         qtex->value = LittleLong(value);
574         sprintf (qtex->name, "%s/%s", mip_prefix, lumpname);
575         if (animname[0])
576                 sprintf (qtex->animname, "%s/%s", mip_prefix, animname);
577         
578         lump_p = (byte *)(&qtex->value+1);
579         
580         screen_p = byteimage + yl*byteimagewidth + xl;
581         linedelta = byteimagewidth - w;
582
583         source = lump_p;
584         qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex);
585
586         for (y=yl ; y<yh ; y++)
587         {
588                 for (x=xl ; x<xh ; x++)
589                 {
590                         pix = *screen_p++;
591                         if (pix == 255)
592                                 pix = 1;                // should never happen
593                         *lump_p++ = pix;
594                 }
595                 screen_p += linedelta;
596         }
597         
598 //
599 // subsample for greater mip levels
600 //
601         d_red = d_green = d_blue = 0;   // no distortion yet
602
603         for (miplevel = 1 ; miplevel<4 ; miplevel++)
604         {
605                 qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex);
606                 
607                 mipstep = 1<<miplevel;
608                 for (y=0 ; y<h ; y+=mipstep)
609                 {
610
611                         for (x = 0 ; x<w ; x+= mipstep)
612                         {
613                                 count = 0;
614                                 for (yy=0 ; yy<mipstep ; yy++)
615                                         for (xx=0 ; xx<mipstep ; xx++)
616                                         {
617                                                 pixdata[count] = source[ (y+yy)*w + x + xx ];
618                                                 count++;
619                                         }
620                                 *lump_p++ = AveragePixels (count);
621                         }       
622                 }
623         }
624
625 //
626 // dword align the size
627 //
628         while ((int)lump_p&3)
629                 *lump_p++ = 0;
630
631 //
632 // write it out
633 //
634         printf ("writing %s\n", filename);
635         SaveFile (filename, (byte *)qtex, lump_p - (byte *)qtex);
636
637         free (qtex);
638 }
639
640 /*
641 ===============
642 Cmd_Mippal
643 ===============
644 */
645 void Cmd_Mippal (void)
646 {
647         colormap_issued = true;
648         if (g_release)
649                 return;
650
651         memcpy (colormap_palette, lbmpalette, 768);
652
653         BuildPalmap();
654 }
655
656
657 /*
658 ===============
659 Cmd_Mipdir
660 ===============
661 */
662 void Cmd_Mipdir (void)
663 {
664         char    filename[1024];
665
666         GetToken (false);
667         strcpy (mip_prefix, token);
668         // create the directory if needed
669         sprintf (filename, "%stextures", gamedir, mip_prefix);
670         Q_mkdir (filename); 
671         sprintf (filename, "%stextures/%s", gamedir, mip_prefix);
672         Q_mkdir (filename); 
673 }
674
675
676 /*
677 =============================================================================
678
679 ENVIRONMENT MAP GRABBING
680
681 Creates six pcx files from tga files without any palette edge seams
682 also copies the tga files for GL rendering.
683 =============================================================================
684 */
685
686 // 3dstudio environment map suffixes
687 char    *suf[6] = {"rt", "ft", "lf", "bk", "up", "dn"};
688
689 /*
690 =================
691 Cmd_Environment
692 =================
693 */
694 void Cmd_Environment (void)
695 {
696         char    name[1024];
697         int             i, x, y;
698         byte    image[256*256];
699         byte    *tga;
700
701         GetToken (false);
702
703         if (g_release)
704         {
705                 for (i=0 ; i<6 ; i++)
706                 {
707                         sprintf (name, "env/%s%s.pcx", token, suf[i]);
708                         ReleaseFile (name);
709                         sprintf (name, "env/%s%s.tga", token, suf[i]);
710                         ReleaseFile (name);
711                 }
712                 return;
713         }
714         // get the palette
715         BuildPalmap ();
716
717         sprintf (name, "%senv/", gamedir);
718         CreatePath (name);
719
720         // convert the images
721         for (i=0 ; i<6 ; i++)
722         {
723                 sprintf (name, "%senv/%s%s.tga", gamedir, token, suf[i]);
724                 printf ("loading %s...\n", name);
725                 LoadTGA (name, &tga, NULL, NULL);
726
727                 for (y=0 ; y<256 ; y++)
728                 {
729                         for (x=0 ; x<256 ; x++)
730                         {
731                                 image[y*256+x] = FindColor (tga[(y*256+x)*4+0],tga[(y*256+x)*4+1],tga[(y*256+x)*4+2]);
732                         }
733                 }
734                 free (tga);
735                 sprintf (name, "%senv/%s%s.pcx", gamedir, token, suf[i]);
736                 if (FileTime (name) != -1)
737                         printf ("%s already exists, not overwriting.\n", name);
738                 else
739                         WritePCXfile (name, image, 256, 256, colormap_palette);
740         }
741 }
742