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