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
28 #define strlwr strlower
29 #endif // !GDEF_OS_WINDOWS
57 byte *pixels = NULL; // Buffer to load image
58 long *outpixels = NULL; // Buffer to store combined textures
59 long *usagemap = NULL; // Buffer of usage map
60 void *bmptemp = NULL; // Buffer of usage map
71 //////////////////////////////////////////////////
72 // Setting the char based usage map //
73 //////////////////////////////////////////////////
75 byte TryPlace( Coords *coord ){
80 mapitem = map + ( coord->x / xcharsize ) + ( ( coord->y / ycharsize ) * out.cw );
82 for ( y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw )
84 for ( x = 0; x < coord->cw; x++ )
86 if ( entry |= *mapitem++ & 8 ) {
94 void SetMap( Coords *coord ){
98 mapitem = map + ( coord->x / xcharsize ) + ( ( coord->y / ycharsize ) * out.cw );
100 for ( y = 0; y < coord->ch; y++, mapitem += out.cw - coord->cw )
101 for ( x = 0; x < coord->cw; x++ )
105 //////////////////////////////////////////////////
106 // Setting the pixel based usage map //
107 //////////////////////////////////////////////////
109 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++ )
131 void SetUsageMap( Coords *coord ){
139 dest = (long *)( usagemap + x + ( y * out.w ) );
141 for ( y = 0; y < coord->h; y++, dest += out.w - coord->w )
143 for ( x = 0; x < coord->w; x++ )
145 *dest++ = coord->col;
150 //////////////////////////////////////////////////
151 // Flips the BMP image to the correct way up //
152 //////////////////////////////////////////////////
154 void CopyLine( byte *dest, byte *src, int size ){
157 for ( x = 0; x < size; x++ )
161 /****************************************************/
162 /* Printing headers etc */
163 /****************************************************/
165 void RemoveLeading( char *name ){
169 for ( i = strlen( name ) - 1; i > 0; i-- )
171 if ( ( name[i] == '\\' ) || ( name[i] == '/' ) ) {
172 strcpy( temp, name + i + 1 );
173 strcpy( name, temp );
179 void RemoveExt( char *name ){
180 while ( ( *name != '.' ) && *name )
185 /****************************************************/
186 /* Misc calcualtions */
187 /****************************************************/
193 for ( i = 0; i < ( filenum + 2 ); i++ )
194 total += in[i].w * in[i].h;
199 /****************************************************/
200 /* Setup and checking of all info */
201 /****************************************************/
211 memset( outscript, 0, sizeof( outscript ) );
212 memset( outscript, 0, sizeof( sourcedir ) );
213 memset( outscript, 0, sizeof( outusage ) );
214 memset( outscript, 0, sizeof( root ) );
216 memset( in, 0, sizeof( in ) );
217 memset( &out, 0, sizeof( out ) );
237 typedef struct glxy_s
239 float xl, yt, xr, yb;
243 int SaveScript( char *name ){
248 if ( fp = fopen( name, "wb" ) ) {
249 for ( j = 0; j < filenum; j++ )
251 for ( i = 0; i < filenum; i++ )
253 if ( in[i].index == j ) {
255 buff.xl = (float)in[i].x / (float)out.w;
256 buff.yt = (float)in[i].y / (float)out.h;
257 buff.xr = ( (float)in[i].w + (float)in[i].x ) / (float)out.w;
258 buff.yb = ( (float)in[i].h + (float)in[i].y ) / (float)out.h;
261 buff.baseline = in[i].baseline;
265 memset( &buff, 0, sizeof( glxy_t ) );
267 fwrite( &buff, 1, sizeof( glxy_t ), fp );
280 int GetScriptInfo( char *name ){
284 char delims[] = {" \t,\n"};
286 printf( "Opening script file %s.\n", name );
288 if ( fp = fopen( name, "r" ) ) {
289 while ( fgets( buffer, 256, fp ) )
291 if ( strncmp( buffer, "//", 2 ) && strncmp( buffer, "\n", 1 ) ) {
293 strcpy( tempbuff, buffer );
294 if ( strcmp( strtok( tempbuff, delims ), "OUTPUT" ) == 0 ) {
295 strcpy( out.name, strtok( NULL, delims ) );
299 strcpy( tempbuff, buffer );
300 if ( strcmp( strtok( tempbuff, delims ), "SOURCEDIR" ) == 0 ) {
301 strcpy( tempbuff, strtok( NULL, delims ) );
302 strcpy( sourcedir, ExpandPathAndArchive( tempbuff ) );
305 strcpy( tempbuff, buffer );
306 if ( strcmp( strtok( tempbuff, delims ), "DOSORT" ) == 0 ) {
310 strcpy( tempbuff, buffer );
311 if ( strcmp( strtok( tempbuff, delims ), "XCHARSIZE" ) == 0 ) {
312 xcharsize = strtol( strtok( NULL, delims ), NULL, 0 );
315 strcpy( tempbuff, buffer );
316 if ( strcmp( strtok( tempbuff, delims ), "YCHARSIZE" ) == 0 ) {
317 ycharsize = strtol( strtok( NULL, delims ), NULL, 0 );
320 strcpy( tempbuff, buffer );
321 if ( strcmp( strtok( tempbuff, delims ), "OUTSCRIPT" ) == 0 ) {
322 strcpy( outscript, strtok( NULL, delims ) );
326 strcpy( tempbuff, buffer );
327 if ( strcmp( strtok( tempbuff, delims ), "OUTUSAGE" ) == 0 ) {
328 strcpy( outusage, strtok( NULL, delims ) );
331 strcpy( tempbuff, buffer );
332 if ( strcmp( strtok( tempbuff, delims ), "POS" ) == 0 ) {
333 out.w = strtol( strtok( NULL, delims ), NULL, 0 );
334 out.h = strtol( strtok( NULL, delims ), NULL, 0 );
337 strcpy( tempbuff, buffer );
338 if ( strcmp( strtok( tempbuff, delims ), "FILE" ) == 0 ) {
339 strcpy( in[filenum].name, strtok( NULL, delims ) );
340 in[filenum].x = strtol( strtok( NULL, delims ), NULL, 0 );
341 in[filenum].y = strtol( strtok( NULL, delims ), NULL, 0 );
342 in[filenum].col = strtol( strtok( NULL, delims ), NULL, 0 );
352 printf( "ERROR : Could not open script file.\n" );
360 if ( out.name[0] == 0 ) {
361 printf( "ERROR : No output name specified.\n" );
364 if ( ( out.w <= 0 ) || ( out.h <= 0 ) ) {
365 printf( "ERROR : Invalid VRAM coordinates.\n" );
368 if ( filenum == 0 ) {
369 printf( "ERROR : No input files specified.\n" );
372 for ( i = 0; i < filenum; i++ )
373 if ( in[i].name[0] == 0 ) {
374 printf( "ERROR : Input filename invalid.\n" );
380 // Makes sure texture is totally within the output area
382 int CheckCoords( Coords *coord ){
383 if ( ( coord->x + coord->w ) > out.w ) {
386 if ( ( coord->y + coord->h ) > out.h ) {
392 // Gets the width, height, palette width and palette height of each BMP file
394 int GetFileDimensions(){
399 for ( i = 0; i < filenum; i++ )
403 strcpy( name, sourcedir );
404 strcat( name, in[i].name );
405 printf( "Getting file dimensions, file : %s \r", in[i].name );
406 if ( FileExists( name ) ) {
407 LoadAnyImage( name, NULL, NULL, &width, &height );
410 in[i].w = width; // makes it width in
412 in[i].cw = ( in[i].w + ( xcharsize - 1 ) ) / xcharsize;
413 in[i].ch = ( in[i].h + ( ycharsize - 1 ) ) / ycharsize;
415 if ( !CheckCoords( &in[i] ) && ( in[i].x >= 0 ) ) {
416 printf( "Error : texture %s out of bounds.\n", in[i].name );
434 // Sorts files into order for optimal space finding
435 // Fixed position ones first, followed by the others in descending size
436 // The theory being that it is easier to find space for smaller textures.
437 // size = (width + height)
438 // For space finding it is easier to place a 32x32 than a 128x2
440 #define WEIGHT 0x8000
442 void Swap( Coords *a, Coords *b ){
452 int largest, largcount;
455 printf( "Sorting filenames by size.\n\n" );
457 for ( j = 0; j < filenum; j++ )
462 for ( i = j; i < filenum; i++ )
465 size = in[i].w + in[i].h;
467 if ( ( in[i].x < 0 ) && ( size > largest ) ) {
473 if ( ( largcount >= 0 ) && ( largcount != j ) ) {
474 Swap( &in[j], &in[largcount] );
479 int SetVars( char *name ){
480 if ( !GetScriptInfo( name ) ) {
484 if ( !CheckVars() ) {
488 destsize = out.w * out.h;
490 out.cw = out.w / xcharsize;
491 out.ch = out.h / ycharsize;
493 if ( ( usagemap = (long *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
496 if ( ( outpixels = (long *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
499 if ( ( bmptemp = (void *)SafeMalloc( destsize * 4, "" ) ) == NULL ) {
502 if ( ( map = (byte *)SafeMalloc( destsize / ( xcharsize * ycharsize ), "" ) ) == NULL ) {
506 if ( GetFileDimensions() == false ) {
516 /****************************************************/
517 /* Actual copying routines */
518 /****************************************************/
520 int FindCoords( Coords *coord ){
523 if ( coord->x >= 0 ) {
529 for ( ty = 0; ty < out.ch; ty++ )
531 for ( tx = 0; tx < out.cw; tx++ )
533 coord->x = ( tx * xcharsize );
534 coord->y = ( ty * ycharsize );
536 if ( CheckCoords( coord ) && !TryPlace( coord ) ) {
549 void CheckBaseline( int i ){
554 pix = (long *)pixels;
556 for ( y = 0; y < in[i].h; y++, pix += in[i].w )
558 if ( ( *pix & 0x00ffffff ) == 0x00ff00ff ) {
563 pix = (long *)pixels;
564 for ( y = 0; y < in[i].w * in[i].h; y++, pix++ )
566 if ( ( *pix & 0x00ffffff ) == 0x00ff00ff ) {
571 if ( in[i].baseline == -1 ) {
572 printf( "\nERROR : %s has no baseline\n", in[i].name );
577 void CopyToMain32( Coords *coord ){
586 source = (long *)pixels;
587 dest = (long *)( outpixels + x + ( y * out.w ) );
589 for ( y = 0; y < coord->h; y++, dest += out.w - coord->w )
591 for ( x = 0; x < coord->w; x++ )
603 for ( i = 0, count = 0; i < filenum; i++ )
606 printf( "\rProcessing %d of %d (%d missed, %d overlapping, %d nobase)\r", count + 1, valid, missed, overlap, nobaseline );
608 if ( !FindCoords( &in[i] ) ) {
613 strcpy( name, sourcedir );
614 strcat( name, in[i].name );
615 LoadAnyImage( name, &pixels, NULL, &width, &height );
617 CheckOverlap( &in[i] );
618 CopyToMain32( &in[i] );
619 SetUsageMap( &in[i] );
625 void Cmd_TextureMix(){
632 GetScriptToken( false );
634 strcpy( root, token );
636 RemoveLeading( root );
638 strcpy( filename, ExpandPathAndArchive( token ) );
639 if ( SetVars( filename ) ) {
640 // Create combined texture
641 percent = ( ( TotalArea() * 100 ) / ( out.w * out.h ) );
642 printf( "Total area consumed : %d%%\n", percent );
643 printf( "Texture resolution : %dx%d pixels.\n", xcharsize, ycharsize );
647 sprintf( filename, "%spics/misc/%s.m32", gamedir, out.name );
648 qtex32 = CreateMip32( (unsigned *)outpixels, out.w, out.h, &size, false );
650 qtex32->contents = 0;
652 qtex32->scale_x = 1.0;
653 qtex32->scale_y = 1.0;
654 sprintf( qtex32->name, "misc/%s", out.name );
656 printf( "\n\nwriting %s\n", filename );
657 SaveFile( filename, (byte *)qtex32, size );
660 // Save out script file
661 sprintf( filename, "%spics/misc/%s.fnt", gamedir, outscript );
662 printf( "Writing %s as script file\n", filename );
663 if ( !SaveScript( filename ) ) {
664 printf( "Unable to save output script.\n" );
667 printf( "Everythings groovy.\n" );