mirror of
https://github.com/dborth/fceugx.git
synced 2025-01-09 15:19:26 +01:00
8cdf9df10c
-Rearrange of some functions
376 lines
12 KiB
C
376 lines
12 KiB
C
/****************************************************************************
|
|
* GCVideo
|
|
*
|
|
* This module contains all GameCube video routines
|
|
****************************************************************************/
|
|
|
|
#include <gccore.h>
|
|
#include <ogcsys.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "iplfont.h"
|
|
#include "nesback.h"
|
|
#include "intl.h"
|
|
|
|
//#define FORCE_PAL50 1
|
|
|
|
#define TEX_WIDTH 256
|
|
#define TEX_HEIGHT 512
|
|
#define WIDTH 640
|
|
#define DEFAULT_FIFO_SIZE 256 * 1024
|
|
|
|
unsigned int *xfb[2]; /*** Framebuffer - used throughout ***/
|
|
GXRModeObj *vmode;
|
|
|
|
/*** Backdrop ***/
|
|
extern unsigned char backdrop[614400];
|
|
|
|
/*** Need something to hold the PC palette ***/
|
|
struct pcpal {
|
|
unsigned char r;
|
|
unsigned char g;
|
|
unsigned char b;
|
|
} pcpalette[256];
|
|
|
|
unsigned int gcpalette[256]; /*** Much simpler GC palette ***/
|
|
unsigned short rgb565[256]; /*** Texture map palette ***/
|
|
static unsigned char gp_fifo[DEFAULT_FIFO_SIZE] __attribute__((__aligned__(32)));
|
|
static unsigned char texturemem[TEX_WIDTH * TEX_HEIGHT * 2] __attribute__((__aligned__(32)));
|
|
GXTexObj texobj;
|
|
GXColor background = {0, 0, 0, 0xff};
|
|
static Mtx projectionMatrix,modelViewMatrix;
|
|
void CheesyScale(unsigned char *XBuf);
|
|
int whichfb = 0;
|
|
extern int font_height;
|
|
int copynow = GX_FALSE;
|
|
|
|
/****************************************************************************
|
|
* GX Chip Copy to XFB
|
|
****************************************************************************/
|
|
static void copy_to_xfb() {
|
|
if (copynow == GX_TRUE) {
|
|
GX_CopyDisp(xfb[whichfb],GX_TRUE);
|
|
GX_Flush();
|
|
copynow = GX_FALSE;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Initialise the GX
|
|
****************************************************************************/
|
|
void StartGX() {
|
|
/*** Clear out FIFO area ***/
|
|
memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE);
|
|
|
|
/*** Initialise GX ***/
|
|
GX_Init(&gp_fifo, DEFAULT_FIFO_SIZE);
|
|
GX_SetCopyClear(background, 0x00ffffff);
|
|
|
|
/*** Additions from libogc ***/
|
|
GX_SetViewport(10,0,vmode->fbWidth,vmode->efbHeight,0,1);
|
|
GX_SetDispCopyYScale((f32)vmode->xfbHeight/(f32)vmode->efbHeight);
|
|
GX_SetDispCopySrc(0,0,vmode->fbWidth,vmode->efbHeight);
|
|
GX_SetDispCopyDst(vmode->fbWidth,vmode->xfbHeight);
|
|
|
|
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
GX_SetZMode(GX_FALSE,GX_ALWAYS,GX_TRUE);
|
|
GX_SetColorUpdate(GX_TRUE);
|
|
GX_CopyDisp(xfb[whichfb],GX_TRUE);
|
|
|
|
/*** Additions from ogc spaceship ***/
|
|
GX_SetDispCopyGamma(GX_GM_1_0);
|
|
|
|
GX_ClearVtxDesc();
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0,GX_VA_POS,GX_POS_XYZ,GX_F32,0);
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0,GX_VA_TEX0,GX_TEX_ST,GX_F32,0);
|
|
GX_SetVtxDesc(GX_VA_POS,GX_DIRECT);
|
|
GX_SetVtxDesc(GX_VA_TEX0,GX_DIRECT);
|
|
|
|
GX_SetNumChans(0); /* default, color = vertex color */
|
|
GX_SetNumTexGens(1);
|
|
GX_SetTexCoordGen(GX_TEXCOORD0,GX_TG_MTX2x4,GX_TG_TEX0,GX_IDENTITY);
|
|
GX_SetTevOrder(GX_TEVSTAGE0,GX_TEXCOORD0,GX_TEXMAP0,GX_COLORNULL);
|
|
GX_SetTevOp(GX_TEVSTAGE0,GX_REPLACE);
|
|
|
|
GX_InitTexObj(&texobj,&texturemem,TEX_WIDTH,TEX_HEIGHT,
|
|
GX_TF_RGB565,GX_REPEAT,GX_REPEAT,GX_FALSE);
|
|
|
|
DCFlushRange(&texturemem, TEX_WIDTH * TEX_HEIGHT * 2);
|
|
GX_LoadTexObj(&texobj,GX_TEXMAP0);
|
|
GX_InvalidateTexAll();
|
|
|
|
/* load projection matrix */
|
|
/*** Setting Height to 648 get's it right ? ***/
|
|
guOrtho(projectionMatrix,10,610,640,0,-1,1);
|
|
GX_LoadProjectionMtx(projectionMatrix,GX_ORTHOGRAPHIC);
|
|
|
|
/* load model view matrix */
|
|
c_guMtxScale(modelViewMatrix,660,640,1);
|
|
GX_LoadPosMtxImm(modelViewMatrix,GX_PNMTX0);
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* GXDraw
|
|
*
|
|
* Using the texture map draw with quads
|
|
****************************************************************************/
|
|
void GXDraw(unsigned char *XBuf) {
|
|
float gs = 1.0;
|
|
float gt = 1.0;
|
|
int width, height,t,xb;
|
|
unsigned short *texture;
|
|
|
|
memset(&texturemem, 0, TEX_WIDTH * TEX_HEIGHT * 2);
|
|
texture = (unsigned short *)&texturemem[16 * TEX_WIDTH];
|
|
|
|
/*** Now draw the texture ***/
|
|
t = 0;
|
|
for(height = 0; height < 120; height++) {
|
|
xb = height * 512;
|
|
for(width = 256; width > 0; width -= 4) {
|
|
/*** Row one ***/
|
|
texture[t++] = rgb565[XBuf[xb + width-1]];
|
|
texture[t++] = rgb565[XBuf[xb + width-2]];
|
|
texture[t++] = rgb565[XBuf[xb + width-3]];
|
|
texture[t++] = rgb565[XBuf[xb + width-4]];
|
|
|
|
/*** Row three ***/
|
|
texture[t++] = rgb565[XBuf[xb + width-1]];
|
|
texture[t++] = rgb565[XBuf[xb + width-2]];
|
|
texture[t++] = rgb565[XBuf[xb + width-3]];
|
|
texture[t++] = rgb565[XBuf[xb + width-4]];
|
|
|
|
/*** Row one ***/
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-1]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-2]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-3]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-4]];
|
|
|
|
/*** Row three ***/
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-1]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-2]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-3]];
|
|
texture[t++] = rgb565[XBuf[xb + 256 + width-4]];
|
|
}
|
|
}
|
|
|
|
DCFlushRange(&texturemem, TEX_WIDTH * TEX_HEIGHT * 2);
|
|
|
|
/* setup GX */
|
|
GX_InvalidateTexAll();
|
|
|
|
// ok render the triangles now
|
|
GX_Begin(GX_QUADS,GX_VTXFMT0,4);
|
|
{
|
|
GX_Position3f32(0,0,0);
|
|
GX_TexCoord2f32(0,0);
|
|
|
|
GX_Position3f32(0,1,0);
|
|
GX_TexCoord2f32(0,gt);
|
|
|
|
GX_Position3f32(1,1,0);
|
|
GX_TexCoord2f32(gs,gt);
|
|
|
|
GX_Position3f32(1,0,0);
|
|
GX_TexCoord2f32(gs,0);
|
|
}
|
|
GX_End();
|
|
GX_DrawDone();
|
|
copynow = GX_TRUE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* initDisplay
|
|
*
|
|
* It should be noted that this function forces the system to use a
|
|
* 640x480 viewport for either NTSC or PAL.
|
|
*
|
|
* Helps keep the rendering at 2x sweet
|
|
****************************************************************************/
|
|
void initDisplay() {
|
|
/*** Start VIDEO Subsystem ***/
|
|
VIDEO_Init();
|
|
|
|
vmode = VIDEO_GetPreferredMode(NULL);
|
|
VIDEO_Configure(vmode);
|
|
|
|
xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
|
|
xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
|
|
/*init_font();*/
|
|
|
|
VIDEO_SetNextFramebuffer(xfb[0]);
|
|
VIDEO_SetBlack(FALSE);
|
|
VIDEO_Flush();
|
|
VIDEO_WaitVSync();
|
|
|
|
if(vmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
|
|
VIDEO_SetPostRetraceCallback(PAD_ScanPads);
|
|
/*** Setup a console - guard against spurious printf ***/
|
|
VIDEO_SetPreRetraceCallback(copy_to_xfb);
|
|
VIDEO_SetNextFramebuffer(xfb[0]);
|
|
|
|
PAD_Init();
|
|
StartGX();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* RenderFrame
|
|
*
|
|
* Render a single frame at 2x zoom
|
|
****************************************************************************/
|
|
#define NESWIDTH 256
|
|
#define NESHEIGHT 240
|
|
void RenderFrame(char *XBuf, int style) {
|
|
int gcdispOffset = 32; /*** Offset to centre on screen ***/
|
|
int w,h;
|
|
int c,i;
|
|
|
|
whichfb ^= 1;
|
|
switch(style) {
|
|
case 0 :
|
|
VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK);
|
|
|
|
/*** Simply go through each row ***/
|
|
for(h = 0; h < NESHEIGHT; h++) {
|
|
for(w = 0; w < NESWIDTH; w++) {
|
|
c = (h << 8) + w;
|
|
i = gcdispOffset + w;
|
|
/*** Fast Zoom - Repeat each row, use 1 Xbuf == 2 GC
|
|
To speed up more, use indexed palette array ***/
|
|
|
|
xfb[whichfb][i] = gcpalette[(unsigned char)XBuf[c]];
|
|
xfb[whichfb][i + 320] = gcpalette[(unsigned char)XBuf[c]];
|
|
}
|
|
gcdispOffset += 640;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
CheesyScale(XBuf);
|
|
break;
|
|
|
|
case 2:
|
|
GXDraw(XBuf);
|
|
break;
|
|
}
|
|
|
|
/*** Now resync with VSync ***/
|
|
VIDEO_SetNextFramebuffer(xfb[whichfb]);
|
|
VIDEO_Flush();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* rgbcolor
|
|
*
|
|
* Support routine for gcpalette
|
|
****************************************************************************/
|
|
|
|
unsigned int rgbcolor(unsigned char r1, unsigned char g1, unsigned char b1,
|
|
unsigned char r2, unsigned char g2, unsigned char b2) {
|
|
int y1,cb1,cr1,y2,cb2,cr2,cb,cr;
|
|
|
|
y1=(299*r1+587*g1+114*b1)/1000;
|
|
cb1=(-16874*r1-33126*g1+50000*b1+12800000)/100000;
|
|
cr1=(50000*r1-41869*g1-8131*b1+12800000)/100000;
|
|
|
|
y2=(299*r2+587*g2+114*b2)/1000;
|
|
cb2=(-16874*r2-33126*g2+50000*b2+12800000)/100000;
|
|
cr2=(50000*r2-41869*g2-8131*b2+12800000)/100000;
|
|
|
|
cb=(cb1+cb2) >> 1;
|
|
cr=(cr1+cr2) >> 1;
|
|
|
|
return ((y1 << 24) | (cb << 16) | (y2 << 8) | cr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* SetPalette
|
|
*
|
|
* A shadow copy of the palette is maintained, in case the NES Emu kernel
|
|
* requests a copy.
|
|
****************************************************************************/
|
|
void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g,
|
|
unsigned char b) {
|
|
/*** Make PC compatible copy ***/
|
|
pcpalette[index].r = r;
|
|
pcpalette[index].g = g;
|
|
pcpalette[index].b = b;
|
|
|
|
/*** Generate Gamecube palette ***/
|
|
gcpalette[index] = rgbcolor(r,g,b,r,g,b);
|
|
|
|
/*** Generate RGB565 texture palette ***/
|
|
rgb565[index] = ((r & 0xf8) << 8) |
|
|
((g & 0xfc) << 3) |
|
|
((b & 0xf8) >> 3);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* GetPalette
|
|
****************************************************************************/
|
|
void FCEUD_GetPalette(unsigned char i, unsigned char *r, unsigned char *g,
|
|
unsigned char *b) {
|
|
*r = pcpalette[i].r;
|
|
*g = pcpalette[i].g;
|
|
*b = pcpalette[i].b;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* NES Cheesy Scaler
|
|
*
|
|
* This scaler simply attempts to correct the 1.25 aspect by
|
|
* stretching the initial 256 pixels to 320.
|
|
* The standard 2x2 scaler can then be applied
|
|
****************************************************************************/
|
|
void CheesyScale(unsigned char *XBuf) {
|
|
static int newrow[320]; /*** New cheesy row ***/
|
|
unsigned int cheesypal[256]; /*** Enhanced Cheesy Palette ***/
|
|
int i,j,c,p = 0;
|
|
unsigned char p1,p2;
|
|
unsigned int ofs, gcdispOffset = 0;
|
|
int h, n, nw;
|
|
|
|
/*** Stretch ***/
|
|
for (h = 0; h < NESHEIGHT; h++) {
|
|
j = c = p = 0;
|
|
for (i = 0; i < NESWIDTH; i++) {
|
|
/*** Every fifth pixel is stretched by adding
|
|
the mid colour range ***/
|
|
n = (h << 8) + i;
|
|
newrow[j++] = XBuf[n];
|
|
c++;
|
|
if (c == 4) { /*** Done 4 pixels, so add the fifth ***/
|
|
p1 = XBuf[n];
|
|
p2 = XBuf[n+1];
|
|
cheesypal[p] = rgbcolor(pcpalette[p1].r, pcpalette[p1].g,
|
|
pcpalette[p1].b, pcpalette[p2].r, pcpalette[p2].g,
|
|
pcpalette[p2].b);
|
|
newrow[j++] = 0x8000 + p;
|
|
p++;
|
|
c = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*** Now update the screen display with the new colours ***/
|
|
ofs = gcdispOffset;
|
|
for (nw = 0; nw < 320; nw++) {
|
|
if (newrow[nw] & 0x8000) {
|
|
xfb[whichfb][ofs + nw] = cheesypal[newrow[nw] & 0xff ];
|
|
xfb[whichfb][ofs + 320 + nw] = cheesypal[newrow[nw] & 0xff];
|
|
} else {
|
|
xfb[whichfb][ofs + nw] = gcpalette[newrow[nw]];
|
|
xfb[whichfb][ofs + nw + 320] = gcpalette[newrow[nw]];
|
|
}
|
|
}
|
|
|
|
gcdispOffset += 640;
|
|
}
|
|
}
|
|
|