1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - GX - demos - UnitTours/DEMOLib
3   File:     DEMOBitmap.c
4 
5   Copyright 2007-2008 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   $Date:: 2008-09-17 #$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #ifdef SDK_TWL
19 #include <twl.h>
20 #else
21 #include <nitro.h>
22 #endif
23 #include "DEMOBitmap.h"
24 
25 
26 typedef struct DEMOBitmapContext
27 {
28     u32     require_flip : 1;
29     u32     bitmap_modified : 1;
30     u32     main_bg_modified : 1;
31     u32     main_oam_modified : 1;
32     u32     sub_bg_modified : 1;
33     u32     sub_oam_modified : 1;
34     u32     : 26;
35     OSThreadQueue   flip_wait_q[1];
36     void          (*HookedConsole)(int console, const char *string);
37     GXRgb           bitmap_ground_color;
38     GXRgb           bitmap_text_color;
39     u8              padding[12];
40     GXRgb           bitmap_frame[GX_LCD_SIZE_X * GX_LCD_SIZE_Y] ATTRIBUTE_ALIGN(32);
41     u16             main_bg[32 * 24] ATTRIBUTE_ALIGN(32);
42     GXOamAttr       main_oam[128] ATTRIBUTE_ALIGN(32);
43     u16             sub_bg[32 * 24] ATTRIBUTE_ALIGN(32);
44     GXOamAttr       sub_oam[128] ATTRIBUTE_ALIGN(32);
45     char            sub_log[24][32 + 1];
46     int             sub_log_count;
47 }
48 DEMOBitmapContext;
49 
50 static DEMOBitmapContext bitmap ATTRIBUTE_ALIGN(32);
51 
52 extern void VBlankIntr(void);
53 
54 /*---------------------------------------------------------------------------*
55   Name:         VBlankIntr
56 
57   Description:  V-Blank interrupt handler
58 
59   Arguments:    None
60 
61   Returns:      None
62  *---------------------------------------------------------------------------*/
VBlankIntr(void)63 SDK_WEAK_SYMBOL void VBlankIntr(void)
64 {
65     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
66 }
67 
68 /*---------------------------------------------------------------------------*
69   Name:         LogConsole
70 
71   Description:  Accumulates printf output in a log and also outputs it to the original console
72 
73   Arguments:    string: Output string
74 
75   Returns:      None
76  *---------------------------------------------------------------------------*/
LogConsole(int console,const char * string)77 static void LogConsole(int console, const char *string)
78 {
79     DEMOBitmapContext *const context = &bitmap;
80     DEMOPutLog("%s", string);
81     (*context->HookedConsole)(console, string);
82 }
83 
84 /*---------------------------------------------------------------------------*
85   Name:         OnVBlank
86 
87   Description:  V-Blank processing
88 
89   Arguments:    None
90 
91   Returns:      None
92  *---------------------------------------------------------------------------*/
OnVBlank(void)93 static void OnVBlank(void)
94 {
95     DEMOBitmapContext *const context = &bitmap;
96     if (context->require_flip)
97     {
98         if (context->bitmap_modified)
99         {
100             context->bitmap_modified = 0;
101             GX_LoadBG3Bmp(context->bitmap_frame, 0, sizeof(context->bitmap_frame));
102         }
103         if (context->main_bg_modified)
104         {
105             context->main_bg_modified = 0;
106             GX_LoadBG1Scr(context->main_bg, 0, sizeof(context->main_bg));
107         }
108         if (context->main_oam_modified)
109         {
110             context->main_oam_modified = 0;
111             GX_LoadOAM(context->main_oam, 0, sizeof(context->main_oam));
112         }
113 
114         if (context->sub_bg_modified)
115         {
116             context->sub_bg_modified = 0;
117             GXS_LoadBG0Scr(context->sub_bg, 0, sizeof(context->sub_bg));
118         }
119         if (context->sub_oam_modified)
120         {
121             context->sub_oam_modified = 0;
122             GXS_LoadOAM(context->sub_oam, 0, sizeof(context->sub_oam));
123         }
124         context->require_flip = 0;
125         OS_WakeupThread(context->flip_wait_q);
126     }
127     VBlankIntr();
128 }
129 
130 /*---------------------------------------------------------------------------*
131   Name:         DEMOInitDisplayBitmap
132 
133   Description:  Initializes the DEMO in bitmap render mode
134 
135   Arguments:    None
136 
137   Returns:      None
138  *---------------------------------------------------------------------------*/
DEMOInitDisplayBitmap(void)139 void DEMOInitDisplayBitmap(void)
140 {
141     // Initialize GX master settings
142     //     VRAM-A:  3D       128kB (BG0)
143     //     VRAM-B:
144     //     VRAM-C:  (ext)    128kB
145     //     VRAM-D:  main-BG  128kB (BG1=scr:2kB,chr:24kB) (BG3=scr:2kB,chr:96kB)
146     //     VRAM-E:  3D-PLT    64kB (BG0)
147     //     VRAM-FG: main-OBJ  32kB (OBJ)
148     //     VRAM-H:  sub-BG    32kB (BG0=scr:2kB,chr:24kB)
149     //     VRAM-I:  sub-OBJ   16kB (OBJ)
150     //
151     //     main LCD: mode4,3D-on,BG0,BG1,BG3,OBJ
152     //         BG0: 3D
153     //         BG1: TXT-BG,256x256,4bit,scr=1E800,chr=18000
154     //         BG3: BMP-BG,256x192,16bit,scr=1E000,chr=00000
155     //         OBJ: multi-purpose
156     //
157     //     sub LCD: mode0,BG0,OBJ
158     //         BG0: TXT-BG,256x256,4bit,scr06000,chr00000
159     //         OBJ: multi-purpose
160     G3X_Init();
161     G3X_InitMtxStack();
162     GX_SetBankForTex(GX_VRAM_TEX_0_A);
163     GX_SetBankForBG(GX_VRAM_BG_128_D);
164     GX_SetBankForTexPltt(GX_VRAM_TEXPLTT_0123_E);
165     GX_SetBankForOBJ(GX_VRAM_OBJ_32_FG);
166     GX_SetBankForSubBG(GX_VRAM_SUB_BG_32_H);
167     GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_16_I);
168     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_3D);
169     GX_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3 | GX_PLANEMASK_OBJ);
170     GXS_SetGraphicsMode(GX_BGMODE_0);
171     GXS_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ);
172     G2_BlendNone();
173     G2S_BlendNone();
174     GX_Power2DSub(TRUE);
175     // Main-3D
176     {
177         G2_SetBG0Priority(2);
178         G3X_SetShading(GX_SHADING_TOON);
179         G3X_AntiAlias(TRUE);
180     }
181     // Main-TXT-BG
182     {
183         G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
184                          GX_BG_SCRBASE_0xe800, GX_BG_CHARBASE_0x18000, GX_BG_EXTPLTT_01);
185         GX_SetBGScrOffset(GX_BGSCROFFSET_0x10000);
186         G2_SetBG1Priority(0);
187         G2_BG1Mosaic(FALSE);
188     }
189     // Main-BMP-BG
190     {
191         G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
192         G2_SetBG3Priority(1);
193     }
194     // Sub-TXT-BG
195     {
196         G2S_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
197                           GX_BG_SCRBASE_0x6000, GX_BG_CHARBASE_0x00000, GX_BG_EXTPLTT_01);
198         G2S_SetBG0Priority(1);
199         G2S_BG0Mosaic(FALSE);
200     }
201     G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
202     G3X_SetClearColor(GX_RGB(0, 0, 0), 31, 0x7fff, 63, FALSE);
203     DEMOSetViewPort(0, 0, GX_LCD_SIZE_X, GX_LCD_SIZE_Y);
204 
205     {
206         static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
207         MI_CpuFill32(&bitmap, 0x00000000, sizeof(bitmap));
208         GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
209         GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
210         GXS_LoadBGPltt(pal, 0x0000, sizeof(pal));
211         GXS_LoadBG0Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
212         OS_InitThreadQueue(bitmap.flip_wait_q);
213         OS_SetIrqFunction(OS_IE_V_BLANK, OnVBlank);
214         (void)OS_EnableIrqMask(OS_IE_V_BLANK);
215     }
216 }
217 
218 /*---------------------------------------------------------------------------*
219   Name:         DEMO_DrawFlip
220 
221   Description:  Applies the current rendering content to VRAM
222 
223   Arguments:    None
224 
225   Returns:      None
226  *---------------------------------------------------------------------------*/
DEMO_DrawFlip()227 void DEMO_DrawFlip()
228 {
229     DEMOBitmapContext *const context = &bitmap;
230 
231     if (context->bitmap_modified)
232     {
233         DC_StoreRange(context->bitmap_frame, sizeof(context->bitmap_frame));
234     }
235     if (context->main_bg_modified)
236     {
237         DC_StoreRange(context->main_bg, sizeof(context->main_bg));
238     }
239     if (context->main_oam_modified)
240     {
241         DC_StoreRange(context->main_oam, sizeof(context->main_oam));
242     }
243     if (context->sub_bg_modified)
244     {
245         const int   visible_lines = 20;
246         const int   palette = 0;
247         int         offset = (context->sub_log_count + 1 > visible_lines) ? (context->sub_log_count + 1 - visible_lines) : 0;
248         int         x, y;
249         for (y = 0; y < visible_lines; ++y)
250         {
251             u16        *dst = &context->sub_bg[y * 32];
252             const char *src = context->sub_log[(offset + y) % 24];
253             for (x = 0; (x < 32) && src[x] && (src[x] != '\n'); ++x)
254             {
255                 dst[x] = (u16)((u8)src[x] | (palette << 12));
256             }
257             for (; x < 32; ++x)
258             {
259                 dst[x] = (u16)(0 | (palette << 12));
260             }
261         }
262         DC_StoreRange(context->sub_bg, sizeof(context->sub_bg));
263     }
264     if (context->sub_oam_modified)
265     {
266         DC_StoreRange(context->sub_oam, sizeof(context->sub_oam));
267     }
268     DC_WaitWriteBufferEmpty();
269     {
270         OSIntrMode  bak_intr = OS_DisableInterrupts();
271         context->require_flip = 1;
272 //        while (context->require_flip)
273 //        {
274 //            OS_SleepThread(context->flip_wait_q);
275 //        }
276         (void)OS_RestoreInterrupts(bak_intr);
277     }
278 }
279 
280 /*---------------------------------------------------------------------------*
281   Name:         DEMOVerifyGXRgb
282 
283   Description:  Checks the validity of color values.
284 
285   Arguments:    color: Color value that is thought to be within the GXRgb range
286 
287   Returns:      Returns color unchanged if it is a valid GXRgb value and 0xFFFF if it is out of range
288  *---------------------------------------------------------------------------*/
DEMOVerifyGXRgb(int color)289 GXRgb DEMOVerifyGXRgb(int color)
290 {
291     if((color < 0) || (color > 0xFFFF))
292     {
293         static BOOL once = FALSE;
294         if(!once)
295         {
296             OS_TWarning("color(%04X) exceeds GXRgb range.\n", color);
297             once = TRUE;
298         }
299         color = 0xFFFF;
300     }
301     return (GXRgb)color;
302 }
303 
304 /*---------------------------------------------------------------------------*
305   Name:         DEMOSetBitmapTextColor
306 
307   Description:  Sets the text color for bitmap rendering
308 
309   Arguments:    color: The color to set
310 
311   Returns:      None
312  *---------------------------------------------------------------------------*/
DEMOiSetBitmapTextColor(GXRgb color)313 void DEMOiSetBitmapTextColor(GXRgb color)
314 {
315     DEMOBitmapContext  *context = &bitmap;
316     context->bitmap_text_color = color;
317 }
318 
319 /*---------------------------------------------------------------------------*
320   Name:         DEMOSetBitmapGroundColor
321 
322   Description:  Sets the background color for bitmap rendering
323 
324   Arguments:    color: The color to set
325 
326   Returns:      None
327  *---------------------------------------------------------------------------*/
DEMOiSetBitmapGroundColor(GXRgb color)328 void DEMOiSetBitmapGroundColor(GXRgb color)
329 {
330     DEMOBitmapContext  *context = &bitmap;
331     context->bitmap_ground_color = color;
332 }
333 
334 /*---------------------------------------------------------------------------*
335   Name:         DEMOiFillRect
336 
337   Description:  Renders a rectangle to the bitmap.
338 
339   Arguments:    x: x coordinate for rendering
340                 y: y coordinate for rendering
341                 wx: x width for rendering
342                 wy: y width for rendering
343                 color: The color to set
344 
345   Returns:      None
346  *---------------------------------------------------------------------------*/
DEMOiFillRect(int x,int y,int wx,int wy,GXRgb color)347 void DEMOiFillRect(int x, int y, int wx, int wy, GXRgb color)
348 {
349     if ((x < GX_LCD_SIZE_X) && (y < GX_LCD_SIZE_Y))
350     {
351         if (wx > GX_LCD_SIZE_X - x)
352         {
353             wx = GX_LCD_SIZE_X - x;
354         }
355         if (wy > GX_LCD_SIZE_Y - y)
356         {
357             wy = GX_LCD_SIZE_Y - y;
358         }
359         if ((wx > 0) && (wy > 0))
360         {
361             DEMOBitmapContext  *context = &bitmap;
362             GXRgb              *dst = &context->bitmap_frame[x + y * GX_LCD_SIZE_X];
363             while (--wy >= 0)
364             {
365                 MI_CpuFill16(dst, color, wx * sizeof(GXRgb));
366                 dst += GX_LCD_SIZE_X;
367             }
368             context->bitmap_modified = 1;
369         }
370     }
371 }
372 
373 /*---------------------------------------------------------------------------*
374   Name:         DEMOBlitRect
375 
376   Description:  Transfers a rectangle to a bitmap
377 
378   Arguments:    x: x coordinate for rendering
379                 y: y coordinate for rendering
380                 wx: x width for rendering
381                 wy: y width for rendering
382                 image: The original image to transfer
383                 stroke: Pixel count per each of the original lines to transfer
384 
385   Returns:      None
386  *---------------------------------------------------------------------------*/
DEMOBlitRect(int x,int y,int wx,int wy,const GXRgb * image,int stroke)387 void DEMOBlitRect(int x, int y, int wx, int wy, const GXRgb *image, int stroke)
388 {
389     if ((x < GX_LCD_SIZE_X) && (y < GX_LCD_SIZE_Y))
390     {
391         if (wx > GX_LCD_SIZE_X - x)
392         {
393             wx = GX_LCD_SIZE_X - x;
394         }
395         if (wy > GX_LCD_SIZE_Y - y)
396         {
397             wy = GX_LCD_SIZE_Y - y;
398         }
399         if ((wx > 0) && (wy > 0))
400         {
401             DEMOBitmapContext  *context = &bitmap;
402             GXRgb              *dst = &context->bitmap_frame[x + y * GX_LCD_SIZE_X];
403             while (--wy >= 0)
404             {
405                 MI_CpuCopy16(image, dst, wx * sizeof(GXRgb));
406                 image += stroke;
407                 dst += GX_LCD_SIZE_X;
408             }
409             context->bitmap_modified = 1;
410         }
411     }
412 }
413 
414 /*---------------------------------------------------------------------------*
415   Name:         DEMOBlitTex16
416 
417   Description:  Transfers a 16-color texture to a bitmap
418 
419   Arguments:    x: x coordinate for rendering
420                 y: y coordinate for rendering
421                 wx: Rendering width in the x-direction (this must be an integer multiple of 8 pixels)
422                 wy: Rendering width in the y-direction (this must be an integer multiple of 8 pixels)
423                 chr: Character image (4x8x8 one-dimensional character format)
424                 plt: Palette image (index 0 is treated as transparent)
425 
426   Returns:      None
427  *---------------------------------------------------------------------------*/
DEMOBlitTex16(int x,int y,int wx,int wy,const void * chr,const GXRgb * plt)428 void DEMOBlitTex16(int x, int y, int wx, int wy, const void *chr, const GXRgb *plt)
429 {
430     if ((x < GX_LCD_SIZE_X) && (y < GX_LCD_SIZE_Y))
431     {
432         int     stroke = wx;
433         if (wx > GX_LCD_SIZE_X - x)
434         {
435             wx = GX_LCD_SIZE_X - x;
436         }
437         if (wy > GX_LCD_SIZE_Y - y)
438         {
439             wy = GX_LCD_SIZE_Y - y;
440         }
441         if ((wx > 0) && (wy > 0))
442         {
443             DEMOBitmapContext  *context = &bitmap;
444             const u8           *src = (const u8 *)chr;
445             GXRgb              *dst = &context->bitmap_frame[x + y * GX_LCD_SIZE_X];
446             int                 tx, ty, dx, dy, nx, ny;
447             for (ty = 0; ty < wy; ty += 8)
448             {
449                 ny = MATH_MIN(wy - ty, 8);
450                 for (tx = 0; tx < wx; tx += 8)
451                 {
452                     nx = MATH_MIN(wx - tx, 8);
453                     for (dy = 0; dy < ny; ++dy)
454                     {
455                         for (dx = 0; dx < nx; ++dx)
456                         {
457                             u8      index = (u8)((src[(dy * 8 + dx) / 2] >> ((dx & 1) * 4)) & 0x0F);
458                             if (index > 0)
459                             {
460                                 dst[(ty + dy) * GX_LCD_SIZE_X + tx + dx] = (GXRgb)(plt[index] | 0x8000);
461                             }
462                         }
463                     }
464                     src += 8 * 8 / 2;
465                 }
466                 src += (stroke - tx) * 8 / 2;
467             }
468             context->bitmap_modified = 1;
469         }
470     }
471 }
472 
473 /*---------------------------------------------------------------------------*
474   Name:         DEMODrawLine
475 
476   Description:  Draws a line on a bitmap
477 
478   Arguments:    sx: X-coordinate of the starting point
479                 sy: Y-coordinate of the starting point
480                 tx : Width to the ending point in the x-direction
481                 ty: Width to the ending point in the Y-direction
482                 color: the color to set
483 
484   Returns:      None
485  *---------------------------------------------------------------------------*/
DEMOiDrawLine(int sx,int sy,int tx,int ty,GXRgb color)486 void DEMOiDrawLine(int sx, int sy, int tx, int ty, GXRgb color)
487 {
488     DEMOBitmapContext  *context = &bitmap;
489     int                 tmp;
490     // Normalize in the x-direction
491     if (sx > tx)
492     {
493         tmp = sx + 1, sx = tx + 1, tx = tmp;
494         tmp = sy, sy = ty, ty = tmp;
495     }
496     {
497         GXRgb  *dst = NULL;
498         int     wx = tx - sx;
499         int     wy = ty - sy;
500         // Optimize vertically
501         if (!wx)
502         {
503             if (wy < 0)
504             {
505                 wy = -wy;
506                 tmp = sy + 1, sy = ty + 1, ty = tmp;
507             }
508             if ((sx >= 0) && (sx < GX_LCD_SIZE_X) && (sy < GX_LCD_SIZE_Y))
509             {
510                 if (sy < 0)
511                 {
512                     wy += sy, sy = 0;
513                 }
514                 if (wy > GX_LCD_SIZE_Y - sy)
515                 {
516                     wy = GX_LCD_SIZE_Y - sy;
517                 }
518                 dst = &context->bitmap_frame[sx + sy * GX_LCD_SIZE_X];
519                 while (--wy >= 0)
520                 {
521                     *dst = color;
522                     dst += GX_LCD_SIZE_X;
523                 }
524             }
525         }
526         // Optimize horizontally
527         else if (!wy)
528         {
529             if ((sy >= 0) && (sy < GX_LCD_SIZE_Y) && (sx < GX_LCD_SIZE_X))
530             {
531                 if (sx < 0)
532                 {
533                     wx += sx, sx = 0;
534                 }
535                 if (wx > GX_LCD_SIZE_X - sx)
536                 {
537                     wx = GX_LCD_SIZE_X - sx;
538                 }
539                 dst = &context->bitmap_frame[sx + sy * GX_LCD_SIZE_X];
540                 MI_CpuFill16(dst, color, wx * sizeof(GXRgb));
541             }
542         }
543         // A general all-purpose line with a slope
544         else
545         {
546             int     n, dx, dy;
547             int     y_delta = +1;
548             int     y_ofs = GX_LCD_SIZE_X;
549             dst = &context->bitmap_frame[sx + sy * GX_LCD_SIZE_X];
550             if (wy < 0)
551             {
552                 wy = -wy;
553                 y_delta = -y_delta;
554                 y_ofs = -y_ofs;
555             }
556             dx = wy - 1, dy = wx - 1;
557             --sx, sy -= y_delta;
558             for (n = wx * wy; --n >= 0;)
559             {
560                 BOOL    moved = FALSE;
561                 if (++dx >= wy)
562                 {
563                     moved = TRUE, dx = 0, ++sx, dst += 1;
564                 }
565                 if (++dy >= wx)
566                 {
567                     moved = TRUE, dy = 0, sy += y_delta, dst += y_ofs;
568                 }
569                 if (moved &&
570                     (sx >= 0) && (sx < GX_LCD_SIZE_X) &&
571                     (sy >= 0) && (sy < GX_LCD_SIZE_Y))
572                 {
573                     *dst = color;
574                 }
575             }
576         }
577     }
578 }
579 
580 /*---------------------------------------------------------------------------*
581   Name:         DEMODrawFrame
582 
583   Description:  Renders a frame to the bitmap.
584 
585   Arguments:    x: x coordinate for rendering
586                 y: y coordinate for rendering
587                 wx: x width for rendering
588                 wy: y width for rendering
589                 color: The color to set
590 
591   Returns:      None
592  *---------------------------------------------------------------------------*/
DEMOiDrawFrame(int x,int y,int wx,int wy,GXRgb color)593 void DEMOiDrawFrame(int x, int y, int wx, int wy, GXRgb color)
594 {
595     DEMOiFillRect(x, y, wx, 1, color);
596     DEMOiFillRect(x, y + wy - 1, wx, 1, color);
597     DEMOiFillRect(x, y + 1, 1, wy - 1, color);
598     DEMOiFillRect(x + wx - 1, y + 1, 1, wy - 1, color);
599 }
600 
601 /*---------------------------------------------------------------------------*
602   Name:         DEMODrawText
603 
604   Description:  Renders a string on a bitmap
605 
606   Arguments:    x: x coordinate for rendering
607                 y: y coordinate for rendering
608                 format: Formatted character string
609 
610   Returns:      None
611  *---------------------------------------------------------------------------*/
DEMODrawText(int x,int y,const char * format,...)612 void DEMODrawText(int x, int y, const char *format, ...)
613 {
614     static char tmp[512];
615     {
616         va_list va;
617         va_start(va, format);
618         (void)OS_VSNPrintf(tmp, sizeof(tmp) - 2, format, va);
619         va_end(va);
620     }
621     {
622         DEMOBitmapContext  *context = &bitmap;
623         const char         *s = tmp;
624         int                 n = sizeof(tmp) - 1;
625         GXRgb              *p = &context->bitmap_frame[x + y * GX_LCD_SIZE_X];
626         GXRgb               txt = context->bitmap_text_color;
627         GXRgb               gnd = context->bitmap_ground_color;
628         int     px = 0;
629         int     rep = 0;
630         for (; (n > 0) && *s; ++s, --n)
631         {
632             int     c = (u8)*s;
633             if (STD_IsSjisLeadByte(c))
634             {
635                 c = (c << 8) | (u8)*++s;
636             }
637             switch (c)
638             {
639             case '\0':
640                 return;
641             case '\r':
642                 c = s[1];
643                 if (c == '\n')
644                 {
645                     ++s, --n;
646                 }
647             case '\n':
648                 y += 8;
649                 p += GX_LCD_SIZE_X * 8;
650                 px = 0;
651                 break;
652             case '\t':
653                 {
654                     const int align = 4;
655                     rep = align - ((px / 8) & (align - 1));
656                     c = ' ';
657                 }
658                 goto put_char;
659             default:
660                 rep = 1;
661                 goto put_char;
662 
663               put_char:
664                 while (--rep >= 0)
665                 {
666                     int     tx = x + px;
667                     if ((tx > -8) && (tx < GX_LCD_SIZE_X) &&
668                         (y > -8) && (y < GX_LCD_SIZE_Y))
669                     {
670                         int         ox = 0, oy = 0;
671                         int         wx = 8, wy = 8;
672                         if (tx < 0)
673                         {
674                             ox = -tx;
675                         }
676                         else
677                         {
678                             wx = MATH_MIN(wx, GX_LCD_SIZE_X - tx);
679                         }
680                         if (y < 0)
681                         {
682                             oy = -y;
683                         }
684                         else
685                         {
686                             wy = MATH_MIN(wy, GX_LCD_SIZE_Y - y);
687                         }
688                         {
689                             const u32* DEMO_GetSjisFont(int code);
690                             const u32  *src = DEMO_GetSjisFont(c);
691                             GXRgb      *dst = &p[GX_LCD_SIZE_X * oy + px];
692                             int         stroke = GX_LCD_SIZE_X;
693                             for (; oy < wy; ++oy)
694                             {
695                                 int         i;
696                                 const u32   bits = src[oy];
697                                 for (i = ox; i < wx; ++i)
698                                 {
699                                     if (((bits >> (i * 4)) & 0xF) != 0)
700                                     {
701                                         dst[i] = txt;
702                                     }
703                                     else if (gnd != DEMO_RGB_NONE)
704                                     {
705                                         dst[i] = gnd;
706                                     }
707                                 }
708                                 dst += stroke;
709                             }
710                         }
711                     }
712                     px += 8;
713                 }
714                 break;
715             }
716         }
717         context->bitmap_modified = 1;
718     }
719 }
720 
721 /*---------------------------------------------------------------------------*
722   Name:         DEMOClearString
723 
724   Description:  Clears all BG text
725 
726   Arguments:    None
727 
728   Returns:      None
729  *---------------------------------------------------------------------------*/
DEMOClearString(void)730 void DEMOClearString(void)
731 {
732     DEMOBitmapContext  *context = &bitmap;
733     MI_CpuFillFast(context->main_bg, 0x00000000, sizeof(context->main_bg));
734     context->main_bg_modified = 1;
735 }
736 
737 /*---------------------------------------------------------------------------*
738   Name:         DEMOPutString
739 
740   Description:  Renders BG text.
741 
742   Arguments:    x: x coordinate for rendering
743                 y: y coordinate for rendering
744                 format: Formatted character string
745 
746   Returns:      None
747  *---------------------------------------------------------------------------*/
DEMOPutString(int x,int y,const char * format,...)748 void DEMOPutString(int x, int y, const char *format, ...)
749 {
750     DEMOBitmapContext  *context = &bitmap;
751     u16                *dst = &context->main_bg[y * 32];
752     const int           palette = 0;
753     char                tmp[32 + 1];
754     {
755         va_list     va;
756         va_start(va, format);
757         (void)OS_VSNPrintf(tmp + x, sizeof(tmp) - x, format, va);
758         va_end(va);
759     }
760     for (; (x < 32) && tmp[x]; ++x)
761     {
762         dst[x] = (u16)((u8)tmp[x] | (palette << 12));
763     }
764     context->main_bg_modified = 1;
765 }
766 
767 /*---------------------------------------------------------------------------*
768   Name:         DEMOPutLog
769 
770   Description:  Displays a log string to the sub screen
771 
772   Arguments:    format: Formatted character string
773 
774   Returns:      None
775  *---------------------------------------------------------------------------*/
DEMOPutLog(const char * format,...)776 void DEMOPutLog(const char *format, ...)
777 {
778     DEMOBitmapContext  *context = &bitmap;
779     static char         tmp[512];
780     {
781         va_list     va;
782         va_start(va, format);
783         (void)OS_VSNPrintf(tmp, sizeof(tmp), format, va);
784         va_end(va);
785     }
786     {
787         const char *src = tmp;
788         char       *dst = context->sub_log[context->sub_log_count % 24];
789         int         x = STD_GetStringLength(dst);
790         for (; *src; ++src)
791         {
792             switch (*src)
793             {
794             case '\r':
795                 if (src[1] == '\n')
796                 {
797                     break;
798                 }
799                 // fall
800             case '\n':
801                 dst[(x < 32) ? x : 32] = '\0';
802                 ++context->sub_log_count;
803                 dst = context->sub_log[context->sub_log_count % 24];
804                 x = 0;
805                 break;
806             default:
807                 if (x < 32)
808                 {
809                     dst[x++] = *src;
810                 }
811                 break;
812             }
813         }
814         dst[x] = '\0';
815     }
816     context->sub_bg_modified = 1;
817 }
818 
819 /*---------------------------------------------------------------------------*
820   Name:         DEMOHookConsole
821 
822   Description:  Adds a hook with OS_PutString and configures output to also be sent to the log
823 
824   Arguments:    None
825 
826   Returns:      None
827  *---------------------------------------------------------------------------*/
DEMOHookConsole(void)828 void DEMOHookConsole(void)
829 {
830 #ifndef SDK_FINALROM
831     DEMOBitmapContext  *context = &bitmap;
832     // Dummy output to fix the output target to an unchanging value
833     OS_FPutString(0, "");
834     // Switch the output function
835     context->HookedConsole = OS_FPutString;
836     OS_FPutString = LogConsole;
837 #endif // SDK_FINALROM
838 }
839 
840 /*---------------------------------------------------------------------------*
841   Name:         DEMOSetViewPort
842 
843   Description:  Configures the viewport and projection
844 
845   Arguments:    x: X-coordinate at the upper left
846                 y: Y-coordinate at the upper left
847                 wx: Width of the viewport in the x-direction
848                 wy: Width of the viewport in the y-direction
849 
850   Returns:      None
851  *---------------------------------------------------------------------------*/
DEMOSetViewPort(int x,int y,int wx,int wy)852 void DEMOSetViewPort(int x, int y, int wx, int wy)
853 {
854     G3_ViewPort(x, (GX_LCD_SIZE_Y - (y + wy)), (x + wx) - 1, (GX_LCD_SIZE_Y - y) - 1);
855     {
856         fx32    right = FX32_ONE;
857         fx32    top = FX32_ONE * wy / wx;
858         fx32    near = FX32_ONE;
859         fx32    far = FX32_ONE * 400;
860         G3_Perspective(FX32_SIN30, FX32_COS30, FX32_ONE * wx / wy, near, far, NULL);
861         G3_StoreMtx(0);
862     }
863 }
864