/*
** 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 : WWPhys *
* *
* $Archive:: /Commando/Code/wwphys/visrendercontext.cpp $*
* *
* Author:: Greg Hjelstrom *
* *
* $Modtime:: 5/17/01 10:42a $*
* *
* $Revision:: 16 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* VisRenderContextClass::VisRenderContextClass -- Constructor *
* VisRenderContextClass::Set_Vis_ID -- set the currently active Vis ID *
* VisRenderContextClass::Set_Resolution -- set the vis rendering resolution *
* VisRenderContextClass::Get_Resolution -- get the current vis rendering resolution *
* VisRenderContextClass::Scan_Frame_Buffer -- scan the frame buffer for visible objects *
* VisRenderContextClass::Compute_2D_Bounds -- compute the 2D bounds of a 3D box *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "visrendercontext.h"
#include "simplevec.h"
#include "win.h"
#include "rawfile.h"
#include "visrasterizer.h"
const int CLEAR_VIS_COLOR = 0x00000000; // Vis id for background/clear pixels
const float BACKFACE_OVERFLOW_FRACTION = 0.005f; // max percentage of backface before overflow (rejection)
static VisRasterizerClass _VisRasterizer; // Instance of a vis rasterizer
/***********************************************************************************************
**
** VisRenderContextClass Implementation
**
***********************************************************************************************/
/***********************************************************************************************
* VisRenderContextClass::VisRenderContextClass -- Constructor *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
VisRenderContextClass::VisRenderContextClass
(
CameraClass & cam,
VisTableClass & vtab
) :
SpecialRenderInfoClass(cam,RENDER_VIS),
VisTable(vtab)
{
VisRasterizer = &_VisRasterizer;
VisRasterizer->Set_Camera(&cam);
}
VisRenderContextClass::~VisRenderContextClass(void)
{
VisRasterizer->Set_Camera(NULL);
}
/***********************************************************************************************
* VisRenderContextClass::Set_Vis_ID -- set the currently active Vis ID *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Set_Vis_ID(uint32 id)
{
WWASSERT(id < BACKFACE_VIS_ID);
_VisRasterizer.Set_Frontface_ID(id);
_VisRasterizer.Set_Backface_ID((uint32)BACKFACE_VIS_ID);
}
/***********************************************************************************************
* VisRenderContextClass::Set_Resolution -- set the vis rendering resolution *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 3/29/2001 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Set_Resolution(int resx,int resy)
{
_VisRasterizer.Set_Resolution(resx,resy);
}
/***********************************************************************************************
* VisRenderContextClass::Get_Resolution -- get the current vis rendering resolution *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 3/29/2001 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Get_Resolution(int * set_resx,int * set_resy)
{
_VisRasterizer.Get_Resolution(set_resx,set_resy);
}
/***********************************************************************************************
* VisRenderContextClass::Scan_Frame_Buffer -- scan the frame buffer for visible objects *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Scan_Frame_Buffer
(
const AABoxClass & wrld_bbox,
VisSampleClass * sample
)
{
// transform wrld_bbox into view space and compute the 2d bounding rectangle
Vector2 min_v,max_v;
Compute_2D_Bounds(wrld_bbox,&min_v,&max_v);
Scan_Frame_Buffer(min_v,max_v,sample);
}
/***********************************************************************************************
* VisRenderContextClass::Scan_Frame_Buffer -- scan the frame buffer for visible objects *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Scan_Frame_Buffer(VisSampleClass * sample)
{
Scan_Frame_Buffer(Vector2(0,0),Vector2(1,1),sample);
}
/***********************************************************************************************
* VisRenderContextClass::Scan_Frame_Buffer -- scan the frame buffer for visible objects *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Scan_Frame_Buffer
(
const Vector2 & min,
const Vector2 & max,
VisSampleClass * sample
)
{
int width,height;
VisRasterizer->Get_Resolution(&width,&height);
int minx = MAX(min.X * width , 1); // ignore the far left column
int miny = MAX(min.Y * height , 1); // ignore the top row
int maxx = MIN(max.X * width , width-1);
int maxy = MIN(max.Y * height , height-1);
int backface_count = 0;
const uint32 * pixel_row = NULL;
/*
** Loop over the pixels, counting backfaces and enabling the visibility of
** each object encountered in the buffer
*/
for (int y=miny; yGet_Pixel_Row(y,minx,maxx);
for (int x=0; x BACKFACE_OVERFLOW_FRACTION) {
WWDEBUG_SAY(("%s Backface Overflow ",sample->Get_Cur_Direction_Name()));
sample->Set_Results(VIS_STATUS_BACKFACE_OVERFLOW,backface_fraction);
} else {
if (backface_count > 0) {
WWDEBUG_SAY(("%s Backface Leak ",sample->Get_Cur_Direction_Name()));
sample->Set_Results(VIS_STATUS_BACKFACE_LEAK,backface_fraction);
} else {
WWDEBUG_SAY(("%s ",sample->Get_Cur_Direction_Name()));
sample->Set_Results(VIS_STATUS_OK,0.0f);
}
}
}
}
/***********************************************************************************************
* VisRenderContextClass::Compute_2D_Bounds -- compute the 2D bounds of a 3D box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/18/2000 gth : Created. *
*=============================================================================================*/
void VisRenderContextClass::Compute_2D_Bounds
(
const AABoxClass & wrld_bbox,
Vector2 * min_v,
Vector2 * max_v
)
{
#define NUM_BOX_VERTS 8
static float _boxverts[NUM_BOX_VERTS][3] =
{
{ 1.0f, 1.0f, 1.0f }, // +z ring of 4 verts
{ -1.0f, 1.0f, 1.0f },
{ -1.0f,-1.0f, 1.0f },
{ 1.0f,-1.0f, 1.0f },
{ 1.0f, 1.0f,-1.0f }, // -z ring of 4 verts;
{ -1.0f, 1.0f,-1.0f },
{ -1.0f,-1.0f,-1.0f },
{ 1.0f,-1.0f,-1.0f },
};
// rotate and project the corners of the box
Vector3 corner[8];
for (int ivert=0; ivertSet(0,0);
max_v->Set(1,1);
return;
}
}
// scan for the min and max
min_v->X = max_v->X = corner[0].X;
min_v->Y = max_v->Y = corner[0].Y;
for (ivert = 1; ivertX > corner[ivert].X) min_v->X = corner[ivert].X;
if (min_v->Y > corner[ivert].Y) min_v->Y = corner[ivert].Y;
if (max_v->X < corner[ivert].X) max_v->X = corner[ivert].X;
if (max_v->Y < corner[ivert].Y) max_v->Y = corner[ivert].Y;
}
return;
}