2 Copyright (C) 1999-2007 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 ){
76 mapitem = map + ( coord->x / xcharsize ) + ( ( coord->y / ycharsize ) * out.cw );
78 for ( y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw )
80 for ( x = 0; x < coord->cw; x++ )
82 if ( entry |= *mapitem++ & 8 ) {
90 void SetMap( Coords *coord ){
94 mapitem = map + ( coord->x / xcharsize ) + ( ( coord->y / ycharsize ) * out.cw );
96 for ( y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw )
97 for ( x = 0; x < coord->cw; x++ )
101 //////////////////////////////////////////////////
102 // Setting the pixel based usage map //
103 //////////////////////////////////////////////////
105 void CheckOverlap( Coords *coord ){
113 dest = (long *)( usagemap + x + ( y * out.w ) );
115 for ( y = 0; y < coord->h; y++, dest += out.w - coord->w )
117 for ( x = 0; x < coord->w; x++ )
127 void SetUsageMap( Coords *coord ){
135 dest = (long *)( usagemap + x + ( y * out.w ) );
137 for ( y = 0; y < coord->h; y++, dest += out.w - coord->w )
139 for ( x = 0; x < coord->w; x++ )
141 *dest++ = coord->col;
146 //////////////////////////////////////////////////
147 // Flips the BMP image to the correct way up //
148 //////////////////////////////////////////////////
150 void CopyLine( byte *dest, byte *src, int size ){
153 for ( x = 0; x < size; x++ )
157 /****************************************************/
158 /* Printing headers etc */
159 /****************************************************/
161 void RemoveLeading( char *name ){
165 for ( i = strlen( name ) - 1; i > 0; i-- )
167 if ( ( name[i] == '\\' ) || ( name[i] == '/' ) ) {
168 strcpy( temp, name + i + 1 );
169 strcpy( name, temp );
175 void RemoveExt( char *name ){
176 while ( ( *name != '.' ) && *name )
181 /****************************************************/
182 /* Misc calcualtions */
183 /****************************************************/
189 for ( i = 0; i < ( filenum + 2 ); i++ )
190 total += in[i].w * in[i].h;
195 /****************************************************/
196 /* Setup and checking of all info */
197 /****************************************************/
207 memset( outscript, 0, sizeof( outscript ) );
208 memset( outscript, 0, sizeof( sourcedir ) );
209 memset( outscript, 0, sizeof( outusage ) );
210 memset( outscript, 0, sizeof( root ) );
212 memset( in, 0, sizeof( in ) );
213 memset( &out, 0, sizeof( out ) );
233 typedef struct glxy_s
235 float xl, yt, xr, yb;
239 int SaveScript( char *name ){
244 if ( fp = fopen( name, "wb" ) ) {
245 for ( j = 0; j < filenum; j++ )
247 for ( i = 0; i < filenum; i++ )
249 if ( in[i].index == j ) {
251 buff.xl = (float)in[i].x / (float)out.w;
252 buff.yt = (float)in[i].y / (float)out.h;
253 buff.xr = ( (float)in[i].w + (float)in[i].x ) / (float)out.w;
254 buff.yb = ( (float)in[i].h + (float)in[i].y ) / (float)out.h;
257 buff.baseline = in[i].baseline;
261 memset( &buff, 0, sizeof( glxy_t ) );
263 fwrite( &buff, 1, sizeof( glxy_t ), fp );
276 int GetScriptInfo( char *name ){
280 char delims[] = {" \t,\n"};
282 printf( "Opening script file %s.\n", name );
284 if ( fp = fopen( name, "r" ) ) {
285 while ( fgets( buffer, 256, fp ) )
287 if ( strncmp( buffer, "//", 2 ) && strncmp( buffer, "\n", 1 ) ) {
289 strcpy( tempbuff, buffer );
290 if ( strcmp( strtok( tempbuff, delims ), "OUTPUT" ) == 0 ) {
291 strcpy( out.name, strtok( NULL, delims ) );
295 strcpy( tempbuff, buffer );
296 if ( strcmp( strtok( tempbuff, delims ), "SOURCEDIR" ) == 0 ) {
297 strcpy( tempbuff, strtok( NULL, delims ) );
298 strcpy( sourcedir, ExpandPathAndArchive( tempbuff ) );
301 strcpy( tempbuff, buffer );
302 if ( strcmp( strtok( tempbuff, delims ), "DOSORT" ) == 0 ) {
306 strcpy( tempbuff, buffer );
307 if ( strcmp( strtok( tempbuff, delims ), "XCHARSIZE" ) == 0 ) {
308 xcharsize = strtol( strtok( NULL, delims ), NULL, 0 );
311 strcpy( tempbuff, buffer );
312 if ( strcmp( strtok( tempbuff, delims ), "YCHARSIZE" ) == 0 ) {
313 ycharsize = strtol( strtok( NULL, delims ), NULL, 0 );
316 strcpy( tempbuff, buffer );
317 if ( strcmp( strtok( tempbuff, delims ), "OUTSCRIPT" ) == 0 ) {
318 strcpy( outscript, strtok( NULL, delims ) );
322 strcpy( tempbuff, buffer );
323 if ( strcmp( strtok( tempbuff, delims ), "OUTUSAGE" ) == 0 ) {
324 strcpy( outusage, strtok( NULL, delims ) );
327 strcpy( tempbuff, buffer );
328 if ( strcmp( strtok( tempbuff, delims ), "POS" ) == 0 ) {
329 out.w = strtol( strtok( NULL, delims ), NULL, 0 );
330 out.h = strtol( strtok( NULL, delims ), NULL, 0 );
333 strcpy( tempbuff, buffer );
334 if ( strcmp( strtok( tempbuff, delims ), "FILE" ) == 0 ) {
335 strcpy( in[filenum].name, strtok( NULL, delims ) );
336 in[filenum].x = strtol( strtok( NULL, delims ), NULL, 0 );
337 in[filenum].y = strtol( strtok( NULL, delims ), NULL, 0 );
338 in[filenum].col = strtol( strtok( NULL, delims ), NULL, 0 );
348 printf( "ERROR : Could not open script file.\n" );
356 if ( out.name[0] == 0 ) {
357 printf( "ERROR : No output name specified.\n" );
360 if ( ( out.w <= 0 ) || ( out.h <= 0 ) ) {
361 printf( "ERROR : Invalid VRAM coordinates.\n" );
364 if ( filenum == 0 ) {
365 printf( "ERROR : No input files specified.\n" );
368 for ( i = 0; i < filenum; i++ )
369 if ( in[i].name[0] == 0 ) {
370 printf( "ERROR : Input filename invalid.\n" );
376 // Makes sure texture is totally within the output area
378 int CheckCoords( Coords *coord ){
379 if ( ( coord->x + coord->w ) > out.w ) {
382 if ( ( coord->y + coord->h ) > out.h ) {
388 // Gets the width, height, palette width and palette height of each BMP file
390 int GetFileDimensions(){
395 for ( i = 0; i < filenum; i++ )
399 strcpy( name, sourcedir );
400 strcat( name, in[i].name );
401 printf( "Getting file dimensions, file : %s \r", in[i].name );
402 if ( FileExists( name ) ) {
403 LoadAnyImage( name, NULL, NULL, &width, &height );
406 in[i].w = width; // makes it width in
408 in[i].cw = ( in[i].w + ( xcharsize - 1 ) ) / xcharsize;
409 in[i].ch = ( in[i].h + ( ycharsize - 1 ) ) / ycharsize;
411 if ( !CheckCoords( &in[i] ) && ( in[i].x >= 0 ) ) {
412 printf( "Error : texture %s out of bounds.\n", in[i].name );
430 // Sorts files into order for optimal space finding
431 // Fixed position ones first, followed by the others in descending size
432 // The theory being that it is easier to find space for smaller textures.
433 // size = (width + height)
434 // For space finding it is easier to place a 32x32 than a 128x2
436 #define WEIGHT 0x8000
438 void Swap( Coords *a, Coords *b ){
448 int largest, largcount;
451 printf( "Sorting filenames by size.\n\n" );
453 for ( j = 0; j < filenum; j++ )
458 for ( i = j; i < filenum; i++ )
461 size = in[i].w + in[i].h;
463 if ( ( in[i].x < 0 ) && ( size > largest ) ) {
469 if ( ( largcount >= 0 ) && ( largcount != j ) ) {
470 Swap( &in[j], &in[largcount] );
475 int SetVars( char *name ){
476 if ( !GetScriptInfo( name ) ) {
480 if ( !CheckVars() ) {
484 destsize = out.w * out.h;
486 out.cw = out.w / xcharsize;
487 out.ch = out.h / ycharsize;
489 if ( ( usagemap = (long *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
492 if ( ( outpixels = (long *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
495 if ( ( bmptemp = (void *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
498 if ( ( map = (byte *)SafeMalloc( destsize / ( xcharsize * ycharsize ), "" ) ) == NULL ) {
502 if ( GetFileDimensions() == false ) {
512 /****************************************************/
513 /* Actual copying routines */
514 /****************************************************/
516 int FindCoords( Coords *coord ){
519 if ( coord->x >= 0 ) {
525 for ( ty = 0; ty < out.ch; ty++ )
527 for ( tx = 0; tx < out.cw; tx++ )
529 coord->x = ( tx * xcharsize );
530 coord->y = ( ty * ycharsize );
532 if ( CheckCoords( coord ) && !TryPlace( coord ) ) {
545 void CheckBaseline( int i ){
550 pix = (long *)pixels;
552 for ( y = 0; y < in[i].h; y++, pix += in[i].w )
554 if ( ( *pix & 0x00ffffff ) == 0x00ff00ff ) {
559 pix = (long *)pixels;
560 for ( y = 0; y < in[i].w * in[i].h; y++, pix++ )
562 if ( ( *pix & 0x00ffffff ) == 0x00ff00ff ) {
567 if ( in[i].baseline == -1 ) {
568 printf( "\nERROR : %s has no baseline\n", in[i].name );
573 void CopyToMain32( Coords *coord ){
582 source = (long *)pixels;
583 dest = (long *)( outpixels + x + ( y * out.w ) );
585 for ( y = 0; y < coord->h; y++, dest += out.w - coord->w )
587 for ( x = 0; x < coord->w; x++ )
599 for ( i = 0, count = 0; i < filenum; i++ )
602 printf( "\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline );
604 if ( !FindCoords( &in[i] ) ) {
609 strcpy( name, sourcedir );
610 strcat( name, in[i].name );
611 LoadAnyImage( name, &pixels, NULL, &width, &height );
613 CheckOverlap( &in[i] );
614 CopyToMain32( &in[i] );
615 SetUsageMap( &in[i] );
621 void Cmd_TextureMix(){
628 GetScriptToken( false );
630 strcpy( root, token );
632 RemoveLeading( root );
634 strcpy( filename, ExpandPathAndArchive( token ) );
635 if ( SetVars( filename ) ) {
636 // Create combined texture
637 percent = ( ( TotalArea() * 100 ) / ( out.w * out.h ) );
638 printf( "Total area consumed : %d%%\n", percent );
639 printf( "Texture resolution : %dx%d pixels.\n", xcharsize, ycharsize );
643 sprintf( filename, "%spics/misc/%s.m32", gamedir, out.name );
644 qtex32 = CreateMip32( (unsigned *)outpixels, out.w, out.h, &size, false );
646 qtex32->contents = 0;
648 qtex32->scale_x = 1.0;
649 qtex32->scale_y = 1.0;
650 sprintf( qtex32->name, "misc/%s", out.name );
652 printf( "\n\nwriting %s\n", filename );
653 SaveFile( filename, (byte *)qtex32, size );
656 // Save out script file
657 sprintf( filename, "%spics/misc/%s.fnt", gamedir, outscript );
658 printf( "Writing %s as script file\n", filename );
659 if ( !SaveScript( filename ) ) {
660 printf( "Unable to save output script.\n" );
663 printf( "Everythings groovy.\n" );