clarify the gui
[open-ps2-loader.git] / src / renderman.c
blobd8418ea57add00a151832b1444370bb53fab2ae8
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 static struct rm_texture_list_t *uploadedTextures = NULL;
28 static int order;
29 static int vsync = 0;
30 static enum rm_vmode vmode;
31 // GSKit side detected vmode...
32 static int defaultVMode = GS_MODE_PAL;
34 #define NUM_RM_VMODES 3
35 // RM Vmode -> GS Vmode conversion table
36 static const int rm_mode_table[NUM_RM_VMODES] = {
37 -1,
38 GS_MODE_PAL,
39 GS_MODE_NTSC,
42 // inverse mode conversion table
43 #define MAX_GS_MODE 15
44 static int rm_gsmode_table[MAX_GS_MODE+1] = {
45 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
48 static int rm_height_table[] = {
49 448,
50 512,
51 448
54 static float aspectWidth;
55 static float aspectHeight;
57 // Transposition values - all rendering can be transposed (moved on screen) by these
58 static float transX = 0;
59 static float transY = 0;
61 const u64 gColWhite = GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x00);
62 const u64 gColBlack = GS_SETREG_RGBA(0x00,0x00,0x00,0x00);
63 const u64 gColDarker = GS_SETREG_RGBA(0x00,0x00,0x00,0x60);
64 const u64 gColFocus = GS_SETREG_RGBA(0xFF,0xFF,0xFF,0x50);
66 const u64 gDefaultCol = GS_SETREG_RGBA(0x80,0x80,0x80,0x80);
67 const u64 gDefaultAlpha = GS_SETREG_ALPHA(0,1,0,1,0);
69 static float shiftYVal;
70 static float (*shiftY)(float posY);
72 static float shiftYFunc(float posY) {
73 //return (int) ceil(shiftYVal * posY);
74 return (int) (shiftYVal * posY);
77 static float identityFunc(float posY) {
78 return posY;
81 static void rmAppendUploadedTextures(GSTEXTURE *txt) {
82 struct rm_texture_list_t *entry = (struct rm_texture_list_t *)malloc(sizeof(struct rm_texture_list_t));
83 entry->clut = NULL;
84 entry->txt = txt;
85 entry->next = uploadedTextures;
86 uploadedTextures = entry;
89 static void rmAppendUploadedCLUTs(GSCLUT *clut) {
90 struct rm_texture_list_t *entry = (struct rm_texture_list_t *)malloc(sizeof(struct rm_texture_list_t));
91 entry->txt = NULL;
92 entry->clut = clut;
93 entry->next = uploadedTextures;
94 uploadedTextures = entry;
97 static int rmClutSize(GSCLUT *clut, u32 *size, u32 *w, u32 *h) {
98 switch (clut->PSM) {
99 case GS_PSM_T4:
100 *w = 8;
101 *h = 2;
102 break;
103 case GS_PSM_T8:
104 *w = 16;
105 *h = 16;
106 break;
107 default:
108 return 0;
111 switch(clut->ClutPSM) {
112 case GS_PSM_CT32:
113 *size = (*w) * (*h) * 4;
114 break;
115 case GS_PSM_CT24:
116 *size = (*w) * (*h) * 4;
117 break;
118 case GS_PSM_CT16:
119 *size = (*w) * (*h) * 2;
120 break;
121 case GS_PSM_CT16S:
122 *size = (*w) * (*h) * 2;
123 break;
124 default:
125 return 0;
128 return 1;
131 static int rmUploadClut(GSCLUT *clut) {
132 if (clut->VramClut && clut->VramClut != GSKIT_ALLOC_ERROR) // already uploaded
133 return 1;
135 u32 size;
136 u32 w, h;
138 if (!rmClutSize(clut, &size, &w, &h))
139 return 0;
141 size = (-GS_VRAM_BLOCKSIZE_256)&(size+GS_VRAM_BLOCKSIZE_256-1);
143 // too large to fit VRAM with the currently allocated space?
144 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
147 if (size >= __VRAM_SIZE) {
148 // Only log this if the allocation is too large itself
149 LOG("RM: CLUT: Requested allocation is bigger than VRAM!\n");
150 // We won't allocate this, it's too large
151 clut->VramClut = GSKIT_ALLOC_ERROR;
152 return 0;
155 rmFlush();
158 clut->VramClut = gsGlobal->CurrentPointer;
159 gsGlobal->CurrentPointer += size;
161 rmAppendUploadedCLUTs(clut);
163 gsKit_texture_send(clut->Clut, w, h, clut->VramClut, clut->ClutPSM, 1, GS_CLUT_PALLETE);
164 return 1;
167 static int rmUploadTexture(GSTEXTURE* txt) {
168 // For clut based textures...
169 if (txt->Clut) {
170 // upload CLUT first
171 if (!rmUploadClut((GSCLUT *)txt->Clut))
172 return 0;
174 // copy the new VramClut
175 txt->VramClut = ((GSCLUT*)txt->Clut)->VramClut;
178 u32 size = gsKit_texture_size(txt->Width, txt->Height, txt->PSM);
179 // alignment of the allocation
180 size = (-GS_VRAM_BLOCKSIZE_256)&(size+GS_VRAM_BLOCKSIZE_256-1);
182 // too large to fit VRAM with the currently allocated space?
183 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
186 if (size >= __VRAM_SIZE) {
187 // Only log this if the allocation is too large itself
188 LOG("RM: TXT: Requested allocation is bigger than VRAM!\n");
189 // We won't allocate this, it's too large
190 txt->Vram = GSKIT_ALLOC_ERROR;
191 return 0;
194 rmFlush();
196 // Should not flush CLUT away. If this happenned we have to reupload
197 if (txt->Clut) {
198 if (!rmUploadClut((GSCLUT *)txt->Clut))
199 return 0;
201 txt->VramClut = ((GSCLUT*)txt->Clut)->VramClut;
204 // only could fit CLUT but not the pixmap with it!
205 if(gsGlobal->CurrentPointer + size >= __VRAM_SIZE)
206 return 0;
209 txt->Vram = gsGlobal->CurrentPointer;
210 gsGlobal->CurrentPointer += size;
212 rmAppendUploadedTextures(txt);
214 // We can't do gsKit_texture_upload since it'd assume txt->Clut is the CLUT table directly
215 // whereas we're using it as a pointer to our structure containg clut data
216 gsKit_setup_tbw(txt);
217 gsKit_texture_send(txt->Mem, txt->Width, txt->Height, txt->Vram, txt->PSM, txt->TBW, txt->Clut ? GS_CLUT_TEXTURE : GS_CLUT_NONE);
219 return 1;
222 int rmPrepareTexture(GSTEXTURE* txt) {
223 if (txt->Vram && txt->Vram != GSKIT_ALLOC_ERROR) // already uploaded
224 return 1;
226 return rmUploadTexture(txt);
229 void rmDispatch(void) {
230 gsKit_queue_exec(gsGlobal);
234 void rmFlush(void) {
235 rmDispatch();
237 // release all the uploaded textures
238 gsKit_vram_clear(gsGlobal);
240 while (uploadedTextures) {
241 // free clut and txt if those are filled in
242 if (uploadedTextures->txt) {
243 uploadedTextures->txt->Vram = 0;
244 uploadedTextures->txt->VramClut = 0;
247 if (uploadedTextures->clut)
248 uploadedTextures->clut->VramClut = 0;
250 struct rm_texture_list_t *entry = uploadedTextures;
251 uploadedTextures = uploadedTextures->next;
252 free(entry);
256 void rmStartFrame(void) {
257 order = 0;
260 void rmEndFrame(void) {
261 gsKit_set_finish(gsGlobal);
263 rmFlush();
265 // Wait for draw ops to finish
266 gsKit_finish();
268 if(!gsGlobal->FirstFrame)
270 if (vsync)
271 SleepThread();
273 if(gsGlobal->DoubleBuffering == GS_SETTING_ON)
275 GS_SET_DISPFB2( gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192,
276 gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 );
278 gsGlobal->ActiveBuffer ^= 1;
279 gsGlobal->PrimContext ^= 1;
284 gsKit_setactive(gsGlobal);
287 static int rmOnVSync(void) {
288 if (vsync)
289 iWakeupThread(guiThreadID);
291 return 0;
294 void rmInit(int vsyncon, enum rm_vmode vmodeset) {
295 gsGlobal = gsKit_init_global();
297 defaultVMode = gsGlobal->Mode;
299 int mde;
300 for (mde = 0; mde < NUM_RM_VMODES; ++mde) {
301 int gsmde = rm_mode_table[mde];
302 if (gsmde >= 0 && gsmde <= MAX_GS_MODE)
303 rm_gsmode_table[rm_mode_table[mde]] = mde;
306 // default height
307 rm_height_table[RM_VMODE_AUTO] = rm_height_table[gsGlobal->Mode];
309 dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC,
310 D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF);
312 // Initialize the DMAC
313 dmaKit_chan_init(DMA_CHANNEL_GIF);
314 dmaKit_chan_init(DMA_CHANNEL_FROMSPR);
315 dmaKit_chan_init(DMA_CHANNEL_TOSPR);
317 rmSetMode(vsyncon, vmodeset);
319 order = 0;
321 aspectWidth = 1.0f;
322 aspectHeight = 1.0f;
324 shiftYVal = 1.0f;
325 shiftY = &shiftYFunc;
327 transX = 0.0f;
328 transY = 0.0f;
330 guiThreadID = GetThreadId();
331 gsKit_add_vsync_handler(&rmOnVSync);
334 void rmSetMode(int vsyncon, enum rm_vmode vmodeset) {
335 vsync = vsyncon;
336 vmode = vmodeset;
338 // VMode override...
339 if (vmode != RM_VMODE_AUTO) {
340 gsGlobal->Mode = rm_mode_table[vmode];
341 } else {
342 gsGlobal->Mode = defaultVMode;
345 gsGlobal->Height = 512; // whatever...
347 if (gsGlobal->Mode <= MAX_GS_MODE) {
348 // back to rm mode from gs mode
349 int rmmde = rm_gsmode_table[gsGlobal->Mode];
351 if (rmmde)
352 gsGlobal->Height = rm_height_table[rmmde];
355 gsGlobal->PSM = GS_PSM_CT24;
356 gsGlobal->PSMZ = GS_PSMZ_16S;
357 gsGlobal->ZBuffering = GS_SETTING_OFF;
358 gsGlobal->PrimAlphaEnable = GS_SETTING_ON;
359 gsGlobal->DoubleBuffering = GS_SETTING_ON;
361 gsKit_init_screen(gsGlobal);
363 gsKit_mode_switch(gsGlobal, GS_ONESHOT);
365 gsKit_set_test(gsGlobal, GS_ZTEST_OFF);
367 // reset the contents of the screen to avoid garbage being displayed
368 gsKit_clear(gsGlobal, gColBlack);
369 gsKit_sync_flip(gsGlobal);
371 LOG("New vmode: %d x %d\n", gsGlobal->Width, gsGlobal->Height);
375 void rmGetScreenExtents(int *w, int *h) {
376 *w = gsGlobal->Width;
377 *h = gsGlobal->Height;
380 void rmEnd(void) {
381 rmFlush();
384 /** If txt is null, don't use DIM_UNDEF size */
385 void rmSetupQuad(GSTEXTURE* txt, int x, int y, short aligned, int w, int h, short scaled, u64 color, rm_quad_t* q) {
386 if (aligned) {
387 float dim;
388 if (w == DIM_UNDEF)
389 w = txt->Width;
390 if (h == DIM_UNDEF)
391 h = txt->Height;
393 if (scaled)
394 dim = aspectWidth * (w >> 1);
395 else
396 dim = w >> 1;
397 q->ul.x = x - dim;
398 q->br.x = x + dim;
400 if (scaled)
401 dim = aspectHeight * (h >> 1);
402 else
403 dim = h >> 1;
404 q->ul.y = shiftY(y) - dim;
405 q->br.y = shiftY(y) + dim;
406 } else {
407 if (w == DIM_UNDEF)
408 w = txt->Width;
409 if (h == DIM_UNDEF)
410 h = txt->Height;
412 q->ul.x = x;
413 if (scaled)
414 q->br.x = x + aspectWidth * w;
415 else
416 q->br.x = x + w;
418 q->ul.y = shiftY(y);
419 if (scaled)
420 q->br.y = shiftY(y) + aspectHeight * h;
421 else
422 q->br.y = shiftY(y) + h;
425 q->color = color;
427 if (txt) {
428 q->txt = txt;
429 q->ul.u = 0;
430 q->ul.v = 0;
431 q->br.u = txt->Width;
432 q->br.v = txt->Height;
436 void rmDrawQuad(rm_quad_t* q) { // NO scaling, NO shift, NO alignment
437 if (!rmPrepareTexture(q->txt)) // won't render if not ready!
438 return;
440 if ((q->txt->PSM == GS_PSM_CT32) || (q->txt->Clut && q->txt->ClutPSM == GS_PSM_CT32))
442 gsKit_set_primalpha(gsGlobal, gDefaultAlpha, 0);
445 gsKit_prim_sprite_texture(gsGlobal, q->txt,
446 q->ul.x + transX, q->ul.y + transY,
447 q->ul.u, q->ul.v,
448 q->br.x + transX, q->br.y + transY,
449 q->br.u, q->br.v, order, q->color);
450 order++;
452 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
455 void rmDrawPixmap(GSTEXTURE* txt, int x, int y, short aligned, int w, int h, short scaled, u64 color) {
456 rm_quad_t quad;
457 rmSetupQuad(txt, x, y, aligned, w, h, scaled, color, &quad);
458 rmDrawQuad(&quad);
461 void rmDrawOverlayPixmap(GSTEXTURE* overlay, int x, int y, short aligned, int w, int h, short scaled, u64 color,
462 GSTEXTURE* inlay, int ulx, int uly, int urx, int ury, int blx, int bly, int brx, int bry) {
464 rm_quad_t quad;
465 rmSetupQuad(overlay, x, y, aligned, w, h, scaled, color, &quad);
467 if (!rmPrepareTexture(inlay))
468 return;
470 if (inlay->PSM == GS_PSM_CT32)
471 gsKit_set_primalpha(gsGlobal, gDefaultAlpha, 0);
473 gsKit_prim_quad_texture(gsGlobal, inlay, quad.ul.x + transX + aspectWidth * ulx, quad.ul.y + transY + uly, 0, 0,
474 quad.ul.x + transX + aspectWidth * urx, quad.ul.y + transY + ury, inlay->Width, 0,
475 quad.ul.x + transX + aspectWidth * blx, quad.ul.y + transY + bly, 0, inlay->Height,
476 quad.ul.x + transX + aspectWidth * brx, quad.ul.y + transY + bry, inlay->Width, inlay->Height, order, gDefaultCol);
477 order++;
478 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
480 rmDrawQuad(&quad);
483 void rmDrawRect(int x, int y, int w, int h, u64 color) {
484 gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0,1,0,1,0), 0);
485 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);
486 order++;
487 gsKit_set_primalpha(gsGlobal, GS_BLEND_BACK2FRONT, 0);
490 void rmDrawLine(int x, int y, int x1, int y1, u64 color) {
491 gsKit_prim_line(gsGlobal, x + transX, shiftY(y) + transY, x1 + transX, shiftY(y1) + transY, order, color);
494 void rmSetAspectRatio(float width, float height) {
495 aspectWidth = width;
496 aspectHeight = height;
499 void rmResetAspectRatio() {
500 aspectWidth = 1.0f;
501 aspectHeight = 1.0f;
504 void rmGetAspectRatio(float *w, float *h) {
505 *w = aspectWidth;
506 *h = aspectHeight;
509 void rmApplyAspectRatio(int* w, int* h) {
510 *w = *w * aspectWidth;
511 *h = *h * aspectHeight;
514 void rmSetShiftRatio(float shiftYRatio) {
515 shiftYVal = shiftYRatio;
516 shiftY = &shiftYFunc;
519 void rmResetShiftRatio() {
520 shiftY = &identityFunc;
523 void rmApplyShiftRatio(int* y) {
524 *y = shiftY(*y);
527 void rmSetTransposition(float x, float y) {
528 transX = x;
529 transY = y;