remove RSA's md4.c, replace by DP's
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / tmix.c
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "qdata.h"
23 #include "flex.h"
24
25 #define         MAXFILES        2048
26
27 typedef struct
28 {
29         int                     x;
30         int                     y;
31         int                     w;
32         int                     h;
33         int                     cw;
34         int                     ch;
35         int                     rw;
36         int                     index;
37         int                     depth;
38         int                     col;
39         int                     baseline;
40         char            name[128];
41 } Coords;
42
43 int                             filenum;
44 int                             valid;
45 Coords                  in[MAXFILES];
46 Coords                  out;
47 char                    outscript[256];
48 char                    sourcedir[256];
49 char                    outusage[256];
50 char                    root[32];
51
52 int                             destsize = 0;
53 byte                    *pixels = NULL;                         // Buffer to load image
54 long                    *outpixels = NULL;                      // Buffer to store combined textures
55 long                    *usagemap = NULL;                       // Buffer of usage map
56 void                    *bmptemp = NULL;                        // Buffer of usage map
57 byte                    *map = NULL;
58
59 int                             xcharsize;
60 int                             ycharsize;
61 int                             dosort = 0;
62 int                             missed = 0;
63 int                             overlap = 0;
64 int                             nobaseline = 0;
65 int                             percent;
66
67 //////////////////////////////////////////////////
68 // Setting the char based usage map                             //
69 //////////////////////////////////////////////////
70
71 byte    TryPlace(Coords *coord)
72 {
73         int             x, y;
74         byte    entry = 0;
75         byte    *mapitem;
76         
77         mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
78
79         for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
80         {
81                 for (x = 0; x < coord->cw; x++)
82                 {
83                         if (entry |= *mapitem++ & 8)
84                         {
85                                 return(entry);
86                         }
87                 }
88         }
89         return(entry);
90 }
91
92 void    SetMap(Coords *coord)
93 {
94         int             x, y;
95         byte    *mapitem;
96
97         mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
98
99         for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
100                 for (x = 0; x < coord->cw; x++)
101                         *mapitem++ |= 8;
102 }
103
104 //////////////////////////////////////////////////
105 // Setting the pixel based usage map                    //
106 //////////////////////////////////////////////////
107
108 void    CheckOverlap(Coords *coord)
109 {
110         int                     x;
111         int                     y;
112         long            *dest;
113
114         x = coord->x;
115         y = coord->y;
116
117         dest = (long *)(usagemap + x + (y * out.w));
118
119         for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
120         {
121                 for (x = 0; x < coord->w; x++)
122                 {
123                         if (*dest++)
124                         {
125                                 overlap++;
126                                 return;
127                         }
128                 }
129         }
130 }
131
132 void    SetUsageMap(Coords *coord)
133 {
134         int                     x;
135         int                     y;
136         long            *dest;
137
138         x = coord->x;
139         y = coord->y;
140
141         dest = (long *)(usagemap + x + (y * out.w));
142
143         for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
144         {
145                 for (x = 0; x < coord->w; x++)
146                 {
147                         *dest++ = coord->col;
148                 }
149         }
150 }
151
152 //////////////////////////////////////////////////
153 // Flips the BMP image to the correct way up    //
154 //////////////////////////////////////////////////
155
156 void    CopyLine(byte *dest, byte *src, int size)
157 {
158         int             x;
159         
160         for (x = 0; x < size; x++)
161                 *dest++ = *src++;
162 }
163
164 /****************************************************/
165 /* Printing headers etc                                                         */
166 /****************************************************/
167
168 void RemoveLeading(char *name)
169 {
170         int             i;
171         char    temp[128];
172
173         for(i = strlen(name) - 1; i > 0; i--)
174         {
175                 if((name[i] == '\\') || (name[i] == '/'))
176                 {
177                         strcpy(temp, name + i + 1);
178                         strcpy(name, temp);
179                         return;
180                 }
181         }
182 }
183
184 void RemoveExt(char *name)
185 {
186         while ((*name != '.') && *name)
187                 name++;
188         *name = 0;
189 }
190
191 /****************************************************/
192 /* Misc calcualtions                                                            */
193 /****************************************************/
194
195 int     TotalArea()
196 {
197         int             i;
198         int             total = 0;
199
200         for (i = 0; i < (filenum + 2); i++)
201                 total += in[i].w * in[i].h;
202
203         return(total);
204 }
205
206 /****************************************************/
207 /* Setup and checking of all info                                       */
208 /****************************************************/
209
210 void    InitVars()
211 {
212         filenum = 0;
213         valid = 0;
214         dosort = 0;
215         missed = 0;
216         overlap = 0;
217         nobaseline = 0;
218         
219         memset(outscript, 0, sizeof(outscript));
220         memset(outscript, 0, sizeof(sourcedir));
221         memset(outscript, 0, sizeof(outusage));
222         memset(outscript, 0, sizeof(root));
223
224         memset(in, 0, sizeof(in));
225         memset(&out, 0, sizeof(out));
226 }
227 void Cleanup()
228 {
229         if (pixels)
230                 free(pixels);
231         if (usagemap)
232                 free(usagemap);
233         if (outpixels)
234                 free(outpixels);
235         if (bmptemp)
236                 free(bmptemp);
237         if (map)
238                 free(map);
239 }
240
241 typedef struct glxy_s
242 {
243         float   xl, yt, xr, yb;
244         int             w, h, baseline;
245 } glxy_t;
246
247 int     SaveScript(char *name)
248 {
249         FILE            *fp;
250         int                     i, j;
251         glxy_t          buff;
252         
253         if(fp = fopen(name, "wb"))
254         {
255                 for (j = 0; j < filenum; j++)
256                 {
257                         for (i = 0; i < filenum; i++)
258                         {
259                                 if (in[i].index == j)
260                                 {
261                                         if (in[i].depth)
262                                         {
263                                                 buff.xl = (float)in[i].x / (float)out.w;
264                                                 buff.yt = (float)in[i].y / (float)out.h;
265                                                 buff.xr = ((float)in[i].w + (float)in[i].x) / (float)out.w;
266                                                 buff.yb = ((float)in[i].h + (float)in[i].y) / (float)out.h;
267                                                 buff.w = in[i].w;
268                                                 buff.h = in[i].h;
269                                                 buff.baseline = in[i].baseline;
270                                         }
271                                         else
272                                         {
273                                                 memset(&buff, 0, sizeof(glxy_t));
274                                         }
275                                         fwrite(&buff, 1, sizeof(glxy_t), fp);
276                                         i = filenum;
277                                 }
278                         }
279                 }
280                 fclose(fp);
281                 return(true);
282         }
283         else
284                 return(false);
285 }
286
287 int             GetScriptInfo(char *name)
288 {
289         FILE            *fp;
290         char            buffer[256];
291         char            tempbuff[256];
292         char            delims[] = {" \t,\n"};
293
294         printf("Opening script file %s.\n", name);
295
296         if (fp = fopen(name, "r"))
297         {
298                 while(fgets(buffer, 256, fp))
299                 {
300                         if (strncmp(buffer, "//", 2) && strncmp(buffer, "\n", 1))
301                         {
302                                 strupr(buffer);
303                                 strcpy(tempbuff, buffer);
304                                 if (strcmp(strtok(tempbuff, delims), "OUTPUT") == 0)
305                                 {
306                                         strcpy(out.name, strtok(NULL, delims));
307                                         strlwr(out.name);
308                                 }
309
310                                 strcpy(tempbuff, buffer);
311                                 if (strcmp(strtok(tempbuff, delims), "SOURCEDIR") == 0)
312                                 {
313                                         strcpy(tempbuff, strtok(NULL, delims));
314                                         strcpy(sourcedir, ExpandPathAndArchive(tempbuff));
315                                 }
316
317                                 strcpy(tempbuff, buffer);
318                                 if (strcmp(strtok(tempbuff, delims), "DOSORT") == 0)
319                                         dosort = 1;
320
321                                 strcpy(tempbuff, buffer);
322                                 if (strcmp(strtok(tempbuff, delims), "XCHARSIZE") == 0)
323                                         xcharsize = strtol(strtok(NULL, delims), NULL, 0);
324
325                                 strcpy(tempbuff, buffer);
326                                 if (strcmp(strtok(tempbuff, delims), "YCHARSIZE") == 0)
327                                         ycharsize = strtol(strtok(NULL, delims), NULL, 0);
328
329                                 strcpy(tempbuff, buffer);
330                                 if (strcmp(strtok(tempbuff, delims), "OUTSCRIPT") == 0)
331                                 {
332                                         strcpy(outscript, strtok(NULL, delims));
333                                         strlwr(outscript);
334                                 }
335
336                                 strcpy(tempbuff, buffer);
337                                 if (strcmp(strtok(tempbuff, delims), "OUTUSAGE") == 0)
338                                         strcpy(outusage, strtok(NULL, delims));
339
340                                 strcpy(tempbuff, buffer);
341                                 if (strcmp(strtok(tempbuff, delims), "POS") == 0)
342                                 {
343                                         out.w = strtol(strtok(NULL, delims), NULL, 0);
344                                         out.h = strtol(strtok(NULL, delims), NULL, 0);
345                                 }
346
347                                 strcpy(tempbuff, buffer);
348                                 if (strcmp(strtok(tempbuff, delims), "FILE") == 0)
349                                 {
350                                         strcpy(in[filenum].name, strtok(NULL, delims));
351                                         in[filenum].x = strtol(strtok(NULL, delims), NULL, 0);
352                                         in[filenum].y = strtol(strtok(NULL, delims), NULL, 0);
353                                         in[filenum].col = strtol(strtok(NULL, delims), NULL, 0);
354                                         filenum++;
355                                 }
356                         }
357                 }
358                 fclose(fp);
359                 return(true);
360         }
361         else
362         {
363                 printf("ERROR : Could not open script file.\n");
364                 return(false);
365         }
366 }
367
368 int     CheckVars()
369 {
370         int             i;
371
372          if (out.name[0] == 0)
373          {
374                 printf("ERROR : No output name specified.\n");
375                 return(false);
376         }
377         if ((out.w <= 0) || (out.h <= 0))
378         {
379                 printf("ERROR : Invalid VRAM coordinates.\n");
380                 return(false);
381         }
382         if (filenum == 0)
383         {
384                 printf("ERROR : No input files specified.\n");
385                 return(false);
386         }
387         for (i = 0; i < filenum; i++)
388                 if (in[i].name[0] == 0)
389                 {
390                         printf("ERROR : Input filename invalid.\n");
391                         return(false);
392                 }
393         return(true);
394 }
395
396 // Makes sure texture is totally within the output area
397
398 int     CheckCoords(Coords *coord)
399 {
400         if ((coord->x + coord->w) > out.w)
401                 return(false);
402         if ((coord->y + coord->h) > out.h)
403                 return(false);
404
405         return(true);
406 }
407 // Gets the width, height, palette width and palette height of each BMP file
408
409 int             GetFileDimensions()
410 {
411         int                     i;
412         int                     width, height;
413         char            name[128];
414
415         for (i = 0; i < filenum; i++)
416         {
417                 in[i].index = i;
418
419                 strcpy(name, sourcedir);
420                 strcat(name, in[i].name);
421                 printf("Getting file dimensions, file : %s        \r", in[i].name);
422                 if(FileExists(name))
423                 {
424                         LoadAnyImage(name, NULL, NULL, &width, &height);
425                         in[i].depth = 32;
426                         in[i].rw = width;
427                         in[i].w = width;                                                // makes it width in 
428                         in[i].h = height;
429                         in[i].cw = (in[i].w + (xcharsize - 1)) / xcharsize;
430                         in[i].ch = (in[i].h + (ycharsize - 1)) / ycharsize;
431
432                         if (!CheckCoords(&in[i]) && (in[i].x >= 0))
433                         {
434                                 printf("Error : texture %s out of bounds.\n", in[i].name);
435                                 return(false);
436                         }
437                         valid++;
438                 }
439                 else
440                 {
441                         in[i].depth = 0;
442                         in[i].x = -1;
443                         in[i].y = -1;
444                         in[i].w = 0;
445                         in[i].h = 0;
446                 }
447         }
448         printf("\n\n");
449         return(true);
450 }
451
452 // Sorts files into order for optimal space finding
453 // Fixed position ones first, followed by the others in descending size
454 // The theory being that it is easier to find space for smaller textures.
455 // size = (width + height)
456 // For space finding it is easier to place a 32x32 than a 128x2
457
458 #define WEIGHT  0x8000
459
460 void    Swap(Coords *a, Coords *b)
461 {
462         Coords          c;
463
464         c = *a;
465         *a = *b;
466         *b = c;
467 }
468
469 void    SortInNames()
470 {
471         int             i, j;
472         int             largest, largcount;
473         int             size;
474
475         printf("Sorting filenames by size.\n\n");
476
477         for (j = 0; j < filenum; j++)
478         {
479                 largest = -1;
480                 largcount = -1;
481
482                 for (i = j; i < filenum; i++)
483                 {
484                         if (in[i].depth)
485                         {
486                                 size = in[i].w + in[i].h;
487                 
488                                 if ((in[i].x < 0) && (size > largest))
489                                 {
490                                         largcount = i;
491                                         largest = size;
492                                 }
493                         }
494                 }
495                 if ((largcount >= 0) && (largcount != j))
496                         Swap(&in[j], &in[largcount]);
497         }
498 }
499
500 int     SetVars(char *name)
501 {
502         if (!GetScriptInfo(name))
503                 return(false);
504
505         if (!CheckVars())
506                 return(false);
507
508         destsize = out.w * out.h;
509
510         out.cw = out.w / xcharsize;
511         out.ch = out.h / ycharsize;
512
513         if ((usagemap = (long *)SafeMalloc(destsize * 4, "")) == NULL)
514                 return(false);
515         if ((outpixels = (long *)SafeMalloc(destsize * 4, "")) == NULL)
516                 return(false); 
517         if ((bmptemp = (void *)SafeMalloc(destsize * 4, "")) == NULL)
518                 return(false);
519         if ((map = (byte *)SafeMalloc(destsize / (xcharsize * ycharsize), "")) == NULL)
520                 return(false);
521
522         if (GetFileDimensions() == false)
523                 return(false);
524
525         if (dosort)
526                 SortInNames();
527
528         return(true);
529 }
530 /****************************************************/
531 /* Actual copying routines                                                      */
532 /****************************************************/
533
534 int FindCoords(Coords *coord)
535 {
536         int             tx, ty;
537
538         if (coord->x >= 0)
539         {       
540                 SetMap(coord);
541                 return(true);
542         }
543         else
544         {
545                 for (ty = 0; ty < out.ch; ty++)
546                 {
547                         for (tx = 0; tx < out.cw; tx++)
548                         {
549                                 coord->x = (tx * xcharsize);
550                                 coord->y = (ty * ycharsize);
551         
552                                 if (CheckCoords(coord) && !TryPlace(coord))
553                                 {
554                                         SetMap(coord);
555                                         return(true);
556                                 }
557                         }
558                 }
559         }
560         coord->x = -1;
561         coord->y = -1;
562
563         return(false);
564 }
565
566 void CheckBaseline(int i)
567 {
568         int             y;
569         long    *pix;
570
571         in[i].baseline = -1;
572         pix = (long *)pixels;
573
574         for(y = 0; y < in[i].h; y++, pix += in[i].w)
575         {
576                 if((*pix & 0x00ffffff) == 0x00ff00ff)
577                 {
578                         in[i].baseline = y;
579                         break;
580                 }
581         }
582         pix = (long *)pixels;
583         for(y = 0; y < in[i].w * in[i].h; y++, pix++)
584         {
585                 if((*pix & 0x00ffffff) == 0x00ff00ff)
586                 {
587                         *pix = 0;
588                 }
589         }
590
591         if(in[i].baseline == -1)
592         {
593                 printf("\nERROR : %s has no baseline\n", in[i].name);
594                 nobaseline++;
595         }
596 }
597
598 void    CopyToMain32(Coords *coord)
599 {
600         int                     x;
601         int                     y;
602         long            *source;
603         long            *dest;
604
605         x = coord->x;
606         y = coord->y;
607
608         source = (long *)pixels;
609         dest = (long *)(outpixels + x + (y * out.w));
610
611         for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
612         {
613                 for (x = 0; x < coord->w; x++)
614                 {
615                         *dest++ = *source++;
616                 }
617         }
618 }
619
620 void CreateMain()
621 {
622         int                     i, count;
623         int                     width, height;
624         char            name[128];
625         
626         for (i = 0, count = 0; i < filenum; i++)
627         {
628                 if (in[i].depth)
629                 {
630                         printf("\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline);
631                         count++;
632                         if (!FindCoords(&in[i]))
633                                 missed++;
634                         else
635                         {
636                                 strcpy(name, sourcedir);
637                                 strcat(name, in[i].name);
638                                 LoadAnyImage(name, &pixels, NULL, &width, &height);
639                                 CheckBaseline(i);
640                                 CheckOverlap(&in[i]);
641                                 CopyToMain32(&in[i]);
642                                 SetUsageMap(&in[i]);
643                         }
644                 }
645         }
646 }
647
648 void Cmd_TextureMix()
649 {
650         miptex32_t              *qtex32;
651         char                    filename[1024];
652         int                             size;
653
654         InitVars();
655
656         GetScriptToken (false);
657
658         strcpy(root, token);
659         RemoveExt(root);
660         RemoveLeading(root);
661
662         strcpy(filename, ExpandPathAndArchive(token));
663         if (SetVars(filename))
664         {
665                 // Create combined texture
666                 percent = ((TotalArea() * 100) / (out.w * out.h));
667                 printf("Total area consumed : %d%%\n", percent);
668                 printf("Texture resolution  : %dx%d pixels.\n", xcharsize, ycharsize);
669                 CreateMain();
670
671                 // Save image as m32
672                 sprintf (filename, "%spics/misc/%s.m32", gamedir, out.name);
673                 qtex32 = CreateMip32((unsigned *)outpixels, out.w, out.h, &size, false);
674
675                 qtex32->contents = 0;
676                 qtex32->value = 0;
677                 qtex32->scale_x = 1.0;
678                 qtex32->scale_y = 1.0;
679                 sprintf (qtex32->name, "misc/%s", out.name);
680
681                 printf ("\n\nwriting %s\n", filename);
682                 SaveFile (filename, (byte *)qtex32, size);
683                 free (qtex32);
684
685                 // Save out script file
686                 sprintf (filename, "%spics/misc/%s.fnt", gamedir, outscript);
687                 printf("Writing %s as script file\n", filename);
688                 if (!SaveScript(filename))
689                 {
690                         printf("Unable to save output script.\n");
691                 }
692         }
693         printf("Everythings groovy.\n");
694         Cleanup();
695 }
696
697 // end
698