/* ** Command & Conquer Generals Zero Hour(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. // // // //////////////////////////////////////////////////////////////////////////////// #include "W3DDevice/GameClient/W3DStatusCircle.h" #include #include #include #include #include #include #include #include #include #include #include "WW3D2/DX8Wrapper.h" #include "WW3D2/Shader.h" #include "Common/GlobalData.h" #include "common/MapObject.h" #include "GameLogic/GameLogic.h" #include "GameLogic/ScriptEngine.h" #define SC_DETAIL_BLEND ( 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::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) ) // Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending #define SC_ALPHA ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, 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_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) // Texturing, no zbuffer, disabled zbuffer write, primary gradient, alpha blending #define SC_ALPHA_Z ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, 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::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) // Texturing, no zbuffer, disabled zbuffer write, no gradient, add src to dest. #define SC_ADD ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \ ShaderClass::DSTBLEND_ONE, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \ ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) #define VERTEX_BUFFER_TILE_LENGTH 32 //tiles of side length 32 (grid of 33x33 vertices). #define VERTS_IN_BLOCK_ROW (VERTEX_BUFFER_TILE_LENGTH+1) static ShaderClass detailOpaqueShader(SC_ALPHA); Bool W3DStatusCircle::m_needUpdate; Int W3DStatusCircle::m_diffuse=255; // blue. W3DStatusCircle::~W3DStatusCircle(void) { freeMapResources(); } W3DStatusCircle::W3DStatusCircle(void) { m_indexBuffer=NULL; m_vertexMaterialClass=NULL; m_vertexBufferCircle=NULL; m_vertexBufferScreen=NULL; } bool W3DStatusCircle::Cast_Ray(RayCollisionTestClass & raytest) { return false; } //@todo: MW Handle both of these properly!! W3DStatusCircle::W3DStatusCircle(const W3DStatusCircle & src) { *this = src; } W3DStatusCircle & W3DStatusCircle::operator = (const W3DStatusCircle & that) { assert(false); return *this; } void W3DStatusCircle::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const { Vector3 ObjSpaceCenter((float)1000*0.5f,(float)1000*0.5f,(float)0); float length = ObjSpaceCenter.Length(); sphere.Init(ObjSpaceCenter, length); } void W3DStatusCircle::Get_Obj_Space_Bounding_Box(AABoxClass & box) const { Vector3 minPt(0,0,0); Vector3 maxPt((float)1000,(float)1000,(float)1000); box.Init(minPt,maxPt); } Int W3DStatusCircle::Class_ID(void) const { return RenderObjClass::CLASSID_UNKNOWN; } RenderObjClass * W3DStatusCircle::Clone(void) const { return NEW W3DStatusCircle(*this); } Int W3DStatusCircle::freeMapResources(void) { REF_PTR_RELEASE(m_indexBuffer); REF_PTR_RELEASE(m_vertexBufferScreen); REF_PTR_RELEASE(m_vertexBufferCircle); REF_PTR_RELEASE(m_vertexMaterialClass); return 0; } #define NUM_TRI 20 //Allocate a heightmap of x by y vertices. //data must be an array matching this size. Int W3DStatusCircle::initData(void) { Int i; m_needUpdate = true; freeMapResources(); //free old data and ib/vb m_numTriangles = NUM_TRI; m_indexBuffer=NEW_REF(DX8IndexBufferClass,(m_numTriangles*3)); // Fill up the IB DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer); UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); for (i=0; i<3*m_numTriangles; i+=3) { ib[0]=i; ib[1]=i+1; ib[2]=i+2; ib+=3; //skip the 3 indices we just filled } m_vertexBufferCircle=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_numTriangles*3,DX8VertexBufferClass::USAGE_DEFAULT)); m_vertexBufferScreen=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,2*3,DX8VertexBufferClass::USAGE_DEFAULT)); //go with a preset material for now. m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); m_shaderClass = ShaderClass::ShaderClass(SC_ALPHA);// _PresetOpaque2DShader;//; //_PresetOpaqueShader; return 0; } /** updateCircleVB puts a circle with a team color vertex buffer. */ Int W3DStatusCircle::updateCircleVB(void) { Int i, k; Real shade; DX8VertexBufferClass *pVB = m_vertexBufferCircle; if (m_vertexBufferCircle ) { m_needUpdate = false; DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); const Real theZ = 0.0f; const Real theRadius = 0.02f; const Int theAlpha = 127; Int diffuse = m_diffuse + (theAlpha<<24); // b g<<8 r<<16 a<<24. Int limit = m_numTriangles; float curAngle = 0; float deltaAngle = 2*PI/limit; for (i=0; iz= theZ; if (k==0) { vb->x= 0; vb->y= 0; } else if (k==1) { Vector3 vec(theRadius,0,theZ); vec.Rotate_Z(curAngle); vb->x= vec.X; vb->y= vec.Y; } else if (k==2) { Real angle = curAngle+deltaAngle; if (i==limit-1) { angle = 0; } Vector3 vec(theRadius,0,theZ); vec.Rotate_Z(angle); vb->x= vec.X; vb->y= vec.Y; } vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; } curAngle += deltaAngle; } return 0; //success. } return -1; } /** updateCircleVB puts a circle with a team color vertex buffer. */ Int W3DStatusCircle::updateScreenVB(Int diffuse) { DX8VertexBufferClass *pVB = m_vertexBufferScreen; if (m_vertexBufferScreen ) { m_needUpdate = false; DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB); VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array(); vb->x = -1; vb->y = -1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; vb->x = 1; vb->y = 1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; vb->x = -1; vb->y = 1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; vb->x = -1; vb->y = -1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; vb->x = 1; vb->y = -1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; vb->x = 1; vb->y = 1; vb->z = 0; vb->diffuse = diffuse; vb->u1=0; vb->v1=0; vb++; return 0; //success. } return -1; } void W3DStatusCircle::Render(RenderInfoClass & rinfo) { if (!TheGameLogic->isInGame() || TheGameLogic->getGameMode() == GAME_SHELL) return; if (m_indexBuffer == NULL) { initData(); } if (m_indexBuffer == NULL) { return; } Bool setIndex = false; Matrix3D tm(true); if( TheGlobalData->m_showTeamDot ) { if (m_needUpdate) { updateCircleVB(); } //Apply the shader and material DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); DX8Wrapper::Set_Texture(0, NULL); DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferCircle); setIndex = true; Vector3 vec(0.95f, 0.67f, 0); Matrix3x3 rot(true); tm.Set_Translation(vec); DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); DX8Wrapper::Draw_Triangles( 0,NUM_TRI, 0, (m_numTriangles*3)); } ScriptEngine::TFade fade = TheScriptEngine->getFade(); if (fade == ScriptEngine::FADE_NONE) { return; } if (!setIndex) { DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); DX8Wrapper::Set_Texture(0, NULL); } tm.Make_Identity(); Real intensity = TheScriptEngine->getFadeValue(); Int clr = 255*intensity; Int diffuse = (0xff<<24)|(clr<<16)|(clr<<8)|clr; // b g<<8 r<<16 a<<24. updateScreenVB(diffuse); DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); DX8Wrapper::Set_Shader(ShaderClass(SC_ADD)); DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferScreen); DX8Wrapper::Apply_Render_State_Changes(); switch (fade) { default: case ScriptEngine::FADE_ADD: DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3)); break; case ScriptEngine::FADE_SUBTRACT: DX8Wrapper::Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT ); DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3)); DX8Wrapper::Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD ); break; case ScriptEngine::FADE_SATURATE: // 4x multiply DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR); DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR); DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3)); DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3)); break; case ScriptEngine::FADE_MULTIPLY: // Straight multiply DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_ZERO); DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR); DX8Wrapper::Draw_Triangles( 0,2, 0, (2*3)); break; } ShaderClass::Invalidate(); }