1 #include "isogen.h"
2 #include "edges.h"
3 #include <vector>
4 #include "../../grinliz/gldynamic.h"
5
6 using namespace grinliz;
7 using namespace std;
8
9 typedef SDL_Surface* (*ImageLoaderFunc)( const char* );
10 ImageLoaderFunc ImageLoader = 0;
11
12 // Set by the top level <isogen> tag
13 string spriteName;
14 int isoWidth = 120;
15 int tileWidth = isoWidth - 2;
16 int tileHeight = isoWidth / 2;
17 int step = 10;
18
19 int outWidth = 800;
20 int outHeight = 600;
21
22 Color3F diffuse = { 0.4f, 0.4f, 0.4f };
23 Color3F ambient = { 0.6f, 0.6f, 0.6f };
24 Vector3F lightVector = { 0, 2, -3 };
25
26
27 const Vector3F ZFACE = { 0, 0, 1 };
28 const Vector3F YFACE = { 0, -1, 0 };
29 const Vector3F XFACE = { -1, 0, 0 };
30
31 int saveX = 0;
32 int saveY = 0;
33 int saveMax = 0;
34
35 vector< SetData > setData;
36 SetData* pSet = 0; // the current setData
37 SDL_Surface* whiteSurface = 0;
38
Clear()39 void SetData::Clear()
40 {
41 unsigned i;
42 for( i=0; i<wallTexture.size(); ++i ) {
43 if ( wallTexture[i].surface != whiteSurface )
44 SDL_FreeSurface( wallTexture[i].surface );
45 }
46
47 for( i=0; i<floorTexture.size(); ++i ) {
48 if ( floorTexture[i].surface != whiteSurface )
49 SDL_FreeSurface( floorTexture[i].surface );
50 }
51 }
52
GetPixel(int u,int v)53 Color4U8 Texture::GetPixel( int u, int v )
54 {
55 GLASSERT( u >=0 && u < surface->w );
56 GLASSERT( v >=0 && v < surface->h );
57
58 // Remember that the texture can be any format:
59 int bytes = surface->format->BytesPerPixel;
60 U8 *p = (U8*)surface->pixels + (surface->h-1-v)*surface->pitch + u*bytes;
61
62 U32 c = 0;
63 switch(bytes) {
64 case 1: c = *p; break;
65 case 2: c = *(U16*)p; break;
66 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
67 case 3: c = p[0] << 16 | p[1] << 8 | p[2];
68 #else
69 case 3: c = p[0] | p[1] << 8 | p[2] << 16;
70 #endif
71 case 4: c = *(U32*)p;
72
73 default: break;
74 }
75
76 Color4U8 color;
77 SDL_GetRGBA( c, surface->format, &color.r, &color.g, &color.b, &color.a );
78 // if ( bytes < 4 ) color.a = 255; // give SDL a little help here. It should always be 255...
79
80 if ( colorKey && ( ( color.r | color.g | color.b ) == 0 ) )
81 color.a = 0;
82
83 return color;
84 }
85
WrapX(SDL_Surface * surface,int x)86 int Texture::WrapX( SDL_Surface* surface, int x )
87 {
88 while ( x >= surface->w )
89 x -= surface->w;
90 while ( x < 0 )
91 x += surface->w;
92 return x;
93 }
94
95
WrapY(SDL_Surface * surface,int y)96 int Texture::WrapY( SDL_Surface* surface, int y )
97 {
98 while ( y >= surface->h )
99 y -= surface->h;
100 while ( y < 0 )
101 y += surface->h;
102 return y;
103 }
104
105
Lookup(int _x,int _y)106 Color4U8 Texture::Lookup( int _x, int _y )
107 {
108 // x,y: pixels on screen
109 // u,x: texels in the texture, normalized
110 // i,j: texels in the texture, pixels
111 int x = _x - origin.x;
112 int y = _y - origin.y;
113
114 float uF = (float)x*a + (float)y*b;
115 float vF = (float)x*c + (float)y*d;
116
117 float iF = uF*(float)(surface->w);
118 float jF = vF*(float)(surface->h);
119
120 int i0 = (int)floorf( iF );
121 int j0 = (int)floorf( jF );
122
123 float di = iF-(float)i0;
124 float dj = jF-(float)j0;
125
126 GLASSERT( InRange( di, 0.0f, 1.0f ) );
127 GLASSERT( InRange( dj, 0.0f, 1.0f ) );
128
129 i0 = WrapX( surface, i0 );
130 j0 = WrapY( surface, j0 );
131
132 Color4U8 c01, c10, c11;
133 Color4U8 c = { 0, 0, 0, 0 };
134 Color4U8 c00 = GetPixel( i0, j0 );
135
136 if ( pSet->useAA )
137 {
138 c10 = GetPixel( WrapX( surface, i0+1 ), j0 );
139 c01 = GetPixel( i0, WrapY( surface, j0+1 ) );
140 c11 = GetPixel( WrapX( surface, i0+1 ), WrapY( surface, j0+1 ) );
141 }
142 else
143 {
144 c10 = c01 = c11 = c00;
145 }
146
147 // Try to deal with the color ghosting problem. A pixel that isn't 0x00000000 probably is
148 // a color with alpha. A truly black, transparent pixel is probably just extra.
149
150 if ( ( ( c00.a | c01.a | c10.a | c11.a ) == 0 )
151 || ( ( c00.a & c01.a & c10.a & c11.a ) == 255 ) )
152 {
153 float r = BilinearInterpolate( (float)c00.r, (float)c10.r, (float)c01.r, (float)c11.r, di, dj );
154 float g = BilinearInterpolate( (float)c00.g, (float)c10.g, (float)c01.g, (float)c11.g, di, dj );
155 float b = BilinearInterpolate( (float)c00.b, (float)c10.b, (float)c01.b, (float)c11.b, di, dj );
156
157 c.r = (U8)(r);
158 c.g = (U8)(g);
159 c.b = (U8)(b);
160 c.a = c00.a; // whatever the value is, they are all the same
161 }
162 else
163 {
164 // float weight = 0.0f;
165 // float r = 0.0f, g = 0.0f, b = 0.0f;
166
167 float qr[4] = { c00.r, c10.r, c01.r, c11.r };
168 float qg[4] = { c00.g, c10.g, c01.g, c11.g };
169 float qb[4] = { c00.b, c10.b, c01.b, c11.b };
170
171 float w[4] = { c00.a ? 1.0f : 0.0f,
172 c01.a ? 1.0f : 0.0f,
173 c10.a ? 1.0f : 0.0f,
174 c11.a ? 1.0f : 0.0f };
175
176 // The RGB channel uses a weighted interpolation to try to not pick up a transparent
177 // pixel of the wrong color. The A channel is a simple bi-linear interp.
178 c.r = (U8)BilinearInterpolate( qr, di, dj, w );
179 c.g = (U8)BilinearInterpolate( qg, di, dj, w );
180 c.b = (U8)BilinearInterpolate( qb, di, dj, w );
181 c.a = (U8)BilinearInterpolate( (float)c00.a, (float)c10.a, (float)c01.a, (float)c11.a, di, dj );
182 }
183 return c;
184 }
185
186 /* Set up a texture. Requires:
187 - P the origin of the texture in screen pixels
188 - Q the u-stride of the texture in screen pixels
189 - R the v-stride of the texture in screen pixels
190 */
InitTexture(SDL_Surface * s,bool overlay,const Vector2I & p,const Vector2I & _q,const Vector2I & _r,U8 alpha,bool emit)191 void Texture::InitTexture( SDL_Surface* s,
192 bool overlay,
193 const Vector2I& p,
194 const Vector2I& _q,
195 const Vector2I& _r,
196 U8 alpha,
197 bool emit )
198 {
199 if ( !s ) {
200 surface = 0;
201 return;
202 }
203 this->alpha = alpha;
204 this->emit = emit;
205
206 if ( overlay && s->format->BytesPerPixel < 4 )
207 colorKey = true;
208
209 surface = s;
210 origin = p;
211
212 Vector2I q = { _q.x - p.x, _q.y - p.y };
213 Vector2I r = { _r.x - p.x, _r.y - p.y };
214
215 // derived from at q, u=1, v=0
216 // at r, u=0, v=1
217
218 int abDenom = q.y*r.x - q.x*r.y;
219 int cdDenom = q.x*r.y - q.y*r.x;
220 GLASSERT( abDenom );
221 GLASSERT( cdDenom );
222
223 a = (float)(-r.y) / (float)(abDenom);
224 b = (float)(r.x) / (float)(abDenom);
225 c = (float)(-q.y) / (float)(cdDenom);
226 d = (float)(q.x) / (float)(cdDenom);
227 }
228
229
CreateSurface(int x,int y,int z)230 SDL_Surface* CreateSurface( int x, int y, int z )
231 {
232 int sx = isoWidth*(x+y)/2;
233 int sy = tileHeight*(1+z);
234
235 SDL_Surface* surface = SDL_CreateRGBSurface( SDL_SWSURFACE,
236 sx, sy,
237 32,
238 0xff, 0xff<<8, 0xff<<16, 0xff<<24 );
239 return surface;
240 }
241
242
Render(SDL_Surface * surface,list<Edge * > * leftEdges,list<Edge * > * rightEdges,const Vector3F & normal,Texture * textureArr,int numTexture)243 void Render( SDL_Surface* surface,
244 list< Edge* > *leftEdges, list< Edge* > *rightEdges,
245 const Vector3F& normal,
246 Texture* textureArr,
247 int numTexture )
248 {
249 // Initialize the edges.
250 Edge* left = leftEdges->front();
251 leftEdges->pop_front();
252 Edge* right = rightEdges->front();
253 rightEdges->pop_front();
254
255 // Compute the color components.
256 Color3F light;
257 float dot = DotProduct( normal, lightVector );
258 GLASSERT( dot >= 0.0f );
259 light.r = ambient.r + diffuse.r * dot;
260 light.g = ambient.g + diffuse.g * dot;
261 light.b = ambient.b + diffuse.b * dot;
262 U8 r = Clamp( LRintf( 255.0f * light.r ), (long)0, (long)255 );
263 U8 g = Clamp( LRintf( 255.0f * light.g ), (long)0, (long)255 );
264 U8 b = Clamp( LRintf( 255.0f * light.b ), (long)0, (long)255 );
265
266 // Main rendering loop.
267 while ( left && right )
268 {
269 GLASSERT( left->Y() == right->Y() );
270
271 int xmin = left->X();
272 int xmax = right->X();
273
274 GLASSERT( xmin <= xmax );
275
276 if ( left->NoTouch() ) xmin++;
277 if ( right->NoTouch() ) xmax--;
278
279 GLASSERT( left->Y() >= 0 && left->Y() < surface->h );
280 U32* scanline = (U32*)((U8*)surface->pixels + left->Y()*surface->pitch);
281
282 const U32 color = (r) | (g<<8) | (b<<16) | (255<<24);
283 Color4U8 frag;
284 Color4U8 cPrime;
285
286 for( int i=0; i<numTexture; ++i )
287 {
288 Texture* texture = &textureArr[i];
289
290 for( int x=xmin; x<=xmax; ++x )
291 {
292 GLASSERT( x >= 0 && x < surface->w );
293 #ifdef DEBUG
294 if ( i == 0 ) GLASSERT( !texture || !texture->Valid() || texture->Alpha() == 255 );
295 #endif
296
297 if ( texture && texture->Valid() ) {
298
299 // Get the textel color
300 grinliz::Color4U8 textel = texture->Lookup( x, left->Y() );
301
302 if ( !texture->Emit() ) {
303 // Not emmissive, so apply the lighting.
304 textel.r = textel.r * r / 255;
305 textel.g = textel.g * g / 255;
306 textel.b = textel.b * b / 255;
307 // the alpha is uneffected
308 }
309
310 if ( texture->Alpha() == 255 && textel.a == 255 )
311 {
312 // Opaque
313 scanline[x] = (textel.r) | (textel.g<<8) | (textel.b<<16) | (255<<24);
314 }
315 else if ( textel.a != 0 )
316 {
317 // Translucent (or possibly transparent)
318 U32 alpha = texture->Alpha() * textel.a / 255;
319 GLASSERT( alpha < 256 );
320
321 frag.r = (scanline[x]>>0) & 0xff;
322 frag.g = (scanline[x]>>8) & 0xff;
323 frag.b = (scanline[x]>>16) & 0xff;
324
325 cPrime.r = ( frag.r*(255-alpha) + textel.r*alpha )/255;
326 cPrime.g = ( frag.g*(255-alpha) + textel.g*alpha )/255;
327 cPrime.b = ( frag.b*(255-alpha) + textel.b*alpha )/255;
328
329 scanline[x] = (cPrime.r) | (cPrime.g<<8) | (cPrime.b<<16) | (255<<24);
330 }
331 }
332 else {
333 scanline[x] = color;
334 }
335 }
336 }
337 // Through all the texture stuff. Back to edge processing.
338 if ( !left->Next() ) {
339 delete left;
340 left = 0;
341 if ( !leftEdges->empty() ) {
342 left = leftEdges->front();
343 leftEdges->pop_front();
344 }
345 }
346 if ( !right->Next() ) {
347 delete right;
348 right = 0;
349 if ( !rightEdges->empty() ) {
350 right = rightEdges->front();
351 rightEdges->pop_front();
352 }
353 }
354 }
355 }
356
357
RenderZ(SDL_Surface * surface,U32 flags)358 void RenderZ( SDL_Surface* surface, U32 flags )
359 {
360 list< Edge* > left, right;
361
362 int leftX0 = tileWidth/2-1;
363 int leftX1 = 0;
364 int leftY0min = 0;
365 int leftY0max = tileHeight/2-1;
366 int leftY1min = tileHeight/2;
367 int leftY1max = tileHeight-1;
368
369 int rightX0 = tileWidth/2;
370 int rightX1 = tileWidth-1;
371 int rightY0min = 0;
372 int rightY0max = tileHeight/2-1;
373 int rightY1min = tileHeight/2;
374 int rightY1max = tileHeight-1;
375
376 int ox = 1;
377
378 if ( flags & NORTH )
379 {
380 left.push_back( new IsoEdgeNeg( leftX0-step*2+ox, leftY0min+step, leftY0max-step ));
381 left.push_back( new IsoEdgePos( leftX1+step*2+ox, leftY1min-step, leftY1max-step*3 ));
382
383 right.push_back( new IsoEdgePos( rightX0-step*2+ox, rightY0min+step, rightY0max-step ));
384 right.push_back( new IsoEdgeNeg( rightX1-step*6+ox, rightY1min-step, rightY1max-step*3 ));
385 }
386 else if ( flags & SOUTH )
387 {
388 left.push_back( new IsoEdgeNeg( leftX0+step*2+ox, leftY0min+step*3, leftY0max+step ));
389 left.push_back( new IsoEdgePos( leftX1+step*6+ox, leftY1min+step, leftY1max-step ));
390
391 right.push_back( new IsoEdgePos( rightX0+step*2+ox, rightY0min+step*3, rightY0max+step ));
392 right.push_back( new IsoEdgeNeg( rightX1-step*2+ox, rightY1min+step, rightY1max-step ));
393 }
394 else if ( flags & CENTER )
395 {
396 left.push_back( new IsoEdgeNeg( leftX0+ox, leftY0min+step*2, leftY0max ));
397 left.push_back( new IsoEdgePos( leftX1+step*4+ox, leftY1min, leftY1max-step*2 ));
398
399 right.push_back( new IsoEdgePos( rightX0+ox, rightY0min+step*2, rightY0max ));
400 right.push_back( new IsoEdgeNeg( rightX1-step*4+ox, rightY1min, rightY1max-step*2 ));
401 }
402 else if ( flags & EAST )
403 {
404 left.push_back( new IsoEdgeNeg( leftX0+step*2+ox, leftY0min+step, leftY0max-step ));
405 left.push_back( new IsoEdgePos( leftX1+step*6+ox, leftY1min-step, leftY1max-step*2 ));
406
407 right.push_back( new IsoEdgePos( rightX0+step*2+ox, rightY0min+step, rightY0max-step ));
408 right.push_back( new IsoEdgeNeg( rightX1-step*2+ox, rightY1min-step, rightY1max-step*3 ));
409 }
410 else if ( flags & WEST )
411 {
412 left.push_back( new IsoEdgeNeg( leftX0-step*2+ox, leftY0min+step*3, leftY0max+step ));
413 left.push_back( new IsoEdgePos( leftX1+step*2+ox, leftY1min+step, leftY1max-step ));
414
415 right.push_back( new IsoEdgePos( rightX0-step*2+ox, rightY0min+step*3, rightY0max+step ));
416 right.push_back( new IsoEdgeNeg( rightX1-step*6+ox, rightY1min+step, rightY1max-step ));
417 }
418 else
419 {
420 // Simple draw.
421 left.push_back( new IsoEdgeNeg( leftX0+ox, leftY0min, leftY0max ));
422 left.push_back( new IsoEdgePos( leftX1+ox, leftY1min, leftY1max ));
423
424 right.push_back( new IsoEdgePos( rightX0+ox, rightY0min, rightY0max ));
425 right.push_back( new IsoEdgeNeg( rightX1+ox, rightY1min, rightY1max ));
426 }
427
428 //Texture tex[ MAX_TEXTURE_COUNT ];
429 std::vector< Texture > tex( pSet->floorTexture.size() );
430
431 if ( flags & USE_TEXTURE )
432 {
433 // Note that for the Z face, the texture coordinates never change if
434 // an inset is used.
435 Vector2I p = { tileWidth/2-1+ox, tileHeight };
436 Vector2I q = { p.x + isoWidth / 2, p.y - isoWidth / 4 };
437 Vector2I r = { p.x - isoWidth / 2, p.y - isoWidth / 4 };
438
439 for( unsigned i=0; i<pSet->floorTexture.size(); ++i ) {
440 tex[i].InitTexture( pSet->floorTexture[i].surface, i>0, p, q, r,
441 pSet->floorTexture[i].alpha,
442 pSet->floorTexture[i].emit );
443 }
444 }
445 GLASSERT( pSet->floorTexture.size() >=1 );
446 int numTexture = (flags & OVERLAYS) ? pSet->floorTexture.size() : 1;
447 Render( surface, &left, &right, ZFACE, &tex[0], numTexture );
448 }
449
RenderX(SDL_Surface * surface,U32 flags,int xFactor=0,int yFactor=0)450 void RenderX( SDL_Surface* surface, U32 flags, int xFactor = 0, int yFactor = 0 )
451 {
452 list< Edge* > left, right;
453
454 int ox = 1 + xFactor*isoWidth/2;
455 int oy = yFactor*isoWidth/2;
456 if ( flags & OFFSET ) {
457 ox += step*2;
458 oy += -step;
459 }
460
461 int tileHeight3_2 = tileHeight + tileHeight/2;
462
463 if ( flags & NORTH )
464 {
465 left.push_back( new VEdge( -1+ox, tileHeight/2+oy, tileHeight3_2-1+oy )); // see comment in simple case about -1
466 left.push_back( new IsoEdgePos( 0+ox, tileHeight3_2+oy, tileHeight3_2+step+oy ));
467
468 Edge* edge = new IsoEdgePos( 0+ox, tileHeight/2+oy, tileHeight/2+step+oy );
469 edge->SetNoTouch();
470 right.push_back( edge );
471 right.push_back( new VEdge( step*2+ox, tileHeight/2+step+1+oy, tileHeight3_2+step+oy ));
472 }
473 else if ( flags & SOUTH )
474 {
475 left.push_back( new VEdge( tileWidth/2-1-2*step+ox, tileHeight-1-step+oy, tileHeight*2-2-step+oy ));
476 left.push_back( new IsoEdgePos( tileWidth/2-1-2*step+ox, tileHeight*2-1-step+oy, tileHeight*2-1+oy ));
477
478 Edge* edge = new IsoEdgePos( tileWidth/2-1-2*step+ox, tileHeight-1-step+oy, tileHeight-1+oy );
479 edge->SetNoTouch();
480 right.push_back( edge );
481 right.push_back( new VEdge( tileWidth/2-1+ox, tileHeight+oy, tileHeight*2-1+oy ));
482 }
483 else if ( flags & CENTER )
484 {
485 left.push_back( new VEdge( 0+step*2+ox, tileHeight/2+step+oy, tileHeight3_2-1+step+oy ));
486 left.push_back( new IsoEdgePos( 0+step*2+ox, tileHeight3_2+step+oy, tileHeight*2-1-step+oy ));
487
488 Edge* edge = new IsoEdgePos( 0+step*2+ox, tileHeight/2+step+oy, tileHeight-1-step+oy );
489 edge->SetNoTouch();
490 right.push_back( edge );
491 right.push_back( new VEdge( tileWidth/2-1-step*2+ox, tileHeight-step+oy, tileHeight*2-1-step+oy ));
492 }
493 else
494 {
495 // Note the -1 "cheat" patches up texture seeming between tiles - filling
496 // the difference between the isoSize and the tileWidth.
497 //
498 left.push_back( new VEdge( -1+ox, tileHeight/2+oy, tileHeight3_2-1+oy ));
499 left.push_back( new IsoEdgePos( 0+ox, tileHeight3_2+oy, tileHeight*2-1+oy ));
500
501 Edge* edge = new IsoEdgePos( 0+ox, tileHeight/2+oy, tileHeight-1+oy );
502 edge->SetNoTouch();
503 right.push_back( edge );
504 right.push_back( new VEdge( tileWidth/2-1+ox, tileHeight+oy, tileHeight*2-1+oy ));
505 }
506
507 //Texture tex[ MAX_TEXTURE_COUNT ];
508 std::vector< Texture > tex( pSet->wallTexture.size() );
509 if ( flags & USE_TEXTURE )
510 {
511 Vector2I p = { -1+ox, -1+tileHeight + tileHeight/2 + oy};
512 Vector2I q = { p.x + isoWidth / 2, p.y + isoWidth / 4 };
513 Vector2I r = { p.x, p.y - isoWidth / 2 };
514 for( unsigned i=0; i<pSet->wallTexture.size(); ++i ) {
515 tex[i].InitTexture( pSet->wallTexture[i].surface, i>0, p, q, r,
516 pSet->wallTexture[i].alpha,
517 pSet->wallTexture[i].emit );
518 }
519 }
520 GLASSERT( pSet->wallTexture.size() >=1 );
521 int numTexture = (flags & OVERLAYS) ? pSet->wallTexture.size() : 1;
522
523 Render( surface, &left, &right, XFACE, &tex[0], numTexture );
524 }
525
526
RenderY(SDL_Surface * surface,U32 flags,int xFactor=0,int yFactor=0)527 void RenderY( SDL_Surface* surface, U32 flags, int xFactor=0, int yFactor=0 )
528 {
529 list< Edge* > left, right;
530
531 int ox = 1 + xFactor*isoWidth/2;
532 int oy = 0 + yFactor*isoWidth/2;
533 if ( flags & OFFSET ) {
534 ox += -step*2;
535 oy += -step;
536 }
537
538 int tileHeight3_2 = tileHeight+tileHeight/2;
539
540 if ( flags & CENTER )
541 {
542 Edge* edge = new IsoEdgeNeg( tileWidth-1-step*2+ox, tileHeight/2+step+oy, tileHeight-1-step+oy );
543 edge->SetNoTouch();
544 left.push_back( edge );
545 left.push_back( new VEdge( tileWidth/2+step*2+ox, tileHeight-step+oy, tileHeight*2-1-step+oy ));
546
547 right.push_back( new VEdge( tileWidth-1-step*2+ox, tileHeight/2+step+oy, tileHeight3_2-1+step+oy ));
548 right.push_back( new IsoEdgeNeg( tileWidth-1-step*2+ox, tileHeight3_2+step+oy, tileHeight*2-1-step+oy ));
549 }
550 else if ( flags & EAST )
551 {
552 Edge* edge = new IsoEdgeNeg( tileWidth-1+ox, tileHeight/2+oy, tileHeight/2+step+oy );
553 edge->SetNoTouch();
554 left.push_back( edge );
555 left.push_back( new VEdge( tileWidth-1-step*2+ox, tileHeight/2+step+1+oy, tileHeight3_2+step+oy ));
556
557 // The +1 in the VEdge x patches the isoTile vs isoWidth discrepancy
558 right.push_back( new VEdge( tileWidth-1+ox+1, tileHeight/2+oy, tileHeight3_2-1+oy ));
559 right.push_back( new IsoEdgeNeg( tileWidth-1+ox, tileHeight3_2+oy, tileHeight3_2+step+oy ));
560 }
561 else if ( flags & WEST )
562 {
563 Edge* edge = new IsoEdgeNeg( tileWidth/2+step*2+ox, tileHeight-1-step+oy, tileHeight-1+oy );
564 edge->SetNoTouch();
565 left.push_back( edge );
566 left.push_back( new VEdge( tileWidth/2+ox, tileHeight+oy, tileHeight*2-1+oy ));
567
568 right.push_back( new VEdge( tileWidth/2+step*2+ox, tileHeight-1-step+oy, tileHeight*2-2-step+oy ));
569 right.push_back( new IsoEdgeNeg( tileWidth/2+step*2+ox, tileHeight*2-1-step+oy, tileHeight*2-1+oy ));
570 }
571 else
572 {
573 Edge* edge = new IsoEdgeNeg( tileWidth-1+ox, tileHeight/2+oy, tileHeight-1+oy );
574 edge->SetNoTouch();
575 left.push_back( edge );
576 left.push_back( new VEdge( tileWidth/2+ox, tileHeight+oy, tileHeight*2-1+oy ));
577
578 // The erraint +1 in the x value of the VEdge account for the difference between
579 // the isoWidth and the tileWidth
580 right.push_back( new VEdge( tileWidth-1+ox+1, tileHeight/2+oy, tileHeight3_2-1+oy ));
581 right.push_back( new IsoEdgeNeg( tileWidth-1+ox, tileHeight3_2+oy, tileHeight*2-1+oy ));
582 }
583
584 //Texture tex[ MAX_TEXTURE_COUNT ];
585 std::vector< Texture > tex( pSet->wallTexture.size() );
586 if ( flags & USE_TEXTURE )
587 {
588 Vector2I p = { tileWidth/2+ox, tileHeight*2-1+oy };
589 Vector2I q = { p.x + isoWidth / 2, p.y - isoWidth / 4 };
590 Vector2I r = { p.x, p.y - isoWidth / 2 };
591
592 for( unsigned i=0; i<pSet->wallTexture.size(); ++i ) {
593 tex[i].InitTexture( pSet->wallTexture[i].surface, i>0, p, q, r,
594 pSet->wallTexture[i].alpha,
595 pSet->wallTexture[i].emit );
596 }
597 }
598 GLASSERT( pSet->wallTexture.size() >=1 );
599 int numTexture = (flags & OVERLAYS) ? pSet->wallTexture.size() : 1;
600
601 Render( surface, &left, &right, YFACE, &tex[0], numTexture );
602 }
603
RenderRamp(SDL_Surface * surface,U32 flags,int size)604 void RenderRamp( SDL_Surface* surface, U32 flags, int size )
605 {
606 list< Edge* > left, right;
607
608 int ox = 1;
609 int oy = 0;
610 int mult = size-1;
611
612 // if ( flags & OFFSET ) {
613 // ox += -step*2;
614 // oy += -step;
615 // }
616
617 int tileHeight3_2 = tileHeight+tileHeight/2;
618
619 Vector2I p, q, r;
620 Vector3F normal;
621
622 if ( flags & NORTH )
623 {
624 left.push_back( new IsoEdgeNeg( tileWidth/2-1+ox, 0+oy, tileHeight/2-1+oy ));
625 left.push_back( new LineEdge( 0+ox, tileHeight/2+oy,
626 tileWidth/2-1+ox+isoWidth*mult/2, tileHeight*2-1+oy+tileHeight3_2*mult ));
627
628 right.push_back( new LineEdge( tileWidth/2+ox, oy,
629 tileWidth-1+ox+isoWidth*mult/2, tileHeight3_2-1+oy+tileHeight3_2*mult ));
630 right.push_back( new IsoEdgeNeg( tileWidth-1+ox+isoWidth*mult/2, tileHeight3_2+oy+tileHeight3_2*mult, tileHeight*2-1+oy+tileHeight3_2*mult ));
631
632 p.x = tileWidth/2-1+ox+tileWidth*mult/2; p.y = tileHeight*2+oy+tileHeight3_2*mult;
633 q.x = p.x + isoWidth/2; q.y = p.y - isoWidth / 4;
634 r.x = p.x - isoWidth/2; r.y = p.y - isoWidth * 3 / 4;
635
636 normal.Set( 0, -1, 1 );
637 }
638 else
639 {
640 left.push_back( new LineEdge( tileWidth/2-1+ox+mult*isoWidth/2, 0+oy,
641 0+ox, tileHeight3_2-1+oy+tileHeight3_2*mult ) );
642 left.push_back( new IsoEdgePos( 0+ox, tileHeight3_2+oy+tileHeight3_2*mult, tileHeight*mult+tileHeight*2-1+oy+tileHeight3_2*mult ) );
643
644 right.push_back( new IsoEdgePos( tileWidth/2+ox+mult*isoWidth/2, 0+oy, tileHeight/2-1+oy ) );
645 right.push_back( new LineEdge( tileWidth-1+ox+mult*isoWidth/2, tileHeight/2+oy,
646 tileWidth/2+ox, tileHeight*2-1+oy+tileHeight3_2*mult ) );
647
648 p.x = tileWidth/2-1+ox; p.y = tileHeight*2+oy+tileHeight3_2*mult;
649 q.x = p.x + isoWidth/2; q.y = p.y - isoWidth*3/ 4;
650 r.x = p.x - isoWidth/2; r.y = p.y - isoWidth / 4;
651
652 normal.Set( -1, 0, 1 );
653 }
654
655 normal.Normalize();
656
657 //Texture tex[ MAX_TEXTURE_COUNT ];
658 std::vector< Texture > tex( pSet->floorTexture.size() );
659 if ( flags & USE_TEXTURE )
660 {
661 for( unsigned i=0; i<pSet->floorTexture.size(); ++i ) {
662 tex[i].InitTexture( pSet->floorTexture[i].surface, i>0, p, q, r,
663 pSet->floorTexture[i].alpha,
664 pSet->floorTexture[i].emit );
665 }
666 }
667 Render( surface, &left, &right, normal,
668 &tex[0], (flags&OVERLAYS) ? pSet->floorTexture.size() : 1);
669 }
670
671 enum {
672 FLOOR_FLAT,
673 CUBE_FLAT,
674 FLOOR_BASIC,
675 CUBE_BASIC,
676
677 JOIN_NWSE,
678 WALL_NS,
679 WALL_WE,
680
681 JOIN_NW,
682 JOIN_NE,
683 JOIN_WS,
684 JOIN_SE,
685
686 JOIN_NWS,
687 JOIN_NSE,
688 JOIN_NWE,
689 JOIN_WSE,
690
691 RAMP_E,
692 RAMP_N,
693
694 JOIN_NWSE_DOUBLE,
695 WALL_NS_DOUBLE,
696 WALL_WE_DOUBLE,
697 JOIN_NW_DOUBLE,
698 JOIN_NE_DOUBLE,
699 JOIN_WS_DOUBLE,
700 JOIN_SE_DOUBLE,
701 JOIN_NWS_DOUBLE,
702 JOIN_NSE_DOUBLE,
703 JOIN_NWE_DOUBLE,
704 JOIN_WSE_DOUBLE,
705 RAMP_E_DOUBLE,
706 RAMP_N_DOUBLE,
707
708 ICON_TYPE_COUNT
709 };
710
711
712 const char* const gIconName[ICON_TYPE_COUNT] =
713 {
714 "BASE_FLOOR",
715 "BASE_CUBE",
716 "FLOOR",
717 "CUBE",
718
719 "JOIN.NWSE",
720 "WALL.NS",
721 "WALL.WE",
722
723 "JOIN.NW",
724 "JOIN.NE",
725 "JOIN.WS",
726 "JOIN.SE",
727
728 "JOIN.NWS",
729 "JOIN.NSE",
730 "JOIN.NWE",
731 "JOIN.WSE",
732
733 "RAMP.E",
734 "RAMP.N",
735
736 "JOIN.NWSE.2",
737 "WALL.NS.2",
738 "WALL.WE.2",
739
740 "JOIN.NW.2",
741 "JOIN.NE.2",
742 "JOIN.WS.2",
743 "JOIN.SE.2",
744
745 "JOIN.NWS.2",
746 "JOIN.NSE.2",
747 "JOIN.NWE.2",
748 "JOIN.WSE.2",
749
750 "RAMP.E.2",
751 "RAMP.N.2",
752 };
753
754
755
WriteIconToXML(TiXmlNode * xmlNode,const char * name,int x,int y,int w,int h,int hotX,int hotY)756 void WriteIconToXML( TiXmlNode* xmlNode, const char* name, int x, int y, int w, int h, int hotX, int hotY )
757 {
758 string actionName = pSet->action + "." + name;
759
760 TiXmlElement frame( "Frame" );
761 frame.SetAttribute( "x", x );
762 frame.SetAttribute( "y", y );
763 frame.SetAttribute( "width", w );
764 frame.SetAttribute( "height", h );
765 frame.SetAttribute( "hotspotx", hotX );
766 frame.SetAttribute( "hotspoty", hotY );
767
768 TiXmlElement action( "Action" );
769 action.InsertEndChild( frame );
770 action.SetAttribute( "name", actionName.c_str() );
771
772 xmlNode->InsertEndChild( action );
773 }
774
775
DrawIcons(SDL_Surface * saveSurface,TiXmlNode * xmlNode)776 void DrawIcons( SDL_Surface* saveSurface, TiXmlNode* xmlNode )
777 {
778 static bool flatWritten = false;
779
780 bool done = false;
781
782 for( int count=0; !done; ++count )
783 {
784 SDL_Surface* surface = 0;
785 int hotX = 0;
786 int hotY = 0;
787
788 switch (count)
789 {
790 case FLOOR_FLAT:
791 if ( ( pSet->drawAll || pSet->drawBasic ) && !flatWritten )
792 {
793 // Draw the top z plane. This
794 // is for creating more tiles and checking color.
795 surface = CreateSurface( 1, 1, 1 );
796 RenderZ( surface, 0 );
797
798 hotX = isoWidth / 2 - 1;
799 hotY = tileHeight * 2 - 1;
800 }
801 break;
802
803 case CUBE_FLAT:
804 if ( ( pSet->drawAll || pSet->drawBasic ) && !flatWritten )
805 {
806 flatWritten = true;
807
808 // Draw a white cube. This
809 // is for creating more tiles and checking color.
810 surface = CreateSurface( 1, 1, 1 );
811 surface = CreateSurface( 1, 1, 1 );
812 RenderZ( surface, 0 );
813 RenderX( surface, 0 );
814 RenderY( surface, 0 );
815
816 hotX = isoWidth / 2 - 1;
817 hotY = tileHeight * 2 - 1;
818 }
819 break;
820
821 case FLOOR_BASIC:
822 if ( pSet->drawAll || pSet->drawBasic )
823 {
824 // Draw the top z plane textured.
825 surface = CreateSurface( 1, 1, 1 );
826 RenderZ( surface, USE_TEXTURE | OVERLAYS );
827
828 hotX = isoWidth / 2 - 1;
829 hotY = tileHeight * 2 - 1;
830 }
831 break;
832
833 case CUBE_BASIC:
834 if ( pSet->drawAll || pSet->drawBasic )
835 {
836 // Draw the basic cube
837 surface = CreateSurface( 1, 1, 1 );
838 RenderZ( surface, USE_TEXTURE | OVERLAYS );
839 RenderX( surface, USE_TEXTURE | OVERLAYS);
840 RenderY( surface, USE_TEXTURE | OVERLAYS);
841
842 hotX = isoWidth / 2 - 1;
843 hotY = tileHeight * 2 - 1;
844 }
845 break;
846
847 case JOIN_NWSE:
848 if ( pSet->drawAll || pSet->drawJoin )
849 {
850 // Draw a NWSE wall (the first one because
851 // it tends to break when something goes wrong).
852 surface = CreateSurface( 1, 1, 1 );
853
854 RenderX( surface, USE_TEXTURE | NORTH | OFFSET );
855 RenderY( surface, USE_TEXTURE | EAST | OFFSET );
856
857 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET );
858 RenderX( surface, USE_TEXTURE | CENTER );
859
860 RenderY( surface, USE_TEXTURE | WEST | OFFSET );
861 RenderY( surface, USE_TEXTURE | CENTER );
862
863 RenderZ( surface, USE_TEXTURE | NORTH );
864 RenderZ( surface, USE_TEXTURE | SOUTH );
865 RenderZ( surface, USE_TEXTURE | CENTER );
866 RenderZ( surface, USE_TEXTURE | EAST );
867 RenderZ( surface, USE_TEXTURE | WEST );
868
869 hotX = isoWidth / 2 - 1;
870 hotY = tileHeight * 2 - 1;
871 }
872 break;
873
874 case WALL_NS:
875 if ( pSet->drawAll || pSet->drawWall )
876 {
877 // Draw a NS wall
878 surface = CreateSurface( 1, 1, 1 );
879 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS);
880
881 RenderY( surface, USE_TEXTURE | CENTER );
882
883 RenderZ( surface, USE_TEXTURE | NORTH );
884 RenderZ( surface, USE_TEXTURE | SOUTH );
885 RenderZ( surface, USE_TEXTURE | CENTER );
886
887 hotX = isoWidth / 2 - 1;
888 hotY = tileHeight * 2 - 1;
889 }
890 break;
891
892 case WALL_WE:
893 if ( pSet->drawAll || pSet->drawWall )
894 {
895 // Draw a WE wall
896 surface = CreateSurface( 1, 1, 1 );
897 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS);
898
899 RenderX( surface, USE_TEXTURE | CENTER );
900
901 RenderZ( surface, USE_TEXTURE | EAST );
902 RenderZ( surface, USE_TEXTURE | WEST );
903 RenderZ( surface, USE_TEXTURE | CENTER );
904
905 hotX = isoWidth / 2 - 1;
906 hotY = tileHeight * 2 - 1;
907 }
908 break;
909
910 case JOIN_NW:
911 if ( pSet->drawAll || pSet->drawJoin )
912 {
913 surface = CreateSurface( 1, 1, 1 );
914
915 RenderX( surface, USE_TEXTURE | NORTH | OFFSET );
916 RenderX( surface, USE_TEXTURE | CENTER );
917
918 RenderY( surface, USE_TEXTURE | WEST | OFFSET );
919 RenderY( surface, USE_TEXTURE | CENTER | OFFSET);
920
921 RenderZ( surface, USE_TEXTURE | NORTH );
922 RenderZ( surface, USE_TEXTURE | CENTER );
923 RenderZ( surface, USE_TEXTURE | WEST );
924
925 hotX = isoWidth / 2 - 1;
926 hotY = tileHeight * 2 - 1;
927 }
928 break;
929
930 case JOIN_NE:
931 if ( pSet->drawAll || pSet->drawJoin )
932 {
933 surface = CreateSurface( 1, 1, 1 );
934
935 RenderX( surface, USE_TEXTURE | NORTH | OFFSET );
936 RenderX( surface, USE_TEXTURE | CENTER | OFFSET );
937
938 RenderY( surface, USE_TEXTURE | EAST | OFFSET );
939 RenderY( surface, USE_TEXTURE | CENTER | OFFSET);
940
941 RenderZ( surface, USE_TEXTURE | NORTH );
942 RenderZ( surface, USE_TEXTURE | CENTER );
943 RenderZ( surface, USE_TEXTURE | EAST );
944
945 hotX = isoWidth / 2 - 1;
946 hotY = tileHeight * 2 - 1;
947 }
948 break;
949
950 case JOIN_WS:
951 if ( pSet->drawAll || pSet->drawJoin )
952 {
953 surface = CreateSurface( 1, 1, 1 );
954
955 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET );
956 RenderX( surface, USE_TEXTURE | CENTER );
957
958 RenderY( surface, USE_TEXTURE | WEST | OFFSET );
959 RenderY( surface, USE_TEXTURE | CENTER);
960
961 RenderZ( surface, USE_TEXTURE | WEST );
962 RenderZ( surface, USE_TEXTURE | CENTER );
963 RenderZ( surface, USE_TEXTURE | SOUTH );
964
965 hotX = isoWidth / 2 - 1;
966 hotY = tileHeight * 2 - 1;
967 }
968 break;
969
970 case JOIN_SE:
971 if ( pSet->drawAll || pSet->drawJoin )
972 {
973 surface = CreateSurface( 1, 1, 1 );
974
975 RenderY( surface, USE_TEXTURE | EAST | OFFSET );
976 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET );
977 RenderX( surface, USE_TEXTURE | CENTER | OFFSET );
978 RenderY( surface, USE_TEXTURE | CENTER );
979
980 RenderZ( surface, USE_TEXTURE | EAST );
981 RenderZ( surface, USE_TEXTURE | CENTER );
982 RenderZ( surface, USE_TEXTURE | SOUTH );
983
984 hotX = isoWidth / 2 - 1;
985 hotY = tileHeight * 2 - 1;
986 }
987 break;
988
989 case JOIN_NWS:
990 if ( pSet->drawAll || pSet->drawJoin )
991 {
992 // NWS
993 surface = CreateSurface( 1, 1, 1 );
994
995 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET );
996 RenderX( surface, USE_TEXTURE | NORTH | OFFSET );
997 RenderX( surface, USE_TEXTURE | CENTER );
998
999 RenderY( surface, USE_TEXTURE | WEST | OFFSET );
1000 RenderY( surface, USE_TEXTURE | CENTER );
1001
1002 RenderZ( surface, USE_TEXTURE | NORTH );
1003 RenderZ( surface, USE_TEXTURE | SOUTH );
1004 RenderZ( surface, USE_TEXTURE | CENTER );
1005 RenderZ( surface, USE_TEXTURE | WEST );
1006
1007 hotX = isoWidth / 2 - 1;
1008 hotY = tileHeight * 2 - 1;
1009 }
1010 break;
1011
1012 case JOIN_NSE:
1013 if ( pSet->drawAll || pSet->drawJoin || pSet->drawWallJoin )
1014 {
1015 // NSE
1016 surface = CreateSurface( 1, 1, 1 );
1017
1018 RenderY( surface, USE_TEXTURE | EAST | OFFSET );
1019 RenderY( surface, USE_TEXTURE | CENTER );
1020
1021 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS );
1022
1023 RenderZ( surface, USE_TEXTURE | NORTH );
1024 RenderZ( surface, USE_TEXTURE | SOUTH );
1025 RenderZ( surface, USE_TEXTURE | CENTER );
1026 RenderZ( surface, USE_TEXTURE | EAST );
1027
1028 hotX = isoWidth / 2 - 1;
1029 hotY = tileHeight * 2 - 1;
1030 }
1031 break;
1032
1033 case JOIN_NWE:
1034 if ( pSet->drawAll || pSet->drawJoin || pSet->drawWallJoin )
1035 {
1036 // NWE
1037 surface = CreateSurface( 1, 1, 1 );
1038
1039 RenderX( surface, USE_TEXTURE | NORTH | OFFSET );
1040 RenderX( surface, USE_TEXTURE | CENTER );
1041
1042 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS );
1043
1044 RenderZ( surface, USE_TEXTURE | NORTH );
1045 RenderZ( surface, USE_TEXTURE | CENTER );
1046 RenderZ( surface, USE_TEXTURE | EAST );
1047 RenderZ( surface, USE_TEXTURE | WEST );
1048
1049 hotX = isoWidth / 2 - 1;
1050 hotY = tileHeight * 2 - 1;
1051 }
1052 break;
1053
1054 case JOIN_WSE:
1055 if ( pSet->drawAll || pSet->drawJoin )
1056 {
1057 // WSE
1058
1059 surface = CreateSurface( 1, 1, 1 );
1060
1061 RenderY( surface, USE_TEXTURE | EAST | OFFSET );
1062 RenderY( surface, USE_TEXTURE | WEST | OFFSET );
1063 RenderY( surface, USE_TEXTURE | CENTER );
1064
1065 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET );
1066 RenderX( surface, USE_TEXTURE | CENTER );
1067
1068 RenderZ( surface, USE_TEXTURE | SOUTH );
1069 RenderZ( surface, USE_TEXTURE | CENTER );
1070 RenderZ( surface, USE_TEXTURE | EAST );
1071 RenderZ( surface, USE_TEXTURE | WEST );
1072
1073 hotX = isoWidth / 2 - 1;
1074 hotY = tileHeight * 2 - 1;
1075 }
1076 break;
1077
1078 case RAMP_E:
1079 if ( pSet->drawAll || pSet->drawRamp )
1080 {
1081 surface = CreateSurface( 1, 1, 1 );
1082
1083 RenderRamp( surface, USE_TEXTURE | EAST | OVERLAYS, 1 );
1084
1085 hotX = isoWidth / 2 - 1;
1086 hotY = tileHeight * 2 - 1;
1087 }
1088 break;
1089
1090 case RAMP_N:
1091 if ( pSet->drawAll || pSet->drawRamp )
1092 {
1093 surface = CreateSurface( 1, 1, 1 );
1094
1095 RenderRamp( surface, USE_TEXTURE | NORTH | OVERLAYS, 1 );
1096
1097 hotX = isoWidth / 2 - 1;
1098 hotY = tileHeight * 2 - 1;
1099 }
1100 break;
1101
1102 case JOIN_NWSE_DOUBLE:
1103 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1104 {
1105 // Draw a NWSE wall (the first one because
1106 // it tends to break when something goes wrong).
1107 surface = CreateSurface( 1, 1, 2 );
1108
1109 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 0 );
1110 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 1 );
1111 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 0 );
1112 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 1 );
1113
1114 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 0 );
1115 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 1 );
1116 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1117 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1118
1119 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 0 );
1120 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 1 );
1121 RenderY( surface, USE_TEXTURE | CENTER, 0, 0 );
1122 RenderY( surface, USE_TEXTURE | CENTER, 0, 1 );
1123
1124 RenderZ( surface, USE_TEXTURE | NORTH );
1125 RenderZ( surface, USE_TEXTURE | SOUTH );
1126 RenderZ( surface, USE_TEXTURE | CENTER );
1127 RenderZ( surface, USE_TEXTURE | EAST );
1128 RenderZ( surface, USE_TEXTURE | WEST );
1129
1130 hotX = isoWidth / 2 - 1;
1131 hotY = tileHeight * 3 - 1;
1132 }
1133 break;
1134
1135 case WALL_NS_DOUBLE:
1136 if ( (pSet->drawAll || pSet->drawWall) && pSet->drawDouble )
1137 {
1138 // Draw a NS wall
1139 surface = CreateSurface( 1, 1, 2 );
1140 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 0 );
1141 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 1 );
1142
1143 RenderY( surface, USE_TEXTURE | CENTER, 0, 0 );
1144 RenderY( surface, USE_TEXTURE | CENTER, 0, 1 );
1145
1146 RenderZ( surface, USE_TEXTURE | NORTH );
1147 RenderZ( surface, USE_TEXTURE | SOUTH );
1148 RenderZ( surface, USE_TEXTURE | CENTER );
1149
1150 hotX = isoWidth / 2 - 1;
1151 hotY = tileHeight * 3 - 1;
1152 }
1153 break;
1154
1155 case WALL_WE_DOUBLE:
1156 if ( (pSet->drawAll || pSet->drawWall )&& pSet->drawDouble )
1157 {
1158 // Draw a WE wall
1159 surface = CreateSurface( 1, 1, 2 );
1160 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 0 );
1161 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 1 );
1162
1163 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1164 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1165
1166 RenderZ( surface, USE_TEXTURE | EAST );
1167 RenderZ( surface, USE_TEXTURE | WEST );
1168 RenderZ( surface, USE_TEXTURE | CENTER );
1169
1170 hotX = isoWidth / 2 - 1;
1171 hotY = tileHeight * 3 - 1;
1172 }
1173 break;
1174
1175 case JOIN_NW_DOUBLE:
1176 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1177 {
1178 surface = CreateSurface( 1, 1, 2 );
1179
1180 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 0 );
1181 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 1 );
1182 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1183 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1184
1185 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 0 );
1186 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 1 );
1187 RenderY( surface, USE_TEXTURE | CENTER | OFFSET, 0, 0);
1188 RenderY( surface, USE_TEXTURE | CENTER | OFFSET, 0, 1);
1189
1190 RenderZ( surface, USE_TEXTURE | NORTH );
1191 RenderZ( surface, USE_TEXTURE | CENTER );
1192 RenderZ( surface, USE_TEXTURE | WEST );
1193
1194 hotX = isoWidth / 2 - 1;
1195 hotY = tileHeight * 3 - 1;
1196 }
1197 break;
1198
1199 case JOIN_NE_DOUBLE:
1200 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1201 {
1202 surface = CreateSurface( 1, 1, 2 );
1203
1204 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 0 );
1205 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 1 );
1206 RenderX( surface, USE_TEXTURE | CENTER | OFFSET, 0, 0 );
1207 RenderX( surface, USE_TEXTURE | CENTER | OFFSET, 0, 1 );
1208
1209 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 0 );
1210 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 1 );
1211 RenderY( surface, USE_TEXTURE | CENTER | OFFSET, 0, 0);
1212 RenderY( surface, USE_TEXTURE | CENTER | OFFSET, 0, 1);
1213
1214 RenderZ( surface, USE_TEXTURE | NORTH );
1215 RenderZ( surface, USE_TEXTURE | CENTER );
1216 RenderZ( surface, USE_TEXTURE | EAST );
1217
1218 hotX = isoWidth / 2 - 1;
1219 hotY = tileHeight * 3 - 1;
1220 }
1221 break;
1222
1223 case JOIN_WS_DOUBLE:
1224 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1225 {
1226 surface = CreateSurface( 1, 1, 2 );
1227
1228 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET , 0, 0);
1229 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET , 0, 1);
1230 RenderX( surface, USE_TEXTURE | CENTER , 0, 0);
1231 RenderX( surface, USE_TEXTURE | CENTER , 0, 1);
1232
1233 RenderY( surface, USE_TEXTURE | WEST | OFFSET , 0, 0);
1234 RenderY( surface, USE_TEXTURE | WEST | OFFSET , 0, 1);
1235 RenderY( surface, USE_TEXTURE | CENTER, 0, 0);
1236 RenderY( surface, USE_TEXTURE | CENTER, 0, 1);
1237
1238 RenderZ( surface, USE_TEXTURE | WEST );
1239 RenderZ( surface, USE_TEXTURE | CENTER );
1240 RenderZ( surface, USE_TEXTURE | SOUTH );
1241
1242 hotX = isoWidth / 2 - 1;
1243 hotY = tileHeight * 3 - 1;
1244 }
1245 break;
1246
1247 case JOIN_SE_DOUBLE:
1248 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1249 {
1250 surface = CreateSurface( 1, 1, 2 );
1251
1252 RenderY( surface, USE_TEXTURE | EAST | OFFSET , 0, 0);
1253 RenderY( surface, USE_TEXTURE | EAST | OFFSET , 0, 1);
1254 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET , 0, 0);
1255 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET , 0, 1);
1256 RenderX( surface, USE_TEXTURE | CENTER | OFFSET , 0, 0);
1257 RenderX( surface, USE_TEXTURE | CENTER | OFFSET , 0, 1);
1258 RenderY( surface, USE_TEXTURE | CENTER , 0, 0);
1259 RenderY( surface, USE_TEXTURE | CENTER , 0, 1);
1260
1261 RenderZ( surface, USE_TEXTURE | EAST );
1262 RenderZ( surface, USE_TEXTURE | CENTER );
1263 RenderZ( surface, USE_TEXTURE | SOUTH );
1264
1265 hotX = isoWidth / 2 - 1;
1266 hotY = tileHeight * 3 - 1;
1267 }
1268 break;
1269
1270 case JOIN_NWS_DOUBLE:
1271 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1272 {
1273 // NWS
1274 surface = CreateSurface( 1, 1, 2 );
1275
1276 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 0 );
1277 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 1 );
1278 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 0 );
1279 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 1 );
1280 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1281 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1282
1283 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 0 );
1284 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 1 );
1285 RenderY( surface, USE_TEXTURE | CENTER, 0, 0 );
1286 RenderY( surface, USE_TEXTURE | CENTER, 0, 1 );
1287
1288 RenderZ( surface, USE_TEXTURE | NORTH );
1289 RenderZ( surface, USE_TEXTURE | SOUTH );
1290 RenderZ( surface, USE_TEXTURE | CENTER );
1291 RenderZ( surface, USE_TEXTURE | WEST );
1292
1293 hotX = isoWidth / 2 - 1;
1294 hotY = tileHeight * 3 - 1;
1295 }
1296 break;
1297
1298 case JOIN_NSE_DOUBLE:
1299 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1300 {
1301 // NSE
1302 surface = CreateSurface( 1, 1, 2 );
1303
1304 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 0 );
1305 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 1 );
1306 RenderY( surface, USE_TEXTURE | CENTER, 0, 0 );
1307 RenderY( surface, USE_TEXTURE | CENTER, 0, 1 );
1308
1309 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 0 );
1310 RenderX( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 1 );
1311
1312 RenderZ( surface, USE_TEXTURE | NORTH );
1313 RenderZ( surface, USE_TEXTURE | SOUTH );
1314 RenderZ( surface, USE_TEXTURE | CENTER );
1315 RenderZ( surface, USE_TEXTURE | EAST );
1316
1317 hotX = isoWidth / 2 - 1;
1318 hotY = tileHeight * 3 - 1;
1319 }
1320 break;
1321
1322 case JOIN_NWE_DOUBLE:
1323 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1324 {
1325 // NWE
1326 surface = CreateSurface( 1, 1, 2 );
1327
1328 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 0 );
1329 RenderX( surface, USE_TEXTURE | NORTH | OFFSET, 0, 1 );
1330 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1331 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1332
1333 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 0 );
1334 RenderY( surface, USE_TEXTURE | OFFSET | OVERLAYS, 0, 1 );
1335
1336 RenderZ( surface, USE_TEXTURE | NORTH );
1337 RenderZ( surface, USE_TEXTURE | CENTER );
1338 RenderZ( surface, USE_TEXTURE | EAST );
1339 RenderZ( surface, USE_TEXTURE | WEST );
1340
1341 hotX = isoWidth / 2 - 1;
1342 hotY = tileHeight * 3 - 1;
1343 }
1344 break;
1345
1346 case JOIN_WSE_DOUBLE:
1347 if ( (pSet->drawAll || pSet->drawJoin ) && pSet->drawDouble )
1348 {
1349 // WSE
1350
1351 surface = CreateSurface( 1, 1, 2 );
1352
1353 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 0 );
1354 RenderY( surface, USE_TEXTURE | EAST | OFFSET, 0, 1 );
1355 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 0 );
1356 RenderY( surface, USE_TEXTURE | WEST | OFFSET, 0, 1 );
1357 RenderY( surface, USE_TEXTURE | CENTER, 0, 0 );
1358 RenderY( surface, USE_TEXTURE | CENTER, 0, 1 );
1359
1360 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 0 );
1361 RenderX( surface, USE_TEXTURE | SOUTH | OFFSET, 0, 1 );
1362 RenderX( surface, USE_TEXTURE | CENTER, 0, 0 );
1363 RenderX( surface, USE_TEXTURE | CENTER, 0, 1 );
1364
1365 RenderZ( surface, USE_TEXTURE | SOUTH );
1366 RenderZ( surface, USE_TEXTURE | CENTER );
1367 RenderZ( surface, USE_TEXTURE | EAST );
1368 RenderZ( surface, USE_TEXTURE | WEST );
1369
1370 hotX = isoWidth / 2 - 1;
1371 hotY = tileHeight * 3 - 1;
1372 }
1373 break;
1374
1375 case RAMP_E_DOUBLE:
1376 if ( pSet->drawDouble && (pSet->drawRamp || pSet->drawAll ))
1377 {
1378 surface = CreateSurface( 2, 1, 3 );
1379
1380 RenderRamp( surface, USE_TEXTURE | EAST | OVERLAYS, 2 );
1381 RenderRamp( surface, USE_TEXTURE | EAST | OVERLAYS, 2 );
1382
1383 hotX = isoWidth / 2 - 1;
1384 hotY = tileHeight*3 + tileHeight/2 - 1;
1385 }
1386 break;
1387
1388 case RAMP_N_DOUBLE:
1389 if ( pSet->drawDouble && (pSet->drawRamp || pSet->drawAll ))
1390 {
1391 surface = CreateSurface( 1, 2, 3 );
1392
1393 RenderRamp( surface, USE_TEXTURE | NORTH | OVERLAYS, 2 );
1394 RenderRamp( surface, USE_TEXTURE | NORTH | OVERLAYS, 2 );
1395
1396 hotX = isoWidth - 1;
1397 hotY = tileHeight*3 + tileHeight/2 - 1;
1398 }
1399 break;
1400
1401 default:
1402 done = true;
1403 }
1404
1405 // Save off the surface we just used.
1406 if ( surface )
1407 {
1408 int border = 0;
1409 if ( saveX + surface->w >= saveSurface->w ) {
1410 saveX = 0;
1411 saveY += saveMax;
1412 saveMax = 0;
1413 }
1414 saveMax = Max( saveMax, surface->h );
1415
1416 SDL_Rect src = { 0, 0, surface->w, surface->h };
1417 SDL_Rect dst = { saveX, saveY, surface->w, surface->h };
1418 saveX += surface->w + border;
1419
1420 SDL_BlitSurface( surface, &src, saveSurface, &dst );
1421 SDL_FreeSurface( surface );
1422
1423 WriteIconToXML( xmlNode, gIconName[count], dst.x, dst.y, dst.w, dst.h, dst.x+hotX, dst.y+hotY );
1424 }
1425 }
1426 }
1427
1428
WriteXMLHeader(TiXmlDocument * doc,const char * imageName,const char * spriteName)1429 TiXmlNode* WriteXMLHeader( TiXmlDocument* doc, const char* imageName, const char* spriteName )
1430 {
1431 TiXmlElement definition( "Definition" );
1432 definition.SetAttribute( "filename", imageName );
1433 definition.SetAttribute( "Transparent0", "#000000" );
1434
1435 TiXmlElement sprite( "Sprite" );
1436 sprite.SetAttribute( "name", spriteName );
1437
1438 definition.InsertEndChild( sprite );
1439 doc->InsertEndChild( definition );
1440
1441 return doc->FirstChildElement()->FirstChildElement();
1442 }
1443
1444
ParseTF(TiXmlElement * ele,const char * value,bool * result)1445 void ParseTF( TiXmlElement* ele, const char* value, bool *result )
1446 {
1447 if ( ele->Attribute( value ) )
1448 {
1449 if ( strcmp( ele->Attribute( value ), "true" ) == 0 ) {
1450 *result = true;
1451 }
1452 else if ( strcmp( ele->Attribute( value ), "false" ) == 0 ) {
1453 *result = false;
1454 }
1455 }
1456 }
1457
1458
ReadOverlayAttributes(TiXmlElement * ele,TexData * tex)1459 void ReadOverlayAttributes( TiXmlElement* ele, TexData* tex )
1460 {
1461 if ( ele->Attribute( "alpha" ) ) {
1462 double alpha = 1.0f;
1463 ele->Attribute( "alpha", &alpha );
1464 tex->alpha = (U8) Clamp( LRint( alpha*255.0 ), (long)0, (long)255 );
1465 }
1466 ParseTF( ele, "emit", &tex->emit );
1467 }
1468
1469
ParseXML(TiXmlDocument * doc)1470 bool ParseXML( TiXmlDocument* doc )
1471 {
1472 static int nameCount = 0;
1473
1474 TiXmlHandle docH( doc );
1475
1476 TiXmlElement* isogen = docH.FirstChildElement( "Isogen" ).Element();
1477 if ( isogen ) {
1478 bool wallInsetSet = false;
1479
1480 if ( isogen->Attribute( "sprite" )) {
1481 spriteName = isogen->Attribute( "sprite" );
1482 }
1483 else {
1484 printf( "Required 'sprite' attribute in <Isogen> not specified.\n" );
1485 return false;
1486 }
1487 if ( isogen->Attribute( "isoWidth" )) {
1488 isogen->Attribute( "isoWidth", &isoWidth );
1489 isoWidth = ((isoWidth+3)/4)*4;
1490 tileWidth = isoWidth - 2;
1491 tileHeight = isoWidth / 2;
1492 }
1493 if ( isogen->Attribute( "wallInset" )) {
1494 isogen->Attribute( "wallInset", &step );
1495 wallInsetSet = true;
1496 }
1497 if ( isogen->Attribute( "width" )) {
1498 isogen->Attribute( "width", &outWidth );
1499 }
1500 if ( isogen->Attribute( "height" )) {
1501 isogen->Attribute( "height", &outHeight );
1502 }
1503 if ( isogen->Attribute( "ambient" )) {
1504 sscanf( isogen->Attribute( "ambient" ), "%f %f %f", &ambient.r, &ambient.g, &ambient.b );
1505 }
1506 if ( isogen->Attribute( "diffuse" )) {
1507 sscanf( isogen->Attribute( "diffuse" ), "%f %f %f", &diffuse.r, &diffuse.g, &diffuse.b );
1508 }
1509 if ( isogen->Attribute( "lightVector" )) {
1510 sscanf( isogen->Attribute( "lightVector" ), "%f %f %f", &lightVector.x, &lightVector.y, &lightVector.z );
1511 }
1512
1513 if ( !wallInsetSet )
1514 step = isoWidth / 12;
1515
1516 lightVector.Normalize();
1517 lightVector.x = -lightVector.x;
1518 lightVector.y = -lightVector.y;
1519 lightVector.z = -lightVector.z;
1520
1521 TiXmlElement* setEle = 0;
1522 for( setEle = isogen->FirstChildElement( "Set" );
1523 setEle;
1524 setEle = setEle->NextSiblingElement( "Set" ) )
1525 {
1526 setData.resize( setData.size() + 1 );
1527 pSet = &setData[ setData.size()-1 ];
1528
1529 pSet->Init();
1530
1531 ParseTF( setEle, "useAA", &pSet->useAA );
1532 ParseTF( setEle, "drawAll", &pSet->drawAll );
1533 ParseTF( setEle, "drawBasic", &pSet->drawBasic );
1534 ParseTF( setEle, "drawWall", &pSet->drawWall );
1535 ParseTF( setEle, "drawJoin", &pSet->drawJoin );
1536 ParseTF( setEle, "drawWallJoin", &pSet->drawWallJoin );
1537 ParseTF( setEle, "drawRamp", &pSet->drawRamp );
1538 ParseTF( setEle, "drawDouble", &pSet->drawDouble );
1539
1540 pSet->floorTexture.resize(1);
1541 pSet->floorTexture[0].Clear();
1542 pSet->floorTexture[0].surface = whiteSurface;
1543
1544 pSet->wallTexture.resize(1);
1545 pSet->wallTexture[0].Clear();
1546 pSet->wallTexture[0].surface = whiteSurface;
1547
1548 if ( setEle->Attribute( "floor" ) ) {
1549 GLASSERT( pSet->floorTexture.size() == 1 );
1550 pSet->floorTexture[0].surface = ImageLoader( setEle->Attribute( "floor" ) );
1551 if ( !pSet->floorTexture[0].surface ) {
1552 printf( "Failed to load texture '%s'\n", setEle->Attribute( "floor" ) );
1553 return false;
1554 }
1555 }
1556 if ( setEle->Attribute( "wall" ) ) {
1557 GLASSERT( pSet->wallTexture.size() == 1 );
1558 pSet->wallTexture[0].surface = ImageLoader( setEle->Attribute( "wall" ) );
1559 if ( !pSet->wallTexture[0].surface ) {
1560 printf( "Failed to load texture '%s'\n", setEle->Attribute( "wall" ) );
1561 return false;
1562 }
1563 }
1564
1565 if ( setEle->Attribute( "action" )) {
1566 pSet->action = setEle->Attribute( "action" );
1567 }
1568 else {
1569 char buf[256];
1570 sprintf( buf, "ICON%d", nameCount++ );
1571 pSet->action = buf;
1572 }
1573
1574 TexData dummy;
1575 dummy.Clear();
1576
1577 TiXmlElement* overEle = 0;
1578 for( overEle = setEle->FirstChildElement( "FloorOverlay" );
1579 overEle;
1580 overEle = overEle->NextSiblingElement( "FloorOverlay" ) )
1581 {
1582 if ( overEle->Attribute( "name" ) ) {
1583 pSet->floorTexture.push_back( dummy );
1584 TexData* tex = &pSet->floorTexture.back();
1585
1586 tex->surface = ImageLoader( overEle->Attribute( "name" ) );
1587 if ( !tex->surface ) {
1588 printf( "Failed to load texture '%s'\n", overEle->Attribute( "name" ) );
1589 return false;
1590 }
1591 ReadOverlayAttributes( overEle, tex );
1592 }
1593 }
1594 for( overEle = setEle->FirstChildElement( "WallOverlay" );
1595 overEle;
1596 overEle = overEle->NextSiblingElement( "WallOverlay" ) )
1597 {
1598 if ( overEle->Attribute( "name" ) ) {
1599 pSet->wallTexture.push_back( dummy );
1600 TexData* tex = &pSet->wallTexture.back();
1601
1602 tex->surface = ImageLoader( overEle->Attribute( "name" ) );
1603 if ( !tex->surface ) {
1604 printf( "Failed to load texture '%s'\n", overEle->Attribute( "name" ) );
1605 return false;
1606 }
1607 ReadOverlayAttributes( overEle, tex );
1608 }
1609 }
1610 //printf( "Set has %d wall and %d floor\n", pSet->wallTexture.size(), pSet->floorTexture.size() );
1611 }
1612 pSet = 0;
1613 return true;
1614 }
1615 return false;
1616 }
1617
1618
main(int argc,char * argv[])1619 int main( int argc, char* argv[] )
1620 {
1621 if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) < 0 ) {
1622 printf( "Couldn't initialize SDL: %s\n", SDL_GetError() );
1623 return 255;
1624 }
1625
1626 void* handle = GL_LoadLibrary( "SDL_image" );
1627 if ( !handle )
1628 {
1629 exit( 1 );
1630 }
1631 ImageLoader = (ImageLoaderFunc) GL_LoadFunction( handle, "IMG_Load" );
1632 GLASSERT( ImageLoader );
1633
1634 if ( argc < 2 ) {
1635 printf( "isogen minimal usage:\n"
1636 " isogen sprite='spriteName'\n"
1637 "Where the 'spriteName' is the name of the output XML and BMP file.\n"
1638 "To provide floor and wall textures:\n"
1639 " isogen sprite='spriteName' floor='floor.bmp' wall='wall.bmp'\n"
1640 "To use an isogen XML file:\n"
1641 " isogen data.xml\n"
1642 "isogen has many more options - please see the docs.\n" );
1643 return 1;
1644 }
1645
1646 TiXmlDocument doc;
1647
1648 if ( argc == 2 && strstr( argv[1], ".xml" ) ) {
1649 doc.LoadFile( argv[1] );
1650 }
1651 else {
1652 string input = "<Isogen ";
1653 int i;
1654 for( i=1; i<argc; ++i ) {
1655 input += argv[i];
1656 input += " ";
1657 }
1658 input += "><Set ";
1659 for( i=1; i<argc; ++i ) {
1660 input += argv[i];
1661 input += " ";
1662 }
1663 input += " /></Isogen>";
1664
1665 doc.Parse( input.c_str() );
1666 }
1667
1668 if ( doc.Error() ) {
1669 printf( "Error parsing input arguments.\n" );
1670 printf( "%s\n", doc.ErrorDesc() );
1671 return 1;
1672 }
1673
1674 if ( ParseXML( &doc ) == false ) {
1675 printf( "Error parsing command line or XML.\n" );
1676 return 1;
1677 }
1678
1679 // Create the surface to save to:
1680 SDL_Surface* surface = SDL_CreateRGBSurface( SDL_SWSURFACE,
1681 outWidth, outHeight,
1682 32,
1683 0xff, 0xff<<8, 0xff<<16, 0xff<<24 );
1684 Uint32 color = SDL_MapRGBA( surface->format, 0, 0, 0, 255 );
1685 SDL_FillRect( surface, 0, color );
1686
1687 whiteSurface = SDL_CreateRGBSurface( SDL_SWSURFACE,
1688 4, 4,
1689 32,
1690 0xff, 0xff<<8, 0xff<<16, 0xff<<24 );
1691 memset( whiteSurface->pixels, 255, whiteSurface->pitch * whiteSurface->h );
1692
1693 string saveXMLName = spriteName + "_encoder.xml";
1694 string saveImageName = spriteName + ".bmp";
1695
1696 TiXmlDocument outputDoc( saveXMLName.c_str() );
1697 TiXmlNode* node = WriteXMLHeader( &outputDoc, saveImageName.c_str(), spriteName.c_str() );
1698
1699 for( unsigned i=0; i<setData.size(); ++i )
1700 {
1701 pSet = &setData[i];
1702 DrawIcons( surface, node );
1703 pSet->Clear();
1704 }
1705
1706 printf( "Writing image file '%s'.\n", saveImageName.c_str() );
1707 SDL_SaveBMP( surface, saveImageName.c_str() );
1708 printf( "Writing kyra encoder file '%s'.\n", outputDoc.Value() );
1709 outputDoc.SaveFile();
1710
1711 SDL_FreeSurface( surface );
1712 surface = 0;
1713 SDL_FreeSurface( whiteSurface );
1714 whiteSurface = 0;
1715
1716 SDL_Quit();
1717 return 0;
1718 }
1719