1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos - CTRDG - backup-1
3 File: draw.c
4
5 Copyright 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:: $
14 $Rev: $
15 $Author: $
16 *---------------------------------------------------------------------------*/
17
18
19 #include "draw.h"
20
21
22
23 /********************************************************************/
24 /* Constants */
25
26 #define DEMO_DRAW_INIT (1 << 0)
27 #define DEMO_DRAW_ENABLE (1 << 1)
28 #define DEMO_DRAW_FLIPPING (1 << 2)
29
30
31 /********************************************************************/
32 /* Variables */
33
34 Point cur_pt; /* Current position */
35 RGB555 col_text; /* Current text color */
36 RGB555 col_gnd; /* Current ground color */
37 RGB555 col_clear;
38
39
40 u16 tmp_surface[GX_LCD_SIZE_X * GX_LCD_SIZE_Y] ATTRIBUTE_ALIGN(32);
41
42 typedef struct DrawiCommon
43 {
44 Rect clip;
45 RGB555 *next_surface; /* VRAM A/B/C/D */
46 u32 draw_flag;
47
48 OSThreadQueue flip_wait_q[1]; /* Flip wait */
49 #if defined(OS_SIZEOF_OSTHREADQUEUE) && (OS_SIZEOF_OSTHREADQUEUE == 16)
50 u8 padding[2];
51 #endif
52 }
53 DrawiCommon;
54
55 static DrawiCommon drawi_common;
56
57
58 /********************************************************************/
59 /* Functions */
60
61
GetSurface(int x,int y)62 static inline RGB555 *GetSurface(int x, int y)
63 {
64 return drawi_common.next_surface + x + y * GX_LCD_SIZE_X;
65 }
66
IsBoundX(DrawiCommon * p,int x)67 static inline BOOL IsBoundX(DrawiCommon * p, int x)
68 {
69 return (x >= p->clip.o.x) && (x < p->clip.t.x);
70 }
IsBoundY(DrawiCommon * p,int y)71 static inline BOOL IsBoundY(DrawiCommon * p, int y)
72 {
73 return (y >= p->clip.o.y) && (y < p->clip.t.y);
74 }
75
NormalizeRegion(Region * p)76 static BOOL NormalizeRegion(Region * p)
77 {
78 DrawiCommon *const pc = &drawi_common;
79 if (p->pos.x >= pc->clip.t.x)
80 return FALSE;
81 else
82 {
83 if (p->pos.x - pc->clip.o.x < 0)
84 p->wid.x += p->pos.x - pc->clip.o.x, p->pos.x = pc->clip.o.x;
85 if (p->wid.x <= 0)
86 return FALSE;
87 else if (p->wid.x > pc->clip.t.x - p->pos.x)
88 p->wid.x = pc->clip.t.x - p->pos.x;
89 }
90 if (p->pos.y >= pc->clip.t.y)
91 return FALSE;
92 else
93 {
94 if (p->pos.y - pc->clip.o.y < 0)
95 p->wid.y += p->pos.y - pc->clip.o.y, p->pos.y = pc->clip.o.y;
96 if (p->wid.y <= 0)
97 return FALSE;
98 else if (p->wid.y > pc->clip.t.y - p->pos.y)
99 p->wid.y = pc->clip.t.y - p->pos.y;
100 }
101 return TRUE;
102 }
103
OnVBlank(void)104 static void OnVBlank(void)
105 {
106 DrawiCommon *const p = &drawi_common;
107 if ((p->draw_flag & DEMO_DRAW_FLIPPING) != 0)
108 {
109 RGB555 *const dst_vram = (RGB555 *) HW_LCDC_VRAM_C;
110 /* Transfer the surface that was being drawn up until just now */
111 MI_CpuCopyFast(tmp_surface, dst_vram, sizeof(tmp_surface));
112 /* Clear if an initial color has been set */
113 if (col_clear != RGB555_CLEAR)
114 {
115 MI_CpuFillFast(tmp_surface,
116 (u32)((col_clear << 0) | (col_clear << 16)), sizeof(tmp_surface));
117 }
118 p->draw_flag &= ~DEMO_DRAW_FLIPPING;
119 p->draw_flag |= DEMO_DRAW_ENABLE;
120 OS_WakeupThread(p->flip_wait_q);
121 }
122 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
123 }
124
125
InitDraw(void)126 void InitDraw(void)
127 {
128 DrawiCommon *const p = &drawi_common;
129 BOOL bak_irq = OS_DisableIrq();
130 if (!p->draw_flag)
131 {
132 p->draw_flag |= DEMO_DRAW_INIT;
133 GX_Init();
134 GX_SetPower(GX_POWER_ALL);
135 OS_SetIrqFunction(OS_IE_V_BLANK, OnVBlank);
136 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
137
138 #if !defined(SDK_NO_THREAD)
139 OS_InitThreadQueue(p->flip_wait_q);
140 #endif
141
142 /* Configuration of shared render variables */
143 col_clear = RGB555_CLEAR;
144 cur_pt.x = 0, cur_pt.y = 0;
145 col_text = RGB555_WHITE;
146 col_gnd = RGB555_CLEAR;
147 p->draw_flag |= DEMO_DRAW_ENABLE;
148 p->clip.o.x = 0;
149 p->clip.o.y = 0;
150 p->clip.t.x = GX_LCD_SIZE_X;
151 p->clip.t.y = GX_LCD_SIZE_Y;
152
153 /* VRAM-C direct display for dump displays and so on in half-width characters */
154 GX_SetGraphicsMode(GX_DISPMODE_VRAM_C, (GXBGMode)0, (GXBG0As)0);
155 GX_SetBankForLCDC(GX_VRAM_LCDC_C);
156
157 p->next_surface = (RGB555 *) tmp_surface;
158 MI_CpuFillFast(tmp_surface,
159 (u32)((col_clear << 0) | (col_clear << 16)), sizeof(tmp_surface));
160
161 (void)GX_VBlankIntr(TRUE);
162 GX_SetDispSelect(GX_DISP_SELECT_SUB_MAIN);
163
164 }
165 (void)OS_RestoreIrq(bak_irq);
166 }
167
DrawBegin(void)168 void DrawBegin(void)
169 {
170 DrawiCommon *const p = &drawi_common;
171 OSIntrMode bak_psr = OS_DisableInterrupts();
172 while (!(p->draw_flag & DEMO_DRAW_ENABLE))
173 OS_SleepThread(p->flip_wait_q);
174 (void)OS_RestoreInterrupts(bak_psr);
175 }
176
DrawEnd(void)177 void DrawEnd(void)
178 {
179 DrawiCommon *const p = &drawi_common;
180 OSIntrMode bak_psr;
181
182 DC_FlushRange(tmp_surface, sizeof(tmp_surface));
183 DC_WaitWriteBufferEmpty();
184
185 bak_psr = OS_DisableInterrupts();
186 p->draw_flag &= ~DEMO_DRAW_ENABLE;
187 p->draw_flag |= DEMO_DRAW_FLIPPING;
188 (void)OS_RestoreInterrupts(bak_psr);
189 }
190
ClipWindow(int ox,int oy,int tx,int ty,Rect * p_bak)191 void ClipWindow(int ox, int oy, int tx, int ty, Rect * p_bak)
192 {
193 DrawiCommon *const p = &drawi_common;
194 if (p_bak)
195 {
196 p_bak->o.x = p->clip.o.x;
197 p_bak->o.y = p->clip.o.y;
198 p_bak->t.x = p->clip.t.x;
199 p_bak->t.y = p->clip.t.y;
200 }
201 if (ox < 0)
202 ox = 0;
203 if (tx > GX_LCD_SIZE_X)
204 tx = GX_LCD_SIZE_X;
205 if (oy < 0)
206 oy = 0;
207 if (ty > GX_LCD_SIZE_Y)
208 ty = GX_LCD_SIZE_Y;
209 p->clip.o.x = ox;
210 p->clip.o.y = oy;
211 p->clip.t.x = tx;
212 p->clip.t.y = ty;
213 }
214
RestoreClipWindow(const Rect * p_bak)215 void RestoreClipWindow(const Rect * p_bak)
216 {
217 DrawiCommon *const p = &drawi_common;
218 if (p_bak)
219 {
220 p->clip.o.x = p_bak->o.x;
221 p->clip.o.y = p_bak->o.y;
222 p->clip.t.x = p_bak->t.x;
223 p->clip.t.y = p_bak->t.y;
224 }
225 }
226
ClearFrame(RGB555 col)227 void ClearFrame(RGB555 col)
228 {
229 DrawiCommon *const p = &drawi_common;
230 MI_CpuFillFast(p->next_surface,
231 (u32)((col << 0) | (col << 16)), GX_LCD_SIZE_X * GX_LCD_SIZE_Y * sizeof(RGB555));
232 }
233
FillRect(int x,int y,int wx,int wy,RGB555 col)234 void FillRect(int x, int y, int wx, int wy, RGB555 col)
235 {
236 Region r;
237 r.pos.x = x, r.pos.y = y;
238 r.wid.x = wx, r.wid.y = wy;
239 if (NormalizeRegion(&r))
240 {
241 RGB555 *p = GetSurface(r.pos.x, r.pos.y);
242 while (--r.wid.y >= 0)
243 {
244 MI_CpuFill16(p, col, r.wid.x * sizeof(RGB555));
245 p += GX_LCD_SIZE_X;
246 }
247 }
248 }
249
BlitRect(int x,int y,int wx,int wy,RGB555 * src,int stroke)250 void BlitRect(int x, int y, int wx, int wy, RGB555 * src, int stroke)
251 {
252 Region r;
253 r.pos.x = x, r.pos.y = y;
254 r.wid.x = wx, r.wid.y = wy;
255 if (NormalizeRegion(&r))
256 {
257 RGB555 *p = GetSurface(r.pos.x, r.pos.y);
258 while (--r.wid.y >= 0)
259 {
260 MI_CpuCopy16(src, p, r.wid.x * sizeof(RGB555));
261 src += stroke;
262 p += GX_LCD_SIZE_X;
263 }
264 }
265 }
266
TransRect(int x,int y,int wx,int wy,RGB555 * src,int stroke)267 void TransRect(int x, int y, int wx, int wy, RGB555 * src, int stroke)
268 {
269 Region r;
270 r.pos.x = x, r.pos.y = y;
271 r.wid.x = wx, r.wid.y = wy;
272 if (NormalizeRegion(&r))
273 {
274 RGB555 *p = GetSurface(r.pos.x, r.pos.y);
275 RGB555 trans = col_gnd;
276 while (--r.wid.y >= 0)
277 {
278 int i;
279 for (i = 0; i < r.wid.x; ++i)
280 {
281 if (p[i] != trans)
282 p[i] = src[i];
283 }
284 src += stroke;
285 p += GX_LCD_SIZE_X;
286 }
287 }
288 }
289
DrawLine(int sx,int sy,int tx,int ty,RGB555 col)290 void DrawLine(int sx, int sy, int tx, int ty, RGB555 col)
291 {
292 DrawiCommon *const pc = &drawi_common;
293
294 RGB555 *p;
295 int tmp;
296 int wx, wy;
297 if (sx > tx)
298 {
299 tmp = sx + 1, sx = tx + 1, tx = tmp;
300 tmp = sy, sy = ty, ty = tmp;
301 }
302 wx = tx - sx, wy = ty - sy;
303
304 if (!wx)
305 {
306 if (wy < 0)
307 {
308 wy = -wy;
309 tmp = sy + 1, sy = ty + 1, ty = tmp;
310 }
311 if (!IsBoundX(pc, sx) || (sy >= pc->clip.t.y))
312 return;
313 else
314 {
315 if (sy < pc->clip.o.y)
316 wy += sy, sy = pc->clip.o.y;
317 if (wy > pc->clip.t.y - sy)
318 wy = pc->clip.t.y - sy;
319 p = GetSurface(sx, sy);
320 while (--wy >= 0)
321 {
322 *p = col;
323 p += GX_LCD_SIZE_X;
324 }
325 }
326 }
327 else if (!wy)
328 {
329 if (!IsBoundY(pc, sy) || (sx >= pc->clip.t.x))
330 return;
331 else
332 {
333 if (sx < pc->clip.o.x)
334 wx += sx, sx = pc->clip.o.x;
335 if (wx > pc->clip.t.x - sx)
336 wx = pc->clip.t.x - sx;
337 p = GetSurface(sx, sy);
338 MI_CpuFill16(p, col, wx * sizeof(RGB555));
339 }
340 }
341 else
342 {
343 int n, dx, dy;
344 int y_delta = +1;
345 int y_ofs = GX_LCD_SIZE_X;
346 if (wy < 0)
347 {
348 wy = -wy;
349 y_delta = -y_delta;
350 y_ofs = -y_ofs;
351 }
352 p = GetSurface(sx, sy);
353 dx = wy - 1, dy = wx - 1;
354 --sx, sy -= y_delta;
355 for (n = wx * wy; --n >= 0;)
356 {
357 BOOL moved = FALSE;
358 if (++dx >= wy)
359 moved = TRUE, dx = 0, ++sx, p += 1;
360 if (++dy >= wx)
361 moved = TRUE, dy = 0, sy += y_delta, p += y_ofs;
362 if (moved && IsBoundX(pc, sx) && IsBoundY(pc, sy))
363 *p = col;
364 }
365 }
366 }
367
DrawCircle(int ox,int oy,int r)368 void DrawCircle(int ox, int oy, int r)
369 {
370 DrawiCommon *const pc = &drawi_common;
371
372 int n, dx, dy, vx, vy;
373 RGB555 col = col_text;
374 vx = 65536 * r, vy = 0;
375 dx = ox * 65536, dy = (oy - r) * 65536;
376
377 for (n = (int)(2 * 3.14 * 256); n > 0; --n)
378 {
379 int ax, ay, x, y;
380 ax = -vy / 256, ay = +vx / 256;
381 vx += ax, vy += ay;
382 dx += ay, dy -= ax;
383 x = dx / 65536, y = dy / 65536;
384 if (IsBoundX(pc, x) && IsBoundY(pc, y))
385 *GetSurface(x, y) = col;
386 }
387 }
388
DrawText(int x,int y,const char * s,...)389 void DrawText(int x, int y, const char *s, ...)
390 {
391 va_list vlist;
392 static char temp[512];
393
394 va_start(vlist, s);
395 (void)OS_VSNPrintf(temp, sizeof(temp) - 2, s, vlist);
396 va_end(vlist);
397 DrawTextLen(x, y, temp, sizeof(temp) - 1);
398 }
399
DrawTextLen(int x,int y,const char * s,int n)400 void DrawTextLen(int x, int y, const char *s, int n)
401 {
402 DrawiCommon *const pc = &drawi_common;
403
404 RGB555 *p = GetSurface(x, y);
405 RGB555 txt = col_text, gnd = col_gnd;
406 int px = 0;
407 int rep = 0;
408
409 for (; n > 0; ++s, --n)
410 {
411
412 int c = MI_ReadByte(s);
413
414 switch (c)
415 {
416
417 case '\0':
418 return;
419
420 case '\r':
421 c = MI_ReadByte(s + 1);
422 if (c == '\n')
423 ++s, --n;
424 case '\n':
425 y += 8;
426 p += GX_LCD_SIZE_X * 8;
427 px = 0;
428 break;
429
430 case '\t':
431 {
432 const int align = 4;
433 rep = align - ((px / 8) & (align - 1));
434 c = ' ';
435 }
436 goto put_char;
437
438 default:
439 rep = 1;
440 goto put_char;
441 put_char:
442 while (--rep >= 0)
443 {
444 int tx = x + px;
445 if ((tx > pc->clip.o.x - 8) && (y > pc->clip.o.y - 8) &&
446 (tx < pc->clip.t.x) && (y < pc->clip.t.y))
447 {
448 const u32 *pf = sampleCharData + c * 8;
449 RGB555 *dst = p + px;
450 int base = 0;
451 int wx = 8, wy = 8;
452 if (pc->clip.o.x - tx > 0)
453 base = pc->clip.o.x - tx;
454 else if (wx > pc->clip.t.x - tx)
455 wx = pc->clip.t.x - tx;
456 if (pc->clip.o.y - y > 0)
457 {
458 wy -= pc->clip.o.y - y;
459 pf += pc->clip.o.y - y;
460 dst += GX_LCD_SIZE_X * (pc->clip.o.y - y);
461 }
462 else if (wy > pc->clip.t.y - y)
463 wy = pc->clip.t.y - y;
464 for (; --wy >= 0; ++pf, dst += GX_LCD_SIZE_X)
465 {
466 int i;
467 const u32 d = *pf;
468 for (i = base; i < wx; ++i)
469 {
470 if ((d & (0xF << (i * 4))) != 0)
471 dst[i] = txt;
472 else if (gnd != RGB555_CLEAR)
473 dst[i] = gnd;
474 }
475 }
476 }
477 px += 8;
478 }
479 break;
480 }
481 }
482 }
483