1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin
3   File:     G2D.c (Dolphin 2D API by Paul Donnelly, Nov. 1999)
4 
5   Copyright 1998, 1999 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Log: G2D.c,v $
14   Revision 1.1.1.1  2005/05/12 02:15:49  yasuh-to
15   Ported from dolphin source tree.
16 
17 
18     5     2000/03/24 4:08p Carl
19     Adjusted screen height for overscan
20 
21     4     2000/01/18 7:54p Hirose
22     Added GXSetNumChans() and GXSetTevOrder() calls to work with
23     new GXInit() defaults
24 
25     3     1999/12/14 7:58p Paul
26 
27     2     1999/12/12 10:08p Paul
28 
29     1     1999/12/09 12:30p Paul
30 
31  *---------------------------------------------------------------------------*/
32 
33 #include <math.h>
34 #include <G2D.h>
35 
36 /*---------------------------------------------------------------------------*
37   Defines
38  *---------------------------------------------------------------------------*/
39 
40 /*---------------------------------------------------------------------------*
41    Global variables
42  *---------------------------------------------------------------------------*/
43 
44 #define nScrX 640
45 #define nScrY 448
46 
47 static struct
48 {
49     u16        nViewportTlcX;
50     u16        nViewportTlcY;
51     u16        nViewportWidth;
52     u16        nViewportHeight;
53 
54     G2DPosOri  poCam;
55 
56     f32        rWorldX;
57     f32        rWorldY;
58     f32        rHalfX;
59     f32        rHalfY;
60 }
61 glob;
62 
63 
64 /*---------------------------------------------------------------------------*
65     Name:           G2DInitSprite
66 
67     Description:    Precalculates sprite texture coordinates
68 
69     Arguments:      G2DSprite *sprite      Pointer to sprite
70 
71     Returns:        none
72  *---------------------------------------------------------------------------*/
G2DInitSprite(G2DSprite * sprite)73 void G2DInitSprite( G2DSprite *sprite )
74 {
75     f32 rInvWidth = 1.0F / GXGetTexObjWidth(sprite->to);
76     f32 rInvHeight = 1.0F / GXGetTexObjHeight(sprite->to);;
77 
78     sprite->rS0 = ((f32)sprite->nTlcS + 0.5F) * rInvWidth;
79     sprite->rS1 = ((f32)sprite->nTlcS + sprite->nWidth - 0.5F) * rInvWidth;
80     sprite->rT0 = ((f32)sprite->nTlcT + 0.5F) * rInvHeight;
81     sprite->rT1 = ((f32)sprite->nTlcT + sprite->nHeight - 0.5F) * rInvHeight;
82 }
83 
84 
85 /*---------------------------------------------------------------------------*
86     Name:           DrawSprite
87 
88     Description:    Draws sprite (Tiles with alpha)
89 
90     Arguments:      none
91 
92     Returns:        none
93  *---------------------------------------------------------------------------*/
G2DDrawSprite(G2DSprite * sprite,G2DPosOri * po)94 void G2DDrawSprite( G2DSprite *sprite, G2DPosOri *po )
95 {
96     f32 rOX, rOY;
97     f32 rWX, rWY, rHX, rHY;
98     f32 rRelX, rRelY;
99 
100     GXClearVtxDesc();
101     GXLoadTexObj(sprite->to, GX_TEXMAP0);
102 
103     // Set Position Params
104     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0);
105     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
106 
107     // Set Tex Coord Params
108     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
109     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
110     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
111     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
112     GXSetNumTexGens(1);
113     GXSetNumChans(0);
114 
115     // Turn on alpha blending
116     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
117 
118     rOX = po->rOriX * 0.5F;
119     rOY = po->rOriY * 0.5F;
120 
121     rWX = sprite->nWidth * rOX;
122     rWY = sprite->nWidth * rOY;
123     rHX = sprite->nHeight * rOX;
124     rHY = sprite->nHeight * rOY;
125 
126     rRelX = po->rPosX - glob.poCam.rPosX;
127     rRelY = po->rPosY - glob.poCam.rPosY;
128 
129     if (rRelX >= glob.rHalfX) rRelX -= glob.rWorldX;
130     if (rRelX < -glob.rHalfX) rRelX += glob.rWorldX;
131     if (rRelY >= glob.rHalfY) rRelY -= glob.rWorldY;
132     if (rRelY < -glob.rHalfY) rRelY += glob.rWorldY;
133 
134     rRelX += glob.poCam.rPosX;
135     rRelY += glob.poCam.rPosY;
136 
137     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
138     {
139         GXPosition2f32( rRelX - rHX + rWY, rRelY - rHY - rWX );
140         GXTexCoord2f32( sprite->rS0, sprite->rT1 );
141 
142         GXPosition2f32( rRelX + rHX + rWY, rRelY + rHY - rWX );
143         GXTexCoord2f32( sprite->rS0, sprite->rT0 );
144 
145         GXPosition2f32( rRelX + rHX - rWY, rRelY + rHY + rWX  );
146         GXTexCoord2f32( sprite->rS1, sprite->rT0 );
147 
148         GXPosition2f32( rRelX - rHX - rWY, rRelY - rHY + rWX  );
149         GXTexCoord2f32( sprite->rS1, sprite->rT1 );
150     }
151     GXEnd();
152 }
153 
154 
155 /*---------------------------------------------------------------------------*
156     Name:           FillSection
157 
158     Description:    Scanline converts from a tile map to a sort buffer
159                     Handles 4 cases separately: 8bit/16bit index, Wrap/No-wrap
160 
161     Arguments:      lots!
162                     (but the function is inline so that should avoid the
163                      parameter-passing overhead)
164 
165     Returns:        none
166  *---------------------------------------------------------------------------*/
FillSection(G2DLayer * layer,s8 * aSortBuffer,s32 * nScanLine,s32 nEvent,s16 * nIdx,s32 * nL,s32 * nR,f32 * rLeft,f32 * rRight,f32 rStep0,f32 rStep1,s32 nMapX,s32 nMapY)167 static inline void FillSection( G2DLayer *layer, s8 *aSortBuffer,
168                                 s32 *nScanLine, s32 nEvent, s16 *nIdx,
169                                 s32 *nL, s32 *nR, f32 *rLeft, f32 *rRight,
170                                 f32 rStep0, f32 rStep1, s32 nMapX, s32 nMapY )
171 {
172     s32 nHMask = (1<<layer->nHS)-1;
173     s32 nVMask = (1<<layer->nVS)-1;
174     s32 nI, nJ, nK, nM;
175     s16 nMaterial;
176     s16 *pAddr;
177 
178     if (layer->nBPI == 1)
179     {
180         u8 nTile;   // 8 bits per index
181 
182         if (layer->bWrap)   // Layer wraps
183         {
184             // Scan from top to bottom
185             for(; *nScanLine <= nEvent; (*nScanLine)++)
186             {
187                 nJ = *nScanLine - 1;
188                 nK = ((nJ + nMapY) & nVMask) << layer->nHS;
189 
190                 // Scan from Left to Right
191                 for(nI=*nL; nI<=*nR; nI++)
192                 {
193                     nTile = ((u8 *)layer->map)[nK + ((nI + nMapX) & nHMask)];
194                     nMaterial = layer->tileDesc[nTile].nMaterial;
195                     pAddr = (s16 *)&layer->matDesc[nMaterial].nReserved;
196 
197                     pAddr[1]++;             // Increment count
198                     if (*pAddr != *nIdx)    // Check continuity
199                     {
200                         *nIdx += 2;
201                         *((s16 *)&aSortBuffer[*pAddr]) = (s16)(*pAddr - *nIdx);
202                     }
203                     *((u16 *)&aSortBuffer[*nIdx]) = (u16)nTile;
204                     *nIdx += 2;
205                     aSortBuffer[(*nIdx)++] = (s8)nI;
206                     aSortBuffer[(*nIdx)++] = (s8)nJ;
207                     *pAddr = *nIdx;
208                 }
209                 *rLeft += rStep0;
210                 *rRight += rStep1;
211                 *nL = (s32)floor(*rLeft);
212                 *nR = (s32)floor(*rRight);
213             }
214         }
215         else // 8 bits per index, layer doesn't wrap
216         {
217             // Scan from top to bottom
218             for(; *nScanLine <= nEvent; (*nScanLine)++)
219             {
220                 nJ = *nScanLine - 1 + nMapY;
221                 if (nJ<0)
222                 {
223                     nK = 0;
224                 }
225                 else if (nJ>nVMask)
226                 {
227                     nK = nVMask << layer->nHS;
228                 }
229                 else
230                 {
231                     nK = nJ << layer->nHS;
232                 }
233 
234                 nM = *nR+nMapX;
235                 // Scan from Left to Right
236                 for(nI=(*nL+nMapX); nI<=nM; nI++)
237                 {
238                     if (nI<0)
239                     {
240                         nTile = ((u8 *)layer->map)[nK];
241                     }
242                     else if (nI>nHMask)
243                     {
244                         nTile = ((u8 *)layer->map)[nK + nHMask];
245                     }
246                     else
247                     {
248                         nTile = ((u8 *)layer->map)[nK + nI];
249                     }
250 
251                     nMaterial = layer->tileDesc[nTile].nMaterial;
252                     pAddr = (s16 *)&layer->matDesc[nMaterial].nReserved;
253 
254                     pAddr[1]++;             // Increment count
255                     if (*pAddr != *nIdx)    // Check continuity
256                     {
257                         *nIdx += 2;
258                         *((s16 *)&aSortBuffer[*pAddr]) = (s16)(*pAddr - *nIdx);
259                     }
260                     *((u16 *)&aSortBuffer[*nIdx]) = (u16)nTile;
261                     *nIdx += 2;
262                     aSortBuffer[(*nIdx)++] = (s8)(nI - nMapX);
263                     aSortBuffer[(*nIdx)++] = (s8)(nJ - nMapY);
264                     *pAddr = *nIdx;
265                 }
266                 *rLeft += rStep0;
267                 *rRight += rStep1;
268                 *nL = (s32)floor(*rLeft);
269                 *nR = (s32)floor(*rRight);
270             }
271         }
272     }
273     else
274     {
275         u16 nTile;  // 16 bits per index
276 
277         if (layer->bWrap)   // Layer wraps
278         {
279             // Scan from top to bottom
280             for(; *nScanLine <= nEvent; (*nScanLine)++)
281             {
282                 nJ = *nScanLine - 1;
283                 nK = ((nJ + nMapY) & nVMask) << layer->nHS;
284 
285                 // Scan from Left to Right
286                 for(nI=*nL; nI<=*nR; nI++)
287                 {
288                     nTile = ((u16 *)layer->map)[nK + ((nI + nMapX) & nHMask)];
289                     nMaterial = layer->tileDesc[nTile].nMaterial;
290                     pAddr = (s16 *)&layer->matDesc[nMaterial].nReserved;
291 
292                     pAddr[1]++;             // Increment count
293                     if (*pAddr != *nIdx)    // Check continuity
294                     {
295                         *nIdx += 2;
296                         *((s16 *)&aSortBuffer[*pAddr]) = (s16)(*pAddr - *nIdx);
297                     }
298                     *((u16 *)&aSortBuffer[*nIdx]) = (u16)nTile;
299                     *nIdx += 2;
300                     aSortBuffer[(*nIdx)++] = (s8)nI;
301                     aSortBuffer[(*nIdx)++] = (s8)nJ;
302                     *pAddr = *nIdx;
303                 }
304                 *rLeft += rStep0;
305                 *rRight += rStep1;
306                 *nL = (s32)floor(*rLeft);
307                 *nR = (s32)floor(*rRight);
308             }
309         }
310         else // 16 bits per index, layer doesn't wrap
311         {
312             // Scan from top to bottom
313             for(; *nScanLine <= nEvent; (*nScanLine)++)
314             {
315                 nJ = *nScanLine - 1 + nMapY;
316                 if (nJ<0)
317                 {
318                     nK = 0;
319                 }
320                 else if (nJ>nVMask)
321                 {
322                     nK = nVMask << layer->nHS;
323                 }
324                 else
325                 {
326                     nK = nJ << layer->nHS;
327                 }
328 
329                 nM = *nR+nMapX;
330                 // Scan from Left to Right
331                 for(nI=*nL+nMapX; nI<=nM; nI++)
332                 {
333                     if (nI<0)
334                     {
335                         nTile = ((u16 *)layer->map)[nK];
336                     }
337                     else if (nI>nHMask)
338                     {
339                         nTile = ((u16 *)layer->map)[nK + nHMask];
340                     }
341                     else
342                     {
343                         nTile = ((u16 *)layer->map)[nK + nI];
344                     }
345 
346                     nMaterial = layer->tileDesc[nTile].nMaterial;
347                     pAddr = (s16 *)&layer->matDesc[nMaterial].nReserved;
348 
349                     pAddr[1]++;             // Increment count
350                     if (*pAddr != *nIdx)    // Check continuity
351                     {
352                         *nIdx += 2;
353                         *((s16 *)&aSortBuffer[*pAddr]) = (s16)(*pAddr - *nIdx);
354                     }
355                     *((u16 *)&aSortBuffer[*nIdx]) = (u16)nTile;
356                     *nIdx += 2;
357                     aSortBuffer[(*nIdx)++] = (s8)(nI - nMapX);
358                     aSortBuffer[(*nIdx)++] = (s8)(nJ - nMapY);
359                     *pAddr = *nIdx;
360                 }
361                 *rLeft += rStep0;
362                 *rRight += rStep1;
363                 *nL = (s32)floor(*rLeft);
364                 *nR = (s32)floor(*rRight);
365             }
366         }
367     }
368 }
369 
370 
371 /*---------------------------------------------------------------------------*
372     Name:           G2DDrawLayer
373 
374     Description:    Draw a background layer.
375 
376     Arguments:      G2DLayer  *layer;
377                     s8        *aSortBuffer
378     Returns:        none
379  *---------------------------------------------------------------------------*/
G2DDrawLayer(G2DLayer * layer,s8 * aSortBuffer)380 void G2DDrawLayer( G2DLayer *layer, s8 *aSortBuffer )
381 {
382     s16 *pAddr;
383     s16 aCount0 = 0;
384     s16 aCount1 = 0;
385     s16 aCount2 = 0;
386     // void *map, s32 nBPI, s32 nHS, s32 nVS,
387     // s32 bWrap, TileDesc tileDesc,
388 
389     //s32 nWidth = 1<<layer->nHS;
390     //s32 nHeight = 1<<layer->nVS;
391 
392     f32 rInvTileWidth = 1.0F / layer->nTileWidth;
393     f32 rInvTileHeight = 1.0F / layer->nTileHeight;
394 
395     s16 nIdx;
396     s32 nI, nJ, nK, nL, nR;
397     f32 rX, rY;
398     f32 rTlcX, rTrcX, rBlcX, rBrcX;
399     f32 rTlcY, rTrcY, rBlcY, rBrcY;
400     s32 nScanLine;
401     f32 rLeft, rRight, rLeftY, rRightY;
402     f32 rStep0, rStep1, rMid;
403     s32 nEvent0, nEvent1, nEvent2;
404     f32 rFrcX, rFrcY;
405     s32 nMapX, nMapY;
406     s32 nLocalMapX, nLocalMapY;
407     f32 rCamOriX, rCamOriY;
408     s16 nTile, nMaterial;
409 
410     // Turn on alpha blending always
411     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
412 
413     // Initialize NumTextures + 2 streams for sorting by texture/color
414     for( nI=0; nI<layer->nNumMaterials; nI++)
415     {
416         pAddr = (s16 *)&layer->matDesc[nI].nReserved;
417 
418         pAddr[0] = (s16)(nI<<1);    // idx
419         pAddr[1] = 0;               // Count
420     }
421     nIdx = (s16)((nI-1)<<1);
422 
423     {
424         rFrcX = glob.poCam.rPosX * rInvTileWidth;
425         rFrcY = glob.poCam.rPosY * rInvTileHeight;
426 
427         nMapX = (s32)rFrcX;
428         nMapY = (s32)rFrcY;
429 
430         rFrcX -= nMapX;
431         rFrcY -= nMapY;
432     }
433 
434     //  Avoid the need for special cases when the screen is axis aligned
435     //  by rotating the screen slightly
436     rCamOriX = glob.poCam.rOriX;
437     rCamOriY = glob.poCam.rOriY;
438 
439     if ((rCamOriX < 0.0001) && (rCamOriX > -0.0001) )
440     {
441         rCamOriX = 0.0001F;  // This is an approximation to a small rotation
442     }
443     else if ((rCamOriY < 0.0001) && (rCamOriY > -0.0001) )
444     {
445         rCamOriY = 0.0001F;
446     }
447 
448     rX = glob.nViewportWidth  * 0.5F;
449     rY = glob.nViewportHeight * 0.5F;
450 
451     //  scan-line convert a rectangle for the screen to find the minimal
452     //  set of tiles that need to be rendered.
453 
454     rTlcX = rFrcX + (((rY * rCamOriX) + (rX * rCamOriY)) * rInvTileWidth);
455     rTlcY = rFrcY + (((rY * rCamOriY) - (rX * rCamOriX)) * rInvTileHeight);
456 
457     rTrcX = rFrcX + (((rY * rCamOriX) - (rX * rCamOriY)) * rInvTileWidth);
458     rTrcY = rFrcY + (((rY * rCamOriY) + (rX * rCamOriX)) * rInvTileHeight);
459 
460     rBlcX = rFrcX - (((rY * rCamOriX) - (rX * rCamOriY)) * rInvTileWidth);
461     rBlcY = rFrcY - (((rY * rCamOriY) + (rX * rCamOriX)) * rInvTileHeight);
462 
463     rBrcX = rFrcX - (((rY * rCamOriX) + (rX * rCamOriY)) * rInvTileWidth);
464     rBrcY = rFrcY - (((rY * rCamOriY) - (rX * rCamOriX)) * rInvTileHeight);
465 
466     // Sort the corners on Y
467 
468     if (rCamOriY < 0)
469     {
470         if (rCamOriX >= 0)
471         {
472             nScanLine = 1 + (s32)floor(rTlcY);
473             rY = (nScanLine - rTlcY);  // Fraction of Y
474             rLeft = rTlcX;
475             rLeftY = rBlcY;
476             rRightY = rTrcY;
477             nEvent2 = (s32)floor(rBrcY);
478 
479             rStep0 = rCamOriX / rCamOriY;
480             rStep1 = -rCamOriY / rCamOriX;
481         }
482         else
483         {
484             nScanLine = 1 + (s32)floor(rTrcY);
485             rY = (nScanLine - rTrcY);
486             rLeft = rTrcX;
487             rLeftY = rTlcY;
488             rRightY = rBrcY;
489             nEvent2 = (s32)floor(rBlcY);
490 
491             rStep0 = -rCamOriY / rCamOriX;       // ALERT: Assumes width==height
492             rStep1 = rCamOriX / rCamOriY;
493         }
494     }
495     else
496     {
497         if (rCamOriX >= 0)
498         {
499             nScanLine = 1 + (s32)floor(rBlcY);
500             rY = (nScanLine - rBlcY);  // Fraction of Y
501             rLeft = rBlcX;
502             rLeftY = rBrcY;
503             rRightY = rTlcY;
504             nEvent2 = (s32)floor(rTrcY);
505 
506             rStep0 = -rCamOriY / rCamOriX;       // ALERT: Assumes width==height
507             rStep1 = rCamOriX / rCamOriY;
508         }
509         else
510         {
511             nScanLine = 1 + (s32)floor(rBrcY);
512             rY = (nScanLine - rBrcY);
513             rLeft = rBrcX;
514             rLeftY = rTrcY;
515             rRightY = rBlcY;
516             nEvent2 = (s32)floor(rTlcY);
517 
518             rStep0 = rCamOriX / rCamOriY;       // ALERT: Assumes width==height
519             rStep1 = -rCamOriY / rCamOriX;
520         }
521     }
522 
523     {
524         f32 rRatio = (f32) layer->nTileHeight / layer->nTileWidth;
525         rStep0 *= rRatio;
526         rStep1 *= rRatio;
527     }
528 
529     rRight = rLeft + rY * rStep1;
530     rLeft += rY * rStep0;
531 
532     // Scanline Rasterizing algorithm
533     // Top line is a special case
534     if (rLeftY < rRightY)
535     {
536         nEvent0 = (s32)floor(rLeftY);
537         nEvent1 = (s32)floor(rRightY);
538         rMid = rStep1;
539     }
540     else
541     {
542         nEvent0 = (s32)floor(rRightY);
543         nEvent1 = (s32)floor(rLeftY);
544         rMid = rStep0;
545     }
546 
547     nL = (s32)floor(rLeft);
548     nR = (s32)floor(rRight);
549 
550     nLocalMapX = nMapX;
551     nLocalMapY = nMapY;
552 
553     if (!(layer->bWrap))  // Special care is needed when map doesn't wrap
554     {
555         f32 rInvTileWidth = 1.0F / layer->nTileWidth;
556         f32 rInvTileHeight = 1.0F / layer->nTileHeight;
557         f32 rLocalPosX = glob.poCam.rPosX;
558         f32 rLocalPosY = glob.poCam.rPosY;
559         f32 rSplitX = 0.5F * (glob.rWorldX + (layer->nTileWidth * (1<<layer->nHS)));
560         f32 rSplitY = 0.5F * (glob.rWorldY + (layer->nTileHeight * (1<<layer->nVS)));
561 
562         if (rLocalPosX >= rSplitX) rLocalPosX -= glob.rWorldX;
563         if (rLocalPosY >= rSplitY) rLocalPosY -= glob.rWorldY;
564 
565         rFrcX = rLocalPosX * rInvTileWidth;
566         rFrcY = rLocalPosY * rInvTileHeight;
567 
568         nLocalMapX = (s32)floor(rFrcX);
569         nLocalMapY = (s32)floor(rFrcY);
570     }
571 
572     FillSection(layer, aSortBuffer, &nScanLine, nEvent0, &nIdx, &nL, &nR, &rLeft, &rRight, rStep0, rStep1, nLocalMapX, nLocalMapY);
573 
574     {
575         pAddr = (s16 *)&layer->matDesc[0].nReserved;
576         aCount0 = pAddr[1];
577         pAddr = (s16 *)&layer->matDesc[1].nReserved;
578         aCount1 = pAddr[1];
579         pAddr = (s16 *)&layer->matDesc[2].nReserved;
580         aCount2 = pAddr[1];
581     }
582 
583     // The case where Event0 == Event1 must be handled
584     if (nScanLine > rLeftY)
585     {
586         rLeft -= (nScanLine - rLeftY) * rStep0;
587         nL = (s32)floor(rLeft);
588         rLeft += (nScanLine - rLeftY - 1) * rStep1;
589         rLeftY = 1000;      // Make sure the test further down fails
590     }
591 
592     if (nScanLine > rRightY)
593     {
594         rRight -= (nScanLine - rRightY) * rStep1;
595         nR = (s32)floor(rRight);
596         rRight += (nScanLine - rRightY - 1) * rStep0;
597         rRightY = 1000;      // Make sure the test further down fails
598     }
599 
600     FillSection(layer, aSortBuffer, &nScanLine, nEvent1, &nIdx, &nL, &nR, &rLeft, &rRight, rMid, rMid, nLocalMapX, nLocalMapY);
601 
602     {
603         pAddr = (s16 *)&layer->matDesc[0].nReserved;
604         aCount0 = pAddr[1];
605         pAddr = (s16 *)&layer->matDesc[1].nReserved;
606         aCount1 = pAddr[1];
607         pAddr = (s16 *)&layer->matDesc[2].nReserved;
608         aCount2 = pAddr[1];
609     }
610 
611     if (nScanLine > rLeftY)
612     {
613         rLeft -= (nScanLine - rLeftY) * rStep0;
614         nL = (s32)floor(rLeft);
615         rLeft += (nScanLine - rLeftY - 1) * rStep1;
616     }
617 
618     if (nScanLine > rRightY)
619     {
620         rRight -= (nScanLine - rRightY) * rStep1;
621         nR = (s32)floor(rRight);
622         rRight += (nScanLine - rRightY - 1) * rStep0;
623     }
624 
625     FillSection(layer, aSortBuffer, &nScanLine, nEvent2+1, &nIdx, &nL, &nR, &rLeft, &rRight, rStep1, rStep0, nLocalMapX, nLocalMapY);
626 
627     {
628         pAddr = (s16 *)&layer->matDesc[0].nReserved;
629         aCount0 = pAddr[1];
630         pAddr = (s16 *)&layer->matDesc[1].nReserved;
631         aCount1 = pAddr[1];
632         pAddr = (s16 *)&layer->matDesc[2].nReserved;
633         aCount2 = pAddr[1];
634     }
635 
636     // We now have the tiles sorted into streams by material:
637 
638     for( nMaterial=0; nMaterial<layer->nNumMaterials; nMaterial++)
639     {
640         pAddr = (s16 *)&layer->matDesc[nMaterial].nReserved;
641 
642         if (pAddr[1] == 0)  // Count
643         {
644             continue;
645         }
646 
647         switch( layer->matDesc[nMaterial].nCategory )
648         {
649             case G2D_CTG_EMPTY:
650             {
651                 continue;   // Empty tiles don't need to be rendered
652             }
653 
654             case G2D_CTG_RGBA_INDEX8:
655             {
656                 // Colored tiles using color index
657                 GXClearVtxDesc();
658 
659                 // Set Position Params
660                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); //PositionShift);
661                 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
662 
663                 // Set Color for Vertex Format 0
664                 GXSetNumTexGens(0);
665                 GXSetVtxDesc(GX_VA_TEX0, GX_NONE);
666                 GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
667                 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
668                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
669                 GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
670                 GXSetArray(GX_VA_CLR0, layer->matDesc[nMaterial].clut, 4);
671 
672                 GXSetNumChans(1);
673                 GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX,
674                               GX_LIGHT0, GX_DF_NONE, GX_AF_NONE);
675 
676                 nIdx = (s16)(nMaterial<<1);
677                 GXBegin(GX_QUADS, GX_VTXFMT0, (u16)(pAddr[1]<<2));
678                 for(nK = (s32)pAddr[1]; nK--;)
679                 {
680                     f32 rI, rJ;
681                     u8 nCI;
682 
683                     nTile = *((s16 *)&aSortBuffer[nIdx]);
684                     if (nTile < 0)
685                     {
686                         nIdx -= nTile;
687                         nTile = *((s16 *)&aSortBuffer[nIdx]);
688                     }
689                     nIdx+=2;
690                     nI = aSortBuffer[nIdx++];
691                     nJ = aSortBuffer[nIdx++];
692 
693                     rI = (f32)(nI + nMapX) * layer->nTileWidth;
694                     rJ = (f32)(nJ + nMapY) * layer->nTileHeight;
695 
696                     nCI = layer->tileDesc[nTile].nCI;
697 
698                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ     );
699                     GXColor1x8( nCI );
700 
701                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight );
702                     GXColor1x8( nCI );
703 
704                     GXPosition2f32( rI                     , rJ + (f32)layer->nTileHeight );
705                     GXColor1x8( nCI );
706 
707                     GXPosition2f32( rI                     , rJ      );
708                     GXColor1x8( nCI );
709                 }
710                 GXEnd();
711                 break;
712             }
713 
714             case G2D_CTG_RGB_DIRECT:
715             {
716                 // Colored tiles using color index
717                 GXClearVtxDesc();
718 
719                 // Set Position Params
720                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); //PositionShift);
721                 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
722 
723                 // Set Color for Vertex Format 0
724                 GXSetNumTexGens(0);
725                 GXSetVtxDesc(GX_VA_TEX0, GX_NONE);
726                 GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
727                 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
728                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
729                 GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
730 
731                 GXSetNumChans(1);
732                 GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX,
733                               GX_LIGHT0, GX_DF_NONE, GX_AF_NONE);
734 
735                 nIdx = (s16)(nMaterial<<1);
736                 GXBegin(GX_QUADS, GX_VTXFMT0, (u16)(pAddr[1]<<2));
737                 for(nK = (s32)pAddr[1]; nK--;)
738                 {
739                     f32 rI, rJ;
740                     u8 nR, nG, nB;
741 
742                     nTile = *((s16 *)&aSortBuffer[nIdx]);
743                     if (nTile < 0)
744                     {
745                         nIdx -= nTile;
746                         nTile = *((s16 *)&aSortBuffer[nIdx]);
747                     }
748                     nIdx+=2;
749                     nI = aSortBuffer[nIdx++];
750                     nJ = aSortBuffer[nIdx++];
751 
752                     rI = (f32)(nI + nMapX) * layer->nTileWidth;
753                     rJ = (f32)(nJ + nMapY) * layer->nTileHeight;
754 
755                     nR = layer->tileDesc[nTile].nS;
756                     nG = layer->tileDesc[nTile].nT;
757                     nB = layer->tileDesc[nTile].nCI;
758 
759                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ     );
760                     GXColor3u8( nR, nG, nB );
761 
762                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight );
763                     GXColor3u8( nR, nG, nB );
764 
765                     GXPosition2f32( rI                     , rJ + (f32)layer->nTileHeight );
766                     GXColor3u8( nR, nG, nB );
767 
768                     GXPosition2f32( rI                     , rJ      );
769                     GXColor3u8( nR, nG, nB );
770                 }
771                 GXEnd();
772                 break;
773             }
774 
775             case G2D_CTG_TEXTURE:
776             {
777                 f32 rInvTexWidth = 1.0F / GXGetTexObjWidth(layer->matDesc[nMaterial].to);
778                 f32 rInvTexHeight = 1.0F / GXGetTexObjHeight(layer->matDesc[nMaterial].to);
779                 f32 rWidth = layer->nTileWidth * rInvTexWidth;
780                 f32 rHeight = layer->nTileHeight * rInvTexHeight;
781                 f32 rS0 = 0; //0.5F * rInvTexWidth;
782                 f32 rT0 = 0; //0.5F * rInvTexHeight;
783                 f32 rS1 = rWidth;// - rInvTexWidth;
784                 f32 rT1 = rHeight;// - rInvTexHeight;
785 
786                 // Second, the textured tiles
787                 GXClearVtxDesc();
788                 GXLoadTexObj(layer->matDesc[nMaterial].to, GX_TEXMAP0);
789 
790                 // Set Position Params
791                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0);
792                 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
793 
794                 // Set Tex Coord Params
795                 GXSetNumTexGens(1);
796                 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
797                 GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
798 
799                 if (layer->matDesc[nMaterial].color)
800                 {
801                     GXSetNumChans(1);
802                     GXSetChanMatColor(GX_COLOR0A0, *layer->matDesc[nMaterial].color);
803                     GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_REG,
804                                   GX_LIGHT0, GX_DF_NONE, GX_AF_NONE);
805                     GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
806                     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
807                 }
808                 else
809                 {
810                     GXSetNumChans(0);
811                     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
812                     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
813                 }
814 
815                 nIdx = (s16)(nMaterial<<1);
816                 GXBegin(GX_QUADS, GX_VTXFMT0, (u16)(pAddr[1]<<2));
817                 for(nK = (s32)pAddr[1]; nK--;)
818                 {
819                     f32 rI, rJ, rS, rT;
820 
821                     nTile = *((s16 *)&aSortBuffer[nIdx]);
822                     if (nTile < 0)
823                     {
824                         nIdx -= nTile;
825                         nTile = *((s16 *)&aSortBuffer[nIdx]);
826                     }
827                     nIdx+=2;
828                     nI = aSortBuffer[nIdx++];
829                     nJ = aSortBuffer[nIdx++];
830 
831                     rS = (layer->tileDesc[nTile].nS * rWidth) + rS0;
832                     rT = (layer->tileDesc[nTile].nT * rHeight) + rT0;
833                     rI = (f32)(nI + nMapX) * layer->nTileWidth;
834                     rJ = (f32)(nJ + nMapY) * layer->nTileHeight;
835 
836                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ     );
837                     GXTexCoord2f32( rS + rS1               , rT     );
838 
839                     GXPosition2f32( rI + (f32)layer->nTileWidth, rJ + (f32)layer->nTileHeight );
840                     GXTexCoord2f32( rS + rS1               , rT + rT1 );
841 
842                     GXPosition2f32( rI                     , rJ + (f32)layer->nTileHeight );
843                     GXTexCoord2f32( rS                     , rT + rT1 );
844 
845                     GXPosition2f32( rI                     , rJ      );
846                     GXTexCoord2f32( rS                     , rT      );
847                 }
848                 GXEnd();
849                 break;
850             }
851         }
852     }
853 }
854 
855 
856 /*---------------------------------------------------------------------------*
857     Name:           G2DSetCamera
858 
859     Description:    Set up a viewing matrix corresponding to a camera
860                     at the supplied position and orientation
861 
862     Arguments:      G2DPosOri *po           Position and Orientation
863     Returns:        none
864  *---------------------------------------------------------------------------*/
G2DSetCamera(G2DPosOri * po)865 void G2DSetCamera( G2DPosOri *po )
866 {
867     Mtx mView;
868     Vec vPos;
869     Vec vUp;
870     Vec vAt;
871     f32 rX, rY;
872 
873     glob.poCam = *po;
874 
875     // Setup vertex transform (no need to transform normals for 2D)
876 
877     vUp.x = po->rOriX;
878     vUp.y = po->rOriY;
879     vUp.z = 0.0F;
880 
881     rX = ((nScrX - glob.nViewportWidth)>>1)  - glob.nViewportTlcX;
882     rY = ((nScrY - glob.nViewportHeight)>>1) - glob.nViewportTlcY;
883 
884     vPos.x = po->rPosX - (vUp.x * rY) - (vUp.y * rX);
885     vPos.y = po->rPosY + (vUp.x * rX) - (vUp.y * rY);
886     vPos.z = -300.0F;
887 
888     vAt.x = vPos.x;
889     vAt.y = vPos.y;
890     vAt.z = 0.0F;
891 
892     MTXLookAt(mView, &vPos, &vUp, &vAt);
893 	GXLoadPosMtxImm(mView, GX_PNMTX0);
894 }
895 
896 
897 /*---------------------------------------------------------------------------*
898     Name:           G2DInitWorld
899 
900     Description:    Initialize world
901 
902     Arguments:      u32 nWorldX    world width (in pixels)
903                     u32 nWorldY    world height (in pixels)
904     Returns:        none
905  *---------------------------------------------------------------------------*/
G2DInitWorld(u32 nWorldX,u32 nWorldY)906 void G2DInitWorld( u32 nWorldX, u32 nWorldY )
907 {
908     Mtx44 mProjection;
909 
910     // Store world dimensions in global variables
911     glob.rWorldX = (f32)nWorldX;
912     glob.rWorldY = (f32)nWorldY;
913     glob.rHalfX  = (f32)(nWorldX>>1);
914     glob.rHalfY  = (f32)(nWorldY>>1);
915 
916     // Turn off Z buffer
917     GXSetZMode(GX_FALSE, GX_ALWAYS, GX_TRUE);
918 
919     // Set up orthographic projection
920     MTXOrtho(mProjection, nScrY>>1, -(nScrY>>1), -(nScrX>>1), nScrX>>1, 100, 1000);
921     GXSetProjection(mProjection, GX_ORTHOGRAPHIC);
922 }
923 
924 
925 /*---------------------------------------------------------------------------*
926     Name:           G2DSetViewport
927 
928     Description:    Set up viewport in screenspace
929 
930     Arguments:      u16 nLeft     Leftmost X coordinate of viewport (in pixels)
931                     u16 nTop      Topmost Y coordinate of viewport (in pixels)
932                     u16 nWidth    Width of viewport (in pixels)
933                     u16 nHeight   Height of viewport (in pixels)
934     Returns:        none
935  *---------------------------------------------------------------------------*/
G2DSetViewport(u16 nLeft,u16 nTop,u16 nWidth,u16 nHeight)936 void G2DSetViewport( u16 nLeft, u16 nTop, u16 nWidth, u16 nHeight )
937 {
938     // Set up internal global variable used by renderer
939     glob.nViewportTlcX = nLeft;
940     glob.nViewportTlcY = nTop;
941     glob.nViewportWidth = nWidth;
942     glob.nViewportHeight = nHeight;
943 
944     // Use scissoring to clip to the viewport
945     GXSetScissor(nLeft, nTop, nWidth, nHeight);
946 }
947