//----------------------------------------------------------------------------- // V12 Engine // // Copyright (c) 2001 GarageGames.Com // Portions Copyright (c) 2001 by Sierra Online, Inc. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "platform/platformVideo.h" #include "platform/platformAudio.h" #include "platform/platformInput.h" #include "core/findMatch.h" #include "dgl/dgl.h" #include "game/game.h" #include "math/mMath.h" #include "console/simBase.h" #include "console/console.h" #include "terrain/terrData.h" #include "terrain/terrRender.h" #include "terrain/waterBlock.h" #include "game/collisionTest.h" #include "game/showTSShape.h" #include "scenegraph/sceneGraph.h" #include "gui/guiTSControl.h" #include "game/moveManager.h" #include "console/consoleTypes.h" #include "game/shapeBase.h" #include "core/dnet.h" #include "game/gameConnection.h" #include "core/fileStream.h" #include "gui/guiCanvas.h" #include "dgl/gTexManager.h" #include "scenegraph/sceneLighting.h" #include "terrain/Sky.h" #include "game/ambientAudioManager.h" #include "sim/frameAllocator.h" #include "scenegraph/detailManager.h" #include "gui/guiMLTextCtrl.h" #include "platform/profiler.h" #include "game/underLava.h" static void cPanoramaScreenShot(SimObject *, S32, const char ** argv); void wireCube(F32 size, Point3F pos); void GameRenderTest(); CollisionTest collisionTest; F32 gMovementSpeed = 1; namespace { //-------------------------------------------------------------------------- void cScreenShot(SimObject *, S32, const char ** argv) { FileStream fStream; if(!fStream.open(argv[1], FileStream::Write)) { Con::printf("Failed to open file '%s'.", argv[1]); return; } glReadBuffer(GL_FRONT); Point2I extent = Canvas->getExtent(); U8 * pixels = new U8[extent.x * extent.y * 3]; glReadPixels(0, 0, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels); GBitmap * bitmap = new GBitmap; bitmap->allocateBitmap(U32(extent.x), U32(extent.y)); // flip the rows for(U32 y = 0; y < extent.y; y++) dMemcpy(bitmap->getAddress(0, extent.y - y - 1), pixels + y * extent.x * 3, U32(extent.x * 3)); bitmap->writePNG(fStream); fStream.close(); delete [] pixels; delete bitmap; } //-------------------------------------------------------------------------- ConsoleFunction( gotoWebPage, void, 2, 2, "gotoWebPage( address )" ) { argc; Platform::openWebBrowser( argv[1] ); } //-------------------------------------------------------------------------- ConsoleFunction( deactivateDirectInput, void, 1, 1, "deactivateDirectInput()" ) { argc; argv; if ( Input::isActive() ) Input::deactivate(); } //-------------------------------------------------------------------------- ConsoleFunction( activateDirectInput, void, 1, 1, "activateDirectInput()" ) { argc; argv; if ( !Input::isActive() ) Input::activate(); } //-------------------------------------------------------------------------- void cPurgeResources(SimObject *, S32, const char **) { ResourceManager->purge(); } //-------------------------------------------------------------------------- static bool cLightScene(SimObject*, S32 argc, const char ** argv) { const char * callback = StringTable->insert(argv[1]); BitSet32 flags = 0; // might have more flags some day... for(S32 i = 2; i < argc; i++) { if(!dStricmp(argv[2], "forceAlways")) flags.set(SceneLighting::ForceAlways); else if(!dStricmp(argv[2], "forceWritable")) flags.set(SceneLighting::ForceWritable); } return(SceneLighting::lightScene(callback, flags)); } //-------------------------------------------------------------------------- static const U32 MaxPlayerNameLength = 16; ConsoleFunction( strToPlayerName, const char*, 2, 2, "strToPlayerName( string )" ) { argc; const char* ptr = argv[1]; // Strip leading spaces and underscores: while ( *ptr == ' ' || *ptr == '_' ) ptr++; U32 len = dStrlen( ptr ); if ( len ) { char* ret = Con::getReturnBuffer( MaxPlayerNameLength + 1 ); char* rptr = ret; ret[MaxPlayerNameLength - 1] = '\0'; ret[MaxPlayerNameLength] = '\0'; bool space = false; U8 ch; while ( *ptr && dStrlen( ret ) < MaxPlayerNameLength ) { ch = (U8) *ptr; // Strip all illegal characters: if ( ch < 32 || ch == ',' || ch == '.' || ch == '\'' || ch == '`' ) { ptr++; continue; } // Don't allow double spaces or space-underline combinations: if ( ch == ' ' || ch == '_' ) { if ( space ) { ptr++; continue; } else space = true; } else space = false; *rptr++ = *ptr; ptr++; } *rptr = '\0'; //finally, strip out the ML text control chars... return GuiMLTextCtrl::stripControlChars(ret); return( ret ); } return( "" ); } //-------------------------------------------------------------------------- ConsoleFunction( stripTrailingSpaces, const char*, 2, 2, "stripTrailingSpaces( string )" ) { argc; S32 temp = S32(dStrlen( argv[1] )); if ( temp ) { while ( ( argv[1][temp - 1] == ' ' || argv[1][temp - 1] == '_' ) && temp >= 1 ) temp--; if ( temp ) { char* returnString = Con::getReturnBuffer( temp + 1 ); dStrncpy( returnString, argv[1], U32(temp) ); returnString[temp] = '\0'; return( returnString ); } } return( "" ); } //-------------------------------------------------------------------------- void cFlushTextureCache(SimObject *, S32, const char **) { TextureManager::flush(); } #ifdef GATHER_METRICS void cDumpTextureStats(SimObject*, S32, const char**) { TextureManager::dumpStats(); } #endif #ifdef DEBUG void cDumpResourceStats(SimObject*, S32, const char**) { ResourceManager->dumpLoadedResources(); } #endif } // namespace {} //------------------------------------------------------------------------------ static U32 moveCount = 0; bool GameGetCameraTransform(MatrixF *mat, Point3F *velocity) { // Return the position and velocity of the control object GameConnection* connection = GameConnection::getServerConnection(); return connection && connection->getControlCameraTransform(0, mat) && connection->getControlCameraVelocity(velocity); } //------------------------------------------------------------------------------ // Camera and FOV info //------------------------------------------------------------------------------ namespace { const U32 MaxZoomSpeed = 2000; // max number of ms to reach target FOV static F32 sConsoleCameraFov = 90.f; // updated to camera FOV each frame static F32 sDefaultFov = 90.f; // normal FOV static F32 sCameraFov = 90.f; // current camera FOV static F32 sTargetFov = 90.f; // the desired FOV static F32 sLastCameraUpdateTime = 0; // last time camera was updated static S32 sZoomSpeed = 0; // ms per 90deg fov change } // namespace {} //------------------------------------------------------------------------------ ConsoleFunction(setDefaultFov, void, 2,2, "setDefaultFov(defaultFov);") { argc; sDefaultFov = mClampF(dAtof(argv[1]), MinCameraFov, MaxCameraFov); if(sCameraFov == sTargetFov) sTargetFov = sDefaultFov; } ConsoleFunction(setZoomSpeed, void, 2,2, "setZoomSpeed(speed);") { argc; sZoomSpeed = mClamp(dAtoi(argv[1]), 0, MaxZoomSpeed); } ConsoleFunction(setFov, void, 2, 2, "setFov(fov);") { argc; sTargetFov = mClampF(dAtof(argv[1]), MinCameraFov, MaxCameraFov); } F32 GameGetCameraFov() { return(sCameraFov); } void GameSetCameraFov(F32 fov) { sTargetFov = sCameraFov = fov; } void GameSetCameraTargetFov(F32 fov) { sTargetFov = fov; } void GameUpdateCameraFov() { F32 time = F32(Platform::getVirtualMilliseconds()); // need to update fov? if(sTargetFov != sCameraFov) { F32 delta = time - sLastCameraUpdateTime; // snap zoom? if((sZoomSpeed == 0) || (delta <= 0.f)) sCameraFov = sTargetFov; else { // gZoomSpeed is time in ms to zoom 90deg F32 step = 90.f * (delta / F32(sZoomSpeed)); if(sCameraFov > sTargetFov) { sCameraFov -= step; if(sCameraFov < sTargetFov) sCameraFov = sTargetFov; } else { sCameraFov += step; if(sCameraFov > sTargetFov) sCameraFov = sTargetFov; } } } // the game connection controls the vertical and the horizontal GameConnection * connection = GameConnection::getServerConnection(); if(connection) { // check if fov is valid on control object if(connection->isValidControlCameraFov(sCameraFov)) connection->setControlCameraFov(sCameraFov); else { // will set to the closest fov (fails only on invalid control object) if(connection->setControlCameraFov(sCameraFov)) { F32 setFov = sCameraFov; connection->getControlCameraFov(&setFov); sTargetFov = sCameraFov = setFov; } } } // update the console variable sConsoleCameraFov = sCameraFov; sLastCameraUpdateTime = time; } //-------------------------------------------------------------------------- #ifdef DEBUG // ConsoleFunction(dumpTSShapes, void, 1, 1, "dumpTSShapes();") // { // argc, argv; // FindMatch match("*.dts", 4096); // ResourceManager->findMatches(&match); // for (U32 i = 0; i < match.numMatches(); i++) // { // U32 j; // Resource shape = ResourceManager->load(match.matchList[i]); // if (bool(shape) == false) // Con::errorf(" aaa Couldn't load: %s", match.matchList[i]); // U32 numMeshes = 0, numSkins = 0; // for (j = 0; j < shape->meshes.size(); j++) // if (shape->meshes[j]) // numMeshes++; // for (j = 0; j < shape->skins.size(); j++) // if (shape->skins[j]) // numSkins++; // Con::printf(" aaa Shape: %s (%d meshes, %d skins)", match.matchList[i], numMeshes, numSkins); // Con::printf(" aaa Meshes"); // for (j = 0; j < shape->meshes.size(); j++) // { // if (shape->meshes[j]) // Con::printf(" aaa %d -> nf: %d, nmf: %d, nvpf: %d (%d, %d, %d, %d, %d)", // shape->meshes[j]->meshType & TSMesh::TypeMask, // shape->meshes[j]->numFrames, // shape->meshes[j]->numMatFrames, // shape->meshes[j]->vertsPerFrame, // shape->meshes[j]->verts.size(), // shape->meshes[j]->norms.size(), // shape->meshes[j]->tverts.size(), // shape->meshes[j]->primitives.size(), // shape->meshes[j]->indices.size()); // } // Con::printf(" aaa Skins"); // for (j = 0; j < shape->skins.size(); j++) // { // if (shape->skins[j]) // Con::printf(" aaa %d -> nf: %d, nmf: %d, nvpf: %d (%d, %d, %d, %d, %d)", // shape->skins[j]->meshType & TSMesh::TypeMask, // shape->skins[j]->numFrames, // shape->skins[j]->numMatFrames, // shape->skins[j]->vertsPerFrame, // shape->skins[j]->verts.size(), // shape->skins[j]->norms.size(), // shape->skins[j]->tverts.size(), // shape->skins[j]->primitives.size(), // shape->skins[j]->indices.size()); // } // } // } #endif static const char* cGetControlObjectAltitude(SimObject *, S32, const char**) { GameConnection* connection = GameConnection::getServerConnection(); if (connection) { ShapeBase* pSB = connection->getControlObject(); if (pSB != NULL && pSB->isClientObject()) { Point3F pos(0.f, 0.f, 0.f); // if this object is mounted, then get the bottom position of the mount's bbox if(pSB->getObjectMount()) { static Point3F BoxPnts[] = { Point3F(0,0,0), Point3F(0,0,1), Point3F(0,1,0), Point3F(0,1,1), Point3F(1,0,0), Point3F(1,0,1), Point3F(1,1,0), Point3F(1,1,1) }; ShapeBase * mount = pSB->getObjectMount(); Box3F box = mount->getObjBox(); MatrixF mat = mount->getTransform(); VectorF scale = mount->getScale(); Point3F projPnts[8]; F32 minZ = 1e30; for(U32 i = 0; i < 8; i++) { Point3F pnt(BoxPnts[i].x ? box.max.x : box.min.x, BoxPnts[i].y ? box.max.y : box.min.y, BoxPnts[i].z ? box.max.z : box.min.z); pnt.convolve(scale); mat.mulP(pnt, &projPnts[i]); if(projPnts[i].z < minZ) pos = projPnts[i]; } } else pSB->getTransform().getColumn(3, &pos); TerrainBlock* pBlock = gClientSceneGraph->getCurrentTerrain(); if (pBlock != NULL) { Point3F terrPos = pos; pBlock->getWorldTransform().mulP(terrPos); terrPos.convolveInverse(pBlock->getScale()); F32 height; if (pBlock->getHeight(Point2F(terrPos.x, terrPos.y), &height) == true) { terrPos.z = height; terrPos.convolve(pBlock->getScale()); pBlock->getTransform().mulP(terrPos); pos.z -= terrPos.z; } } char* retBuf = Con::getReturnBuffer(128); dSprintf(retBuf, 128, "%g", mFloor(getMax(pos.z, 0.f))); return retBuf; } } return "0"; } static const char* cGetControlObjectSpeed(SimObject *, S32, const char**) { GameConnection* connection = GameConnection::getServerConnection(); if (connection) { ShapeBase* pSB = connection->getControlObject(); if (pSB != NULL && pSB->isClientObject()) { Point3F vel = pSB->getVelocity(); F32 speed = vel.len(); // We're going to force the formating to be what we want... F32 intPart = mFloor(speed); speed -= intPart; speed *= 10; speed = mFloor(speed); char* retBuf = Con::getReturnBuffer(128); dSprintf(retBuf, 128, "%g.%g", intPart, speed); return retBuf; } } return "0"; } //------------------------------------------------------------------------------ void GameInit() { // Make sure the exporter draws from the correct directories... // TSMaterialList::csmTSTexturePrefix = ""; TSMaterialList::csmOldTSTexturePrefix = "skins/"; Con::addVariable("movementSpeed", TypeF32, &gMovementSpeed); Con::addCommand("screenShot", cScreenShot, "screenShot(file);", 2, 2); Con::addCommand("panoramaScreenShot", cPanoramaScreenShot, "panoramaScreenShot(file);", 2, 2); Con::addCommand("purgeResources", cPurgeResources, "purgeResources();", 1, 1); Con::addCommand("lightScene", cLightScene, "lightScene(, ;", 1, 7); Con::addVariable("$pref::OpenGL::disableEXTPalettedTexture", TypeBool, &gOpenGLDisablePT); Con::addVariable("$pref::OpenGL::disableEXTCompiledVertexArray", TypeBool, &gOpenGLDisableCVA); Con::addVariable("$pref::OpenGL::disableARBMultitexture", TypeBool, &gOpenGLDisableARBMT); Con::addVariable("$pref::OpenGL::disableEXTFogCoord", TypeBool, &gOpenGLDisableFC); Con::addVariable("$pref::OpenGL::disableEXTTexEnvCombine", TypeBool, &gOpenGLDisableTEC); Con::addVariable("$pref::OpenGL::disableARBTextureCompression", TypeBool, &gOpenGLDisableTCompress); Con::addVariable("$pref::OpenGL::noEnvColor", TypeBool, &gOpenGLNoEnvColor); Con::addVariable("$pref::OpenGL::gammaCorrection", TypeF32, &gOpenGLGammaCorrection); Con::addVariable("$pref::OpenGL::noDrawArraysAlpha", TypeBool, &gOpenGLNoDrawArraysAlpha); Con::addVariable("$pref::TS::autoDetail", TypeF32, &DetailManager::smDetailScale); Con::addVariable("$pref::visibleDistanceMod", TypeF32, &SceneGraph::smVisibleDistanceMod); Con::addCommand("flushTextureCache", cFlushTextureCache, "flushTextureCache()", 1, 1); #ifdef GATHER_METRICS Con::addCommand("dumpTextureStats", cDumpTextureStats, "dumpTextureStats()", 1, 1); #endif #ifdef DEBUG Con::addCommand("dumpResourceStats", cDumpResourceStats, "dumpResourceStats()", 1, 1); #endif // updated every frame Con::addVariable("cameraFov", TypeF32, &sConsoleCameraFov); Con::addCommand("getControlObjectAltitude", cGetControlObjectAltitude, "getControlObjectAltitude();", 1, 1); Con::addCommand("getControlObjectSpeed", cGetControlObjectSpeed, "getControlObjectSpeed();", 1, 1); collisionTest.consoleInit(); gAmbientAudioManager.consoleInit(); } const U32 AudioUpdatePeriod = 125; // milliseconds for audio update void clientProcess(U32 timeDelta) { ShowTSShape::advanceTime(timeDelta); gClientProcessList.advanceClientTime(timeDelta); // Run the collision test and update the Audio system // by checking the controlObject MatrixF mat; Point3F velocity; if (GameGetCameraTransform(&mat, &velocity)) { alxListenerMatrixF(&mat); // alxListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); collisionTest.collide(mat); } // all seeker audio is managed here GameConnection* connection = GameConnection::getServerConnection(); if(connection) { // if a seeker is being used, update all tones //ShapeBase *obj = connection->getControlObject(); //if(obj) //{ //if(obj->getMountedImage(0) != NULL && obj->getMountedImage(0)->isSeeker) connection->updateLockTones(); //} // update all possible lock or homes on us connection->updateLockWarnings(); } // determine if were lagging if(connection) connection->detectLag(); // alxUpdate is somewhat expensive and does not need to be updated constantly, // though it does need to be updated in real time static U32 lastAudioUpdate = 0; U32 realTime = Platform::getRealMilliseconds(); if((realTime - lastAudioUpdate) >= AudioUpdatePeriod) { alxUpdate(); gAmbientAudioManager.update(); lastAudioUpdate = realTime; } } void serverProcess(U32 timeDelta) { gServerProcessList.advanceServerTime(timeDelta); } static ColorF cubeColors[8] = { ColorF(0, 0, 0), ColorF(1, 0, 0), ColorF(0, 1, 0), ColorF(0, 0, 1), ColorF(1, 1, 0), ColorF(1, 0, 1), ColorF(0, 1, 1), ColorF(1, 1, 1) }; static Point3F cubePoints[8] = { Point3F(-1, -1, -1), Point3F(-1, -1, 1), Point3F(-1, 1, -1), Point3F(-1, 1, 1), Point3F( 1, -1, -1), Point3F( 1, -1, 1), Point3F( 1, 1, -1), Point3F( 1, 1, 1) }; static U32 cubeFaces[6][4] = { { 0, 2, 6, 4 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 }, { 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 } }; void wireCube(F32 size, Point3F pos) { glDisable(GL_CULL_FACE); for (S32 i = 0; i < 6; i++) { glBegin(GL_LINE_LOOP); for(S32 vert = 0; vert < 4; vert++) { U32 idx = cubeFaces[i][vert]; glColor3f(cubeColors[idx].red, cubeColors[idx].green, cubeColors[idx].blue); glVertex3f(cubePoints[idx].x * size + pos.x, cubePoints[idx].y * size + pos.y, cubePoints[idx].z * size + pos.z); } glEnd(); } } bool GameProcessCameraQuery(CameraQuery *query) { GameConnection* connection = GameConnection::getServerConnection(); if (connection && connection->getControlCameraTransform(0.032f, &query->cameraMatrix)) { query->object = connection->getControlObject(); query->nearPlane = 0.1f; Sky* pSky = gClientSceneGraph->getCurrentSky(); if (pSky) { query->farPlane = pSky->getVisibleDistance(); } else { query->farPlane = 1000.0f; } F32 cameraFov; if(!connection->getControlCameraFov(&cameraFov)) return(false); query->fov = mDegToRad(cameraFov); return true; } return false; } struct OutputPoint { Point3F point; U8 color[4]; Point2F texCoord; Point2F fogCoord; }; //---------------------------------------------------------------------------- void GameRenderTest() { glClearColor(1, 1, 1, 1); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glViewport(0, 0, 640, 480); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.3, 1.3, -1.0, 1.0, 1.0, 10.0); GLubyte lum[4] = {0xFF, 0x80, 0x80, 0x00}; GLubyte color[3] = { 0xFF, 0x00, 0xFF }; GLuint names[2]; glGenTextures(2, names); glBindTexture(GL_TEXTURE_2D, names[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, color); glBindTexture(GL_TEXTURE_2D, names[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, lum); OutputPoint outputPoints[4]; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(OutputPoint), &outputPoints[0].point); glClientActiveTextureARB(GL_TEXTURE0_ARB); glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, names[1]); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(OutputPoint), &outputPoints[0].fogCoord); glClientActiveTextureARB(GL_TEXTURE0_ARB); glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, names[0]); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(OutputPoint), &outputPoints[0].texCoord); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(OutputPoint), &outputPoints[0].color[0]); ColorF fogColor(0.5, 0.5, 0.5, 1); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fogColor); outputPoints[0].point.x = 0; outputPoints[0].point.y = 0; outputPoints[0].point.z = -2; outputPoints[0].color[0] = 0xFF; outputPoints[0].color[1] = 0xFF; outputPoints[0].color[2] = 0xFF; outputPoints[0].color[3] = 0xFF; outputPoints[0].texCoord.x = 0; outputPoints[0].texCoord.y = 0; outputPoints[0].fogCoord.x = 0; outputPoints[0].fogCoord.y = 0; outputPoints[1].point.x = 0; outputPoints[1].point.y = 1; outputPoints[1].point.z = -2; outputPoints[1].color[0] = 0xFF; outputPoints[1].color[1] = 0xFF; outputPoints[1].color[2] = 0xFF; outputPoints[1].color[3] = 0xFF; outputPoints[1].texCoord.x = 0; outputPoints[1].texCoord.y = 0; outputPoints[1].fogCoord.x = 0; outputPoints[1].fogCoord.y = 1; outputPoints[2].point.x = 1; outputPoints[2].point.y = 1; outputPoints[2].point.z = -2; outputPoints[2].color[0] = 0xFF; outputPoints[2].color[1] = 0xFF; outputPoints[2].color[2] = 0xFF; outputPoints[2].color[3] = 0xFF; outputPoints[2].texCoord.x = 0; outputPoints[2].texCoord.y = 0; outputPoints[2].fogCoord.x = 1; outputPoints[2].fogCoord.y = 1; outputPoints[3].point.x = 1; outputPoints[3].point.y = 0; outputPoints[3].point.z = -2; outputPoints[3].color[0] = 0xFF; outputPoints[3].color[1] = 0xFF; outputPoints[3].color[2] = 0xFF; outputPoints[3].color[3] = 0xFF; outputPoints[3].texCoord.x = 0; outputPoints[3].texCoord.y = 0; outputPoints[3].fogCoord.x = 1; outputPoints[3].fogCoord.y = 0; glLockArraysEXT(0, 4); GLuint windings[6] = { 0, 1, 2, 0, 2, 3 }; glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, windings); glUnlockArraysEXT(); glDisableClientState(GL_VERTEX_ARRAY); glClientActiveTextureARB(GL_TEXTURE1_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDeleteTextures(2, names); } #define USEOLDFILTERS 1 void GameRenderFilters(const CameraQuery& camq) { #if USEOLDFILTERS GameConnection* connection = GameConnection::getServerConnection(); F32 damageFlash = 0; F32 whiteOut = 0; F32 blackOut = 0; if(connection) { damageFlash = connection->getDamageFlash(); whiteOut = connection->getWhiteOut(); blackOut = connection->getBlackOut(); } ShapeBase* psb = dynamic_cast(camq.object); if (psb != NULL) { if (damageFlash > 0.0) { if (damageFlash > 0.76) damageFlash = 0.76f; glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1, 0, 0, damageFlash); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } if (whiteOut > 0.0) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1.0f, 1.0f, 0.92f, (whiteOut > 1.0f ? 1.0f : whiteOut)); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } if (blackOut > 0.0) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.0f, 0.0f, 0.0f, (blackOut > 1.0f ? 1.0f : blackOut)); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } F32 invincible = psb->getInvincibleEffect(); if (invincible > 0.0) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0, 0, 1, (invincible > 1.0f ? 1.0f : invincible)); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } if (WaterBlock::mCameraSubmerged) { if (WaterBlock::isWater(WaterBlock::mSubmergedType)) { // view filter for camera below the water surface glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(.2, .6, .6, .3); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } else if (WaterBlock::isLava(WaterBlock::mSubmergedType)) { gLavaFX.render(); } else if (WaterBlock::isQuicksand(WaterBlock::mSubmergedType)) { } } WaterBlock::mCameraSubmerged = false; WaterBlock::mSubmergedType = 0; } #else // // Need to build a filter for damage, invincibility, underwater, whiteout... ect // // Damage, Whiteout, and invincible effects have constant color with variable // alpha values. The water filter has a constant color and alpha value. This // looks kinda tricky, and it is. See Frohn for more details Jett- // first get the game connection for this player GameConnection* connection = GameConnection::getServerConnection(); bool addWaterFilter = false; bool addLavaFilter = false; F32 maxDamageFilter = 0.77; F32 damageFlash = 0.f; ColorF damageFilterColor(1.f, 0.f, 0.f, 0.f); F32 whiteOut = 0.f; ColorF whiteoutFilterColor(1.f, 1.f, 1.f, 0.f); F32 waterFilter = 0.f; ColorF waterFilterColor(0.2, 0.6, 0.6, 0.6); F32 invincible = 0.f; ColorF invincibleFilterColor(0.f, 0.f, 1.f, 0.f); // final color and alpha of filter + an adder ColorF Xcolor(0.f, 0.f, 0.f, 1.f); if(connection) { // grab the damage flash alpha value damageFlash = connection->getDamageFlash(); if( damageFlash > maxDamageFilter ) damageFlash = maxDamageFilter; damageFilterColor.alpha = damageFlash; // grab the whiteout value whiteoutFilterColor.alpha = connection->getWhiteOut(); // need to grab the player obj to get inv. alpha value ShapeBase* psb = dynamic_cast(camq.object); if(psb != NULL) invincibleFilterColor.alpha = psb->getInvincibleEffect(); // determine if we need to add in our water filter (constant color and alpha) if( WaterBlock::mCameraSubmerged ) { if( WaterBlock::isWater( WaterBlock::mSubmergedType ) ) addWaterFilter = true; else if( WaterBlock::isLava( WaterBlock::mSubmergedType)) addLavaFilter = true; } // compute the final color and alpha Xcolor = ( Xcolor * ( 1 - damageFilterColor.alpha ) ) + ( damageFilterColor * damageFilterColor.alpha ); Xcolor.alpha = Xcolor.alpha * ( 1 - damageFilterColor.alpha ); Xcolor = ( Xcolor * ( 1 - whiteoutFilterColor.alpha ) ) + ( whiteoutFilterColor * whiteoutFilterColor.alpha ); Xcolor.alpha = Xcolor.alpha * ( 1 - whiteoutFilterColor.alpha ); Xcolor = ( Xcolor * ( 1 - invincibleFilterColor.alpha ) ) + ( invincibleFilterColor * invincibleFilterColor.alpha ); Xcolor.alpha = Xcolor.alpha * ( 1 - invincibleFilterColor.alpha ); // if were sitting in water, then add that filter in as well. if(addWaterFilter) { Xcolor = ( Xcolor * ( 1 - waterFilterColor.alpha ) ) + ( waterFilterColor * waterFilterColor.alpha ); Xcolor.alpha = Xcolor.alpha * ( 1 - waterFilterColor.alpha ); } // draw our filter with final color glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4f(Xcolor.red, Xcolor.blue, Xcolor.blue, Xcolor.alpha); glBegin(GL_TRIANGLE_FAN); glVertex3f(-1, -1, 0); glVertex3f(-1, 1, 0); glVertex3f( 1, 1, 0); glVertex3f( 1, -1, 0); glEnd(); glDisable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDepthMask(GL_TRUE); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); // if were under lava, apply appropriate texture if( addLavaFilter ) { gLavaFX.render(); } WaterBlock::mCameraSubmerged = false; WaterBlock::mSubmergedType = 0; } #endif } void GameRenderWorld() { PROFILE_START(GameRenderWorld); FrameAllocator::setWaterMark(0); #if defined(GATHER_METRICS) && GATHER_METRICS > 1 TextureManager::smTextureCacheMisses = 0; #endif glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glClear(GL_DEPTH_BUFFER_BIT); glDisable(GL_CULL_FACE); glMatrixMode(GL_MODELVIEW); dglSetCanonicalState(); gClientSceneGraph->renderScene(); glDisable(GL_DEPTH_TEST); collisionTest.render(); #if defined(GATHER_METRICS) && GATHER_METRICS > 1 Con::setFloatVariable("Video::texResidentPercentage", TextureManager::getResidentFraction()); Con::setIntVariable("Video::textureCacheMisses", TextureManager::smTextureCacheMisses); #endif AssertFatal(FrameAllocator::getWaterMark() == 0, "Error, someone didn't reset the water mark on the frame allocator!"); FrameAllocator::setWaterMark(0); PROFILE_END(); } //-------------------------------------------------------------------------- static void cPanoramaScreenShot(SimObject *, S32 argc, const char ** argv) { S32 numShots = 3; if (argc == 3) numShots = dAtoi(argv[2]); CameraQuery query; if (!GameProcessCameraQuery( &query )) return; SceneObject *object = dynamic_cast(query.object); if (!object) return; F32 rotInc = query.fov * 0.75f; FileStream fStream; GBitmap bitmap; Point2I extent = Canvas->getExtent(); bitmap.allocateBitmap(U32(extent.x), U32(extent.y)); U8 * pixels = new U8[extent.x * extent.y * 3]; S32 start = -(numShots/2); for (S32 i=0; isetTransform( result ); Canvas->renderFrame(false); dSprintf(buffer, sizeof(buffer), "%s-%d.png", argv[1], i); glReadBuffer(GL_FRONT); glReadPixels(0, 0, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels); if(!fStream.open(buffer, FileStream::Write)) { Con::printf("Failed to open file '%s'.", buffer); break; } // flip the rows for(U32 y = 0; y < extent.y; y++) dMemcpy(bitmap.getAddress(0, extent.y - y - 1), pixels + y * extent.x * 3, U32(extent.x * 3)); bitmap.writePNG(fStream); fStream.close(); } delete [] pixels; }