/* ** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: W3DBridgeBuffer.cpp //////////////////////////////////////////////// //----------------------------------------------------------------------------- // // Westwood Studios Pacific. // // Confidential Information // Copyright (C) 2001 - All Rights Reserved // //----------------------------------------------------------------------------- // // Project: RTS3 // // File name: W3DBridgeBuffer.cpp // // Created: John Ahlquist, May 2001 // // Desc: Draw buffer to handle all the bridges in a scene. // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- #include "W3DDevice/GameClient/W3DBridgeBuffer.h" #include #include #include "W3DDevice/GameClient/W3DAssetManager.h" #include #include "common/GlobalData.h" #include "common/RandomValue.h" #include "Common/ThingFactory.h" #include "Common/ThingTemplate.h" #include "GameClient/TerrainRoads.h" #include "GameLogic/Damage.h" #include "GameLogic/Module/BodyModule.h" #include "W3DDevice/GameLogic/W3DTerrainLogic.h" #include "W3DDevice/GameClient/TerrainTex.h" #include "W3DDevice/GameClient/HeightMap.h" #include "W3DDevice/GameClient/W3DDynamicLight.h" #include "W3DDevice/GameClient/Module/W3DModelDraw.h" #include "W3DDevice/GameClient/W3DShaderManager.h" #include "W3DDevice/GameClient/W3DShroud.h" #include "WW3D2/Camera.h" #include "WW3D2/DX8Wrapper.h" #include "WW3D2/DX8Renderer.h" #include "WW3D2/Mesh.h" #include "WW3D2/MeshMdl.h" #include "WW3D2/Scene.h" //----------------------------------------------------------------------------- // Private Data //----------------------------------------------------------------------------- // A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \ ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \ ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_DISABLE, \ ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL); #define SC_ALPHA_MIRROR ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \ ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \ ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \ ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) static ShaderClass detailShader(SC_ALPHA_MIRROR); #define NO_USE_BRIDGE_NORMALS //----------------------------------------------------------------------------- // Private Classes //----------------------------------------------------------------------------- //============================================================================= // W3DBridge constructor. //============================================================================= /** Initializes pointers & values. */ //============================================================================= W3DBridge::W3DBridge() : m_bridgeTexture(NULL), m_leftMesh(NULL), m_sectionMesh(NULL), m_rightMesh(NULL), m_visible(false), m_curDamageState(BODY_PRISTINE), m_scale(1.0) { } //============================================================================= // W3DBridge destructor. //============================================================================= /** Frees objects. */ //============================================================================= W3DBridge::~W3DBridge(void) { clearBridge(); } //============================================================================= // W3DBridge::renderBridge //============================================================================= /** Renders the bride. It is assumed that the shared vertex and index buffers are already set. */ //============================================================================= void W3DBridge::renderBridge(Bool wireframe) { if (m_visible) { if (!wireframe) DX8Wrapper::Set_Texture(0,m_bridgeTexture); // Draw all the bridges. DX8Wrapper::Draw_Triangles( m_firstIndex, m_numPolygons, m_firstVertex, m_numVertex); } } //============================================================================= // W3DBridge::clearBridge //============================================================================= /** Frees all bridge objects (meshes & texture). */ //============================================================================= void W3DBridge::clearBridge(void) { m_visible = false; REF_PTR_RELEASE(m_bridgeTexture); REF_PTR_RELEASE(m_leftMesh); REF_PTR_RELEASE(m_sectionMesh); REF_PTR_RELEASE(m_rightMesh); } //============================================================================= // W3DBridge::cullBridge //============================================================================= /** Culls bridge to camera. */ //============================================================================= Bool W3DBridge::cullBridge(CameraClass * camera) { ///@todo - cull bridges. Bool wasVisible = m_visible; m_visible = true; return(wasVisible != m_visible); } #define BRIDGE_FLOAT_AMT (0.25f) //============================================================================= // W3DBridge::init //============================================================================= /** Inits a bridges location & type so it can be load'ed. */ //============================================================================= void W3DBridge::init(Vector3 fromLoc, Vector3 toLoc, AsciiString bridgeTemplateName) { m_start = fromLoc; m_end = toLoc; m_templateName = bridgeTemplateName; m_enabled = true; } //============================================================================= // W3DBridge::init //============================================================================= /** Loads a bridge model(if not already loaded) and gets meshes for use at specified location. */ //============================================================================= Bool W3DBridge::load(enum BodyDamageType curDamageState) { REF_PTR_RELEASE(m_bridgeTexture); REF_PTR_RELEASE(m_leftMesh); REF_PTR_RELEASE(m_sectionMesh); REF_PTR_RELEASE(m_rightMesh); Real scale, width, length; char textureFile[_MAX_PATH] = "No Texture"; char modelName[_MAX_PATH] = "BRIDGESECTIONAL"; /// @todo, should these be defaults in INI??? CBD scale = 0.7f; width = 34; length = 170; // try to find bridge in INI TerrainRoadType *bridge = TheTerrainRoads->findBridge( m_templateName ); if (!bridge) return false; scale = bridge->getBridgeScale(); switch (curDamageState) { default: return false; case BODY_PRISTINE: strcpy( textureFile, bridge->getTexture().str() ); strcpy( modelName, bridge->getBridgeModel().str() ); break; case BODY_DAMAGED: strcpy( textureFile, bridge->getTextureDamaged().str() ); strcpy( modelName, bridge->getBridgeModelNameDamaged().str() ); break; case BODY_REALLYDAMAGED: strcpy( textureFile, bridge->getTextureReallyDamaged().str() ); strcpy( modelName, bridge->getBridgeModelNameReallyDamaged().str() ); break; case BODY_RUBBLE: strcpy( textureFile, bridge->getTextureBroken().str() ); strcpy( modelName, bridge->getBridgeModelNameBroken().str() ); break; } WW3DAssetManager *pMgr = W3DAssetManager::Get_Instance(); char left[_MAX_PATH]; char section[_MAX_PATH]; char right[_MAX_PATH]; strcpy(left, modelName); strcat(left, ".BRIDGE_LEFT"); strcpy(section, modelName); strcat(section, ".BRIDGE_SPAN"); strcpy(right, modelName); strcat(right, ".BRIDGE_RIGHT"); m_bridgeTexture = pMgr->Get_Texture(textureFile, TextureClass::MIP_LEVELS_3); m_leftMtx.Make_Identity(); m_rightMtx.Make_Identity(); m_sectionMtx.Make_Identity(); RenderObjClass *pObj = pMgr->Create_Render_Obj(modelName ); if (!pObj) return false; Int i; for (i=0; iGet_Num_Sub_Objects(); i++) { RenderObjClass *pSub = pObj->Get_Sub_Object(i); Matrix3D mtx = pSub->Get_Transform(); if (0==strnicmp(left, pSub->Get_Name(), strlen(left))) { m_leftMtx = mtx; strcpy(left, pSub->Get_Name()); } if (0==strnicmp(section, pSub->Get_Name(), strlen(section))) { m_sectionMtx = mtx; strcpy(section, pSub->Get_Name()); } if (0==strnicmp(right, pSub->Get_Name(), strlen(right))) { m_rightMtx = mtx; strcpy(right, pSub->Get_Name()); } REF_PTR_RELEASE(pSub); //DEBUG_LOG(("Sub obj name %s\n", pSub->Get_Name())); } REF_PTR_RELEASE(pObj); m_leftMesh = (MeshClass*)pMgr->Create_Render_Obj(left ); m_sectionMesh = (MeshClass*)pMgr->Create_Render_Obj(section); m_rightMesh = (MeshClass*)pMgr->Create_Render_Obj(right); m_scale = scale; if (m_leftMesh == NULL) { clearBridge(); return(false); } m_bridgeType = SECTIONAL_BRIDGE; if (m_rightMesh == NULL || m_sectionMesh == NULL) { m_bridgeType = FIXED_BRIDGE; } Int numVertex = m_leftMesh->Peek_Model()->Get_Vertex_Count(); Vector3 *pVert = m_leftMesh->Peek_Model()->Get_Vertex_Array(); m_leftMinX = FLT_MAX; m_leftMaxX = -FLT_MAX; m_minY = FLT_MAX; m_maxY = -FLT_MAX; for (i=0; i vert.X) m_leftMinX = vert.X; if (m_minY > vert.Y) m_minY = vert.Y; if (vert.X > m_leftMaxX) m_leftMaxX = vert.X; if (vert.Y > m_maxY) m_maxY = vert.Y; // Note - we assume all sections are the same width, so we only do maxY for first section. } if (m_bridgeType == SECTIONAL_BRIDGE) { numVertex = m_sectionMesh->Peek_Model()->Get_Vertex_Count(); pVert = m_sectionMesh->Peek_Model()->Get_Vertex_Array(); m_sectionMinX = FLT_MAX; m_sectionMaxX = -FLT_MAX; for (i=0; i vert.X) m_sectionMinX = vert.X; if (vert.X > m_sectionMaxX) m_sectionMaxX = vert.X; } numVertex = m_rightMesh->Peek_Model()->Get_Vertex_Count(); pVert = m_rightMesh->Peek_Model()->Get_Vertex_Array(); m_rightMinX = FLT_MAX; m_rightMaxX = -FLT_MAX; for (i=0; i vert.X) m_rightMinX = vert.X; if (vert.X > m_rightMaxX) m_rightMaxX = vert.X; } } else { m_sectionMinX = m_leftMaxX; m_sectionMaxX = m_leftMaxX; m_rightMinX = m_leftMaxX; m_rightMaxX = m_leftMaxX; } length = m_rightMaxX - m_leftMinX; if (length < 1) length = 1; m_length = length; if (m_bridgeType == SECTIONAL_BRIDGE) { Real allowableError = 0.05f*length; // make sure the sections align. if (m_leftMaxX>m_sectionMinX+allowableError) { m_bridgeType = FIXED_BRIDGE; } if (m_rightMinXfrom.x = m_start.X; pInfo->from.y = m_start.Y; pInfo->from.z = m_start.Z; pInfo->to.x = m_end.X; pInfo->to.y = m_end.Y; pInfo->to.z = m_end.Z; pInfo->bridgeWidth = (m_maxY - m_minY) *m_scale; Vector3 vec = m_end-m_start; Vector3 vecNormal(-vec.Y, vec.X, 0); vecNormal.Normalize(); // From left = from + vecNormal*maxY*scale pInfo->fromLeft.x = m_start.X + vecNormal.X * m_maxY * m_scale; pInfo->fromLeft.y = m_start.Y + vecNormal.Y * m_maxY * m_scale; pInfo->fromLeft.z = m_start.Z + vecNormal.Z * m_maxY * m_scale; // From right = from + vecNormal*minY*scale pInfo->fromRight.x = m_start.X + vecNormal.X * m_minY * m_scale; pInfo->fromRight.y = m_start.Y + vecNormal.Y * m_minY * m_scale; pInfo->fromRight.z = m_start.Z + vecNormal.Z * m_minY * m_scale; // to left = to + vecNormal*maxY*scale pInfo->toLeft.x = m_end.X + vecNormal.X * m_maxY * m_scale; pInfo->toLeft.y = m_end.Y + vecNormal.Y * m_maxY * m_scale; pInfo->toLeft.z = m_end.Z + vecNormal.Z * m_maxY * m_scale; // to right = to + vecNormal*minY*scale pInfo->toRight.x = m_end.X + vecNormal.X * m_minY * m_scale; pInfo->toRight.y = m_end.Y + vecNormal.Y * m_minY * m_scale; pInfo->toRight.z = m_end.Z + vecNormal.Z * m_minY * m_scale; } //============================================================================= // W3DBridge::getModelVertices //============================================================================= /** Gets the vertex values for a section of a bridge. */ //============================================================================= Int W3DBridge::getModelVertices(VertexFormatXYZNDUV1 *destination_vb, Int curVertex, Real xOffset, Vector3 &vec, Vector3 &vecNormal, Vector3 &vecZ, Vector3 &offset, const Matrix3D &mtx, MeshClass *pMesh, RefRenderObjListIterator *pLightsIterator) { if (pMesh == NULL) return(0); Int i; Int numVertex = pMesh->Peek_Model()->Get_Vertex_Count(); Vector3 *pVert = pMesh->Peek_Model()->Get_Vertex_Array(); const Vector3 *pNormal = pMesh->Peek_Model()->Get_Vertex_Normal_Array(); // If we happen to have too many bridges, stop. if (curVertex+numVertex+2>= W3DBridgeBuffer::MAX_BRIDGE_VERTEX) { return(0); } Vector3 lightRay[MAX_GLOBAL_LIGHTS]; const Coord3D *lightPos; for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++) { lightPos=&TheGlobalData->m_terrainLightPos[lightIndex]; lightRay[lightIndex].Set(-lightPos->x,-lightPos->y, -lightPos->z); // __asm {int 3}; //see if it really needs normalization!! lightRay[lightIndex].Normalize(); } const Vector2*uvs=pMesh->Peek_Model()->Get_UV_Array_By_Index(0); VertexFormatXYZNDUV1 *curVb = destination_vb+curVertex; for (i=0; iu1 = uvs[i].U; curVb->v1 = uvs[i].V; Vector3 vLoc; Vector3 vertex; Matrix3D::Transform_Vector(mtx, pVert[i], &vertex); vLoc = (vertex.X+xOffset) * vec + vertex.Y*vecNormal + vertex.Z*vecZ; vLoc.X += m_start.X; vLoc.Y += m_start.Y; vLoc.Z += m_start.Z; curVb->x = vLoc.X; curVb->y = vLoc.Y; curVb->z = vLoc.Z; VERTEX_FORMAT vb; vb.x = vLoc.X; vb.y = vLoc.Y; vb.z = vLoc.Z; Vector3 normal; Matrix3D::Rotate_Vector(mtx, pNormal[i], &normal); curVb->diffuse = 0xFF000000; #ifdef USE_BRIDGE_NORMALS curVb->nx = normal.X; curVb->ny = normal.Y; curVb->nz = normal.Z; #else normal = (normal.X) * vec + normal.Y*vecNormal + normal.Z*vecZ; normal.Normalize(); TheTerrainRenderObject->doTheLight(&vb, lightRay, &normal, NULL, 1.0f); curVb->diffuse = vb.diffuse | 0xFF000000; #endif curVb++; } return(numVertex); } //============================================================================= // W3DBridge::getModelVerticesFixed //============================================================================= /** Gets the vertex values for a section of a fixed bridge. */ //============================================================================= Int W3DBridge::getModelVerticesFixed(VertexFormatXYZNDUV1 *destination_vb, Int curVertex, const Matrix3D &mtx, MeshClass *pMesh, RefRenderObjListIterator *pLightsIterator) { if (pMesh == NULL) return(0); Vector3 vec = m_end - m_start; if (vec.Length2() < 1.0f) { vec.Normalize(); } Vector3 vecNormal(-vec.Y, vec.X, 0); vecNormal.Normalize(); Real deltaZ = m_end.Z - m_start.Z; deltaZ /= vec.Length(); Real deltaX = sqrt(1.0 - deltaZ*deltaZ); Vector3 vecZ(-deltaZ, 0, deltaX); vec /= m_length; vecNormal *= m_scale; vecZ *= m_scale; Real xOffset = -m_leftMinX; return(getModelVertices(destination_vb, curVertex, xOffset, vec, vecNormal, vecZ, m_start, mtx, pMesh, pLightsIterator)); } //============================================================================= // W3DBridge::getIndicesNVertices //============================================================================= /** Gets the index values and vertex values for a bridge. */ //============================================================================= void W3DBridge::getIndicesNVertices(UnsignedShort *destination_ib, VertexFormatXYZNDUV1 *destination_vb, Int *curIndexP, Int *curVertexP, RefRenderObjListIterator *pLightsIterator) { Int numI; Int numV; m_firstVertex = *curVertexP; m_firstIndex = *curIndexP; m_numVertex = 0; m_numPolygons = 0; if (m_sectionMesh == NULL) { numV = getModelVerticesFixed(destination_vb, *curVertexP, m_leftMtx, m_leftMesh, pLightsIterator); numI = getModelIndices( destination_ib, *curIndexP, *curVertexP, m_leftMesh); *curIndexP += numI; *curVertexP += numV; m_numVertex += numV; m_numPolygons += numI/3; return; } Vector3 vec = m_end - m_start; if (vec.Length2() < 1.0f) { vec.Normalize(); } Vector3 vecNormal(-vec.Y, vec.X, 0); vecNormal.Normalize(); vecNormal *= m_scale; // Rotate along the y axis to get the appropriate Z height adjustment. Real deltaZ = m_end.Z - m_start.Z; Real desiredLength = vec.Length(); deltaZ /= desiredLength; Real deltaX = sqrt(1.0 - deltaZ*deltaZ); Vector3 vecZ(-deltaZ, 0, deltaX); vecZ *= m_scale; Real spanLength = m_rightMinX - m_leftMaxX; Int numSpans = 1; if (m_bridgeType != FIXED_BRIDGE) { Real spannable = desiredLength - (m_length-spanLength); numSpans = REAL_TO_INT_FLOOR( (spannable + spanLength/2)/spanLength); if (numSpans<0) numSpans = 0; } Real bridgeLength = m_length + (numSpans-1)*spanLength; Real xOffset = -m_leftMinX; // Draw the left end. vec /= bridgeLength; numV = getModelVertices(destination_vb, *curVertexP, xOffset, vec, vecNormal, vecZ, m_start, m_leftMtx, m_leftMesh, pLightsIterator); numI = getModelIndices( destination_ib, *curIndexP, *curVertexP, m_leftMesh); *curIndexP += numI; *curVertexP += numV; m_numVertex += numV; m_numPolygons += numI/3; Int i; // draw the spans. for (i=0; iPeek_Model()->Get_Polygon_Count(); const Vector3i *pPoly =pMesh->Peek_Model()->Get_Polygon_Array(); if (curIndex+3*numPoly+6 >= W3DBridgeBuffer::MAX_BRIDGE_INDEX) { return(0); } UnsignedShort *curIb = destination_ib+curIndex; Int i; for (i=0; iSet_Shininess(0.0); m_vertexMaterial->Set_Ambient(1,1,1); m_vertexMaterial->Set_Diffuse(1,1,1); m_vertexMaterial->Set_Specular(0,0,0); m_vertexMaterial->Set_Emissive(0,0,0); m_vertexMaterial->Set_Opacity(1); m_vertexMaterial->Set_Lighting(true); m_vertexMaterial->Set_Diffuse_Color_Source(VertexMaterialClass::COLOR1); #endif m_curNumBridgeVertices=0; m_curNumBridgeIndices=0; } //============================================================================= // W3DBridgeBuffer::clearAllBridges //============================================================================= /** Removes all bridges. */ //============================================================================= void W3DBridgeBuffer::clearAllBridges(void) { Int curBridge; for (curBridge=0; curBridgegetNext()) { if (pMapObj->getFlag(FLAG_BRIDGE_POINT1)) { pMapObj2 = pMapObj->getNext(); if ( !pMapObj2 || !pMapObj2->getFlag(FLAG_BRIDGE_POINT2)) { DEBUG_LOG(("Missing second bridge point. Ignoring first.\n")); } if (pMapObj2==NULL) break; if (!pMapObj2->getFlag(FLAG_BRIDGE_POINT2)) continue; Vector3 from, to; from.Set(pMapObj->getLocation()->x, pMapObj->getLocation()->y, 0); from.Z = TheTerrainRenderObject->getHeightMapHeight(from.X, from.Y, NULL) + BRIDGE_FLOAT_AMT; to.Set(pMapObj2->getLocation()->x, pMapObj2->getLocation()->y, 0); to.Z = TheTerrainRenderObject->getHeightMapHeight(to.X, to.Y, NULL) + BRIDGE_FLOAT_AMT; addBridge(from, to, pMapObj->getName(), pTerrainLogic, pMapObj->getProperties()); pMapObj = pMapObj2; } } if (pTerrainLogic) { pTerrainLogic->updateBridgeDamageStates(); } } //============================================================================= //============================================================================= static RenderObjClass* createTower( SimpleSceneClass *scene, W3DAssetManager *assetManager, MapObject *mapObject, BridgeTowerType type, BridgeInfo *bridgeInfo ) { RenderObjClass* tower = NULL; // sanity if( scene == NULL || assetManager == NULL || mapObject == NULL || bridgeInfo == NULL || type < 0 || type >= BRIDGE_MAX_TOWERS ) return NULL; // get template for this bridge DEBUG_ASSERTCRASH( TheTerrainRoads, ("createTower: TheTerrainRoads is NULL\n") ); TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( mapObject->getName() ); if( bridgeTemplate == NULL ) return NULL; // given the type of tower (corner position) find the appropriate spot to put the tower Coord3D towerPos; switch( type ) { case BRIDGE_TOWER_FROM_LEFT: towerPos = bridgeInfo->fromLeft; break; case BRIDGE_TOWER_FROM_RIGHT: towerPos = bridgeInfo->fromRight; break; case BRIDGE_TOWER_TO_LEFT: towerPos = bridgeInfo->toLeft; break; case BRIDGE_TOWER_TO_RIGHT: towerPos = bridgeInfo->toRight; break; default: return NULL; } // end switch // set the Z position to that of the terrain towerPos.z = TheTerrainRenderObject->getHeightMapHeight( towerPos.x, towerPos.y, NULL); // find the thing template for the tower we want to construct AsciiString towerTemplateName = bridgeTemplate->getTowerObjectName( type ); DEBUG_ASSERTCRASH( TheThingFactory, ("createTower: TheThingFactory is NULL\n") ); const ThingTemplate *towerTemplate = TheThingFactory->findTemplate( towerTemplateName ); if( towerTemplate == NULL ) return NULL; // find the name of the render object to show const ModuleInfo& mi = towerTemplate->getDrawModuleInfo( ); if( mi.getCount() <= 0 ) return NULL; const ModuleData* mdd = mi.getNthData(0); const W3DModelDrawModuleData* md = mdd ? mdd->getAsW3DModelDrawModuleData() : NULL; if( md == NULL ) return NULL; ModelConditionFlags state; state.clear(); AsciiString modelName = md->getBestModelNameForWB( state ); // create the render object Int playerColor = 0xFFFFFF; tower = assetManager->Create_Render_Obj( modelName.str(), 1.0f, playerColor ); // tie the render object into the map object mapObject->setBridgeRenderObject( type, tower ); // set the position of the tower render object to the position in the world Matrix3D transform; transform.Make_Identity(); transform.Set_X_Translation( towerPos.x ); transform.Set_Y_Translation( towerPos.y ); transform.Set_Z_Translation( towerPos.z ); tower->Set_Transform( transform ); // set the angle for the tower /// @todo --> write me // add tower render object to the scene scene->Add_Render_Object( tower ); // return the render object of the tower created return tower; } //============================================================================= //============================================================================= static void updateTowerPos( RenderObjClass* tower, BridgeTowerType type, BridgeInfo* bridgeInfo ) { // sanity if( tower == NULL || type < 0 || type >= BRIDGE_MAX_TOWERS || bridgeInfo == NULL ) return; // // compute the angle of the bridge ... we consider the angle of the bridge to be // from 'from' to 'to' in the bridge info ... and so does the game // Coord2D v; v.x = bridgeInfo->toLeft.x - bridgeInfo->fromLeft.x; v.y = bridgeInfo->toLeft.y - bridgeInfo->fromLeft.y; Real angle = v.toAngle(); // // given the type of tower (corner position) find the appropriate spot to put the tower // NOTE that we're also adjusting the angle for the from side to point the // opposite way the "bridge is pointing" // Coord3D towerPos; switch( type ) { case BRIDGE_TOWER_FROM_LEFT: towerPos = bridgeInfo->fromLeft; angle += PI; break; case BRIDGE_TOWER_FROM_RIGHT: towerPos = bridgeInfo->fromRight; angle += PI; break; case BRIDGE_TOWER_TO_LEFT: towerPos = bridgeInfo->toLeft; break; case BRIDGE_TOWER_TO_RIGHT: towerPos = bridgeInfo->toRight; break; default: return; } // end switch // set the position of the tower render object to the position in the world Matrix3D transform; transform.Make_Identity(); transform.Set_X_Translation( towerPos.x ); transform.Set_Y_Translation( towerPos.y ); transform.Set_Z_Translation( towerPos.z ); transform.Rotate_Z( angle ); tower->Set_Transform( transform ); // set the angle for the tower // tower->setAngle( angle ); } //============================================================================= // W3DBridgeBuffer::worldBuilderUpdateBridgeTowers //============================================================================= /** loadBridges. When loaded, tell the terrain logic where the bridge is. */ //============================================================================= void W3DBridgeBuffer::worldBuilderUpdateBridgeTowers( W3DAssetManager *assetManager, SimpleSceneClass *scene ) { MapObject *pMapObj; MapObject *pMapObj2; for( pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext() ) { if( pMapObj->getFlag( FLAG_BRIDGE_POINT1 ) ) { pMapObj2 = pMapObj->getNext(); if( !pMapObj2 || !pMapObj2->getFlag( FLAG_BRIDGE_POINT2 ) ) DEBUG_LOG(("Missing second bridge point. Ignoring first.\n")); if( pMapObj2 == NULL ) break; if( !pMapObj2->getFlag( FLAG_BRIDGE_POINT2 ) ) continue; // // now that we've got the two map objects that are bridge point 1 and 2, get the // bridge info that has been stored // for( Int i = 0; i < m_numBridges; ++i ) { // // find the bridge with the matching name and position ... note we're just matching // (x,y) here cause name and location (without the additional complication of Z) is // really all we have to match bridges. /// @todo integrate the editor with the game ... will never happen tho ... // if( m_bridges[ i ].getTemplateName() == pMapObj->getName() && m_bridges[ i ].getStart()->X == pMapObj->getLocation()->x && m_bridges[ i ].getStart()->Y == pMapObj->getLocation()->y && m_bridges[ i ].getEnd()->X == pMapObj2->getLocation()->x && m_bridges[ i ].getEnd()->Y == pMapObj2->getLocation()->y ) { RenderObjClass *towerRenderObj; // get the bridge info BridgeInfo bridgeInfo; m_bridges[ i ].getBridgeInfo( &bridgeInfo ); // go through all bridge tower render objects Bool created; for( Int j = 0; j < BRIDGE_MAX_TOWERS; ++j ) { // create render object if needed created = FALSE; towerRenderObj = pMapObj->getBridgeRenderObject( (BridgeTowerType)j ); if( towerRenderObj == NULL ) { towerRenderObj = createTower( scene, assetManager, pMapObj, (BridgeTowerType)j, &bridgeInfo ); created = TRUE; } // end if // sanity DEBUG_ASSERTCRASH( towerRenderObj != NULL, ("worldBuilderUpdateBridgeTowers: unable to create tower for bridge '%s'\n", m_bridges[ i ].getTemplateName().str()) ); // update the position of the towers updateTowerPos( towerRenderObj, (BridgeTowerType)j, &bridgeInfo ); // release the initial ref count of 1 for a newly created tower if( created ) REF_PTR_RELEASE( towerRenderObj ); } // end for j } // end if } // end for i // skip the 2nd map object representing the second half of the bridgef pMapObj = pMapObj2; } } } //============================================================================= // W3DBridgeBuffer::addBridge //============================================================================= /** Adds a bridge. Name is the GDF object name. */ //============================================================================= void W3DBridgeBuffer::addBridge(Vector3 fromLoc, Vector3 toLoc, AsciiString name, W3DTerrainLogic *pTerrainLogic, Dict *props) { if (m_numBridges >= MAX_BRIDGES) { return; } if (!m_initialized) { return; } m_bridges[m_numBridges].init(fromLoc, toLoc, name); if (m_bridges[m_numBridges].load(BODY_PRISTINE)) { W3DBridge *pBridge = m_bridges+m_numBridges; if (pTerrainLogic) { BridgeInfo info; pBridge->getBridgeInfo(&info); info.bridgeIndex = m_numBridges; pTerrainLogic->addBridgeToLogic(&info, props, name); } m_numBridges++; } } //============================================================================= // W3DBridgeBuffer::updateCenter //============================================================================= /** Updates the drawing buffer, based on the camera position. */ //============================================================================= void W3DBridgeBuffer::updateCenter(CameraClass *camera, RefRenderObjListIterator *pLightsIterator) { cull(camera); if (m_anythingChanged || m_curNumBridgeIndices == 0) { loadBridgesInVertexAndIndexBuffers(pLightsIterator); } m_updateVis = false; } //============================================================================= // W3DBridgeBuffer::drawBridges //============================================================================= /** Draws the bridges. */ //============================================================================= void W3DBridgeBuffer::drawBridges(CameraClass * camera, Bool wireframe, TextureClass *cloudTexture) { Int curBridge; if (TheTerrainLogic) { for (curBridge=0; curBridgegetFirstBridge(); bridge; bridge = bridge->getNext()) { BridgeInfo info; bridge->getBridgeInfo(&info); if (info.bridgeIndex<0 || info.bridgeIndex>=m_numBridges) { continue; } m_bridges[info.bridgeIndex].setEnabled(true); if (m_bridges[info.bridgeIndex].getDamageState() != info.curDamageState) { changed = true; enum BodyDamageType curState = m_bridges[info.bridgeIndex].getDamageState(); m_bridges[info.bridgeIndex].setDamageState(info.curDamageState); if (!m_bridges[info.bridgeIndex].load(info.curDamageState)) { // put the old model back. m_bridges[info.bridgeIndex].load(curState); m_bridges[info.bridgeIndex].setDamageState(info.curDamageState); } } } if (changed) { loadBridgesInVertexAndIndexBuffers(NULL); } } else { // In wb, all are enabled. for (curBridge=0; curBridgegetShroud()) { //Reset to a known shader. DX8Wrapper::Invalidate_Cached_Render_States(); DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); DX8Wrapper::Set_Material(m_vertexMaterial); DX8Wrapper::Set_Index_Buffer(m_indexBridge,0); DX8Wrapper::Set_Vertex_Buffer(m_vertexBridge); DX8Wrapper::Apply_Render_State_Changes(); //Apply custom shroud projection shader. W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0); for (curBridge=0; curBridge