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