#include #include #include #include #include "ffecfg.h" #include "ffeapi.h" extern "C" int asmmain (int argc, char **argv); int main (int argc, char **argv) { return asmmain (argc, argv); } static SDL_Surface *pScreen = 0; static SDL_Overlay *pOverlay = 0; static UCHAR pBackBufBase[320*200+32]; static UCHAR *pBackBuf; static UCHAR pPalTable[3][64]; static SDL_Color pPalette[256]; static USHORT pPal15[256]; static USHORT pPal16[256]; static ULONG pPal32[256]; static ULONG pPalYUV[256]; static int fullscreen = 0; static int glpackedtex = 0; static int glreusetex = 0; static int glbilinear = 0; static int overlayrefresh = 1; static int fsmode = 0; static int fsletterbox = 1; static int fswidth = 320; static int fsheight = 200; static int fsprefbpp = 16; static int winmode = 0; static int winwidth = 640; static int winheight = 400; static int mode; static int letterbox; static int width; static int height; static int drawheight; static int yoff; static unsigned int pTexNames[5]; static int GLVideoInit () { if (fullscreen) { if (fsprefbpp == 32) { SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 32); } else { SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5); SDL_GL_SetAttribute (SDL_GL_BUFFER_SIZE, 16); } } SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 0); SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); if (!fullscreen) pScreen = SDL_SetVideoMode (width, height, 0, SDL_OPENGL); else pScreen = SDL_SetVideoMode (width, height, 0, SDL_OPENGL | SDL_FULLSCREEN); if (pScreen == 0) return 0; glDisable (GL_LIGHTING); glDisable (GL_CULL_FACE); glDisable (GL_DEPTH_TEST); glDisable (GL_BLEND); glViewport (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glClearColor (0.0f, 0.0f, 0.0f, 0.0f); glEnable (GL_TEXTURE_2D); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glGenTextures (5, pTexNames); int i; for (i=0; i<5; i++) { glBindTexture (GL_TEXTURE_2D, pTexNames[i]); if (glpackedtex) glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 64, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); else glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 64, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); if (glbilinear) { glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } } for (i=0; i<5; i++) { glClear (GL_COLOR_BUFFER_BIT); SDL_GL_SwapBuffers (); } return 1; } static int SDLVideoInit () { if (fsprefbpp != 16 && fsprefbpp != 32) fsprefbpp = 16; int flags = SDL_ANYFORMAT; if (fullscreen) flags |= SDL_FULLSCREEN; // Double buffering? back buffer? pScreen = SDL_SetVideoMode (width, height, fsprefbpp, flags); if (pScreen == 0) return 0; SDL_Rect r1 = { 0, 0, width, height }; SDL_FillRect (pScreen, &r1, 0); if (mode != 2) return 1; // No overlays pOverlay = SDL_CreateYUVOverlay (640, 200, SDL_YUY2_OVERLAY, pScreen); SDL_Rect r2 = { 0, (USHORT)yoff, (USHORT)width, (USHORT)drawheight }; SDL_DisplayYUVOverlay (pOverlay, &r2); return 1; } static void VideoInitWorker () { if (fullscreen) VideoPointerDisable (); else VideoPointerEnable (); if (fullscreen) { mode = fsmode; letterbox = fsletterbox; width = fswidth; height = fsheight; } else { mode = winmode; letterbox = 0; width = winwidth; height = winheight; } yoff = 0; drawheight = height; if (letterbox) { drawheight = (width * 200) / 320; yoff = (height - drawheight) >> 1; } if (drawheight > height) { drawheight = height; yoff = 0; } if (drawheight == height) letterbox = 0; int rval; if (mode == 0) rval = GLVideoInit (); else rval = SDLVideoInit (); if (rval == 0) { fprintf (stderr, "Failed to initialise video mode\n"); fprintf (stderr, "Switching to backup 640x400 windowed non-GL\n"); fullscreen = 0; mode = 1; letterbox = 0; width = 640; height = 400; VideoPointerEnable (); rval = SDLVideoInit (); if (rval != 0) return; fprintf (stderr, "Backup mode failed, exiting\n"); SystemCleanup (); exit (0); } } void VideoInit (void) { CfgStruct cfg; int pPalBase[3] = { 0, 0, 0 }; int step, i, j, col; CfgOpen (&cfg, __CONFIGFILE__); CfgFindSection (&cfg, "VIDEO"); CfgGetKeyVal (&cfg, "RedBase", pPalBase); CfgGetKeyVal (&cfg, "GreenBase", pPalBase+1); CfgGetKeyVal (&cfg, "BlueBase", pPalBase+2); CfgGetKeyVal (&cfg, "startfullscreen", &fullscreen); CfgGetKeyVal (&cfg, "glpackedtex", &glpackedtex); CfgGetKeyVal (&cfg, "glreusetex", &glreusetex); CfgGetKeyVal (&cfg, "glbilinear", &glbilinear); CfgGetKeyVal (&cfg, "overlayrefresh", &overlayrefresh); CfgGetKeyVal (&cfg, "fsmode", &fsmode); CfgGetKeyVal (&cfg, "fsletterbox", &fsletterbox); CfgGetKeyVal (&cfg, "fswidth", &fswidth); CfgGetKeyVal (&cfg, "fsheight", &fsheight); CfgGetKeyVal (&cfg, "fsprefbpp", &fsprefbpp); CfgGetKeyVal (&cfg, "winmode", &winmode); CfgGetKeyVal (&cfg, "winwidth", &winwidth); CfgGetKeyVal (&cfg, "winheight", &winheight); CfgClose (&cfg); for (i=0; i<3; i++) { col = pPalBase[i] << 8; step = ((64<<8) - col) / 63; for (j=0; j<64; j++) { int tcol = col >> 8; if (tcol < 0) tcol = 0; pPalTable[i][j] = (UCHAR)tcol; col += step; } } for (i=0; i<256; i++) { pPalette[i].r = 0; pPalette[i].g = 0; pPalette[i].b = 0; pPal15[i] = 0; pPal16[i] = 0; pPal32[i] = 0; } pBackBuf = (UCHAR *)((ULONG)pBackBufBase + 31 & -32); VideoInitWorker (); } void VideoCleanup (void) { if (mode == 0) glDeleteTextures (5, pTexNames); if (pOverlay) SDL_FreeYUVOverlay (pOverlay); pOverlay = 0; } void GLFillPackedTex (int offset) { USHORT pTexBuf[64*200]; UCHAR *pBuf = pBackBuf + 64*offset; USHORT *pBuf16 = pTexBuf; int cw, ch; for (ch=0; ch<200; ++ch, pBuf+=320, pBuf16+=64) for (cw=0; cw<64; ++cw) pBuf16[cw] = (USHORT)pPal16[pBuf[cw]]; glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 64, 200, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pTexBuf); } void GLFillUnpackedTex (int offset) { UCHAR pTexBuf[64*200*3]; UCHAR *pBuf = pBackBuf + 64*offset; UCHAR *pBuf24 = pTexBuf; int cw, ch; for (ch=0; ch<200; ++ch, pBuf+=320, pBuf24+=192) { for (cw=0; cw<64; ++cw) { SDL_Color *pCol = pPalette + pBuf[cw]; pBuf24[3*cw+0] = pCol->r; pBuf24[3*cw+1] = pCol->g; pBuf24[3*cw+2] = pCol->b; } } glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 64, 200, GL_RGB, GL_UNSIGNED_BYTE, pTexBuf); } static void VideoStretch16 (void *pDest, int dw, int dh, int pitch, USHORT *pPal) { int xfrac, yfrac; int xpos, ypos, x, y; xfrac = 0x1400000 / dw; // 320 << 16 yfrac = 0xc80000 / dh; // 200 << 16 ypos = yfrac >> 1; for (y=0; y>16); USHORT *pDestL = (USHORT *)((UCHAR *)pDest + pitch*y); xpos = xfrac >> 1; for (x=0; x>16]]; } } } static void VideoStretch32 (void *pDest, int dw, int dh, int pitch, ULONG *pPal) { int xfrac, yfrac; int xpos, ypos, x, y; xfrac = 0x1400000 / dw; // 320 << 16 yfrac = 0xc80000 / dh; // 200 << 16 ypos = yfrac >> 1; for (y=0; y>16); ULONG *pDestL = (ULONG *)((UCHAR *)pDest + pitch*y); xpos = xfrac >> 1; for (x=0; x>16)]]; } } } extern "C" void VideoBlit (UCHAR *pData, long x, long y, long w, long h, long jump) { UCHAR *pBuf = pBackBuf + x + y*320; for (; h; --h, pData+=jump+w, pBuf+=320) memcpy (pBuf, pData, w); if (w != 320) return; // One flip per frame if (mode == 0) { float ypos = 1.0f; if (letterbox) ypos = (0.625f * width) / height; int i; for (i=0; i<5; i++) { if (!glreusetex) glBindTexture (GL_TEXTURE_2D, pTexNames[i]); if (glpackedtex) GLFillPackedTex (i); else GLFillUnpackedTex (i); float xs = -1.0f + 0.4f*i; float xe = xs + 0.4f; glBegin (GL_TRIANGLE_STRIP); glTexCoord2f (0.0f, 0.0f); glVertex3f (xs, ypos, 0.5f); glTexCoord2f (1.0f, 0.0f); glVertex3f (xe, ypos, 0.5f); glTexCoord2f (0.0f, 0.78125f); glVertex3f (xs, -ypos, 0.5f); glTexCoord2f (1.0f, 0.78125f); glVertex3f (xe, -ypos, 0.5f); glEnd (); } SDL_GL_SwapBuffers (); return; } // SDL version? w = width; h = drawheight; if (mode == 2) { SDL_LockYUVOverlay (pOverlay); pBuf = pBackBuf; ULONG *pDataYUV = (ULONG *)pOverlay->pixels[0]; int djump = pOverlay->pitches[0] >> 2; for (y=0; y<200; y++, pDataYUV+=djump, pBuf+=320) for (x=0; x<320; x++) pDataYUV[x] = pPalYUV[pBuf[x]]; SDL_UnlockYUVOverlay (pOverlay); if (!overlayrefresh) return; SDL_Rect r = { 0, (USHORT)yoff, (USHORT)w, (USHORT)h }; SDL_DisplayYUVOverlay (pOverlay, &r); return; } SDL_LockSurface (pScreen); UCHAR *pSurf = (UCHAR *)pScreen->pixels + yoff*pScreen->pitch; int bpp = pScreen->format->BitsPerPixel; if (bpp==15) VideoStretch16 (pSurf, w, h, pScreen->pitch, pPal15); if (bpp==16) VideoStretch16 (pSurf, w, h, pScreen->pitch, pPal16); if (bpp==24) return; if (bpp==32) VideoStretch32 (pSurf, w, h, pScreen->pitch, pPal32); SDL_UnlockSurface (pScreen); SDL_UpdateRect (pScreen, 0, 0, 0, 0); } extern "C" void VideoMaskedBlit (UCHAR *pData, long x, long y, long w, long h, long jump) { int cw; int dJump = 320-w; UCHAR *pBuf = (UCHAR *)pBackBuf + x + 320*y; for (; h; --h, pData+=jump, pBuf+=dJump) for (cw=w; cw; --cw, ++pData, ++pBuf) if (*pData) *pBuf = *pData; } extern "C" void VideoReverseBlit (UCHAR *pData, long x, long y, long w, long h, long jump) { UCHAR *pBuf = pBackBuf + x + y*320; for (; h; --h, pData+=jump+w, pBuf+=320) memcpy (pData, pBuf, w); } extern "C" void VideoSetPalValue (long palindex, UCHAR *pVal) { int pCol[4]; int Y, U, V; pCol[0] = pPalette[palindex].r = pPalTable[0][pVal[0]] << 2; pCol[1] = pPalette[palindex].g = pPalTable[1][pVal[1]] << 2; pCol[2] = pPalette[palindex].b = pPalTable[2][pVal[2]] << 2; pPal15[palindex] = (USHORT)((pCol[0] << 7 & 0x7c00) + (pCol[1] << 2 & 0x03e0) + (pCol[2] >> 3)); pPal16[palindex] = (USHORT)(((pCol[0] << 8) & 0xf800) + ((pCol[1] << 3) & 0x07e0) + (pCol[2] >> 3)); pPal32[palindex] = (ULONG)((pCol[0] << 16 & 0xfc0000) + (pCol[1] << 8 & 0xfc00) + (pCol[2])); Y = ((9798*pCol[0] + 19235*pCol[1] + 3736*pCol[2] + 0x4000) >> 15); U = ((-4784*pCol[0] - 9437*pCol[1] + 14221*pCol[2] + 0x4000) >> 15) + 128; V = ((20218*pCol[0] - 16941*pCol[1] - 3277*pCol[2] + 0x4000) >> 15) + 128; if (Y<0) Y=0; if (Y>255) Y=255; if (U<0) U=0; if (U>255) U=255; if (V<0) V=0; if (V>255) V=255; pPalYUV[palindex] = (V<<24) | (Y<<16) | (U<<8) | Y; // YUY2 } extern "C" void VideoGetPalValue (long palindex, UCHAR *pVal) { pVal[0] = pPalette[palindex].r >> 2; pVal[1] = pPalette[palindex].g >> 2; pVal[2] = pPalette[palindex].b >> 2; } extern "C" long VideoPointerExclusive (void) { return fullscreen; } extern "C" void VideoPointerEnable (void) { SDL_WM_GrabInput (SDL_GRAB_OFF); SDL_ShowCursor (SDL_ENABLE); } extern "C" void VideoPointerDisable (void) { SDL_WM_GrabInput (SDL_GRAB_ON); SDL_ShowCursor (SDL_DISABLE); } void InputInit (); void InputCleanup (); void TimerInit (); void TimerCleanup (); void SoundInit (); void SoundCleanup (); extern "C" void DirInit (); extern "C" void DirCleanup (); extern "C" void SystemInit (void) { int rval; rval = SDL_Init (SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_AUDIO); if (rval != 0) exit (0); TimerInit(); DirInit(); VideoInit(); InputInit(); SoundInit(); } extern "C" void SystemCleanup (void) { SoundCleanup(); InputCleanup(); VideoCleanup(); DirCleanup(); TimerCleanup(); SDL_Quit (); } void VideoSwitchMode () { VideoCleanup (); fullscreen ^= 1; VideoInitWorker (); return; }