| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 : Linegroup.cpp *
- * *
- * $Archive:: $*
- * *
- * Original Author:: Hector Yee *
- * *
- * $Author:: Kenny Mitchell *
- * *
- * $Modtime:: 06/26/02 4:04p $*
- * *
- * $Revision:: 2 $*
- * *
- * 06/26/02 KM Matrix name change to avoid MAX conflicts *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "sharebuf.h"
- #include "linegrp.h"
- #include "texture.h"
- #include "vertmaterial.h"
- #include "dx8wrapper.h"
- #include "wwmath.h"
- #include "rinfo.h"
- #include "camera.h"
- #include "dx8indexbuffer.h"
- #include "dx8vertexbuffer.h"
- #include "sortingrenderer.h"
- // Line groups are a rendering primitive similar to point groups
- // They are tetrahedra which are aligned with the view plane with their centers
- // at StartLineLoc. The apex of the tetrahedron is at EndLineLoc.
- // They can be individually colored LineDiffuse
- // and the LineUCoord determines the U coordinate of the texture to use
- // the V coordinate is always 0 at the flat end of the tetrahedron
- // and 1 at the apex
- LineGroupClass::LineGroupClass(void) :
- StartLineLoc(NULL),
- EndLineLoc(NULL),
- LineDiffuse(NULL),
- TailDiffuse(NULL),
- ALT(NULL),
- LineSize(NULL),
- LineUCoord(NULL),
- LineCount(0),
- Texture(NULL),
- Flags(0),
- Shader(ShaderClass::_PresetAdditiveSpriteShader),
- DefaultLineSize(0.0f),
- DefaultLineColor(1.0f, 1.0f, 1.0f),
- DefaultLineAlpha(1.0f),
- DefaultLineUCoord(0.0f),
- DefaultTailDiffuse(0.0f, 0.0f, 0.0f, 0.0f),
- LineMode(TETRAHEDRON)
- {
- }
- LineGroupClass::~LineGroupClass(void)
- {
- REF_PTR_RELEASE(StartLineLoc);
- REF_PTR_RELEASE(EndLineLoc);
- REF_PTR_RELEASE(LineDiffuse);
- REF_PTR_RELEASE(TailDiffuse);
- REF_PTR_RELEASE(ALT);
- REF_PTR_RELEASE(LineSize);
- REF_PTR_RELEASE(LineUCoord);
- REF_PTR_RELEASE(Texture);
- }
- void LineGroupClass::Set_Arrays(
- ShareBufferClass<Vector3> *startlocs,
- ShareBufferClass<Vector3> *endlocs,
- ShareBufferClass<Vector4> *diffuse,
- ShareBufferClass<Vector4> *taildiffuse,
- ShareBufferClass<unsigned int> *alt,
- ShareBufferClass<float> *sizes,
- ShareBufferClass<float> *ucoords,
- int active_line_count
- )
- {
- // The Line locations arrays are NOT optional!
- WWASSERT(startlocs);
- WWASSERT(endlocs);
- // Ensure lengths of all arrays are the same:
- WWASSERT(startlocs->Get_Count() == endlocs->Get_Count());
- WWASSERT(!diffuse || startlocs->Get_Count() == diffuse->Get_Count());
- WWASSERT(!alt || startlocs->Get_Count() == alt->Get_Count());
- WWASSERT(!sizes || startlocs->Get_Count() == sizes->Get_Count());
- WWASSERT(!ucoords || startlocs->Get_Count() == ucoords->Get_Count());
- WWASSERT(!taildiffuse || startlocs->Get_Count() == taildiffuse->Get_Count());
- REF_PTR_SET(StartLineLoc,startlocs);
- REF_PTR_SET(EndLineLoc,endlocs);
- REF_PTR_SET(LineDiffuse,diffuse);
- REF_PTR_SET(TailDiffuse,taildiffuse);
- REF_PTR_SET(ALT,alt);
- REF_PTR_SET(LineSize,sizes);
- REF_PTR_SET(LineUCoord,ucoords);
- if (ALT) {
- LineCount = active_line_count;
- } else {
- LineCount = (active_line_count >= 0) ? active_line_count : StartLineLoc->Get_Count();
- }
- }
- void LineGroupClass::Set_Line_Size(float size)
- {
- DefaultLineSize = size;
- }
- float LineGroupClass::Get_Line_Size(void)
- {
- return DefaultLineSize;
- }
- void LineGroupClass::Set_Line_Color(const Vector3 &color)
- {
- DefaultLineColor = color;
- }
- Vector3 LineGroupClass::Get_Line_Color(void)
- {
- return DefaultLineColor;
- }
- void LineGroupClass::Set_Tail_Diffuse(const Vector4 &tdiffuse)
- {
- DefaultTailDiffuse = tdiffuse;
- }
- Vector4 LineGroupClass::Get_Tail_Diffuse(void)
- {
- return DefaultTailDiffuse;
- }
- void LineGroupClass::Set_Line_Alpha(float alpha)
- {
- DefaultLineAlpha = alpha;
- }
- float LineGroupClass::Get_Line_Alpha(void)
- {
- return DefaultLineAlpha;
- }
- void LineGroupClass::Set_Line_UCoord(float ucoord)
- {
- DefaultLineUCoord = ucoord;
- }
- float LineGroupClass::Get_Line_UCoord(void)
- {
- return DefaultLineUCoord;
- }
- void LineGroupClass::Set_Flag(FlagsType flag, bool on)
- {
- if (on) Flags |= 1 << flag;
- else
- Flags &= ~(1 << flag);
- }
- int LineGroupClass::Get_Flag(FlagsType flag)
- {
- return (Flags >> flag) & 0x1;
- }
- void LineGroupClass::Set_Texture(TextureClass* texture)
- {
- REF_PTR_SET(Texture,texture);
- }
- TextureClass * LineGroupClass::Get_Texture(void)
- {
- if (Texture) Texture->Add_Ref();
- return Texture;
- }
- TextureClass * LineGroupClass::Peek_Texture(void)
- {
- return Texture;
- }
- void LineGroupClass::Set_Shader(const ShaderClass &shader)
- {
- Shader = shader;
- }
- ShaderClass LineGroupClass::Get_Shader(void)
- {
- return Shader;
- }
- void LineGroupClass::Set_Line_Mode(LineModeType linemode)
- {
- LineMode = linemode;
- }
- LineGroupClass::LineModeType LineGroupClass::Get_Line_Mode(void)
- {
- return LineMode;
- }
- void LineGroupClass::Render(RenderInfoClass &rinfo)
- {
- int i;
- // If no lines, do nothing:
- if (LineCount == 0) return;
- // Shader handling
- Shader.Set_Cull_Mode(ShaderClass::CULL_MODE_ENABLE);
- // 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 = ( DefaultLineColor.X > value_255 &&
- DefaultLineColor.Y > value_255 &&
- DefaultLineColor.Z > value_255 &&
- DefaultLineAlpha > value_255);
- if (LineDiffuse || !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);
- }
- VertexMaterialClass * linemat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
- DX8Wrapper::Set_Material(linemat);
- DX8Wrapper::Set_Shader(Shader);
- DX8Wrapper::Set_Texture(0, Texture);
- REF_PTR_RELEASE(linemat);
- WWASSERT(StartLineLoc && StartLineLoc->Get_Array());
- WWASSERT(EndLineLoc && EndLineLoc->Get_Array());
- // 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());
- // the 3 offsets in view space
- const static Vector3 offset_a = Vector3(WWMath::Cos(WWMATH_PI / 2), WWMath::Sin(WWMATH_PI /2 ), 0);
- const static Vector3 offset_b = Vector3(WWMath::Cos(7 * WWMATH_PI / 6), WWMath::Sin(7 * WWMATH_PI / 6), 0);
- const static Vector3 offset_c = Vector3(WWMath::Cos(11 * WWMATH_PI / 6), WWMath::Sin(11 * WWMATH_PI / 6), 0);
- static Vector3 offset[3];
-
- offset[0].Set(offset_a);
- offset[1].Set(offset_b);
- offset[2].Set(offset_c);
- // Save off the view matrix
- Matrix4x4 view;
- DX8Wrapper::Get_Transform(D3DTS_VIEW, view);
- Matrix4x4 identity(true);
- DX8Wrapper::Set_Transform(D3DTS_WORLD, identity);
- // if the points are in world space, transform the offsets
- if (Get_Flag(TRANSFORM)) {
- Matrix3D xform_mat;
- xform_mat = rinfo.Camera.Get_Transform();
- xform_mat.Set_Translation(Vector3(0, 0, 0));
- xform_mat.Get_Orthogonal_Inverse(xform_mat);
- for (i = 0; i < 3; i++) {
- Matrix3D::Transform_Vector(xform_mat, offset[i], &offset[i]);
- }
- } else {
- DX8Wrapper::Set_Transform(D3DTS_VIEW, identity);
- }
-
- int num_tris=0;
- int num_indices=0;
- int num_vertices=0;
- switch (LineMode) {
- case TETRAHEDRON:
- num_tris =4 * LineCount;
- num_indices =3 * num_tris;
- num_vertices =4 * LineCount;
- break;
- case PRISM:
- num_tris =8 * LineCount;
- num_indices =3 * num_tris;
- num_vertices =6 * LineCount;
- break;
- }
- // construct the tetrahedra in the index buffers
- // assume first vertex is the apex, followed by offset[0-3]
- DynamicIBAccessClass iba(sort?BUFFER_TYPE_DYNAMIC_SORTING:BUFFER_TYPE_DYNAMIC_DX8,num_indices);
- {
- DynamicIBAccessClass::WriteLockClass lock(&iba);
- unsigned short *ibptr = lock.Get_Index_Array();
- unsigned short j, idx;
- try {
- switch (LineMode) {
- case TETRAHEDRON:
- for (j=0; j<LineCount; j++) {
- idx = 4 * j;
- // apex, offset[1], offset[0]
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 2;
- *ibptr++ = idx + 1;
- // apex, offset[2], offset[1]
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 3;
- *ibptr++ = idx + 2;
- // apex, offset[0], offset[2]
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 3;
- // offset[0-3]
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 2;
- *ibptr++ = idx + 3;
- }
- break;
- case PRISM:
- for (j=0; j<LineCount; j++) {
- idx = 6 * j;
- // starting cap 0,1,2
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 2;
- // left side
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 3;
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 3;
- *ibptr++ = idx + 4;
- // bottom side
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 4;
- *ibptr++ = idx + 5;
- *ibptr++ = idx + 1;
- *ibptr++ = idx + 5;
- *ibptr++ = idx + 2;
- // right side
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 2;
- *ibptr++ = idx + 5;
- *ibptr++ = idx + 0;
- *ibptr++ = idx + 5;
- *ibptr++ = idx + 3;
- // end cap
- *ibptr++ = idx + 3;
- *ibptr++ = idx + 5;
- *ibptr++ = idx + 4;
- }
- break;
- }
- IndexBufferExceptionFunc();
- } catch(...) {
- IndexBufferExceptionFunc();
- }
- } // writing to ib
- // make the vertex buffers
- DynamicVBAccessClass vba(sort ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,num_vertices);
- {
- DynamicVBAccessClass::WriteLockClass lock(&vba);
- VertexFormatXYZNDUV2 *vb = lock.Get_Formatted_Vertex_Array();
- Vector3 loc, start, end;
- int point, j;
- float size = DefaultLineSize;
- Vector4 diffuse(DefaultLineColor.X, DefaultLineColor.Y, DefaultLineColor.Z, DefaultLineAlpha);
- float ucoord = DefaultLineUCoord;
- Vector4 taildiffuse = DefaultTailDiffuse;
- for (i = 0; i < LineCount; i++)
- {
- point = (ALT) ? ALT->Get_Element(i) : i;
- if (LineSize) size = LineSize->Get_Element(point);
- if (LineDiffuse) diffuse = LineDiffuse->Get_Element(point);
- if (LineUCoord) ucoord = LineUCoord->Get_Element(point);
- if (TailDiffuse) taildiffuse = TailDiffuse->Get_Element(point);
- end.Set(EndLineLoc->Get_Element(point));
- start.Set(StartLineLoc->Get_Element(point));
- switch (LineMode) {
- case TETRAHEDRON:
- // apex
- vb->x = end.X;
- vb->y = end.Y;
- vb->z = end.Z;
- vb->diffuse = DX8Wrapper::Convert_Color(taildiffuse);
- vb->u1 = ucoord;
- vb->v1 = 1.0f;
- vb++;
- for (j=0; j<3; j++) {
- loc.Set(start + size * offset[j]);
- vb->x = loc.X;
- vb->y = loc.Y;
- vb->z = loc.Z;
- vb->diffuse = DX8Wrapper::Convert_Color(diffuse);
- vb->u1 = ucoord;
- vb->v1 = 0.0f;
- vb++;
- }
- break;
- case PRISM:
- // start cap
- for (j = 0; j < 3; j++) {
- loc.Set(start + size * offset[j]);
- vb->x = loc.X;
- vb->y = loc.Y;
- vb->z = loc.Z;
- vb->diffuse = DX8Wrapper::Convert_Color(diffuse);
- vb->u1 = ucoord;
- vb->v1 = 0.0f;
- vb++;
- }
- // Do not merge loops. The vb has to be written in a specific order
- // (This is to optimize AGP memory write)
- // end cap
- for (j=0; j<3; j++) {
- loc.Set(end + size * offset[j]);
- vb->x = loc.X;
- vb->y = loc.Y;
- vb->z = loc.Z;
- vb->diffuse = DX8Wrapper::Convert_Color(taildiffuse);
- vb->u1 = ucoord;
- vb->v1 = 1.0f;
- vb++;
- }
- break;
- }
- }
- } // writing to vb
- DX8Wrapper::Set_Index_Buffer(iba, 0);
- DX8Wrapper::Set_Vertex_Buffer(vba);
-
- if (sort) {
- SortingRendererClass::Insert_Triangles(0, num_tris, 0, num_vertices);
- } else {
- DX8Wrapper::Draw_Triangles(0, num_tris, 0, num_vertices);
- }
-
- // restore the matrices
- DX8Wrapper::Set_Transform(D3DTS_VIEW, view);
- }
- int LineGroupClass::Get_Polygon_Count(void)
- {
- switch (LineMode) {
- case TETRAHEDRON:
- return LineCount * 4;
- break;
- case PRISM:
- return LineCount * 8;
- break;
- }
- WWASSERT(0);
- return 0;
- }
|