2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
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
67 //////////////////////////////////////////////////
68 // Setting the char based usage map //
69 //////////////////////////////////////////////////
71 byte TryPlace(Coords *coord)
77 mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
79 for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
81 for (x = 0; x < coord->cw; x++)
83 if (entry |= *mapitem++ & 8)
92 void SetMap(Coords *coord)
97 mapitem = map + (coord->x / xcharsize) + ((coord->y / ycharsize) * out.cw);
99 for (y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw)
100 for (x = 0; x < coord->cw; x++)
104 //////////////////////////////////////////////////
105 // Setting the pixel based usage map //
106 //////////////////////////////////////////////////
108 void CheckOverlap(Coords *coord)
117 dest = (long *)(usagemap + x + (y * out.w));
119 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
121 for (x = 0; x < coord->w; x++)
132 void SetUsageMap(Coords *coord)
141 dest = (long *)(usagemap + x + (y * out.w));
143 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
145 for (x = 0; x < coord->w; x++)
147 *dest++ = coord->col;
152 //////////////////////////////////////////////////
153 // Flips the BMP image to the correct way up //
154 //////////////////////////////////////////////////
156 void CopyLine(byte *dest, byte *src, int size)
160 for (x = 0; x < size; x++)
164 /****************************************************/
165 /* Printing headers etc */
166 /****************************************************/
168 void RemoveLeading(char *name)
173 for(i = strlen(name) - 1; i > 0; i--)
175 if((name[i] == '\\') || (name[i] == '/'))
177 strcpy(temp, name + i + 1);
184 void RemoveExt(char *name)
186 while ((*name != '.') && *name)
191 /****************************************************/
192 /* Misc calcualtions */
193 /****************************************************/
200 for (i = 0; i < (filenum + 2); i++)
201 total += in[i].w * in[i].h;
206 /****************************************************/
207 /* Setup and checking of all info */
208 /****************************************************/
219 memset(outscript, 0, sizeof(outscript));
220 memset(outscript, 0, sizeof(sourcedir));
221 memset(outscript, 0, sizeof(outusage));
222 memset(outscript, 0, sizeof(root));
224 memset(in, 0, sizeof(in));
225 memset(&out, 0, sizeof(out));
241 typedef struct glxy_s
243 float xl, yt, xr, yb;
247 int SaveScript(char *name)
253 if(fp = fopen(name, "wb"))
255 for (j = 0; j < filenum; j++)
257 for (i = 0; i < filenum; i++)
259 if (in[i].index == j)
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;
269 buff.baseline = in[i].baseline;
273 memset(&buff, 0, sizeof(glxy_t));
275 fwrite(&buff, 1, sizeof(glxy_t), fp);
287 int GetScriptInfo(char *name)
292 char delims[] = {" \t,\n"};
294 printf("Opening script file %s.\n", name);
296 if (fp = fopen(name, "r"))
298 while(fgets(buffer, 256, fp))
300 if (strncmp(buffer, "//", 2) && strncmp(buffer, "\n", 1))
303 strcpy(tempbuff, buffer);
304 if (strcmp(strtok(tempbuff, delims), "OUTPUT") == 0)
306 strcpy(out.name, strtok(NULL, delims));
310 strcpy(tempbuff, buffer);
311 if (strcmp(strtok(tempbuff, delims), "SOURCEDIR") == 0)
313 strcpy(tempbuff, strtok(NULL, delims));
314 strcpy(sourcedir, ExpandPathAndArchive(tempbuff));
317 strcpy(tempbuff, buffer);
318 if (strcmp(strtok(tempbuff, delims), "DOSORT") == 0)
321 strcpy(tempbuff, buffer);
322 if (strcmp(strtok(tempbuff, delims), "XCHARSIZE") == 0)
323 xcharsize = strtol(strtok(NULL, delims), NULL, 0);
325 strcpy(tempbuff, buffer);
326 if (strcmp(strtok(tempbuff, delims), "YCHARSIZE") == 0)
327 ycharsize = strtol(strtok(NULL, delims), NULL, 0);
329 strcpy(tempbuff, buffer);
330 if (strcmp(strtok(tempbuff, delims), "OUTSCRIPT") == 0)
332 strcpy(outscript, strtok(NULL, delims));
336 strcpy(tempbuff, buffer);
337 if (strcmp(strtok(tempbuff, delims), "OUTUSAGE") == 0)
338 strcpy(outusage, strtok(NULL, delims));
340 strcpy(tempbuff, buffer);
341 if (strcmp(strtok(tempbuff, delims), "POS") == 0)
343 out.w = strtol(strtok(NULL, delims), NULL, 0);
344 out.h = strtol(strtok(NULL, delims), NULL, 0);
347 strcpy(tempbuff, buffer);
348 if (strcmp(strtok(tempbuff, delims), "FILE") == 0)
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);
363 printf("ERROR : Could not open script file.\n");
372 if (out.name[0] == 0)
374 printf("ERROR : No output name specified.\n");
377 if ((out.w <= 0) || (out.h <= 0))
379 printf("ERROR : Invalid VRAM coordinates.\n");
384 printf("ERROR : No input files specified.\n");
387 for (i = 0; i < filenum; i++)
388 if (in[i].name[0] == 0)
390 printf("ERROR : Input filename invalid.\n");
396 // Makes sure texture is totally within the output area
398 int CheckCoords(Coords *coord)
400 if ((coord->x + coord->w) > out.w)
402 if ((coord->y + coord->h) > out.h)
407 // Gets the width, height, palette width and palette height of each BMP file
409 int GetFileDimensions()
415 for (i = 0; i < filenum; i++)
419 strcpy(name, sourcedir);
420 strcat(name, in[i].name);
421 printf("Getting file dimensions, file : %s \r", in[i].name);
424 LoadAnyImage(name, NULL, NULL, &width, &height);
427 in[i].w = width; // makes it width in
429 in[i].cw = (in[i].w + (xcharsize - 1)) / xcharsize;
430 in[i].ch = (in[i].h + (ycharsize - 1)) / ycharsize;
432 if (!CheckCoords(&in[i]) && (in[i].x >= 0))
434 printf("Error : texture %s out of bounds.\n", in[i].name);
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
458 #define WEIGHT 0x8000
460 void Swap(Coords *a, Coords *b)
472 int largest, largcount;
475 printf("Sorting filenames by size.\n\n");
477 for (j = 0; j < filenum; j++)
482 for (i = j; i < filenum; i++)
486 size = in[i].w + in[i].h;
488 if ((in[i].x < 0) && (size > largest))
495 if ((largcount >= 0) && (largcount != j))
496 Swap(&in[j], &in[largcount]);
500 int SetVars(char *name)
502 if (!GetScriptInfo(name))
508 destsize = out.w * out.h;
510 out.cw = out.w / xcharsize;
511 out.ch = out.h / ycharsize;
513 if ((usagemap = (long *)SafeMalloc(destsize * 4, "")) == NULL)
515 if ((outpixels = (long *)SafeMalloc(destsize * 4, "")) == NULL)
517 if ((bmptemp = (void *)SafeMalloc(destsize * 4, "")) == NULL)
519 if ((map = (byte *)SafeMalloc(destsize / (xcharsize * ycharsize), "")) == NULL)
522 if (GetFileDimensions() == false)
530 /****************************************************/
531 /* Actual copying routines */
532 /****************************************************/
534 int FindCoords(Coords *coord)
545 for (ty = 0; ty < out.ch; ty++)
547 for (tx = 0; tx < out.cw; tx++)
549 coord->x = (tx * xcharsize);
550 coord->y = (ty * ycharsize);
552 if (CheckCoords(coord) && !TryPlace(coord))
566 void CheckBaseline(int i)
572 pix = (long *)pixels;
574 for(y = 0; y < in[i].h; y++, pix += in[i].w)
576 if((*pix & 0x00ffffff) == 0x00ff00ff)
582 pix = (long *)pixels;
583 for(y = 0; y < in[i].w * in[i].h; y++, pix++)
585 if((*pix & 0x00ffffff) == 0x00ff00ff)
591 if(in[i].baseline == -1)
593 printf("\nERROR : %s has no baseline\n", in[i].name);
598 void CopyToMain32(Coords *coord)
608 source = (long *)pixels;
609 dest = (long *)(outpixels + x + (y * out.w));
611 for (y = 0; y < coord->h; y++, dest += out.w - coord->w)
613 for (x = 0; x < coord->w; x++)
626 for (i = 0, count = 0; i < filenum; i++)
630 printf("\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline);
632 if (!FindCoords(&in[i]))
636 strcpy(name, sourcedir);
637 strcat(name, in[i].name);
638 LoadAnyImage(name, &pixels, NULL, &width, &height);
640 CheckOverlap(&in[i]);
641 CopyToMain32(&in[i]);
648 void Cmd_TextureMix()
656 GetScriptToken (false);
662 strcpy(filename, ExpandPathAndArchive(token));
663 if (SetVars(filename))
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);
672 sprintf (filename, "%spics/misc/%s.m32", gamedir, out.name);
673 qtex32 = CreateMip32((unsigned *)outpixels, out.w, out.h, &size, false);
675 qtex32->contents = 0;
677 qtex32->scale_x = 1.0;
678 qtex32->scale_y = 1.0;
679 sprintf (qtex32->name, "misc/%s", out.name);
681 printf ("\n\nwriting %s\n", filename);
682 SaveFile (filename, (byte *)qtex32, size);
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))
690 printf("Unable to save output script.\n");
693 printf("Everythings groovy.\n");