1 /*--License:
2 	Kyra Sprite Engine
3 	Copyright Lee Thomason (Grinning Lizard Software) 2001-2005
4 	www.grinninglizard.com/kyra
5 	www.sourceforge.net/projects/kyra
6 
7 	Kyra is provided under the LGPL.
8 
9 	I kindly request you display a splash screen (provided in the HTML documentation)
10 	to promote Kyra and acknowledge the software and everyone who has contributed to it,
11 	but it is not required by the license.
12 
13 --- LGPL License --
14 
15     This library is free software; you can redistribute it and/or
16     modify it under the terms of the GNU Lesser General Public
17     License as published by the Free Software Foundation; either
18     version 2.1 of the License, or (at your option) any later version.
19 
20     This library is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23     Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public
26     License along with this library; if not, write to the Free Software
27     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 
29 	The full text of the license can be found in lgpl.txt
30 */
31 
32 #ifdef _MSC_VER
33 // Disable the no-exception handling warning.
34 #pragma warning( disable : 4530 )
35 #pragma warning( disable : 4786 )
36 #endif
37 
38 #include <algorithm>
39 
40 #include "encoder.h"
41 #include "SDL_image.h"
42 #include "../engine/painter.h"
43 #include "../../grinliz/gldebug.h"
44 #include "../../grinliz/gldynamic.h"
45 #include "../engine/parser.h"
46 #include "SDL_rwops.h"
47 #include "SDL_endian.h"
48 #include "../engine/rle.h"
49 #include "../engine/sdlutil.h"
50 #include "../engine/pixelblock.h"
51 #include "../engine/canvasresource.h"
52 #include "../engine/fontresource.h"
53 #include "../engine/tileresource.h"
54 #include "../engine/dataresource.h"
55 #include "../engine/engine.h"
56 #include "../gui/console.h"
57 #include "../util/glstring.h"
58 
59 #ifdef __APPLE__
60 #include <dlfcn.h>
61 #endif
62 
63 using namespace grinliz;
64 
65 ImageLoaderFunc KrEncoder::ImageLoader = 0;
66 
GetImageLoader()67 void KrEncoder::GetImageLoader()
68 {
69 	GLLOG(( "GetImageLoader called\n" ));
70 
71 	void* handle = GL_LoadLibrary( "SDL_image" );
72 	if ( !handle )
73 	{
74 		exit( 1 );
75 	}
76 	ImageLoader = (ImageLoaderFunc) GL_LoadFunction( handle, "IMG_Load" );
77 	GLASSERT( ImageLoader );
78 }
79 
80 
KrEncoder(SDL_RWops * _stream)81 KrEncoder::KrEncoder( SDL_RWops* _stream ) : cachedWrite( _stream ), stream( _stream )
82 {
83 //	idShift[0] = 0;
84 //	idShift[1] = 12;	//0x1000;
85 //	idShift[2] = 10;	//0x400000;
86 //
87 	output = 0;
88 	numRGBA = 0;
89 	numLine = 0;
90 	numSegment = 0;
91 }
92 
93 
Load32Surface(const char * filename,Transparent * trans,int nTrans,std::string * error)94 SDL_Surface* KrEncoder::Load32Surface(	const char* filename,
95 										Transparent* trans,
96 										int nTrans,
97 										std::string* error )
98 {
99 	if ( !ImageLoader )
100 		GetImageLoader();
101 
102 	// Make sure SetImageLoader has been called!
103 	GLASSERT( ImageLoader );
104 	if ( !ImageLoader )
105 	{
106 		return 0;
107 	}
108 
109 	if ( !filename )
110 	{
111 		if ( error ) *error = "No filename for a surface specified";
112 		GLOUTPUT(( "No filename for a surface specified\n" ));
113 		return 0;
114 	}
115 
116 	// Try to load the file.
117 	SDL_Surface* surface = ImageLoader( filename );
118 	if ( !surface )
119 	{
120 		char buf[256];
121 		sprintf( buf, "Failed to load surface '%s'.", filename );
122 
123 		if ( error ) *error = buf;
124 		GLOUTPUT(( "No filename for a surface specified\n" ));
125 		return 0;
126 	}
127 
128 	// The image can be 32 bits or less. A NON-32 bit image has
129 	// color(s) that are marked transparent. A 32 bit image
130 	// simply uses the alpha channel. To simplify things,
131 	// images are converted to 32 bit before they
132 	// are returned.
133 	//
134 	// Oddly, SDL_Image will sometimes return a 32 bit image,
135 	// when it wasn't. This will *really* screw up kyra.
136 
137 	if ( surface->format->BytesPerPixel < 4 )
138 	{
139 		SDL_Surface* s32 = SDL_CreateRGBSurface(	SDL_SWSURFACE,
140 													surface->w,
141 													surface->h,
142 													32,
143 													0xff000000,
144 													0x00ff0000,
145 													0x0000ff00,
146 													0x000000ff );
147 		GLASSERT( s32 );
148 		//GLOUTPUT(( "Creating 32 bit SDL surface.\n" ));
149 
150 		// Now copy one surface to the other,
151 		// set transparency as needed afterwards.
152 		SDL_BlitSurface( surface, 0, s32, 0 );
153 
154 		int i;
155 		KrPainter painter( s32 );
156 
157 		// Covert color keys to RGB values.
158 		for ( i=0; i<nTrans; i++ )
159 		{
160 			if ( trans[i].type != RGBA )
161 			{
162 				switch( trans[i].type )
163 				{
164 					case LowerLeft:
165 						painter.BreakPixel( 0, surface->h - 1, &trans[i].rgba );
166 						break;
167 					case UpperLeft:
168 						painter.BreakPixel( 0, 0, &trans[i].rgba );
169 						break;
170 					case LowerRight:
171 						painter.BreakPixel( surface->w - 1, surface->h - 1, &trans[i].rgba );
172 						break;
173 					case UpperRight:
174 						painter.BreakPixel( surface->w - 1, 0, &trans[i].rgba );
175 						break;
176 					default:
177 						GLASSERT( 0 );
178 				}
179 			}
180 		}
181 
182 		// Now set the transparency.
183 		int x, y;
184 		int nTransPixels = 0;
185 
186 		for( x=0; x<surface->w; x++ )
187 		{
188 			for( y=0; y<surface->h; y++ )
189 			{
190 				KrRGBA rgba;
191 				painter.BreakPixel( x, y, &rgba );
192 
193 				for ( i=0; i<nTrans; i++ )
194 				{
195 					if (	rgba.c.red   == trans[i].rgba.c.red
196 						 && rgba.c.green == trans[i].rgba.c.green
197 						 && rgba.c.blue  == trans[i].rgba.c.blue )
198 					{
199 						rgba.c.alpha = KrRGBA::KR_TRANSPARENT;
200 
201 						// Set the surface alpha to transparent.
202 						painter.SetPixel( x, y, rgba );
203 						nTransPixels++;
204 						break;
205 					}
206 				}
207 			}
208 		}
209 
210 		//GLOUTPUT(( "Transparency converted=%d\n", nTransPixels ));
211 		SDL_FreeSurface( surface );
212 		return s32;
213 	}
214 	return surface;
215 }
216 
217 
Load32Canvas(const char * filename,const KrRGBA * transparent,int nTrans,std::string * error)218 KrCanvasResource* KrEncoder::Load32Canvas(	const char* filename,
219 											const KrRGBA* transparent,
220 											int nTrans,
221 											std::string* error )
222 {
223 	if ( !filename )
224 	{
225 		if ( error ) *error = "No filename for a surface specified";
226 		return 0;
227 	}
228 
229 	// Try to load the file
230 	if ( !ImageLoader )
231 		GetImageLoader();
232 
233 	SDL_Surface* surface = ImageLoader( filename );
234 	if ( !surface )
235 	{
236 		char buf[256];
237 		sprintf( buf, "Failed to load surface '%s'.", filename );
238 
239 		if ( error ) *error = buf;
240 		return 0;
241 	}
242 
243 	// The image can be 32 bits or less. A NON-32 bit image has
244 	// color(s) that are marked transparent. A 32 bit image
245 	// simply uses the alpha channel. Canvas's are always 32 bit,
246 	// and we always use a canvas that supports alpha.
247 
248 	KrCanvasResource* canvas = new KrCanvasResource(	"encoder",
249 														surface->w,
250 														surface->h,
251 														true );
252 
253 	if ( !canvas )
254 	{
255 		if ( error ) *error = "Failed to create canvas.";
256 		return 0;
257 	}
258 
259 	// Copy from the surface to the canvas.
260 	int x, y;
261 	int i;
262 
263 	KrPaintInfo canvasPaintInfo( canvas->Pixels(), canvas->Width(), canvas->Height() );
264 	KrPainter	canvasPainter( &canvasPaintInfo );
265 	KrPainter	surfacePainter( surface );
266 
267 	for( x=0; x<surface->w; x++ )
268 	{
269 		for( y=0; y<surface->h; y++ )
270 		{
271 			KrRGBA rgba;
272 			surfacePainter.BreakPixel( x, y, &rgba );
273 
274 			for ( i=0; i<nTrans; i++ )
275 			{
276 				if (	rgba.c.red   == transparent[i].c.red
277 					 && rgba.c.green == transparent[i].c.green
278 					 && rgba.c.blue  == transparent[i].c.blue )
279 				{
280 					// Set the surface alpha to transparent.
281 					rgba.c.alpha = KrRGBA::KR_TRANSPARENT;
282 					break;
283 				}
284 			}
285 			canvasPainter.SetPixel( x, y, rgba );
286 		}
287 	}
288 	return canvas;
289 }
290 
291 
LoadSurface(const TiXmlElement * def,std::string * error)292 SDL_Surface* KrEncoder::LoadSurface( const TiXmlElement* def, std::string* error )
293 {
294 	const char* surfaceName = def->Attribute( "filename" );
295 	if ( !surfaceName )
296 	{
297 		*error = "No filename for a surface specified.";
298 		return 0;
299 	}
300 
301 	// Get the pixel colors that mark the background.
302 	int i;
303 	const int MAX_TRANS = 4;
304 	int nTrans = 0;
305 	Transparent trans[MAX_TRANS];
306 
307 	for ( i=0; i<MAX_TRANS; i++ )
308 	{
309 		char attrib[64];
310 		sprintf( attrib, "Transparent%d", i );
311 
312 		if ( def->Attribute( attrib ) )
313 		{
314 			const char* colorString = def->Attribute( attrib );
315 			GLASSERT( colorString && *colorString );
316 			if ( colorString )
317 			{
318 				if ( colorString[0] == '#' )
319 				{
320 					trans[ nTrans ].type = RGBA;
321 					trans[ nTrans ].rgba.FromString( colorString );
322 				}
323 				else if ( StrEqual( colorString, "LowerLeft" ) )
324 				{
325 					trans[ nTrans ].type = LowerLeft;
326 				}
327 				else if ( StrEqual( colorString, "UpperLeft" ) )
328 				{
329 					trans[ nTrans ].type = UpperLeft;
330 				}
331 				else if ( StrEqual( colorString, "LowerRight" ) )
332 				{
333 					trans[ nTrans ].type = LowerRight;
334 				}
335 				else if ( StrEqual( colorString, "UpperRight" ) )
336 				{
337 					trans[ nTrans ].type = UpperRight;
338 				}
339 				else
340 				{
341 					GLASSERT( 0 );
342 				}
343 			}
344 			nTrans++;
345 		}
346 	}
347 
348 	SDL_Surface* surface = Load32Surface( surfaceName,
349 										  trans,
350 										  nTrans,
351 										  error );
352 	GLASSERT( surface || !error->empty() );
353 
354 	GLOUTPUT(( "Surface %s loaded.\n", surfaceName ));
355 	return surface;
356 }
357 
358 
EndDat()359 bool KrEncoder::EndDat()
360 {
361 	StartTag( KYRATAG_END );
362 	EndTag();
363 
364 	SDL_RWseek( stream, numRlePos, SEEK_SET );
365 	GLASSERT( numRGBA >= numSegment );
366 	GLASSERT( numSegment >= numLine );
367 	SDL_WriteLE32( stream, numRGBA );
368 	SDL_WriteLE32( stream, numLine );
369 	SDL_WriteLE32( stream, numSegment );
370 
371 	GLOUTPUT(( "Tally count: rgba=%d line=%d segment=%d\n", numRGBA, numLine, numSegment ));
372 
373 	cachedWrite.Flush();
374 	return true;
375 }
376 
377 
Save()378 void KrEncoder::Save()
379 {
380 	GlSListIterator< KrResource* > it = vault.GetResourceIterator();
381 
382 	for( it.Begin(); !it.Done(); it.Next() )
383 	{
384 		it.Current()->Save( this );
385 	}
386 }
387 
388 
StartDat()389 bool KrEncoder::StartDat()
390 {
391 	numRGBA = 0;
392 
393 	// The header:
394 	const char* magic = "KYRA";
395 	char version[16];
396 	sprintf( version, "%d.%d.%d", KyraVersionMajor, KyraVersionMinor, KyraVersionBuild );
397 
398 	SDL_RWwrite( stream, magic, 4, 1 );
399 	WriteString( stream, version );
400 
401 	numRlePos   = SDL_RWtell( stream );
402 	SDL_WriteLE32( stream, 0 );		// placeholder for number of RGBAs
403 	SDL_WriteLE32( stream, 0 );		// placeholder for number of lines
404 	SDL_WriteLE32( stream, 0 );		// placeholder for number of segments
405 
406 	return true;
407 }
408 
409 
ProcessDoc(const TiXmlDocument & doc)410 bool KrEncoder::ProcessDoc( const TiXmlDocument& doc )
411 {
412 	const TiXmlElement* root = 0;
413 	const TiXmlElement* rootChild = 0;
414 	const TiXmlElement* action = 0;
415 	const TiXmlElement* frame = 0;
416 	const TiXmlElement* file = 0;
417 	const TiXmlElement* child = 0;
418 
419 	if ( ( root = doc.FirstChildElement( "Definition" ) ) != 0 )
420 	{
421 		mode = DEFINITION;
422 	}
423 	else if ( ( root = doc.FirstChildElement( "Direct" ) ) != 0 )
424 	{
425 		mode = DIRECT;
426 	}
427 	else
428 	{
429 		//console->Print( "ERROR: 'Definition' or 'Direct' root element not found.\n" );
430 		printf( "ERROR: 'Definition' or 'Direct' root element not found.\n" );
431 		return false;
432 	}
433 
434 	SDL_Surface* surface = 0;
435 	std::string error;
436 
437 	if ( mode == DEFINITION )
438 	{
439 		// The surface.
440 		surface = LoadSurface( root, &error );
441 		if ( !surface )
442 		{
443 			printf( "Error loading surface: '%s'\n", error.c_str() );
444 			return false;
445 		}
446 
447 		// Walk the tree, and process.
448 		for( rootChild = root->FirstChildElement();
449 			 rootChild;
450 			 rootChild = rootChild->NextSiblingElement() )
451 		{
452 			if ( StrEqual( rootChild->Value(), "Sprite" ) )
453 			{
454 				for( action = rootChild->FirstChildElement( "Action" );
455 					 action;
456 					 action = action->NextSiblingElement( "Action" ) )
457 				{
458 					for( frame = action->FirstChildElement( "Frame" );
459 						 frame;
460 						 frame = frame->NextSiblingElement( "Frame" ) )
461 					{
462 							AllInfo allInfo;
463 							CalcAllInfo( frame, &allInfo, surface );
464 							EncodeSprite( surface, allInfo );
465 					}
466 				}
467 			}
468 			else if ( StrEqual( rootChild->Value(), "Tile" ) )
469 			{
470 				AllInfo allInfo;
471 				CalcAllInfo( rootChild, &allInfo, surface );
472 				EncodeTile( surface, allInfo );
473 			}
474 			else if ( StrEqual( rootChild->Value(), "Font" ) )
475 			{
476 				AllInfo allInfo;
477 				CalcAllInfo( rootChild, &allInfo, surface );
478 				EncodeFont( surface, allInfo );
479 			}
480 			else
481 			{
482 				printf( "ERROR: Unrecognized element name. (Not Sprite, Tile, or Font.).\n" );
483 				return false;
484 			}
485 //			engine->Draw();
486 		}
487 		return true;
488 	}
489 	else
490 	{
491 		for( file = root->FirstChildElement( "File" );
492 			 file;
493 			 file = file->NextSiblingElement( "File" ) )
494 		{
495 			surface = LoadSurface( file, &error );
496 			if ( !surface )
497 			{
498 				printf( "Error loading surface: '%s'\n", error.c_str() );
499 				return false;
500 			}
501 			scan.Init();
502 
503 			for( child = file->FirstChildElement();
504 				 child;
505 				 child = child->NextSiblingElement() )
506 			{
507 				if ( StrEqual( child->Value(), "ColorKey" ) )
508 				{
509 					AllInfo allInfo;
510 					CalcAllInfo( child, &allInfo, surface );
511 					EncodeColorKey( surface, allInfo );
512 				}
513 				else if ( StrEqual( child->Value(), "Image" ) )
514 				{
515 					AllInfo allInfo;
516 					CalcAllInfo( child, &allInfo, surface );
517 					if ( allInfo.type == TYPE_SPRITE )
518 						EncodeSprite( surface, allInfo );
519 					else if ( allInfo.type == TYPE_TILE )
520 						EncodeTile( surface, allInfo );
521 					else
522 						printf( "ERROR: Direct encoding can not identify whether Sprite or Tile.\n" );
523 				}
524 				else
525 				{
526 					printf( "ERROR: Unrecognized element name '%s'. (Not ColorKey or Image.).\n", child->Value() );
527 					return false;
528 				}
529 //				engine->Draw();
530 			}
531 		}
532 		for (	file = root->FirstChildElement( "BinaryFile" );
533 				file;
534 				file = file->NextSiblingElement( "BinaryFile" ) )
535 		{
536 			EncodeBinary( file );
537 		}
538 		for (	file = root->FirstChildElement( "TextFile" );
539 				file;
540 				file = file->NextSiblingElement( "TextFile" ) )
541 		{
542 			EncodeText( file );
543 		}
544 		return false;
545 	}
546 }
547 
548 
549 /*
550 bool KrEncoder::EncodeSpriteOrTile(	KrPaintInfo* info,
551 									const AllInfo& allInfo,
552 									KrConsole* console,
553 									int x, int y,
554 									int width, int height,
555 									int hotx, int hoty )
556 {
557 	int deltax = 0, deltay = 0;
558 	int isotile = 0;
559 
560 	std::string spriteName = "NONE";
561 	std::string actionName = "NONE";
562 	std::string tileName   = "NONE";
563 
564 	if ( e->Attribute( "sprite" ) )
565 	{
566 		spriteName = *( e->Attribute( "sprite" ) );
567 
568 		if ( e->Attribute( "action" ) )
569 			actionName = *( e->Attribute( "action" ) );
570 
571 		if ( e->Attribute( "hotspotx" ) )
572 			e->Attribute( "hotspotx", &hotx );
573 
574 		if ( e->Attribute( "hotspoty" ) )
575 			e->Attribute( "hotspoty", &hoty );
576 
577 		if ( e->Attribute( "deltax" ) )
578 			e->Attribute( "deltax", &deltax );
579 
580 		if ( e->Attribute( "deltay" ) )
581 			e->Attribute( "deltay", &deltay );
582 
583 		if ( e->Attribute( "isotile" ) )
584 		{
585 			e->Attribute( "isotile", &isotile );
586 			if ( isotile == 0 )
587 				isotile = width;
588 		}
589 
590 		// Create or locate the sprite.
591 		if ( !vault.GetSpriteResource( spriteName ) )
592 		{
593 			vault.AddResource( new KrSpriteResource( spriteName ) );
594 		}
595 		KrSpriteResource* spriteResource = vault.GetSpriteResource( spriteName );
596 		GLASSERT( spriteResource );
597 
598 		// Get or create the action.
599 		if ( !spriteResource->GetAction( actionName ) )
600 		{
601 			spriteResource->AddAction( new KrAction( actionName ) );
602 		}
603 		KrAction* actionRes = spriteResource->GetAction( actionName );
604 		GLASSERT( actionRes );
605 
606 		actionRes->AddFrame();
607 		KrRle* rle = actionRes->GetFrame( actionRes->NumFrames() - 1 );
608 
609 		if ( isotile )
610 		{
611 			CreateIsoTile( info, console, x, y, width, height, rle, isotile );
612 		}
613 		else
614 		{
615 			rle->Create( info,
616 						 x, y,
617 						 width, height,
618 						 hotx, hoty,
619 						 deltax, deltay );
620 		}
621 
622 		PrintSprite( console, spriteName, actionName, actionRes->NumFrames() - 1, rle );
623 
624 		return true;
625 	}
626 	else if ( e->Attribute( "tile" ) )
627 	{
628 		if ( width != height )
629 		{
630 			console->Print( "ERROR: Image encoding tile. Width and height of source image are not equal.\n" );
631 			return false;
632 		}
633 
634 		tileName = *( e->Attribute( "tile" ) );
635 
636 		if ( vault.GetTileResource( tileName ) )
637 		{
638 			console->Print( "ERROR: Tile resource '%s' already created.\n" );
639 			return false;
640 		}
641 
642 		KrTileResource* tileRes = new KrTileResource( tileName, info, x, y, width );
643 		vault.AddResource( tileRes );
644 
645 		PrintTile( console, tileName, tileRes );
646 		return true;
647 	}
648 
649 	console->Print( "ERROR: 'sprite' or 'tile' attribute not found.\n" );
650 	return false;
651 }
652 */
653 
654 
EncodeColorKey(SDL_Surface * surface,const AllInfo & allInfo)655 bool KrEncoder::EncodeColorKey( SDL_Surface* surface, const AllInfo& allInfo )
656 {
657 	//GLASSERT( e->Value() == "ColorKey" );
658 
659 //	KrRGBA color;
660 //	color.Set( 255, 255, 0 );
661 //	int frameCount = 1024 * 1024;		// really big
662 
663 //	if ( e->Attribute( "color" ) )
664 //	{
665 //		std::string colorName = *( e->Attribute( "color" ) );
666 //		color.FromString( colorName.c_str() );
667 //	}
668 //
669 //	if ( e->Attribute( "frameCount" ) )
670 //		e->Attribute( "frameCount", &frameCount );
671 
672 	KrPaintInfo info( surface );
673 	KrPainter painter( surface );
674 	// ignore alpha channel
675 	// color.c.alpha = 0;
676 	int frames = 0;
677 
678 	// Go scan by scan, looking for color keys.
679 	for( ; scan.y<info.height - 2;	/* no increment */ )
680 	{
681 		if ( scan.x >= info.width - 2 )
682 		{
683 			scan.x = 0;
684 			++scan.y;
685 			continue;
686 		}
687 
688 		for( ; scan.x<info.width - 2; ++scan.x )
689 		{
690 			KrRGBA	rgba00, rgba10, rgba01, rgba11,
691 					rgba21, rgba12;
692 
693 			painter.BreakPixel(	scan.x, scan.y, &rgba00 );
694 			painter.BreakPixel(	scan.x+1, scan.y, &rgba10 );
695 			painter.BreakPixel(	scan.x, scan.y+1, &rgba01 );
696 			painter.BreakPixel(	scan.x+1, scan.y+1, &rgba11 );
697 
698 			painter.BreakPixel(	scan.x+2, scan.y+1, &rgba21 );
699 			painter.BreakPixel(	scan.x+1, scan.y+2, &rgba12 );
700 
701 			rgba00.c.alpha = KrRGBA::KR_OPAQUE;
702 			rgba10.c.alpha = KrRGBA::KR_OPAQUE;
703 			rgba01.c.alpha = KrRGBA::KR_OPAQUE;
704 			rgba11.c.alpha = KrRGBA::KR_OPAQUE;
705 			rgba21.c.alpha = KrRGBA::KR_OPAQUE;
706 			rgba12.c.alpha = KrRGBA::KR_OPAQUE;
707 
708 			if (	rgba00 == allInfo.keyColor
709 			     && rgba10 == allInfo.keyColor
710 				 && rgba01 == allInfo.keyColor
711 				 && rgba11 != allInfo.keyColor		// don't want an empty one.
712 				 && rgba21 != allInfo.keyColor  	// don't be fooled by a hittest nock (x)
713 				 && rgba12 != allInfo.keyColor		// don't be fooled by a hittest nock (y)
714 				)
715 			{
716 				// Find the width and height of the image inside the color block.
717 				int width, height;
718 				int run;
719 
720 				run = painter.FindPixel( scan.x+1, scan.y+1, 1, 0, allInfo.keyColor, false, false );
721 
722 				if ( run < 0 )
723 				{
724 					printf( "ERROR: ColorKey box not closed on right side.\n" );
725 					return false;
726 				}
727 				width = run;
728 
729 				run = painter.FindPixel( scan.x+1, scan.y+1, 0, 1, allInfo.keyColor, false, false );
730 
731 				if ( run < 0 )
732 				{
733 					printf( "ERROR: ColorKey box not closed on bottom side.\n" );
734 					return false;
735 				}
736 				height = run;
737 
738 				// find the hotspot markers
739 				int hotx = 0, hoty = 0;
740 
741 				run = painter.FindPixel( scan.x+1, scan.y, 1, 0, allInfo.keyColor, false, true );
742 				if ( run > 0 && run < width )
743 				{
744 					hotx = run;
745 				}
746 
747 				run = painter.FindPixel( scan.x, scan.y+1, 0, 1, allInfo.keyColor, false, true );
748 				if ( run > 0 && run < height )
749 				{
750 					hoty = run;
751 				}
752 
753 				bool ret = false;
754 
755 				{
756 					AllInfo temp = allInfo;
757 					temp.x = scan.x+1;
758 					temp.y = scan.y+1;
759 					temp.width = width;
760 					temp.height = height;
761 					temp.hotx = scan.x + 1 + hotx;
762 					temp.hoty = scan.y + 1 + hoty;
763 
764 					if ( temp.type == TYPE_SPRITE )
765 						ret = EncodeSprite( surface, temp );
766 					else if ( temp.type == TYPE_TILE )
767 						ret = EncodeTile( surface, temp );
768 					else
769 						printf( "ERROR: Color Key encoding can not identify whether Sprite or Tile.\n" );
770 	//				bool ret = EncodeSpriteOrTile(  &info, e, console,
771 	//												scan.x+1, scan.y+1,
772 	//												width, height,
773 	//												scan.x + 1 + hotx, scan.y + hoty + 1);
774 				}
775 				if ( !ret )
776 				{
777 					printf( "ERROR: Sprite or Tile encoding failed.\n" );
778 					return false;
779 				}
780 
781 				++frames;
782 				scan.x += width + 1;		// the for loop will add one as well.
783 				if ( allInfo.frameCount != 0 && frames == allInfo.frameCount )
784 					return true;
785 			}
786 		}
787 	}
788 	return true;
789 }
790 
791 
PrintSprite(const std::string & spriteName,const std::string & actionName,int frameNum,KrRle * rle)792 void KrEncoder::PrintSprite( const std::string& spriteName, const std::string& actionName,
793 							int frameNum, KrRle* rle )
794 {
795 	printf( "Sprite: %s :: %s :: %d  [hot:%d,%d delta:%d,%d]\n",
796 					spriteName.c_str(),
797 					actionName.c_str(),
798 					frameNum,
799 					rle->Hotspot().x, rle->Hotspot().y,
800 					rle->Delta().x, rle->Delta().y );
801 }
802 
PrintTile(const std::string & tileName,KrTileResource * tile)803 void KrEncoder::PrintTile( const std::string& tileName, KrTileResource* tile )
804 {
805 	printf( "Tile: %s  [size:%d]\n", tileName.c_str(), tile->Size() );
806 }
807 
808 
EncodeSprite(SDL_Surface * surface,const AllInfo & allInfo)809 bool KrEncoder::EncodeSprite( SDL_Surface* surface, const AllInfo& allInfo )
810 {
811 //	std::string spriteName, actionName;
812 //	TiXmlElement* action;
813 //	TiXmlElement* frame;
814 //
815 //	spriteName = "no_sprite_name";
816 //	if ( sprite->Attribute( "name" ) )
817 //	{
818 //		spriteName = *(sprite->Attribute( "name" ));
819 //	}
820 
821 	// Create or locate the sprite.
822 	if ( !vault.GetSpriteResource( allInfo.name ) )
823 	{
824 		vault.AddResource( new KrSpriteResource( allInfo.name ) );
825 	}
826 	KrSpriteResource* spriteResource = vault.GetSpriteResource( allInfo.name );
827 	GLASSERT( spriteResource );
828 
829 	std::vector< int > rotation;
830 	if ( allInfo.rotation.size() )
831 		rotation = allInfo.rotation;
832 	else
833 		rotation.push_back( 0 );
834 
835 	for( int i=0; i<(int) rotation.size(); ++i )
836 	{
837 		// Get or create the action.
838 		// If using rotation, append to the name.
839 		std::string action = allInfo.action;
840 		if ( rotation.size() > 1 )
841 		{
842 			char buf[16];
843 			sprintf( buf, ".ROT%03d", rotation[i] );
844 			action += buf;
845 		}
846 
847 		if ( !spriteResource->GetAction( action ) )
848 		{
849 			spriteResource->AddAction( new KrAction( action ) );
850 		}
851 		KrAction* actionRes = spriteResource->GetAction( action );
852 		GLASSERT( actionRes );
853 
854 		int index = actionRes->NumFrames();
855 		actionRes->AddFrame();
856 
857 		KrPaintInfo info( surface );
858 		KrRle* rle = actionRes->GetFrame( index );
859 
860 		if ( allInfo.isoTargetWidth > 0 )
861 		{
862 			CreateIsoTile(  &info,
863 							allInfo.x, allInfo.y, allInfo.width, allInfo.height,
864 							rle, allInfo.isoTargetWidth,
865 							rotation[i] );
866 		}
867 		else
868 		{
869 			rle->Create( &info, allInfo.x, allInfo.y, allInfo.width, allInfo.height, allInfo.hotx, allInfo.hoty, allInfo.deltax, allInfo.deltay );
870 		}
871 		PrintSprite( allInfo.name, action, index, actionRes->GetFrame( index ) );
872 	}
873 
874 	return true;
875 }
876 
877 
EncodeFont(SDL_Surface * surface,const AllInfo & allInfo)878 bool KrEncoder::EncodeFont( SDL_Surface* surface, const AllInfo& allInfo )
879 {
880 	GLASSERT( surface->format->BytesPerPixel == 4 );
881 
882 	// Create or locate the font.
883 	if ( vault.GetFontResource( allInfo.name ) )
884 	{
885 		printf( "ERROR: Font %s encoded twice.\n", allInfo.name.c_str() );
886 		return false;
887 	}
888 
889 	int type = KrFontResource::FIXED;
890 	if ( allInfo.subType == SUBTYPE_SFONT )
891 		type = KrFontResource::SFONT;
892 
893 	if ( type == KrFontResource::FIXED && allInfo.fontLength == 0 )
894 	{
895 		printf( "ERROR: Fixed font created without the 'length' attribute.\n" );
896 		return false;
897 	}
898 
899 	KrPaintInfo info( surface );
900 	KrFontResource* fontRes = new KrFontResource(	allInfo.name,
901 													&info,
902 													allInfo.fontStart,
903 													allInfo.space,
904 													type,
905 													allInfo.fontLength );
906 	vault.AddResource( fontRes );
907 
908 	printf( "Font: %s\n", allInfo.name.c_str() );
909 
910 	return true;
911 }
912 
913 
EncodeText(const TiXmlElement * e)914 bool KrEncoder::EncodeText( const TiXmlElement* e )
915 {
916 	std::string filename = "no_file";
917 	std::string resname	 = "no_text_name";
918 
919 	if ( e->Attribute( "filename" ) )
920 	{
921 		filename = e->Attribute( "filename" );
922 	}
923 	else
924 	{
925 		printf( "ERROR: Text data has no 'filename' attribute.\n" );
926 		return false;
927 	}
928 	if ( e->Attribute( "name" ) )
929 	{
930 		resname = e->Attribute( "name" );
931 	}
932 	else
933 	{
934 		printf( "ERROR: Text data has no 'name' attribute.\n" );
935 		return false;
936 	}
937 
938 	KrTextDataResource* res = new KrTextDataResource( resname );
939 	if ( !res || !res->LoadTextFile( filename.c_str() ) )
940 	{
941 		printf( "ERROR: Encoding text failed to load '%s'.\n", filename.c_str() );
942 		return false;
943 	}
944 
945 	vault.AddResource( res );
946 
947 	printf( "TextData: %s\n", resname.c_str() );
948 
949 	return true;
950 }
951 
952 
EncodeBinary(const TiXmlElement * e)953 bool KrEncoder::EncodeBinary( const TiXmlElement* e )
954 {
955 	std::string filename = "no_file";
956 	std::string resname	 = "no_binary_name";
957 
958 	if ( e->Attribute( "filename" ) )
959 	{
960 		filename = e->Attribute( "filename" );
961 	}
962 	else
963 	{
964 		printf( "ERROR: Binary data tag has no 'filename' attribute.\n" );
965 		return false;
966 	}
967 	if ( e->Attribute( "name" ) )
968 	{
969 		resname = e->Attribute( "name" );
970 	}
971 	else
972 	{
973 		printf( "ERROR: Binary data tag has no 'name' attribute.\n" );
974 		return false;
975 	}
976 
977 	KrBinaryDataResource* res = new KrBinaryDataResource( resname );
978 	if ( !res || !res->LoadFile( filename.c_str() ) )
979 	{
980 		printf( "ERROR: Binary data tag failed to load file '%s'.\n", filename.c_str() );
981 		return false;
982 	}
983 
984 	vault.AddResource( res );
985 
986 	printf( "BinaryData: %s\n", resname.c_str() );
987 
988 	return true;
989 }
990 
991 
EncodeTile(SDL_Surface * surface,const AllInfo & allInfo)992 bool KrEncoder::EncodeTile( SDL_Surface* surface, const AllInfo& allInfo )
993 {
994 //	std::string name;
995 //	int x = 0, y = 0, size = 0;
996 //
997 //	name = "no_tile_name";
998 //	if ( tile->Attribute( "name" ) )
999 //	{
1000 //		name = *( tile->Attribute( "name" ) );
1001 //	}
1002 	if ( vault.GetTileResource( allInfo.name ) )
1003 	{
1004 		printf( "ERROR: Tile '%s' created multiple times.\n", allInfo.name.c_str() );
1005 		return false;
1006 	}
1007 
1008 //	tile->Attribute( "x", &x );
1009 //	tile->Attribute( "y", &y );
1010 //	tile->Attribute( "size", &size );
1011 //
1012 	// Do not write an empty tile.
1013 	if ( allInfo.width <= 0 )
1014 	{
1015 		printf( "ERROR: Tile size not specified, or 0.\n" );
1016 		return false;
1017 	}
1018 
1019 	KrPaintInfo info( surface );
1020 	KrTileResource* tileRes = new KrTileResource( allInfo.name, &info, allInfo.x, allInfo.y, allInfo.width );
1021 	vault.AddResource( tileRes );
1022 
1023 	PrintTile( allInfo.name, tileRes );
1024 
1025 	return true;
1026 }
1027 
1028 
StartTag(U32 tag)1029 void KrEncoder::StartTag( U32 tag )
1030 {
1031 	SDL_WriteLE32( stream, tag );
1032 	tagpos = SDL_RWtell( stream );
1033 	SDL_WriteLE32( stream, 0 );
1034 }
1035 
1036 
EndTag()1037 void KrEncoder::EndTag()
1038 {
1039 	U32 current = SDL_RWtell( stream );
1040 
1041 	// Write the jump.
1042 	GLASSERT( current > tagpos );
1043 	U32 jump = current - tagpos - 4;	// Add the 4 to skip over the offset value itself
1044 
1045 	SDL_RWseek( stream, tagpos, SEEK_SET );
1046 	SDL_WriteLE32( stream, jump );
1047 	SDL_RWseek( stream, current, SEEK_SET );
1048 	tagpos = 0;
1049 }
1050 
1051 
WriteHeader(const char * name,FILE * file,const char * prefix)1052 void KrEncoder::WriteHeader(	const char* name,
1053 								FILE* file,
1054 								const char* prefix )
1055 {
1056 	std::string defName;
1057 	for( const char* p = name; p && *p; ++p )
1058 	{
1059 		if (    ( *p >= 'a' && *p <= 'z' )
1060 			 || ( *p >= 'A' && *p <= 'Z' )
1061 			 || ( *p >= '0' && *p <= '9' ) )
1062 		{
1063 			defName += *p;
1064 		}
1065 		else
1066 		{
1067 			defName += '_';
1068 		}
1069 	}
1070 
1071 	fprintf( file, "#ifndef KYRA_%s_INCLUDED\n", defName.c_str() );
1072 	fprintf( file, "#define KYRA_%s_INCLUDED\n\n", defName.c_str() );
1073 	fprintf( file, "// Machine generated Kyra header file.\n" );
1074 	fprintf( file, "// Will be overwritten by the encoder.\n" );
1075 	fprintf( file, "// Generated by kyra version %d.%d.%d\n\n", KyraVersionMajor, KyraVersionMinor, KyraVersionBuild );
1076 
1077 	cachedWrite.WriteHeader( file, prefix );
1078 	fprintf( file, "#endif\n" );
1079 }
1080 
1081 
CreateIsoTile(KrPaintInfo * info,int x,int y,int width,int height,KrRle * rle,int isoWidth,int rotation)1082 void KrEncoder::CreateIsoTile(	KrPaintInfo* info,
1083 								int x, int y,
1084 								int width, int height,
1085 								KrRle* rle,
1086 								int isoWidth,
1087 								int rotation )
1088 {
1089 	if ( isoWidth % 4 )
1090 	{
1091 		printf( "ERROR: Isometric tile created with non-multiplo of 4 width (%d).\n", isoWidth );
1092 		return;
1093 	}
1094 
1095 	int isoHeight = isoWidth / 2;
1096 	KrPainter painter( info );
1097 	KrRGBA rgba;
1098 
1099 	// Create a memory buffer to hold the tile:
1100 	KrRGBA* isoMemory = new KrRGBA[ isoWidth * isoHeight ];
1101 	::memset( isoMemory, 0, isoWidth * isoHeight * sizeof( KrRGBA ) );
1102 
1103 	for( int iy = 0; iy < isoHeight; ++iy )
1104 	{
1105 		int rowwidth = 0;
1106 		if ( iy < isoHeight / 2 )
1107 			rowwidth = 2 + 4 * iy;
1108 		else
1109 			rowwidth = 2 + 4 * ( isoHeight - iy - 1 );
1110 
1111 		const int QUALITY = 4;		// 2, 4
1112 		const int QUALITYAREA = 16;	// 4, 16
1113 		const int QUALITYBIAS = 7;	// 1, 7
1114 		const GlFixed increment = GlFixed( 1  ) / GlFixed( QUALITY );
1115 
1116 		for( int ix =  isoWidth / 2 - rowwidth / 2;
1117 		         ix <  isoWidth / 2 + rowwidth / 2;
1118 				 ++ix )
1119 		{
1120 			int red = 0, green = 0, blue = 0, alpha = 0;
1121 
1122 			for ( int i=0; i<QUALITY; ++i )
1123 			{
1124 				for ( int j=0; j<QUALITY; ++j )
1125 				{
1126 					GlFixed fsx, fsy;
1127 					int sx, sy;
1128 
1129 					IsoToSource( ix + increment*i,
1130 								 iy - isoHeight / 2 + increment*j,
1131 								 isoWidth, width, height, &fsx, &fsy,
1132 								 rotation, increment );
1133 
1134 					//sx = fsx.ToInt();
1135 					//sy = fsy.ToInt();
1136 
1137 					sx = Clamp( fsx.ToIntRound(), 0, width - 1 );
1138 					sy = Clamp( fsy.ToIntRound(), 0, height - 1 );
1139 
1140 					painter.BreakPixel( sx + x, sy + y, &rgba );
1141 
1142 					red   += rgba.c.red;
1143 					green += rgba.c.green;
1144 					blue  += rgba.c.blue;
1145 					alpha += rgba.c.alpha;
1146 				}
1147 			}
1148 
1149 			// Whew! all that for one pixel.
1150 			// Use rounding on the colors, to gamma-correct
1151 			rgba.Set(	( red + QUALITYBIAS ) / QUALITYAREA,
1152 						( green + QUALITYBIAS ) / QUALITYAREA,
1153 						( blue + QUALITYBIAS ) / QUALITYAREA,
1154 						( alpha + QUALITYBIAS ) / QUALITYAREA );
1155 			GLASSERT( iy >= 0 && iy < isoHeight );
1156 			GLASSERT( ix >= 0 && ix < isoWidth );
1157 			isoMemory[ iy * isoWidth + ix ] = rgba;
1158 		}
1159 	}
1160 	KrPaintInfo isoInfo( isoMemory, isoWidth, isoHeight );
1161 	rle->Create( &isoInfo, 0, 0,
1162 				 isoWidth, isoHeight,
1163 				 ( isoWidth - 1 ) / 2, ( isoHeight - 1 ) / 2,
1164 				 isoWidth, isoHeight );
1165 	delete [] isoMemory;
1166 }
1167 
1168 
IsoToSource(GlFixed x,GlFixed y,GlFixed isoWidth,GlFixed sourceW,GlFixed sourceH,GlFixed * sourceX,GlFixed * sourceY,int rotation,GlFixed increment)1169 void KrEncoder::IsoToSource(	GlFixed x, GlFixed y, GlFixed isoWidth,
1170 								GlFixed sourceW, GlFixed  sourceH,
1171 								GlFixed* sourceX, GlFixed* sourceY,
1172 								int rotation,
1173 								GlFixed increment )
1174 {
1175 	// x, y are in iso coordinates.
1176 	GlFixed isoHeight  = isoWidth / 2;
1177 
1178 	switch( rotation )
1179 	{
1180 		case 90:
1181 		{
1182 			*sourceX = (sourceW - increment) - x * sourceW / ( isoWidth ) - y * sourceH / ( isoHeight );
1183 			*sourceY =						   x * sourceW / ( isoWidth ) - y * sourceH / ( isoHeight );
1184 		}
1185 		break;
1186 
1187 		case 180:
1188 		{
1189 			*sourceX = (sourceW - increment) - x * sourceW / ( isoWidth ) + y * sourceH / ( isoHeight );
1190 			*sourceY = (sourceH - increment) - x * sourceW / ( isoWidth ) - y * sourceH / ( isoHeight );
1191 		}
1192 		break;
1193 
1194 		case 270:
1195 		{
1196 			*sourceX =						 x * sourceW / ( isoWidth ) + y * sourceH / ( isoHeight );
1197 			*sourceY = (sourceH-increment) - x * sourceW / ( isoWidth ) + y * sourceH / ( isoHeight );
1198 		}
1199 		break;
1200 
1201 		default:
1202 		{
1203 			GLASSERT( x <= isoWidth );
1204 			GLASSERT( y <= isoHeight );
1205 			*sourceX = x * sourceW / ( isoWidth ) - y * sourceH / ( isoHeight );
1206 			*sourceY = x * sourceW / ( isoWidth ) + y * sourceH / ( isoHeight );
1207 		}
1208 		break;
1209 	}
1210 }
1211 
1212 
CalcAllInfo(const TiXmlNode * node,AllInfo * i,SDL_Surface * surface)1213 void KrEncoder::CalcAllInfo( const TiXmlNode* node,
1214 							 AllInfo* i,
1215 							 SDL_Surface* surface )
1216 {
1217 	const TiXmlElement* ele = node->ToElement();
1218 	if ( !ele )
1219 	{
1220 		GLASSERT( 0 );
1221 		return;
1222 	}
1223 
1224 	// Walk up the tree, get information as we go.
1225 	const TiXmlNode* parent = ele->Parent();
1226 	while( parent )
1227 	{
1228 		const TiXmlElement* parentEle = parent->ToElement();
1229 		if ( parentEle )
1230 		{
1231 			if ( StrEqual( parentEle->Value(), "Definition" ) )
1232 			{
1233 //				i->format = FORMAT_DEF;
1234 //
1235 //				if ( parentEle->Attribute( "filename" ) )
1236 //					i->filename = *parentEle->Attribute( "filename" );
1237 
1238 				// We need go no higher.
1239 				break;
1240 			}
1241 			else if ( StrEqual( parentEle->Value(), "Sprite" ) )
1242 			{
1243 				i->type = TYPE_SPRITE;
1244 
1245 				if ( parentEle->Attribute( "name" ) )
1246 					i->name = parentEle->Attribute( "name" );
1247 			}
1248 			else if ( StrEqual( parentEle->Value(), "Action" ) )
1249 			{
1250 				if ( parentEle->Attribute( "name" ) )
1251 					i->action = parentEle->Attribute( "name" );
1252 			}
1253 			else if ( StrEqual( parentEle->Value(), "File" ) )
1254 			{
1255 //				if ( parentEle->Attribute( "filename" ) )
1256 //					i->filename = parentEle->Attribute( "filename" );
1257 			}
1258 			else if ( StrEqual( parentEle->Value(), "Direct" ) )
1259 			{
1260 				//i->format = FORMAT_DIRECT;
1261 				// Go no higher.
1262 				break;
1263 			}
1264 		}
1265 		parent = parent->Parent();
1266 	}
1267 
1268 	// Now interpret the element itself:
1269 	if ( StrEqual( ele->Value(), "Image" ) )
1270 	{
1271 		// Could be sprite or tile.
1272 		//i->useEntireImage = true;
1273 	}
1274 	else if ( StrEqual( ele->Value(), "ColorKey" ) )
1275 	{
1276 		// Could be sprite on tile.
1277 		//i->useEntireImage = false;
1278 	}
1279 	else if ( StrEqual( ele->Value(), "Frame" ) )
1280 	{
1281 		i->type = TYPE_SPRITE;
1282 	}
1283 	else if ( StrEqual( ele->Value(), "Font" ) )
1284 	{
1285 		i->type = TYPE_FONT;
1286 	}
1287 	else if ( StrEqual( ele->Value(), "Tile" ) )
1288 	{
1289 		i->type = TYPE_TILE;
1290 	}
1291 
1292 	// And its attributes. They don't have different meanings in different
1293 	// tags, so they can all be read in together.
1294 
1295 	// ColorKey and Image attributes:
1296 	if ( ele->Attribute( "tile" ) )
1297 	{
1298 		GLASSERT( i->type == TYPE_NONE );
1299 		i->name = ele->Attribute( "tile" );
1300 		i->type = TYPE_TILE;
1301 	}
1302 	if ( ele->Attribute( "sprite" ) )
1303 	{
1304 		GLASSERT( i->type == TYPE_NONE );
1305 		i->name = ele->Attribute( "sprite" );
1306 		i->type = TYPE_SPRITE;
1307 	}
1308 	if ( ele->Attribute( "color" ) )
1309 	{
1310 		const char* c = ele->Attribute( "color" );
1311 		i->keyColor.FromString( c );
1312 		i->keyColor.c.alpha = KrRGBA::KR_OPAQUE;	// alpha not used
1313 	}
1314 	if ( ele->Attribute( "frameCount" ) )
1315 	{
1316 		ele->Attribute( "frameCount", &i->frameCount );
1317 	}
1318 	if ( ele->Attribute( "action" ) )
1319 	{
1320 		i->action = ele->Attribute( "action" );
1321 	}
1322 	if ( ele->Attribute( "sprite" ) )
1323 	{
1324 		i->name = ele->Attribute( "sprite" );
1325 	}
1326 
1327 	// Used by tile and font:
1328 	if ( ele->Attribute( "name" ) )
1329 	{
1330 		i->name = ele->Attribute( "name" );
1331 	}
1332 
1333 	// Font attributes:
1334 	if ( i->type == TYPE_FONT )
1335 	{
1336 		if ( ele->Attribute( "start" ) )
1337 		{
1338 			ele->Attribute( "start", &i->fontStart );
1339 		}
1340 		if ( ele->Attribute( "space" ) )
1341 		{
1342 			ele->Attribute( "space", &i->space );
1343 		}
1344 		if ( ele->Attribute( "type" ) )
1345 		{
1346 			if ( StrEqual( ele->Attribute( "type" ), "sfont" ) )
1347 				i->subType = SUBTYPE_SFONT;
1348 		}
1349 	}
1350 
1351 	// Generic attributes:
1352 	if ( ele->Attribute( "x" ) )
1353 	{
1354 		ele->Attribute( "x", &i->x );
1355 		i->hotx = i->x;
1356 	}
1357 	if ( ele->Attribute( "y" ) )
1358 	{
1359 		ele->Attribute( "y", &i->y );
1360 		i->hoty = i->y;
1361 	}
1362 	if ( ele->Attribute( "size" ) )
1363 	{
1364 		GLASSERT( i->type == TYPE_TILE );
1365 		ele->Attribute( "size", &i->width );
1366 		i->height = i->width;					// size is height and width for tiles.
1367 	}
1368 	if ( ele->Attribute( "width" ) )
1369 	{
1370 		ele->Attribute( "width", &i->width );
1371 	}
1372 	if ( ele->Attribute( "height" ) )
1373 	{
1374 		ele->Attribute( "height", &i->height );
1375 	}
1376 	if ( ele->Attribute( "hotspotx" ) )
1377 	{
1378 		//i->hasHotspot = true;
1379 		ele->Attribute( "hotspotx", &i->hotx);
1380 	}
1381 	if ( ele->Attribute( "hotspoty" ) )
1382 	{
1383 		//i->hasHotspot = true;
1384 		ele->Attribute( "hotspoty", &i->hoty );
1385 	}
1386 	if ( ele->Attribute( "deltax" ) )
1387 	{
1388 		//i->hasDelta = true;
1389 		ele->Attribute( "deltax", &i->deltax );
1390 	}
1391 	if ( ele->Attribute( "deltay" ) )
1392 	{
1393 		//i->hasDelta = true;
1394 		ele->Attribute( "deltay", &i->deltay );
1395 	}
1396 	if ( ele->Attribute( "isotile" ) )
1397 	{
1398 		i->isoTargetWidth = 0;
1399 		ele->Attribute( "isotile", &i->isoTargetWidth );
1400 	}
1401 	if ( ele->Attribute( "length" ) )
1402 	{
1403 		ele->Attribute( "length", &i->fontLength );
1404 	}
1405 	if ( ele->Attribute( "rotation" ) )
1406 	{
1407 		std::string r( ele->Attribute( "rotation" ) );
1408 		GlString::RemoveWhiteSpace( &r );
1409 
1410 		std::vector< std::string > strArray;
1411 		GlString::Split( &strArray, r, ",", false );
1412 
1413 		for( int k=0; k<(int)strArray.size(); ++k )
1414 		{
1415 			if ( strArray[k].length() > 1 && strArray[k].at( 0 ) == 'd' )
1416 			{
1417 				int division = atoi( &strArray[k].at( 1 ) );
1418 				if ( division > 0 )
1419 				{
1420 					int increment = 360 / division;
1421 					if ( increment > 0 )
1422 					{
1423 						for( int theta = 0; theta < 360; theta += increment )
1424 						{
1425 							i->rotation.push_back( theta );
1426 						}
1427 					}
1428 				}
1429 			}
1430 			else
1431 			{
1432 				int theta = atoi( strArray[k].c_str() );
1433 				i->rotation.push_back( theta );
1434 			}
1435 		}
1436 		//i->rotation.Sort();
1437 		std::sort( i->rotation.begin(), i->rotation.end() );
1438 	}
1439 
1440 	if ( i->width == 0 || i->height == 0 )	//i->useEntireImage )
1441 	{
1442 		i->x = 0;
1443 		i->y = 0;
1444 		i->width = surface->w;
1445 		i->height = surface->h;
1446 	}
1447 	if ( i->x >= surface->w-1 )
1448 	{
1449 		printf( "ERROR: x value out of range.\n" );
1450 		i->x = 0;
1451 	}
1452 	if ( i->y >= surface->h-1 )
1453 	{
1454 		printf( "ERROR: y value out of range.\n" );
1455 		i->y = 0;
1456 	}
1457 	if ( i->x + i->width > surface->w )
1458 	{
1459 		printf( "ERROR: width value out of range.\n" );
1460 		i->width = 1;
1461 	}
1462 	if ( i->y + i->height > surface->h )
1463 	{
1464 		printf( "ERROR: height value out of range.\n" );
1465 		i->height = 1;
1466 	}
1467 }
1468 
1469 
CreateFixedFontResource(const char * name,const U8 * buffer,int bufferSize)1470 /*static*/ KrFontResource* KrEncoder::CreateFixedFontResource(	const char* name,
1471 																const U8* buffer,
1472 																int bufferSize )
1473 {
1474 	SDL_RWops* rw = SDL_RWFromMem( (void*) buffer, bufferSize );
1475 	SDL_Surface* surfaceBMP = SDL_LoadBMP_RW( rw, false );
1476 	GLASSERT( surfaceBMP );
1477 	SDL_FreeRW( rw );
1478 
1479 	SDL_Surface* s32 = SDL_CreateRGBSurface(	SDL_SWSURFACE,
1480 												surfaceBMP->w,
1481 												surfaceBMP->h,
1482 												32,
1483 												0xff << ( KrRGBA::RED * 8 ),
1484 												0xff << ( KrRGBA::GREEN * 8 ),
1485 												0xff << ( KrRGBA::BLUE * 8 ),
1486 												0xff << ( KrRGBA::ALPHA * 8 ) );
1487 	GLASSERT( s32 );
1488 
1489 	// Now copy one surface to the other,
1490 	// set transparency as needed afterwards.
1491 	SDL_BlitSurface( surfaceBMP, 0, s32, 0 );
1492 
1493 	KrPaintInfo info( s32 );
1494 
1495 	KrRGBA* rgba = (KrRGBA*) s32->pixels;
1496 	KrRGBA  tr = *rgba;
1497 
1498 	int count = info.width * info.height;
1499 	for( int i=0; i<count; ++i )
1500 	{
1501 		if (	rgba[i].c.red == tr.c.red
1502 			 && rgba[i].c.green == tr.c.green
1503 			 && rgba[i].c.blue == tr.c.blue )
1504 
1505 			rgba[i].all = 0;
1506 	}
1507 
1508 	KrFontResource* fontRes = new KrFontResource( name, &info,
1509 												  0, 0,
1510 												  KrFontResource::FIXED, 256 );
1511 
1512 	SDL_FreeSurface( surfaceBMP );
1513 	SDL_FreeSurface( s32 );
1514 	return fontRes;
1515 }
1516 
1517 
1518