2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
25 #define MAXFILES 2048
\r
45 Coords in[MAXFILES];
\r
47 char outscript[256];
\r
48 char sourcedir[256];
\r
53 byte *pixels = NULL; // Buffer to load image
\r
54 long *outpixels = NULL; // Buffer to store combined textures
\r
55 long *usagemap = NULL; // Buffer of usage map
\r
56 void *bmptemp = NULL; // Buffer of usage map
\r
67 //////////////////////////////////////////////////
\r
68 // Setting the char based usage map //
\r
69 //////////////////////////////////////////////////
\r
71 byte TryPlace(Coords *coord)
\r
77 mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
\r
79 for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
\r
81 for (x = 0; x < coord->cw; x++)
\r
83 if (entry |= *mapitem++ & 8)
\r
92 void SetMap(Coords *coord)
\r
97 mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
\r
99 for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
\r
100 for (x = 0; x < coord->cw; x++)
\r
104 //////////////////////////////////////////////////
\r
105 // Setting the pixel based usage map //
\r
106 //////////////////////////////////////////////////
\r
108 void CheckOverlap(Coords *coord)
\r
117 dest = (long *)(usagemap + x + (y * out.w));
\r
119 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
\r
121 for (x = 0; x < coord->w; x++)
\r
132 void SetUsageMap(Coords *coord)
\r
141 dest = (long *)(usagemap + x + (y * out.w));
\r
143 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
\r
145 for (x = 0; x < coord->w; x++)
\r
147 *dest++ = coord->col;
\r
152 //////////////////////////////////////////////////
\r
153 // Flips the BMP image to the correct way up //
\r
154 //////////////////////////////////////////////////
\r
156 void CopyLine(byte *dest, byte *src, int size)
\r
160 for (x = 0; x < size; x++)
\r
164 /****************************************************/
\r
165 /* Printing headers etc */
\r
166 /****************************************************/
\r
168 void RemoveLeading(char *name)
\r
173 for(i = strlen(name) - 1; i > 0; i--)
\r
175 if((name[i] == '\\') || (name[i] == '/'))
\r
177 strcpy(temp, name + i + 1);
\r
178 strcpy(name, temp);
\r
184 void RemoveExt(char *name)
\r
186 while ((*name != '.') && *name)
\r
191 /****************************************************/
\r
192 /* Misc calcualtions */
\r
193 /****************************************************/
\r
200 for (i = 0; i < (filenum + 2); i++)
\r
201 total += in[i].w * in[i].h;
\r
206 /****************************************************/
\r
207 /* Setup and checking of all info */
\r
208 /****************************************************/
\r
219 memset(outscript, 0, sizeof(outscript));
\r
220 memset(outscript, 0, sizeof(sourcedir));
\r
221 memset(outscript, 0, sizeof(outusage));
\r
222 memset(outscript, 0, sizeof(root));
\r
224 memset(in, 0, sizeof(in));
\r
225 memset(&out, 0, sizeof(out));
\r
241 typedef struct glxy_s
\r
243 float xl, yt, xr, yb;
\r
244 int w, h, baseline;
\r
247 int SaveScript(char *name)
\r
253 if(fp = fopen(name, "wb"))
\r
255 for (j = 0; j < filenum; j++)
\r
257 for (i = 0; i < filenum; i++)
\r
259 if (in[i].index == j)
\r
263 buff.xl = (float)in[i].x / (float)out.w;
\r
264 buff.yt = (float)in[i].y / (float)out.h;
\r
265 buff.xr = ((float)in[i].w + (float)in[i].x) / (float)out.w;
\r
266 buff.yb = ((float)in[i].h + (float)in[i].y) / (float)out.h;
\r
269 buff.baseline = in[i].baseline;
\r
273 memset(&buff, 0, sizeof(glxy_t));
\r
275 fwrite(&buff, 1, sizeof(glxy_t), fp);
\r
287 int GetScriptInfo(char *name)
\r
291 char tempbuff[256];
\r
292 char delims[] = {" \t,\n"};
\r
294 printf("Opening script file %s.\n", name);
\r
296 if (fp = fopen(name, "r"))
\r
298 while(fgets(buffer, 256, fp))
\r
300 if (strncmp(buffer, "//", 2) && strncmp(buffer, "\n", 1))
\r
303 strcpy(tempbuff, buffer);
\r
304 if (strcmp(strtok(tempbuff, delims), "OUTPUT") == 0)
\r
306 strcpy(out.name, strtok(NULL, delims));
\r
310 strcpy(tempbuff, buffer);
\r
311 if (strcmp(strtok(tempbuff, delims), "SOURCEDIR") == 0)
\r
313 strcpy(tempbuff, strtok(NULL, delims));
\r
314 strcpy(sourcedir, ExpandPathAndArchive(tempbuff));
\r
317 strcpy(tempbuff, buffer);
\r
318 if (strcmp(strtok(tempbuff, delims), "DOSORT") == 0)
\r
321 strcpy(tempbuff, buffer);
\r
322 if (strcmp(strtok(tempbuff, delims), "XCHARSIZE") == 0)
\r
323 xcharsize = strtol(strtok(NULL, delims), NULL, 0);
\r
325 strcpy(tempbuff, buffer);
\r
326 if (strcmp(strtok(tempbuff, delims), "YCHARSIZE") == 0)
\r
327 ycharsize = strtol(strtok(NULL, delims), NULL, 0);
\r
329 strcpy(tempbuff, buffer);
\r
330 if (strcmp(strtok(tempbuff, delims), "OUTSCRIPT") == 0)
\r
332 strcpy(outscript, strtok(NULL, delims));
\r
336 strcpy(tempbuff, buffer);
\r
337 if (strcmp(strtok(tempbuff, delims), "OUTUSAGE") == 0)
\r
338 strcpy(outusage, strtok(NULL, delims));
\r
340 strcpy(tempbuff, buffer);
\r
341 if (strcmp(strtok(tempbuff, delims), "POS") == 0)
\r
343 out.w = strtol(strtok(NULL, delims), NULL, 0);
\r
344 out.h = strtol(strtok(NULL, delims), NULL, 0);
\r
347 strcpy(tempbuff, buffer);
\r
348 if (strcmp(strtok(tempbuff, delims), "FILE") == 0)
\r
350 strcpy(in[filenum].name, strtok(NULL, delims));
\r
351 in[filenum].x = strtol(strtok(NULL, delims), NULL, 0);
\r
352 in[filenum].y = strtol(strtok(NULL, delims), NULL, 0);
\r
353 in[filenum].col = strtol(strtok(NULL, delims), NULL, 0);
\r
363 printf("ERROR : Could not open script file.\n");
\r
372 if (out.name[0] == 0)
\r
374 printf("ERROR : No output name specified.\n");
\r
377 if ((out.w <= 0) || (out.h <= 0))
\r
379 printf("ERROR : Invalid VRAM coordinates.\n");
\r
384 printf("ERROR : No input files specified.\n");
\r
387 for (i = 0; i < filenum; i++)
\r
388 if (in[i].name[0] == 0)
\r
390 printf("ERROR : Input filename invalid.\n");
\r
396 // Makes sure texture is totally within the output area
\r
398 int CheckCoords(Coords *coord)
\r
400 if ((coord->x + coord->w) > out.w)
\r
402 if ((coord->y + coord->h) > out.h)
\r
407 // Gets the width, height, palette width and palette height of each BMP file
\r
409 int GetFileDimensions()
\r
415 for (i = 0; i < filenum; i++)
\r
419 strcpy(name, sourcedir);
\r
420 strcat(name, in[i].name);
\r
421 printf("Getting file dimensions, file : %s \r", in[i].name);
\r
422 if(FileExists(name))
\r
424 LoadAnyImage(name, NULL, NULL, &width, &height);
\r
427 in[i].w = width; // makes it width in
\r
429 in[i].cw = (in[i].w + (xcharsize - 1)) / xcharsize;
\r
430 in[i].ch = (in[i].h + (ycharsize - 1)) / ycharsize;
\r
432 if (!CheckCoords(&in[i]) && (in[i].x >= 0))
\r
434 printf("Error : texture %s out of bounds.\n", in[i].name);
\r
452 // Sorts files into order for optimal space finding
\r
453 // Fixed position ones first, followed by the others in descending size
\r
454 // The theory being that it is easier to find space for smaller textures.
\r
455 // size = (width + height)
\r
456 // For space finding it is easier to place a 32x32 than a 128x2
\r
458 #define WEIGHT 0x8000
\r
460 void Swap(Coords *a, Coords *b)
\r
472 int largest, largcount;
\r
475 printf("Sorting filenames by size.\n\n");
\r
477 for (j = 0; j < filenum; j++)
\r
482 for (i = j; i < filenum; i++)
\r
486 size = in[i].w + in[i].h;
\r
488 if ((in[i].x < 0) && (size > largest))
\r
495 if ((largcount >= 0) && (largcount != j))
\r
496 Swap(&in[j], &in[largcount]);
\r
500 int SetVars(char *name)
\r
502 if (!GetScriptInfo(name))
\r
508 destsize = out.w * out.h;
\r
510 out.cw = out.w / xcharsize;
\r
511 out.ch = out.h / ycharsize;
\r
513 if ((usagemap = (long *)SafeMalloc(destsize * 4, "")) == NULL)
\r
515 if ((outpixels = (long *)SafeMalloc(destsize * 4, "")) == NULL)
\r
517 if ((bmptemp = (void *)SafeMalloc(destsize * 4, "")) == NULL)
\r
519 if ((map = (byte *)SafeMalloc(destsize / (xcharsize * ycharsize), "")) == NULL)
\r
522 if (GetFileDimensions() == false)
\r
530 /****************************************************/
\r
531 /* Actual copying routines */
\r
532 /****************************************************/
\r
534 int FindCoords(Coords *coord)
\r
545 for (ty = 0; ty < out.ch; ty++)
\r
547 for (tx = 0; tx < out.cw; tx++)
\r
549 coord->x = (tx * xcharsize);
\r
550 coord->y = (ty * ycharsize);
\r
552 if (CheckCoords(coord) && !TryPlace(coord))
\r
566 void CheckBaseline(int i)
\r
571 in[i].baseline = -1;
\r
572 pix = (long *)pixels;
\r
574 for(y = 0; y < in[i].h; y++, pix += in[i].w)
\r
576 if((*pix & 0x00ffffff) == 0x00ff00ff)
\r
578 in[i].baseline = y;
\r
582 pix = (long *)pixels;
\r
583 for(y = 0; y < in[i].w * in[i].h; y++, pix++)
\r
585 if((*pix & 0x00ffffff) == 0x00ff00ff)
\r
591 if(in[i].baseline == -1)
\r
593 printf("\nERROR : %s has no baseline\n", in[i].name);
\r
598 void CopyToMain32(Coords *coord)
\r
608 source = (long *)pixels;
\r
609 dest = (long *)(outpixels + x + (y * out.w));
\r
611 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
\r
613 for (x = 0; x < coord->w; x++)
\r
615 *dest++ = *source++;
\r
626 for (i = 0, count = 0; i < filenum; i++)
\r
630 printf("\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline);
\r
632 if (!FindCoords(&in[i]))
\r
636 strcpy(name, sourcedir);
\r
637 strcat(name, in[i].name);
\r
638 LoadAnyImage(name, &pixels, NULL, &width, &height);
\r
640 CheckOverlap(&in[i]);
\r
641 CopyToMain32(&in[i]);
\r
642 SetUsageMap(&in[i]);
\r
648 void Cmd_TextureMix()
\r
650 miptex32_t *qtex32;
\r
651 char filename[1024];
\r
656 GetScriptToken (false);
\r
658 strcpy(root, token);
\r
660 RemoveLeading(root);
\r
662 strcpy(filename, ExpandPathAndArchive(token));
\r
663 if (SetVars(filename))
\r
665 // Create combined texture
\r
666 percent = ((TotalArea() * 100) / (out.w * out.h));
\r
667 printf("Total area consumed : %d%%\n", percent);
\r
668 printf("Texture resolution : %dx%d pixels.\n", xcharsize, ycharsize);
\r
671 // Save image as m32
\r
672 sprintf (filename, "%spics/misc/%s.m32", gamedir, out.name);
\r
673 qtex32 = CreateMip32((unsigned *)outpixels, out.w, out.h, &size, false);
\r
675 qtex32->contents = 0;
\r
677 qtex32->scale_x = 1.0;
\r
678 qtex32->scale_y = 1.0;
\r
679 sprintf (qtex32->name, "misc/%s", out.name);
\r
681 printf ("\n\nwriting %s\n", filename);
\r
682 SaveFile (filename, (byte *)qtex32, size);
\r
685 // Save out script file
\r
686 sprintf (filename, "%spics/misc/%s.fnt", gamedir, outscript);
\r
687 printf("Writing %s as script file\n", filename);
\r
688 if (!SaveScript(filename))
\r
690 printf("Unable to save output script.\n");
\r
693 printf("Everythings groovy.\n");
\r