int RunRenderThreads (int nTask, int nThreads) { #if USE_OPENMP return 0; #else # if DBG time_t t0 = 0, t2 = 0; int nActive; static int nLockups = 0; # endif int i; if (!gameStates.app.bMultiThreaded) return 0; tiRender.nTask = (tRenderTask) nTask; if (nThreads < 0) nThreads = gameStates.app.nThreads; for (i = 0; i < nThreads; i++) tiRender.ti [i].bExec = 1; #if DBG t0 = clock (); while ((nActive = ThreadsActive (nThreads)) && (clock () - t0 < 1000)) { G3_SLEEP (0); if (nActive < nThreads) { if (!t2) t2 = clock (); else if (clock () - t2 > 33) { //slower threads must not take more than 33 ms over the fastest one PrintLog ("threads locked up (task: %d)\n", nTask); for (i = 0; i < nThreads; i++) tiRender.ti [i].bExec = 0; if (++nLockups > 100) { gameStates.app.bMultiThreaded = 0; gameStates.app.nThreads = 1; } } } } # else while (ThreadsActive (nThreads)) G3_SLEEP (0); # endif return 1; #endif }
void hmp_stop(hmp_file *hmp) { MIDIHDR *mhdr; if (!hmp->stop) { hmp->stop = 1; //PumpMessages(); midiStreamStop(hmp->hmidi); while (hmp->bufs_in_mm) { //PumpMessages(); G3_SLEEP(0); } } while ((mhdr = hmp->evbuf)) { midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR)); hmp->evbuf = mhdr->lpNext; delete[] mhdr; mhdr = NULL; } if (hmp->hmidi) { midiStreamClose(hmp->hmidi); hmp->hmidi = NULL; } }
int _CDECL_ SoundThread (void *pThreadId) { do { while (!tiSound.ti.bExec) { G3_SLEEP (1); if (tiSound.ti.bDone) return 0; } if (tiSound.nTask == stOpenAudio) { DigiInit (tiSound.fSlowDown); } else if (tiSound.nTask == stCloseAudio) { DigiExit (); } else if (tiSound.nTask == stReconfigureAudio) { FreeAddonSounds (); DigiExit (); DigiInit (tiSound.fSlowDown); if (tiSound.fSlowDown == 1.0f) { gameData.songs.tPos = gameData.songs.tSlowDown - gameData.songs.tStart + 2 * (SDL_GetTicks () - gameData.songs.tSlowDown) / gameOpts->gameplay.nSlowMotionSpeedup; } else { gameData.songs.tSlowDown = SDL_GetTicks (); gameData.songs.tPos = gameData.songs.tSlowDown - gameData.songs.tStart; } PlayLevelSong (gameData.missions.nCurrentLevel, 1); } tiSound.ti.bExec = 0; } while (!tiSound.ti.bDone); return 0; }
void EndEffectsThread (void) { if (!tiEffects.pThread) return; tiEffects.bDone = 1; while (tiEffects.bDone) G3_SLEEP (0); tiEffects.pThread = NULL; }
void EndSoundThread (void) { if (tiSound.ti.pThread) { WaitForSoundThread (); tiSound.ti.bDone = 1; G3_SLEEP (100); //SDL_KillThread (tiSound.ti.pThread); tiSound.ti.pThread = NULL; } }
bool WaitForRenderThreads (void) { #if !USE_OPENMP if (gameStates.app.bMultiThreaded) { while (tiRender.ti [0].bExec || tiRender.ti [1].bExec) G3_SLEEP (0); //already running, so wait return true; } #endif return false; }
bool WaitForEffectsThread (void) { #if !USE_OPENMP if ((gameStates.app.bMultiThreaded > 1) && tiEffects.pThread) { while (tiEffects.bExec) G3_SLEEP (0); return true; } #endif return false; }
void EndTranspRenderThread (void) { #if TRANSPRENDER_THREADS tiTranspRender.ti [0].bDone = tiTranspRender.ti [1].bDone = 1; G3_SLEEP (10); for (int i = 0; i < 2; i++) { if (tiTranspRender.ti [i].pThread) { //SDL_KillThread (tiTranspRender.ti [0].pThread); tiTranspRender.ti [i].pThread = NULL; } } #endif }
void DonationNotification (void) { if (gameConfig.nTotalTime > (25 * 60)) { // played for more than 25 hours SetScreenMode (SCREEN_MENU); int nFade = gameOpts->menus.nFade; gameOpts->menus.nFade = 250; messageBox.Show (TXT_PLEASE_DONATE); G3_SLEEP (10000); gameOpts->menus.nFade = 500; messageBox.Clear (); gameOpts->menus.nFade = nFade; gameConfig.nTotalTime = 0; // only display after another 25 hours } }
float CoronaVisibility (int nQuery) { GLuint nSamples = 0; GLint bAvailable = 0; int nAttempts = 2; float fIntensity; #if DBG GLint nError; #endif if (! (ogl.m_states.bOcclusionQuery && nQuery) || (CoronaStyle () != 1)) return 1; if (! (gameStates.render.bQueryCoronas || gameData.render.lights.coronaSamples [nQuery - 1])) return 0; for (;;) { glGetQueryObjectiv (gameData.render.lights.coronaQueries [nQuery - 1], GL_QUERY_RESULT_AVAILABLE_ARB, &bAvailable); if (glGetError ()) { #if DBG glGetQueryObjectiv (gameData.render.lights.coronaQueries [nQuery - 1], GL_QUERY_RESULT_AVAILABLE_ARB, &bAvailable); if ((nError = glGetError ())) #endif return 0; } if (bAvailable) break; if (!--nAttempts) return 0; G3_SLEEP (1); }; glGetQueryObjectuiv (gameData.render.lights.coronaQueries [nQuery - 1], GL_QUERY_RESULT_ARB, &nSamples); if (glGetError ()) return 0; if (gameStates.render.bQueryCoronas == 1) { #if DBG if (!nSamples) { GLint nBits; glGetQueryiv (GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &nBits); glGetQueryObjectuiv (gameData.render.lights.coronaQueries [nQuery - 1], GL_QUERY_RESULT_ARB, &nSamples); } #endif return (float) (gameData.render.lights.coronaSamples [nQuery - 1] = nSamples); } fIntensity = (float) nSamples / (float) gameData.render.lights.coronaSamples [nQuery - 1]; #if DBG if (fIntensity > 1) fIntensity = 1; #endif return (fIntensity > 1) ? 1 : (float) sqrt (fIntensity); }
int RunEmitterThread (tParticleEmitter *emitterP, int nCurTime, tRenderTask nTask) { int i; if (!gameStates.app.bMultiThreaded) return 0; while (tiRender.ti [0].bExec && tiRender.ti [1].bExec) G3_SLEEP (0); i = tiRender.ti [0].bExec ? 1 : 0; tiRender.emitters [i] = emitterP; tiRender.nCurTime [i] = nCurTime; tiRender.nTask = nTask; tiRender.ti [i].bExec = 1; return 1; }
int _CDECL_ EffectsThread (void *pThreadId) { do { while (!tiEffects.bExec) { G3_SLEEP (0); if (tiEffects.bDone) { tiEffects.bDone = 0; return 0; } } DoParticleFrame (); lightningManager.DoFrame (); sparkManager.DoFrame (); tiEffects.bExec = 0; } while (!tiEffects.bDone); tiEffects.bDone = 0; return 0; }
void StartSoundThread (void) { #if 1 if (!tiSound.ti.pThread) { #else if (gameData.app.bUseMultiThreading [rtSound] && !tiSound.ti.pThread) { #endif memset (&tiSound, 0, sizeof (tiSound)); tiSound.ti.nId = 0; tiSound.ti.pThread = SDL_CreateThread (SoundThread, &tiSound.ti.nId); } } //------------------------------------------------------------------------------ void EndSoundThread (void) { if (tiSound.ti.pThread) { WaitForSoundThread (); tiSound.ti.bDone = 1; do { G3_SLEEP (1); } while (tiSound.ti.bDone); //SDL_KillThread (tiSound.ti.pThread); tiSound.ti.pThread = NULL; } } //------------------------------------------------------------------------------ void ControlSoundThread (void) { #if 1 StartSoundThread (); #else if (gameStates.app.bMultiThreaded) { if (gameData.app.bUseMultiThreading [rtSound]) StartSoundThread (); else EndSoundThread (); } #endif }
void EndRenderThreads (void) { if (!gameStates.app.bMultiThreaded) return; #if !USE_OPENMP for (int i = 0; i < gameStates.app.nThreads; i++) tiRender.ti [i].bDone = 1; G3_SLEEP (10); for (int i = 0; i < gameStates.app.nThreads; i++) { if (tiRender.ti [i].pThread) { //SDL_KillThread (tiRender.ti [0].pThread); tiRender.ti [i].pThread = NULL; } } SDL_DestroyMutex (tiRender.semaphore); tiRender.semaphore = NULL; EndTranspRenderThread (); #endif EndEffectsThread (); }
int _CDECL_ TranspRenderThread (void *pThreadId) { #if TRANSPRENDER_THREADS do { while (!(tiTranspRender.ti [0].bExec || tiTranspRender.ti [1].bExec)) G3_SLEEP (0); for (int i = 0; i < 2; i++) { if (tiTranspRender.ti [i].bExec) { transparencyRenderer.Add ((tTranspItemType) tiTranspRender.itemData [i].nType, &tiTranspRender.itemData [i].item, tiTranspRender.itemData [i].nSize, tiTranspRender.itemData [i].nDepth, tiTranspRender.itemData [i].nIndex); tiTranspRender.ti [i].bExec = 0; } } } while (!(tiTranspRender.ti [0].bDone && tiTranspRender.ti [1].bDone)); #endif return 0; }
void BadHardwareNotification (void) { #if 1//!DBG if (!ogl.m_states.bShadersOk && (gameConfig.nVersion != D2X_IVER)) { SetScreenMode (SCREEN_MENU); int nFade = gameOpts->menus.nFade; gameOpts->menus.nFade = 250; #if 1 for (int i = 0; i < 2; i++) { // make the message flash a few times messageBox.Show (TXT_BAD_HARDWARE); messageBox.Clear (); } #endif messageBox.Show (TXT_BAD_HARDWARE); G3_SLEEP (4000); gameOpts->menus.nFade = 500; messageBox.Clear (); gameOpts->menus.nFade = nFade; gameConfig.nVersion = D2X_IVER; } #endif }
int CTransparencyRenderer::AddMT (tTranspItemType nType, void *itemData, int itemSize, int nDepth, int nIndex, int nThread) { if (!gameStates.app.bMultiThreaded || (nThread < 0) || !gameData.app.bUseMultiThreading [rtTranspRender]) return Add (nType, itemData, itemSize, nDepth, nIndex); #if UNIFY_THREADS WaitForRenderThreads (); #else while (tiTranspRender.ti [nThread].bExec) G3_SLEEP (0); #endif tiTranspRender.itemData [nThread].nType = nType; tiTranspRender.itemData [nThread].nSize = itemSize; tiTranspRender.itemData [nThread].nDepth = nDepth; tiTranspRender.itemData [nThread].nIndex = nIndex; memcpy (&tiTranspRender.itemData [nThread].item, itemData, itemSize); #if UNIFY_THREADS RunRenderThreads (rtTranspRender, 2); #else tiTranspRender.ti [nThread].bExec = 1; #endif return 1; }
int KeyInKeyTime (fix * time) { int key = 0; int bLegacy = gameOpts->legacy.bInput; gameOpts->legacy.bInput = 1; if (!bInstalled) KeyInit (); event_poll (SDL_KEYDOWNMASK | SDL_KEYUPMASK); if (keyData.nKeyTail != keyData.nKeyHead) { key = keyData.keyBuffer [keyData.nKeyHead]; if (key == KEY_CTRLED + KEY_ALTED + KEY_ENTER) exit (0); keyData.nKeyHead = KeyAddKey(keyData.nKeyHead); if (time) *time = keyData.xTimePressed [keyData.nKeyHead]; } else if (!time) G3_SLEEP (0); gameOpts->legacy.bInput = bLegacy; return key; }
int _CDECL_ SoundThread (void *pThreadId) { do { while (!tiSound.ti.bExec) { G3_SLEEP (1); if (tiSound.ti.bDone) { tiSound.ti.bDone = 0; return 0; } } if (tiSound.nTask == stOpenAudio) { audio.Setup (tiSound.fSlowDown); } else if (tiSound.nTask == stCloseAudio) { audio.Shutdown (); } else if (tiSound.nTask == stReconfigureAudio) { FreeAddonSounds (); audio.Shutdown (); audio.Setup (tiSound.fSlowDown); if (tiSound.fSlowDown == 1.0f) { songManager.SetPos (songManager.SlowDown () - songManager.Start () + 2 * (SDL_GetTicks () - songManager.SlowDown ()) / gameOpts->gameplay.nSlowMotionSpeedup); songManager.SetSlowDown (0); } else { songManager.SetSlowDown (SDL_GetTicks ()); songManager.SetPos (songManager.SlowDown () - songManager.Start ()); } songManager.PlayLevelSong (gameData.missions.nCurrentLevel, 1, false); } tiSound.ti.bExec = 0; } while (!tiSound.ti.bDone); tiSound.ti.bDone = 0; return 0; }
int PiggyBitmapPageIn (int bmi, int bD1, bool bHires) { CBitmap* bmP, * bmoP; int i, bmiSave; //bD1 = gameStates.app.bD1Mission; bmiSave = 0; #if 0 Assert (bmi >= 0); Assert (bmi < MAX_BITMAP_FILES); Assert (bmi < gameData.pig.tex.nBitmaps [bD1]); Assert (bitmapCacheSize > 0); #endif if (bmi < 1) return 0; if (bmi >= MAX_BITMAP_FILES) return 0; if (bmi >= gameData.pig.tex.nBitmaps [bD1]) return 0; if (bitmapOffsets [bD1][bmi] == 0) return 0; // A read-from-disk bmi!!! #if DBG if (bmi == nDbgTexture) nDbgTexture = nDbgTexture; #endif bmP = &gameData.pig.tex.bitmaps [bD1][bmi]; if ((bmoP = bmP->Override ())) bmP = bmoP; while (0 > (i = PageInBitmap (bmP, gameData.pig.tex.bitmapFiles [bD1][bmi].name, bmi, bD1, bHires))) G3_SLEEP (0); if (!i) return 0; gameData.pig.tex.bitmaps [bD1][bmi].DelFlags (BM_FLAG_PAGED_OUT); return 1; }
void WaitForSoundThread (void) { //time_t t1 = SDL_GetTicks (); while (tiSound.ti.pThread && tiSound.ti.bExec /*&& (SDL_GetTicks () - t1 < 1000)*/) G3_SLEEP (1); }
int _CDECL_ RenderThread (void *pThreadId) { int nId = *reinterpret_cast<int*> (pThreadId); int nStart, nEnd; #ifdef _WIN32 HGLRC myContext = 0; #endif do { while (!tiRender.ti [nId].bExec) { G3_SLEEP (0); if (tiRender.ti [nId].bDone) return 0; } if (tiRender.nTask == rtSortSegZRef) { ComputeThreadRange (nId, gameData.render.mine.nRenderSegs, nStart, nEnd); QSortSegZRef (nStart, nEnd); } else if (tiRender.nTask == rtInitSegZRef) { ComputeThreadRange (nId, gameData.render.mine.nRenderSegs, nStart, nEnd); InitSegZRef (nStart, nEnd, nId); } else if (tiRender.nTask == rtStaticVertLight) { ComputeThreadRange (nId, gameData.segs.nVertices, nStart, nEnd); lightManager.GatherStaticVertexLights (nStart, nEnd, nId); } else if (tiRender.nTask == rtComputeFaceLight) { if (gameStates.render.bTriangleMesh || !gameStates.render.bApplyDynLight || (gameData.render.mine.nRenderSegs < gameData.segs.nSegments)) { // special handling: // tiMiddle is the index at which an equal number of visible faces is both at indices below and above it // use it to balance thread load if (gameStates.app.nThreads & 1) { ComputeThreadRange (nId, gameData.render.mine.nRenderSegs, nStart, nEnd); ComputeFaceLight (nStart, nEnd, nId); } else { int nPivot = gameStates.app.nThreads / 2; if (nId < nPivot) { ComputeThreadRange (nId, tiRender.nMiddle, nStart, nEnd, nPivot); ComputeFaceLight (nStart, nEnd, nId); } else { ComputeThreadRange (nId - nPivot, gameData.render.mine.nRenderSegs - tiRender.nMiddle, nStart, nEnd, nPivot); ComputeFaceLight (nStart + tiRender.nMiddle, nEnd + tiRender.nMiddle, nId); } } } else { if (gameStates.app.bEndLevelSequence < EL_OUTSIDE) ComputeThreadRange (nId, gameData.segs.nFaces, nStart, nEnd); else ComputeThreadRange (nId, gameData.segs.nSegments, nStart, nEnd); ComputeFaceLight (nStart, nEnd, nId); } } else if (tiRender.nTask == rtPolyModel) { short iVerts, nVerts, iFaceVerts, nFaceVerts; if (nId) { nVerts = tiRender.pm->m_nVerts; iVerts = nVerts / 2; nFaceVerts = tiRender.pm->m_nFaceVerts; iFaceVerts = nFaceVerts / 2; } else { iVerts = 0; nVerts = tiRender.pm->m_nVerts / 2; iFaceVerts = 0; nFaceVerts = tiRender.pm->m_nFaceVerts / 2; } G3DynLightModel (tiRender.objP, tiRender.pm, iVerts, nVerts, iFaceVerts, nFaceVerts); } else if (tiRender.nTask == rtLightmap) lightmapManager.Build (nId); else if (tiRender.nTask == rtParticles) particleManager.SetupParticles (nId); tiRender.ti [nId].bExec = 0; } while (!tiRender.ti [nId].bDone); #ifdef _WIN32 if (myContext) wglDeleteContext (myContext); #endif return 0; }
//Process selected keys until game unpaused. returns key that left pause (p or esc) int DoGamePause (void) { int key = 0; int bScreenChanged; char msg [1000]; char totalTime [9], xLevelTime [9]; if (gameData.app.bGamePaused) { //unpause! gameData.app.bGamePaused = 0; gameStates.app.bEnterGame = 1; #if defined (TACTILE) if (TactileStick) EnableForces(); #endif return KEY_PAUSE; } if (gameData.app.nGameMode & GM_NETWORK) { DoShowNetgameHelp(); return (KEY_PAUSE); } else if (gameData.app.nGameMode & GM_MULTI) { HUDInitMessage (TXT_MODEM_PAUSE); return (KEY_PAUSE); } PauseGame (); SetPopupScreenMode (); paletteManager.LoadEffect (); formatTime (totalTime, X2I (LOCALPLAYER.timeTotal) + LOCALPLAYER.hoursTotal * 3600); formatTime (xLevelTime, X2I (LOCALPLAYER.timeLevel) + LOCALPLAYER.hoursLevel * 3600); if (gameData.demo.nState!=ND_STATE_PLAYBACK) sprintf (msg, TXT_PAUSE_MSG1, GAMETEXT (332 + gameStates.app.nDifficultyLevel), LOCALPLAYER.hostages.nOnBoard, xLevelTime, totalTime); else sprintf (msg, TXT_PAUSE_MSG2, GAMETEXT (332 + gameStates.app.nDifficultyLevel), LOCALPLAYER.hostages.nOnBoard); if (!gameOpts->menus.nStyle) { gameStates.menus.nInMenu++; GameRenderFrame (); gameStates.menus.nInMenu--; } messageBox.Show (pszPauseMsg = msg, false); GrabMouse (0, 0); while (gameData.app.bGamePaused) { if (!(gameOpts->menus.nStyle && gameStates.app.bGameRunning)) key = KeyGetChar(); else { gameStates.menus.nInMenu++; while (!(key = KeyInKey ())) { GameRenderFrame (); paletteManager.LoadEffect (NULL); messageBox.Render (); G3_SLEEP (1); } gameStates.menus.nInMenu--; } #if DBG HandleTestKey(key); #endif bScreenChanged = HandleSystemKey (key); HandleVRKey (key); if (bScreenChanged) { GameRenderFrame (); messageBox.Render (); #if 0 show_extraViews (); if ((gameStates.render.cockpit.nType == CM_FULL_COCKPIT) || (gameStates.render.cockpit.nType == CM_STATUS_BAR)) RenderGauges(); #endif } } GrabMouse (1, 0); messageBox.Clear (); ResumeGame (); return key; }
short TerminateWinsock () { G3_SLEEP(50); G3_SLEEP(50); return (WSACleanup() == SOCKET_ERROR ? WSAGetLastError () : 0); }
void CalcFrameTime (void) { if (gameData.app.bGamePaused) { gameData.time.xLast = TimerGetFixedSeconds (); gameData.time.xFrame = 0; gameData.time.xRealFrame = 0; return; } fix timerValue, xLastFrameTime = gameData.time.xFrame; GetSlowTicks (); #if EXACT_FRAME_TIME static float fSlack = 0; int nFrameTime, nMinFrameTime, nDeltaTime; if (MAXFPS <= 1) nDeltaTime = 0; else { #ifdef RELEASE if (!gameOpts->app.bExpertMode && (gameOpts->render.nMaxFPS > 1)) gameOpts->render.nMaxFPS = MAX_FRAMERATE; #endif if (!gameData.time.tLast) nDeltaTime = 0; else { nFrameTime = gameStates.app.nSDLTicks - gameData.time.tLast; nMinFrameTime = 1000 / MAXFPS; nDeltaTime = nMinFrameTime - nFrameTime; fSlack += 1000.0f / MAXFPS - nMinFrameTime; if (fSlack >= 1) { nDeltaTime += int (fSlack); fSlack -= int (fSlack); } if (0 < nDeltaTime) G3_SLEEP (nDeltaTime); } } timerValue = MSEC2X (gameStates.app.nSDLTicks); #else fix xMinFrameTime = ((MAXFPS > 1) ? I2X (1) / MAXFPS : 1); do { timerValue = TimerGetFixedSeconds (); gameData.time.xFrame = timerValue - gameData.time.xLast; if (MAXFPS < 2) break; G3_SLEEP (1); } while (gameData.time.xFrame < xMinFrameTime); #endif gameData.time.xFrame = timerValue - gameData.time.xLast; gameData.time.xRealFrame = gameData.time.xFrame; if (gameStates.app.cheats.bTurboMode) gameData.time.xFrame *= 2; gameData.time.xLast = timerValue; #if EXACT_FRAME_TIME gameData.time.tLast = gameStates.app.nSDLTicks; if (nDeltaTime > 0) gameData.time.tLast += nDeltaTime; #else gameData.time.tLast = SDL_GetTicks (); #endif if (gameData.time.xFrame < 0) //if bogus frametimed:\temp\dm_test. gameData.time.xFrame = xLastFrameTime; //d:\temp\dm_test.then use time from last frame #if Arcade_mode gameData.time.xFrame /= 2; #endif #if defined (TIMER_TEST) && defined (_DEBUG) gameData.time.xStops = gameData.time.xStarts = 0; #endif // Set value to determine whether homing missile can see target. // The lower frametime is, the more likely that it can see its target. if (gameStates.limitFPS.bHomers) xMinTrackableDot = MIN_TRACKABLE_DOT; else if (gameData.time.xFrame <= I2X (1)/64) xMinTrackableDot = MIN_TRACKABLE_DOT; // -- 3* (I2X (1) - MIN_TRACKABLE_DOT)/4 + MIN_TRACKABLE_DOT; else if (gameData.time.xFrame < I2X (1)/32) xMinTrackableDot = MIN_TRACKABLE_DOT + I2X (1)/64 - 2*gameData.time.xFrame; // -- FixMul (I2X (1) - MIN_TRACKABLE_DOT, I2X (1)-4*gameData.time.xFrame) + MIN_TRACKABLE_DOT; else if (gameData.time.xFrame < I2X (1)/4) xMinTrackableDot = MIN_TRACKABLE_DOT + I2X (1)/64 - I2X (1)/16 - gameData.time.xFrame; // -- FixMul (I2X (1) - MIN_TRACKABLE_DOT, I2X (1)-4*gameData.time.xFrame) + MIN_TRACKABLE_DOT; else xMinTrackableDot = MIN_TRACKABLE_DOT + I2X (1)/64 - I2X (1)/8; }
//if filename passed is NULL, show Normal credits void ShowCredits(char *credits_filename) { int i, j, l, bDone; CFile cf; char buffer [NUM_LINES_HIRES][80]; grsBitmap bmBackdrop; int nPcxError; unsigned int nLine = 0; unsigned int nXlLine = 0; fix xTimeout, xDelay = X2I (2800 * 1000); int nFirstLineOffs, nExtraInc = 0; int bBinary = 0; char *pszTemp; char filename [32]; int xOffs, yOffs; box dirtyBox [NUM_LINES_HIRES]; gsrCanvas *creditsOffscreenBuf = NULL; gsrCanvas *saveCanv = grdCurCanv; // Clear out all tex buffer lines. memset (buffer, 0, sizeof (buffer)); memset (dirtyBox, 0, sizeof (dirtyBox)); sprintf(filename, "%s", CREDITS_FILE); bBinary = 0; if (credits_filename) { strcpy(filename,credits_filename); bBinary = 1; } if (!cf.Open (filename, gameFolders.szDataDir, "rb", 0)) { char nfile [32]; if (credits_filename) return; //ok to not find special filename if ((pszTemp = strchr (filename, '.'))) *pszTemp = '\0'; sprintf (nfile, "%s.txb", filename); if (!cf.Open (nfile, gameFolders.szDataDir, "rb", 0)) Error("Missing CREDITS.TEX and CREDITS.TXB &cf\n"); bBinary = 1; } SetScreenMode(SCREEN_MENU); xOffs = (grdCurCanv->cvBitmap.bmProps.w - 640) / 2; yOffs = (grdCurCanv->cvBitmap.bmProps.h - 480) / 2; if (xOffs < 0) xOffs = 0; if (yOffs < 0) yOffs = 0; creditsPalette = GrUsePaletteTable("credits.256", NULL); GrPaletteStepLoad (NULL); header_font = GrInitFont(gameStates.menus.bHires ? (char *) "font1-1h.fnt" : (char *) "font1-1.fnt"); title_font = GrInitFont(gameStates.menus.bHires ? (char *) "font2-3h.fnt" : (char *) "font2-3.fnt"); names_font = GrInitFont(gameStates.menus.bHires ? (char *) "font2-2h.fnt" : (char *) "font2-2.fnt"); bmBackdrop.bmTexBuf = NULL; bmBackdrop.bmPalette = NULL; //MWA Made bmBackdrop bitmap linear since it should always be. the current canvas may not //MWA be linear, so we can't rely on grdCurCanv->cvBitmap->bmProps.nType. nPcxError = PCXReadBitmap ((char *) CREDITS_BACKGROUND_FILENAME, &bmBackdrop, BM_LINEAR, 0); if (nPcxError != PCX_ERROR_NONE) { cf.Close(); return; } SongsPlaySong(SONG_CREDITS, 1); GrRemapBitmapGood(&bmBackdrop, NULL, -1, -1); if (!gameOpts->menus.nStyle) { GrSetCurrentCanvas(NULL); GrBitmap(xOffs,yOffs,&bmBackdrop); if ((grdCurCanv->cvBitmap.bmProps.w > 640) || (grdCurCanv->cvBitmap.bmProps.h > 480)) { GrSetColorRGBi (RGBA_PAL (0,0,32)); GrUBox(xOffs,yOffs,xOffs+bmBackdrop.bmProps.w+1,yOffs+bmBackdrop.bmProps.h+1); } } GrPaletteFadeIn(NULL, 32, 0); // Create a new offscreen buffer for the credits screen //MWA Let's be a little smarter about this and check the VR_offscreen buffer //MWA for size to determine if we can use that buffer. If the game size //MWA matches what we need, then lets save memory. if (gameStates.menus.bHires && !gameOpts->menus.nStyle && gameStates.render.vr.buffers.offscreen->cv_w == 640) creditsOffscreenBuf = gameStates.render.vr.buffers.offscreen; else if (gameStates.menus.bHires) creditsOffscreenBuf = GrCreateCanvas(640,480); else creditsOffscreenBuf = GrCreateCanvas(320,200); if (!creditsOffscreenBuf) Error("Not enough memory to allocate Credits Buffer."); creditsOffscreenBuf->cvBitmap.bmPalette = grdCurCanv->cvBitmap.bmPalette; if (gameOpts->menus.nStyle) creditsOffscreenBuf->cvBitmap.bmProps.flags |= BM_FLAG_TRANSPARENT; KeyFlush (); bDone = 0; nFirstLineOffs = 0; xTimeout = SDL_GetTicks () + xDelay; glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gameStates.menus.nInMenu = 1; while (1) { int k; do { nLine = (nLine + 1) % NUM_LINES; get_line:; if (cf.GetS (buffer [nLine], 80)) { char *p = buffer [nLine]; if (bBinary) // is this a binary tbl &cf for (i = (int) strlen (buffer [nLine]); i > 0; i--, p++) *p = EncodeRotateLeft ((char) (EncodeRotateLeft (*p) ^ BITMAP_TBL_XOR)); p = buffer [nLine]; if (*p == ';') goto get_line; if (*p == '%') { if (p [1] == ALLOWED_CHAR) strcpy (p, p + 2); else goto get_line; } if ((p = strchr (buffer [nLine], '\n'))) *p = '\0'; } else if (nXlLine < NUM_XL_LINES) { strcpy (buffer [nLine], xlCredits [nXlLine++]); } else { //fseek(&cf, 0, SEEK_SET); buffer [nLine][0] = 0; bDone++; } } while (nExtraInc--); nExtraInc = 0; //PrintLog ("%s\n", buffer [nLine]); for (i = 0; i < ROW_SPACING; i += gameStates.menus.bHires + 1) { int y; if (gameOpts->menus.nStyle) { GrSetCurrentCanvas (NULL); ShowFullscreenImage (&bmBackdrop); // GrUpdate (0); #if 0 if ((grdCurCanv->cvBitmap.bmProps.w > 640) || (grdCurCanv->cvBitmap.bmProps.h > 480)) { GrSetColorRGBi (RGBA_PAL (0,0,32)); GrUBox (xOffs, yOffs, xOffs + bmBackdrop. bmProps.w + 1, yOffs + bmBackdrop.bmProps.h + 1); } #endif } y = nFirstLineOffs - i; GrSetCurrentCanvas (creditsOffscreenBuf); if (gameOpts->menus.nStyle) GrClearCanvas (0); else GrBitmap (0, 0, &bmBackdrop); for (j = 0; j < NUM_LINES; j++) { char *s; l = (nLine + j + 1) % NUM_LINES; s = buffer [l]; if (s[0] == '!') s++; else if (s[0] == '$') { grdCurCanv->cvFont = header_font; s++; } else if (s[0] == '*') { grdCurCanv->cvFont = title_font; s++; } else grdCurCanv->cvFont = names_font; grBitBltFadeTable = (gameStates.menus.bHires ? fadeValues_hires : fadeValues); pszTemp = strchr (s, '\t'); if (pszTemp) { // Wacky Credits thing int w, h, aw, w2, x1, x2; *pszTemp = 0; GrGetStringSize(s, &w, &h, &aw); x1 = ((gameStates.menus.bHires?320:160)-w)/2; cr_gr_printf (x1 , y, s); GrGetStringSize (pszTemp + 1, &w2, &h, &aw); x2 = (gameStates.menus.bHires ? 320 : 160) + (((gameStates.menus.bHires ? 320 : 160) - w2) / 2); cr_gr_printf(x2, y, &pszTemp[1]); dirtyBox [j].left = ((gameStates.menus.bHires?320:160)-w)/2; dirtyBox [j].top = y; dirtyBox [j].width =(x2+w2)-x1; dirtyBox [j].height = h; *pszTemp = '\t'; } else { // Wacky Fast Credits thing int w, h, aw; GrGetStringSize (s, &w, &h, &aw); dirtyBox [j].width = w; dirtyBox [j].height = h; dirtyBox [j].top = y; dirtyBox [j].left = ((gameStates.menus.bHires?640:320) - w) / 2; cr_gr_printf (0x8000, y, s); } grBitBltFadeTable = NULL; if (buffer[l][0] == '!') y += ROW_SPACING / 2; else y += ROW_SPACING; } if (gameOpts->menus.nStyle) GrSetCurrentCanvas (NULL); { // Wacky Fast Credits Thing box *newBox; grsBitmap *tempBmP; for (j = 0; j < NUM_LINES; j++) { newBox = dirtyBox + j; tempBmP = &creditsOffscreenBuf->cvBitmap; GrBmBitBlt (newBox->width + 1, newBox->height +4, newBox->left + xOffs, newBox->top + yOffs, newBox->left, newBox->top, tempBmP, &grdCurScreen->scCanvas.cvBitmap); } } GrUpdate (0); #if 1 { int t = xTimeout - SDL_GetTicks (); if (t > 0) G3_SLEEP (t); xTimeout = SDL_GetTicks () + xDelay; } #endif //see if redbook song needs to be restarted SongsCheckRedbookRepeat(); k = KeyInKey (); #if DBG if (k == KEY_BACKSP) { Int3(); k = 0; } #endif if ((k == KEY_PRINT_SCREEN) || (k == KEY_ALTED+KEY_F9)) { gameStates.app.bSaveScreenshot = 1; SaveScreenShot (NULL, 0); k = 0; } else if (k == KEY_PADPLUS) xDelay /= 2; else if (k == KEY_PADMINUS) { if (xDelay) xDelay *= 2; else xDelay = 1; } else if ((k == KEY_ESC) || (bDone > NUM_LINES)) { GrCloseFont (header_font); GrCloseFont (title_font); GrCloseFont (names_font); GrPaletteFadeOut (NULL, 32, 0); GrUsePaletteTable (D2_DEFAULT_PALETTE, NULL); D2_FREE (bmBackdrop.bmTexBuf); cf.Close (); GrSetCurrentCanvas (saveCanv); SongsPlaySong (SONG_TITLE, 1); if (creditsOffscreenBuf != gameStates.render.vr.buffers.offscreen) GrFreeCanvas (creditsOffscreenBuf); glDisable (GL_BLEND); gameStates.menus.nInMenu = 0; return; } } if (buffer [(nLine + 1) % NUM_LINES][0] == '!') { nFirstLineOffs -= ROW_SPACING - ROW_SPACING / 2; if (nFirstLineOffs <= -ROW_SPACING) { nFirstLineOffs += ROW_SPACING; nExtraInc++; } } } }