This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/linegrp.cpp

493 lines
No EOL
14 KiB
C++

/*
** 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 <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:: /VSS_Sync/ww3d2/linegrp.cpp $*
* *
* Original Author:: Hector Yee *
* *
* $Author:: Vss_sync $*
* *
* $Modtime:: 10/26/01 3:12p $*
* *
* $Revision:: 1 $*
* *
*---------------------------------------------------------------------------------------------*
* 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
Matrix4 view;
DX8Wrapper::Get_Transform(D3DTS_VIEW, view);
Matrix4 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;
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;
}
} // 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;
}