extracted code branching from ItemsList drawing and main drawing method
[open-ps2-loader.git] / src / renderman.c
blobe94c4c98b4ecf9d60a695fed2724d3c586e8d559
1 /*
2 Copyright 2010, Volca
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include <stdio.h>
8 #include <kernel.h>
10 #include "include/renderman.h"
11 #include "include/ioman.h"
13 // Allocateable space in vram, as indicated in GsKit's code
14 #define __VRAM_SIZE 4194304
16 GSGLOBAL *gsGlobal;
17 s32 guiThreadID;
19 /** Helper texture list */
20 struct rm_texture_list_t {
21 GSTEXTURE *txt;
22 GSCLUT *clut;
23 struct rm_texture_list_t *next;
26 typedef struct {
27 int used;
28 int x, y, x1, y1;
29 } rm_clip_rect_t;
31 static struct rm_texture_list_t *uploadedTextures = NULL;
33 static rm_clip_rect_t clipRect;
35 static int order;
36 static int vsync = 0;
37 static enum rm_vmode vmode;
38 // GSKit side detected vmode...
39 static int defaultVMode = GS_MODE_PAL;
41 #define NUM_RM_VMODES 3
42 // RM Vmode -> GS Vmode conversion table
43 static const int rm_mode_table[NUM_RM_VMODES] = {
44 -1,
45 GS_MODE_PAL,
46 GS_MODE_NTSC,
49 // inverse mode conversion table
50 #define MAX_GS_MODE 15
51 static int rm_gsmode_table[MAX_GS_MODE+1] = {
52 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
55 static int rm_height_table[] = {
56 448,
57 512,
58 448
61 static float aspectWidth;
62 static float aspectHeight;
64 // Transposition values - all rendering can be transposed (moved on screen) by these
65 // this is a post-clipping operation
66 static float transX = 0;
67 static float transY = 0;
69 const u64 gColWhite = GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x00);
70 const u64 gColBlack = GS_SETREG_RGBA(0x00,0x00,0x00,0x00);
71 const u64 gColDarker = GS_SETREG_RGBA(0x00,0x00,0x00,0x60);
72 const u64 gColFocus = GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x50);
74 const u64 gDefaultCol = GS_SETREG_RGBA(0x80,0x80,0x80,0x80);
75 const u64 gDefaultAlpha = GS_SETREG_ALPHA(0,1,0,1,0);
77 static float shiftYVal;
78 static float (*shiftY)(float posY);
80 static float shiftYFunc(float posY) {
81 //return (int) ceil(shiftYVal * posY);
82 return (int) (shiftYVal * posY);
85 static float identityFunc(float posY) {
86 return posY;
89 static int rmClipQuad(rm_quad_t* quad) {
90 if (!clipRect.used)
91 return 1;
93 if (quad->ul.x > clipRect.x1)
94 return 0;
95 if (quad->ul.y > clipRect.y1)
96 return 0;
97 if (quad->br.x < clipRect.x)
98 return 0;
99 if (quad->br.y < clipRect.y)
100 return 0;
102 float dx = quad->br.x - quad->ul.x;
103 float dy = quad->br.y - quad->ul.x;
104 float du = (quad->br.u - quad->ul.u) / dx;
105 float dv = (quad->br.v - quad->ul.v) / dy;
107 if (quad->ul.x < clipRect.x) {
108 // clip
109 float d = clipRect.x - quad->ul.x;
110 quad->ul.x = clipRect.x;
111 quad->ul.u += d * du;
114 if (quad->ul.y < clipRect.y) {
115 // clip
116 float d = clipRect.y - quad->ul.y;
117 quad->ul.y = clipRect.y;
118 quad->ul.v += d * dv;
121 if (quad->br.x > clipRect.x1) {
122 // clip
123 float d = quad->br.x - clipRect.x1;
124 quad->br.x = clipRect.x1;
125 quad->br.u -= d * du;
128 if (quad->ul.y < clipRect.y) {
129 // clip
130 float d = quad->br.y - clipRect.y1;
131 quad->br.y = clipRect.y1;
132 quad->br.v -= d * dv;
135 return 1;
138 static void rmAppendUploadedTextures(GSTEXTURE *txt) {
139 struct rm_texture_list_t *entry = (struct rm_texture_list_t *)malloc(sizeof(struct rm_texture_list_t));
140 entry->clut = NULL;
141 entry->txt = txt;
142 entry->next = uploadedTextures;
143 uploadedTextures = entry;
146 static void rmAppendUploadedCLUTs(GSCLUT *clut) {
147 struct rm_texture_list_t *entry = (struct rm_texture_list_t *)malloc(sizeof(struct rm_texture_list_t));
148 entry->txt = NULL;
149 entry->clut = clut;
150 entry->next = uploadedTextures;
151 uploadedTextures = entry;
154 static int rmClutSize(GSCLUT *clut, u32 *size, u32 *w, u32 *h) {
155 switch (clut->PSM) {
156 case GS_PSM_T4:
157 *w = 8;
158 *h = 2;
159 break;
160 case GS_PSM_T8:
161 *w = 16;
162 *h = 16;
163 break;
164 default:
165 return 0;
168 switch(clut->ClutPSM) {
169 case GS_PSM_CT32:
170 *size = (*w) * (*h) * 4;
171 break;
172 case GS_PSM_CT24:
173 *size = (*w) * (*h) * 4;
174 break;
175 case GS_PSM_CT16:
176 *size = (*w) * (*h) * 2;
177 break;
178 case GS_PSM_CT16S:
179 *size = (*w) * (*h) * 2;
180 break;
181 default:
182 return 0;
185 return 1;
188 static int rmUploadClut(GSCLUT *clut) {
189 if (clut->VramClut && clut->VramClut != GSKIT_ALLOC_ERROR) // already uploaded
190 return 1;
192 u32 size;
193 u32 w, h;
195 if (!rmClutSize(clut, &size, &w, &h))
196 return 0;
198 size = (-GS_VRAM_BLOCKSIZE_256)&(size+GS_VRAM_BLOCKSIZE_256-1);
200 // too large to fit VRAM with the currently allocated space?
201 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
204 if (size >= __VRAM_SIZE) {
205 // Only log this if the allocation is too large itself
206 LOG("RM: CLUT: Requested allocation is bigger than VRAM!\n");
207 // We won't allocate this, it's too large
208 clut->VramClut = GSKIT_ALLOC_ERROR;
209 return 0;
212 rmFlush();
215 clut->VramClut = gsGlobal->CurrentPointer;
216 gsGlobal->CurrentPointer += size;
218 rmAppendUploadedCLUTs(clut);
220 gsKit_texture_send(clut->Clut, w, h, clut->VramClut, clut->ClutPSM, 1, GS_CLUT_PALLETE);
221 return 1;
224 static int rmUploadTexture(GSTEXTURE* txt) {
225 // For clut based textures...
226 if (txt->Clut) {
227 // upload CLUT first
228 if (!rmUploadClut((GSCLUT *)txt->Clut))
229 return 0;
231 // copy the new VramClut
232 txt->VramClut = ((GSCLUT*)txt->Clut)->VramClut;
235 u32 size = gsKit_texture_size(txt->Width, txt->Height, txt->PSM);
236 // alignment of the allocation
237 size = (-GS_VRAM_BLOCKSIZE_256)&(size+GS_VRAM_BLOCKSIZE_256-1);
239 // too large to fit VRAM with the currently allocated space?
240 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
243 if (size >= __VRAM_SIZE) {
244 // Only log this if the allocation is too large itself
245 LOG("RM: TXT: Requested allocation is bigger than VRAM!\n");
246 // We won't allocate this, it's too large
247 txt->Vram = GSKIT_ALLOC_ERROR;
248 return 0;
251 rmFlush();
253 // Should not flush CLUT away. If this happenned we have to reupload
254 if (txt->Clut) {
255 if (!rmUploadClut((GSCLUT *)txt->Clut))
256 return 0;
258 txt->VramClut = ((GSCLUT*)txt->Clut)->VramClut;
261 // only could fit CLUT but not the pixmap with it!
262 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
263 return 0;
266 txt->Vram = gsGlobal->CurrentPointer;
267 gsGlobal->CurrentPointer += size;
269 rmAppendUploadedTextures(txt);
271 // We can't do gsKit_texture_upload since it'd assume txt->Clut is the CLUT table directly
272 // whereas we're using it as a pointer to our structure containg clut data
273 gsKit_setup_tbw(txt);
274 gsKit_texture_send(txt->Mem, txt->Width, txt->Height, txt->Vram, txt->PSM, txt->TBW, txt->Clut ? GS_CLUT_TEXTURE : GS_CLUT_NONE);
276 return 1;
279 int rmPrepareTexture(GSTEXTURE* txt) {
280 if (txt->Vram && txt->Vram != GSKIT_ALLOC_ERROR) // already uploaded
281 return 1;
283 return rmUploadTexture(txt);
286 void rmDispatch(void) {
287 gsKit_queue_exec(gsGlobal);
291 void rmFlush(void) {
292 rmDispatch();
294 // release all the uploaded textures
295 gsKit_vram_clear(gsGlobal);
297 while (uploadedTextures) {
298 // free clut and txt if those are filled in
299 if (uploadedTextures->txt) {
300 uploadedTextures->txt->Vram = 0;
301 uploadedTextures->txt->VramClut = 0;
304 if (uploadedTextures->clut)
305 uploadedTextures->clut->VramClut = 0;
307 struct rm_texture_list_t *entry = uploadedTextures;
308 uploadedTextures = uploadedTextures->next;
309 free(entry);
313 void rmStartFrame(void) {
314 order = 0;
317 void rmEndFrame(void) {
318 gsKit_set_finish(gsGlobal);
320 rmFlush();
322 // Wait for draw ops to finish
323 gsKit_finish();
325 if(!gsGlobal->FirstFrame)
327 if (vsync)
328 SleepThread();
330 if(gsGlobal->DoubleBuffering == GS_SETTING_ON)
332 GS_SET_DISPFB2( gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192,
333 gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 );
335 gsGlobal->ActiveBuffer ^= 1;
336 gsGlobal->PrimContext ^= 1;
341 gsKit_setactive(gsGlobal);
344 static int rmOnVSync(void) {
345 if (vsync)
346 iWakeupThread(guiThreadID);
348 return 0;
351 void rmInit(int vsyncon, enum rm_vmode vmodeset) {
352 gsGlobal = gsKit_init_global();
354 defaultVMode = gsGlobal->Mode;
356 int mde;
357 for (mde = 0; mde < NUM_RM_VMODES; ++mde) {
358 int gsmde = rm_mode_table[mde];
359 if (gsmde >= 0 && gsmde <= MAX_GS_MODE)
360 rm_gsmode_table[rm_mode_table[mde]] = mde;
363 // default height
364 rm_height_table[RM_VMODE_AUTO] = rm_height_table[gsGlobal->Mode];
366 dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC,
367 D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF);
369 // Initialize the DMAC
370 dmaKit_chan_init(DMA_CHANNEL_GIF);
371 dmaKit_chan_init(DMA_CHANNEL_FROMSPR);
372 dmaKit_chan_init(DMA_CHANNEL_TOSPR);
374 rmSetMode(vsyncon, vmodeset);
376 order = 0;
378 clipRect.used = 0;
380 aspectWidth = 1.0f;
381 aspectHeight = 1.0f;
383 shiftYVal = 1.0f;
384 shiftY = &shiftYFunc;
386 transX = 0.0f;
387 transY = 0.0f;
389 guiThreadID = GetThreadId();
390 gsKit_add_vsync_handler(&rmOnVSync);
393 void rmSetMode(int vsyncon, enum rm_vmode vmodeset) {
394 vsync = vsyncon;
395 vmode = vmodeset;
397 // VMode override...
398 if (vmode != RM_VMODE_AUTO) {
399 gsGlobal->Mode = rm_mode_table[vmode];
400 } else {
401 gsGlobal->Mode = defaultVMode;
404 gsGlobal->Height = 512; // whatever...
406 if (gsGlobal->Mode <= MAX_GS_MODE) {
407 // back to rm mode from gs mode
408 int rmmde = rm_gsmode_table[gsGlobal->Mode];
410 if (rmmde)
411 gsGlobal->Height = rm_height_table[rmmde];
414 gsGlobal->PSM = GS_PSM_CT24;
415 gsGlobal->PSMZ = GS_PSMZ_16S;
416 gsGlobal->ZBuffering = GS_SETTING_OFF;
417 gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
418 gsGlobal->DoubleBuffering = GS_SETTING_ON;
420 gsKit_init_screen(gsGlobal);
422 gsKit_mode_switch(gsGlobal, GS_ONESHOT);
424 gsKit_set_test(gsGlobal, GS_ZTEST_OFF);
426 // reset the contents of the screen to avoid garbage being displayed
427 gsKit_clear(gsGlobal, gColBlack);
428 gsKit_sync_flip(gsGlobal);
430 LOG("New vmode: %d x %d\n", gsGlobal->Width, gsGlobal->Height);
434 void rmGetScreenExtents(int *w, int *h) {
435 *w = gsGlobal->Width;
436 *h = gsGlobal->Height;
439 void rmEnd(void) {
440 rmFlush();
443 /** If txt is null, don't use DIM_ADAPT size */
444 void rmSetupQuad(GSTEXTURE* txt, int x, int y, short aligned, int w, int h, short scaled, u64 color, rm_quad_t* q) {
445 if (aligned) {
446 float dim;
447 if (w == DIM_UNDEF)
448 w = txt->Width;
449 if (h == DIM_UNDEF)
450 h = txt->Height;
452 if (scaled)
453 dim = aspectWidth * (w >> 1);
454 else
455 dim = w >> 1;
456 q->ul.x = x - dim;
457 q->br.x = x + dim;
459 if (scaled)
460 dim = aspectHeight * (h >> 1);
461 else
462 dim = h >> 1;
463 q->ul.y = shiftY(y) - dim;
464 q->br.y = shiftY(y) + dim;
465 } else {
466 if (w == DIM_UNDEF)
467 w = txt->Width;
468 if (h == DIM_UNDEF)
469 h = txt->Height;
471 q->ul.x = x;
472 if (scaled)
473 q->br.x = x + aspectWidth * w;
474 else
475 q->br.x = x + w;
477 q->ul.y = shiftY(y);
478 if (scaled)
479 q->br.y = shiftY(y) + aspectHeight * h;
480 else
481 q->br.y = shiftY(y) + h;
484 q->color = color;
486 if (txt) {
487 q->txt = txt;
488 q->ul.u = 0;
489 q->ul.v = 0;
490 q->br.u = txt->Width;
491 q->br.v = txt->Height;
495 void rmDrawQuad(rm_quad_t* q) { // NO scaling, NO shift, NO alignment
496 if (!rmClipQuad(q))
497 return;
499 if (!rmPrepareTexture(q->txt)) // won't render if not ready!
500 return;
502 if ((q->txt->PSM == GS_PSM_CT32) || (q->txt->Clut && q->txt->ClutPSM == GS_PSM_CT32))
504 gsKit_set_primalpha(gsGlobal, gDefaultAlpha, 0);
507 gsKit_prim_sprite_texture(gsGlobal, q->txt,
508 q->ul.x + transX, q->ul.y + transY,
509 q->ul.u, q->ul.v,
510 q->br.x + transX, q->br.y + transY,
511 q->br.u, q->br.v, order, q->color);
512 order++;
514 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
517 void rmDrawPixmap(GSTEXTURE* txt, int x, int y, short aligned, int w, int h, short scaled, u64 color) {
518 rm_quad_t quad;
519 rmSetupQuad(txt, x, y, aligned, w, h, scaled, color, &quad);
520 rmDrawQuad(&quad);
523 void rmDrawOverlayPixmap(GSTEXTURE* overlay, int x, int y, short aligned, int w, int h, short scaled, u64 color,
524 GSTEXTURE* inlay, int ulx, int uly, int urx, int ury, int blx, int bly, int brx, int bry) {
526 rm_quad_t quad;
527 rmSetupQuad(overlay, x, y, aligned, w, h, scaled, color, &quad);
529 if (!rmPrepareTexture(inlay))
530 return;
532 if (inlay->PSM == GS_PSM_CT32)
533 gsKit_set_primalpha(gsGlobal, gDefaultAlpha, 0);
535 gsKit_prim_quad_texture(gsGlobal, inlay, quad.ul.x + transX + aspectWidth * ulx, quad.ul.y + transY + uly, 0, 0,
536 quad.ul.x + transX + aspectWidth * urx, quad.ul.y + transY + ury, inlay->Width, 0,
537 quad.ul.x + transX + aspectWidth * blx, quad.ul.y + transY + bly, 0, inlay->Height,
538 quad.ul.x + transX + aspectWidth * brx, quad.ul.y + transY + bry, inlay->Width, inlay->Height, order, gDefaultCol);
539 order++;
540 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
542 rmDrawQuad(&quad);
545 void rmDrawRect(int x, int y, int w, int h, u64 color) {
546 gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0,1,0,1,0), 0);
547 gsKit_prim_quad(gsGlobal, x + transX, shiftY(y) + transY, x + w + transX, shiftY(y) + transY, x + transX, shiftY(y) + h + transY, x + w + transX, shiftY(y) + h + transY, order, color);
548 order++;
549 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
552 void rmDrawLine(int x, int y, int x1, int y1, u64 color) {
553 gsKit_prim_line(gsGlobal, x + transX, shiftY(y) + transY, x1 + transX, shiftY(y1) + transY, order, color);
556 /** Sets the clipping rectangle */
557 void rmClip(int x, int y, int w, int h) {
558 clipRect.x = x;
559 clipRect.y = y;
560 if (w == -1)
561 clipRect.x1 = gsGlobal->Width;
562 else
563 clipRect.x1 = x + w;
564 if (h == -1)
565 clipRect.y1 = gsGlobal->Height;
566 else
567 clipRect.y1 = y + h;
568 clipRect.used = 0;
571 /** Sets cipping to none */
572 void rmUnclip(void) {
573 clipRect.used = 0;
576 void rmSetAspectRatio(float width, float height) {
577 aspectWidth = width;
578 aspectHeight = height;
581 void rmResetAspectRatio() {
582 aspectWidth = 1.0f;
583 aspectHeight = 1.0f;
586 void rmGetAspectRatio(float *w, float *h) {
587 *w = aspectWidth;
588 *h = aspectHeight;
591 void rmApplyAspectRatio(int* w, int* h) {
592 *w = *w * aspectWidth;
593 *h = *h * aspectHeight;
596 void rmSetShiftRatio(float shiftYRatio) {
597 shiftYVal = shiftYRatio;
598 shiftY = &shiftYFunc;
601 void rmResetShiftRatio() {
602 shiftY = &identityFunc;
605 void rmApplyShiftRatio(int* y) {
606 *y = shiftY(*y);
609 void rmSetTransposition(float x, float y) {
610 transX = x;
611 transY = y;