/* ** Command & Conquer Renegade(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 O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *************************************************************************** * * * Project Name : G * * * * $Archive:: /VSS_Sync/ww3d2/pointgr.cpp $* * * * $Author:: Vss_sync $* * * * $Modtime:: 9/12/01 10:01p $* * * * $Revision:: 38 $* * * *-------------------------------------------------------------------------* * Functions: * * PointGroupClass::PointGroupClass -- PointGroupClass CTor. * * PointGroupClass::~PointGroupClass -- PointGroupClass DTor. * * PointGroupClass::operator = -- PointGroupClass assignment operator. * * PointGroupClass::Set_Arrays -- Set point location/color/enable arrays.* * PointGroupClass::Set_Point_Size -- Set default point size. * * PointGroupClass::Get_Point_Size -- Get default point size. * * PointGroupClass::Set_Point_Color -- Set default point color. * * PointGroupClass::Get_Point_Color -- Get default point color. * * PointGroupClass::Set_Point_Alpha -- Set default point alpha. * * PointGroupClass::Get_Point_Alpha -- Get default point alpha. * * PointGroupClass::Set_Point_Orientation -- Set default point orientatio* * PointGroupClass::Get_Point_Orientation -- Get default point orientatio* * PointGroupClass::Set_Point_Frame -- Set default point frame. * * PointGroupClass::Get_Point_Frame -- Get default point frame. * * PointGroupClass::Set_Point_Mode -- Set point rendering method. * * PointGroupClass::Get_Point_Mode -- Get point rendering method. * * PointGroupClass::Set_Flag -- Set given flag to on or off. * * PointGroupClass::Get_Flag -- Get current value (on/off) of given flag.* * PointGroupClass::Set_Texture -- Set texture used. * * PointGroupClass::Get_Texture -- Get texture used. * * PointGroupClass::Set_Shader -- Set shader used. * * PointGroupClass::Get_Shader -- Get shader used. * * PointGroupClass::Get_Discrete_Orientation_Count_Log2 -- what it says * * PointGroupClass::Set_Discrete_Orientation_Count_Log2 -- what it says. * * PointGroupClass::Get_Frame_Row_Column_Count_Log2 -- what it says * * PointGroupClass::Set_Frame_Row_Column_Count_Log2 -- what it says. * * PointGroupClass::Get_Polygon_Count -- Get estimated polygon count. * * PointGroupClass::Render -- draw point group. * * PointGroupClass::vInstance -- Create instance of class. * * PointGroupClass::sGetClassName -- Get name of class. * * PointGroupClass::Update_Arrays -- Update all arrays used in rendering * * PointGroupClass::Peek_Texture -- Peeks texture * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "pointgr.h" #include "vertmaterial.h" #include "ww3d.h" #include "aabox.h" #include "statistics.h" #include "simplevec.h" #include "texture.h" #include "vector.h" #include "vp.h" #include "matrix4.h" #include "dx8wrapper.h" #include "dx8vertexbuffer.h" #include "dx8indexbuffer.h" #include "rinfo.h" #include "camera.h" #include "dx8fvf.h" #include "sortingrenderer.h" // Upgraded to DX8 2/2/01 HY // static data members Vector3 PointGroupClass::_TriVertexLocationOrientationTable[256][3]; Vector3 PointGroupClass::_QuadVertexLocationOrientationTable[256][4]; Vector2 *PointGroupClass::_TriVertexUVFrameTable[5] = { NULL, NULL, NULL, NULL, NULL}; Vector2 *PointGroupClass::_QuadVertexUVFrameTable[5] = { NULL, NULL, NULL, NULL, NULL}; VertexMaterialClass *PointGroupClass::PointMaterial=NULL; // This array has vertex locations for screenspace mode - calculated to cover exactly 1x1 and 2x2 pixels. Vector3 PointGroupClass::_ScreenspaceVertexLocationSizeTable[2][3] = { Vector3(0.5f, 0.0f, -1.0f), Vector3(1.0f, 1.0f, -1.0f), Vector3(0.0f, 1.0f, -1.0f), Vector3(1.0f, -0.5f, -1.0f), Vector3(2.7f, 2.0f, -1.0f), Vector3(-0.7f, 2.0f, -1.0f) }; // Some internal variables VectorClass VertexLoc; // camera-space vertex locations VectorClass VertexDiffuse; // vertex diffuse/alpha colors VectorClass VertexUV; // vertex texture coords // Some DX 8 variables #define MAX_VB_SIZE 1200 #define MAX_TRI_POINTS MAX_VB_SIZE/3 #define MAX_TRI_IB_SIZE 3*MAX_TRI_POINTS #define MAX_QUAD_POINTS MAX_VB_SIZE/4 #define MAX_QUAD_IB_SIZE 6*MAX_QUAD_POINTS DX8IndexBufferClass *Tris, *Quads; // Index buffers. SortingIndexBufferClass *SortingTris, *SortingQuads; // Sorting index buffers. /************************************************************************** * PointGroupClass::PointGroupClass -- PointGroupClass CTor. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ PointGroupClass::PointGroupClass(void) : PointLoc(NULL), PointDiffuse(NULL), APT(NULL), PointSize(NULL), PointOrientation(NULL), PointFrame(NULL), PointCount(0), FrameRowColumnCountLog2(0), Texture(NULL), Flags(0), Shader(ShaderClass::_PresetAdditiveSpriteShader), PointMode(TRIS), DefaultPointSize(0.0f), DefaultPointColor(1.0f, 1.0f, 1.0f), DefaultPointAlpha(1.0f), DefaultPointOrientation(0), DefaultPointFrame(0), VPXMin(0.0f), VPYMin(0.0f), VPXMax(0.0f), VPYMax(0.0f) { } /************************************************************************** * PointGroupClass::~PointGroupClass -- PointGroupClass DTor. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ PointGroupClass::~PointGroupClass(void) { if (PointLoc) { PointLoc->Release_Ref(); PointLoc = NULL; } if (PointDiffuse) { PointDiffuse->Release_Ref(); PointDiffuse=NULL; } if (APT) { APT->Release_Ref(); APT = NULL; } if (PointSize) { PointSize->Release_Ref(); PointSize = NULL; } if (PointOrientation) { PointOrientation->Release_Ref(); PointOrientation = NULL; } if (PointFrame) { PointFrame->Release_Ref(); PointFrame = NULL; } if (Texture) { REF_PTR_RELEASE(Texture); Texture = NULL; } } /************************************************************************** * PointGroupClass::operator = -- PointGroupClass assignment operator. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ PointGroupClass & PointGroupClass::operator = (const PointGroupClass & that) { if (this != &that) { WWASSERT(0); // If you hit this assert implement the function! } return *this; } /************************************************************************** * PointGroupClass::Set_Arrays -- Set point location/color/enable arrays. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * NOTES: colors, alphas, APT, sizes, orientations and frames are * * optional. active_point_count can also be used with a NULL apt.* * In this case active_point_count is ignored if it is -1 * * (default value) and otherwise it indicates the first N active * * points in the arrays. * * The view plane rectangle may optionally be passed as well - * * this is only used in SCREENSPACE mode. * * * * HISTORY: * * 11/17/1998 NH : Created. * * 08/25/1999 NH : Alphas added. * * 06/28/2000 NH : Orientations and frames added. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ void PointGroupClass::Set_Arrays( ShareBufferClass *locs, ShareBufferClass *diffuse, ShareBufferClass *apt, ShareBufferClass *sizes, ShareBufferClass *orientations, ShareBufferClass *frames, int active_point_count, float vpxmin, float vpymin, float vpxmax, float vpymax) { // The point locations array is NOT optional! WWASSERT(locs); // Ensure lengths of all arrays are the same: WWASSERT(!diffuse || locs->Get_Count() == diffuse->Get_Count()); WWASSERT(!apt || locs->Get_Count() == apt->Get_Count()); WWASSERT(!sizes || locs->Get_Count() == sizes->Get_Count()); WWASSERT(!orientations || locs->Get_Count() == orientations->Get_Count()); WWASSERT(!frames || locs->Get_Count() == frames->Get_Count()); REF_PTR_SET(PointLoc,locs); REF_PTR_SET(PointDiffuse,diffuse); REF_PTR_SET(APT,apt); REF_PTR_SET(PointSize,sizes); REF_PTR_SET(PointOrientation,orientations); REF_PTR_SET(PointFrame,frames); if (APT) { PointCount = active_point_count; } else { PointCount = (active_point_count >= 0) ? active_point_count : PointLoc->Get_Count(); } // Store view plane rectangle (only used in SCREENSPACE mode) VPXMin = vpxmin; VPYMin = vpymin; VPXMax = vpxmax; VPYMax = vpymax; } /************************************************************************** * PointGroupClass::Set_Point_Size -- Set default point size. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This size is ignored if a size array is present. * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Size(float size) { DefaultPointSize = size; } /************************************************************************** * PointGroupClass::Get_Point_Size -- Get default point size. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This size is ignored if a size array is present. * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ float PointGroupClass::Get_Point_Size(void) { return DefaultPointSize; } /************************************************************************** * PointGroupClass::Set_Point_Color -- Set default point color. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This color is ignored if a color array is present. * * * * HISTORY: * * 04/20/1999 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Color(Vector3 color) { DefaultPointColor = color; } /************************************************************************** * PointGroupClass::Get_Point_Color -- Get default point color. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This color is ignored if a color array is present. * * * * HISTORY: * * 04/20/1999 NH : Created. * *========================================================================*/ Vector3 PointGroupClass::Get_Point_Color(void) { return DefaultPointColor; } /************************************************************************** * PointGroupClass::Set_Point_Alpha -- Set default point alpha. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This alpha is ignored if an alpha array is present. * * * * HISTORY: * * 08/25/1999 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Alpha(float alpha) { DefaultPointAlpha = alpha; } /************************************************************************** * PointGroupClass::Get_Point_Alpha -- Get default point alpha. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This alpha is ignored if an alpha array is present. * * * * HISTORY: * * 08/25/1999 NH : Created. * *========================================================================*/ float PointGroupClass::Get_Point_Alpha(void) { return DefaultPointAlpha; } /************************************************************************** * PointGroupClass::Set_Point_Orientation -- Set default point orientation* * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This is ignored if an orientation array is present. * * * * NOTE: No need to ensure value in valid range - it will be masked later.* * * * HISTORY: * * 06/28/2000 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Orientation(unsigned char orientation) { DefaultPointOrientation = orientation; } /************************************************************************** * PointGroupClass::Get_Point_Orientation -- Get default point orientation* * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This is ignored if an orientation array is present. * * * * HISTORY: * * 06/28/2000 NH : Created. * *========================================================================*/ unsigned char PointGroupClass::Get_Point_Orientation(void) { return DefaultPointOrientation; } /************************************************************************** * PointGroupClass::Set_Point_Frame -- Set default point frame. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This frame is ignored if an frame array is present. * * * * NOTE: No need to ensure value in valid range - it will be masked later.* * * * HISTORY: * * 06/28/2000 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Frame(unsigned char frame) { DefaultPointFrame = frame; } /************************************************************************** * PointGroupClass::Get_Point_Frame -- Get default point frame. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: This frame is ignored if an frame array is present. * * * * HISTORY: * * 06/28/2000 NH : Created. * *========================================================================*/ unsigned char PointGroupClass::Get_Point_Frame(void) { return DefaultPointFrame; } /************************************************************************** * PointGroupClass::Set_Point_Mode -- Set point rendering method. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Point_Mode(PointModeEnum mode) { PointMode = mode; } /************************************************************************** * PointGroupClass::Get_Point_Mode -- Get point rendering method. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ PointGroupClass::PointModeEnum PointGroupClass::Get_Point_Mode(void) { return PointMode; } /************************************************************************** * Set_Flag -- PointGroupClass::Set given flag to on or off. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * *========================================================================*/ void PointGroupClass::Set_Flag(FlagsType flag, bool onoff) { if (onoff) Flags|=1<>flag) & 0x1; } /************************************************************************** * PointGroupClass::Set_Texture -- Set texture used. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ void PointGroupClass::Set_Texture(TextureClass* texture) { REF_PTR_SET(Texture,texture); } /************************************************************************** * PointGroupClass::Get_Texture -- Get texture used. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ TextureClass * PointGroupClass::Get_Texture(void) { if (Texture) Texture->Add_Ref(); return Texture; } /*********************************************************************************************** * PointGroupClass::Peek_Texture -- Peeks texture * * * * * * * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/12/2001 hy : Created. * *=============================================================================================*/ TextureClass * PointGroupClass::Peek_Texture(void) { return Texture; } /************************************************************************** * PointGroupClass::Set_Shader -- Set shader used. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: the primary gradient will be set to MODULATE/DISABLE in * * the shader depending on whether a color or alpha array was * * passed in Set_Point_Arrays. also, texturing will be * * enabled or disabled dependent on whether a non-NULL * * texture was set. * * these will override the primary gradient/texturing * * settings in the given shader. * * * * HISTORY: * * 11/17/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ void PointGroupClass::Set_Shader(ShaderClass shader) { Shader = shader; } /************************************************************************** * PointGroupClass::Get_Shader -- Get shader used. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/17/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ ShaderClass PointGroupClass::Get_Shader(void) { return Shader; } /************************************************************************** * PointGroupClass::Get_Frame_Row_Column_Count_Log2 -- what it says * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 06/28/2000 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ unsigned char PointGroupClass::Get_Frame_Row_Column_Count_Log2(void) { return FrameRowColumnCountLog2; } /************************************************************************** * PointGroupClass::Set_Frame_Row_Column_Count_Log2 -- what it says. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 06/28/2000 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ void PointGroupClass::Set_Frame_Row_Column_Count_Log2(unsigned char frccl2) { FrameRowColumnCountLog2 = MIN(frccl2, 4); } /************************************************************************** * PointGroupClass::Get_Polygon_Count -- Get estimated polygon count. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 11/18/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ int PointGroupClass::Get_Polygon_Count(void) { switch (PointMode) { case TRIS: case SCREENSPACE: return PointCount; break; case QUADS: return PointCount * 2; break; } WWASSERT(0); return 0; } /************************************************************************** * PointGroupClass::Render -- draw point group. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/10/1998 NH : Created. * * 02/08/2001 HY : Upgraded to DX8 * *========================================================================*/ static SimpleVecClass remap; void PointGroupClass::Render(RenderInfoClass &rinfo) { // NB: the winding for pointgroups is wrong, but we // are disabling culling for particles anyway Shader.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); // If no points, do nothing: if (PointCount == 0) return; WWASSERT(PointLoc && PointLoc->Get_Array()); // Process texture reductions: // if (Texture) Texture->Process_Reduction(); // Static arrays for intermediate calcs (never resized down, just up): static VectorClass compressed_loc; // point locations 'compressed' by APT static VectorClass compressed_diffuse; // point colors 'compressed' by APT static VectorClass compressed_size; // point sizes 'compressed' by APT static VectorClass compressed_orient; // point orientations 'compressed' by APT static VectorClass compressed_frame; // point frames 'compressed' by APT static VectorClass transformed_loc; // transformed point locations // Pointers which point into existing buffers (member or static): Vector3 *current_loc = NULL; Vector4 *current_diffuse = NULL; float *current_size = NULL; unsigned char *current_orient = NULL; unsigned char *current_frame = NULL; // If there is a color or alpha array enable gradient in shader - otherwise disable. float value_255 = 0.9961f; //254 / 255 bool default_white_opaque = ( DefaultPointColor.X > value_255 && DefaultPointColor.Y > value_255 && DefaultPointColor.Z > value_255 && DefaultPointAlpha > value_255); // The reason we check for lack of texture here is that SR seems to render black triangles // rather than white triangles as would be expected) when there is no texture AND no gradient. if (PointDiffuse || !default_white_opaque || !Texture) { Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE); } else { Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_DISABLE); } // If Texture is non-NULL enable texturing in shader - otherwise disable. if (Texture) { Shader.Set_Texturing(ShaderClass::TEXTURING_ENABLE); } else { Shader.Set_Texturing(ShaderClass::TEXTURING_DISABLE); } // If there is an active point table, use it to compress the point // locations/colors/alphas/sizes/orientations/frames. if (APT) { // Resize compressed result arrays if needed (2x guardband to prevent // frequent reallocations): if (compressed_loc.Length() < PointCount) { compressed_loc.Resize(PointCount * 2); } VectorProcessorClass::CopyIndexed(&compressed_loc[0], PointLoc->Get_Array(), APT->Get_Array(), PointCount); current_loc = &compressed_loc[0]; if (PointDiffuse) { if (compressed_diffuse.Length() < PointCount) { compressed_diffuse.Resize(PointCount * 2); } VectorProcessorClass::CopyIndexed(&compressed_diffuse[0], PointDiffuse->Get_Array(), APT->Get_Array(), PointCount); current_diffuse = &compressed_diffuse[0]; } if (PointSize) { if (compressed_size.Length() < PointCount) { compressed_size.Resize(PointCount * 2); } VectorProcessorClass::CopyIndexed(&compressed_size[0], PointSize->Get_Array(), APT->Get_Array(), PointCount); current_size = &compressed_size[0]; } if (PointOrientation) { if (compressed_orient.Length() < PointCount) { compressed_orient.Resize(PointCount * 2); } VectorProcessorClass::CopyIndexed(&compressed_orient[0], PointOrientation->Get_Array(), APT->Get_Array(), PointCount); current_orient = &compressed_orient[0]; } if (PointFrame) { if (compressed_frame.Length() < PointCount) { compressed_frame.Resize(PointCount * 2); } VectorProcessorClass::CopyIndexed(&compressed_frame[0], PointFrame->Get_Array(), APT->Get_Array(), PointCount); current_frame = &compressed_frame[0]; } } else { current_loc = PointLoc->Get_Array(); if (PointDiffuse) { current_diffuse = PointDiffuse->Get_Array(); } if (PointSize) { current_size = PointSize->Get_Array(); } if (PointOrientation) { current_orient = PointOrientation->Get_Array(); } if (PointFrame) { current_frame = PointFrame->Get_Array(); } } // Get the world and view matrices Matrix4 view; DX8Wrapper::Get_Transform(D3DTS_VIEW,view); // Transform the point locations from worldspace to camera space if needed // (i.e. if they are not already in camera space): if (Get_Flag(TRANSFORM)) { // Resize transformed location array if needed (2x guardband to prevent // frequent reallocations): if (transformed_loc.Length() < PointCount) { transformed_loc.Resize(PointCount * 2); } // Not using vector processor class because we are discarding w // Not using T&L in DX8 because we don't want DX8 to transform // 3 times per particle when we can do it once for (int i=0; iGet_Count(), vnum, pnum); // the locations are now in view space // so set world and view matrices to identity and render Matrix4 identity(true); DX8Wrapper::Set_Transform(D3DTS_WORLD,identity); DX8Wrapper::Set_Transform(D3DTS_VIEW,identity); DX8Wrapper::Set_Material(PointMaterial); DX8Wrapper::Set_Shader(Shader); DX8Wrapper::Set_Texture(0,Texture); // Enable sorting if the primitives are translucent and alpha testing is not enabled. const bool sort = (Shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO) && (Shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_DISABLE) && (WW3D::Is_Sorting_Enabled()); IndexBufferClass *indexbuffer; int verticesperprimitive, current, delta; if (PointMode == QUADS) { verticesperprimitive = 2; indexbuffer = sort ? static_cast (SortingQuads) : static_cast (Quads); } else { verticesperprimitive = 3; indexbuffer = sort ? static_cast (SortingTris) : static_cast (Tris); } current = 0; while (current