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/dazzle.cpp

1703 lines
52 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 : WW3D *
* *
* $Archive:: /Commando/Code/ww3d2/dazzle.cpp $*
* *
* Original Author:: Jani Penttinen *
* *
* $Author:: Steve_t $*
* *
* $Modtime:: 1/02/02 2:55p $*
* *
* $Revision:: 31 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "dazzle.h"
#include "simplevec.h"
#include "vector2.h"
#include "camera.h"
#include "ww3d.h"
#include "wwstring.h"
#include "wwdebug.h"
#include "assetmgr.h"
#include "vector3i.h"
#include "quat.h"
#include "ini.h"
#include "point.h"
#include "rinfo.h"
#include "vertmaterial.h"
#include "chunkio.h"
#include "wwfile.h"
#include "inisup.h"
#include "persistfactory.h"
#include "ww3dids.h"
#include "dx8wrapper.h"
#include "dx8vertexbuffer.h"
#include "dx8indexbuffer.h"
#include "sortingrenderer.h"
#include "texture.h"
#include "scene.h"
#include "wwprofile.h"
#include "visrasterizer.h"
#include <cstdio>
#include <limits.h>
#include <wwprofile.h>
// All dazzle types appear under Dazzles_List in the dazzle.ini file.
const char* DAZZLE_LIST_STRING="Dazzles_List";
// After the dot product between the camera direction and the camera space location of the light source,
// we do a power to Halopow for the halo size and power to DazzlePow for the dazzle size. Halo/DazzleArea
// defines the angle where the values are valid, so any angle beyond HaloArea/DazzleArea results the halo or
// dazzle being scaled to zero. The angles are re-scaled from normalized angle scale of (-1.0...1.0)
// only HaloArea/DazzleArea defined part is used.
const char* DAZZLE_INTENSITY_POW_STRING = "DazzleIntensityPow";
const char* DAZZLE_SIZE_POW_STRING = "DazzleSizePow";
const char* DAZZLE_AREA_STRING = "DazzleArea"; // Something like 0.05 is a good starting point for a dazzle...
// Halo and dazzle are scaled by these values
const char* HALO_SCALE_X_STRING = "HaloScaleX";
const char* HALO_SCALE_Y_STRING = "HaloScaleY";
const char* DAZZLE_SCALE_X_STRING = "DazzleScaleX";
const char* DAZZLE_SCALE_Y_STRING = "DazzleScaleY";
// Dazzle and halo intensity control the base intensities.
const char* HALO_INTENSITY_STRING = "HaloIntensity";
const char* DAZZLE_INTENSITY_STRING = "DazzleIntensity";
// Direction area defines the maximum difference between the light direction and the eyespace location,
// so the dazzle can only be seen if the camera is inside the light cone. Value 0.0 means dazzle is not
// directional, it can be seen from any direction. Halo is not affected. Dazzle direction defines the light
// direction vector.
const char* DAZZLE_DIRECTION_AREA_STRING = "DazzleDirectionArea"; // Something like 0.5 might be a good test value
const char* DAZZLE_DIRECTION_STRING = "DazzleDirection";
// Dazzle and halo start to afde out after FadeoutStart meters and are completely gone by FadeoutEnd meters.
const char* FADEOUT_START_STRING = "FadeoutStart";
const char* FADEOUT_END_STRING = "FadeoutEnd";
// To be done: This parameter needs to be redefined.
const char* SIZE_OPTIMIZATION_LIMIT_STRING = "SizeOptimizationLimit";
// The weight of history for the intensities. The history weight is per millisecond, so if you want to have
// any real history, values higher than 0.95 are recommended (don't use value of 1.0 or anything higher!)
const char* HISTORY_WEIGHT_STRING = "HistoryWeight";
// Textures to be used.
const char* DAZZLE_TEXTURE_STRING = "DazzleTextureName";
const char* HALO_TEXTURE_STRING = "HaloTextureName";
// If false, camera matrix's translation term isn't used. If translation isn't used the dazzle is treated as
// always visible, scene graph visibility is not used.
const char* USE_CAMERA_TRANSLATION = "UseCameraTranslation";
// Halo and dazzle colors, RGB, (1.0, 1.0, 1.0) is white and (0.0, 0.0, 0.0) is black
const char* HALO_COLOR_STRING = "HaloColor";
const char* DAZZLE_COLOR_STRING = "DazzleColor";
// Dazzle test color could be white in many cases but if the level has a lot of white then another color can be defined.
const char* DAZZLE_TEST_COLOR_STRING = "DazzleTestColor";
// Dazzles can blink on and off. The blink period defines the time for one cycle, the blink "on time" defines
// the amount of time within that period that the dazzle is "on"
const char* BLINK_PERIOD_STRING = "BlinkPeriod";
const char* BLINK_ON_TIME_STRING = "BlinkOnTime";
// Dazzle can use a lensflare by defining a name of lensflare in the ini
const char* DAZZLE_LENSFLARE_STRING = "LensflareName";
// Lensflare definitions
const char* LENSFLARE_LIST_STRING = "Lensflares_List";
// Texture to be used by the lensflare
const char* LENSFLARE_TEXTURE_STRING = "TextureName";
// The number of flare sprites in lensflare. The FlareLocation, FlareSize and FlareColor paremeters are procedural, the
// names are produced based on this parameter. If FlareCount is 3, there exists FlareLocation1, FlareLocation2 and
// FlareLocation3... And so on.
const char* FLARE_COUNT_STRING = "FlareCount";
// 1D-locations of the flares. 0.0 means the location of the center of the screen and 1.0 means the location of the
// lightsource. The values can be smaller than zero and larger than 1.0.
const char* FLARE_LOCATION_STRING = "FlareLocation";
// Normalized flare sizes
const char* FLARE_SIZE_STRING = "FlareSize";
// Colors for each flare sprite
const char* FLARE_COLOR_STRING = "FlareColor";
// Uv coordinates (as there can be only one texture used, but one may want multiple images). The values is a 4-float
// vector: start_u, start_v, end_u, end_v.
const char* FLARE_UV_STRING = "FlareUV";
// Radius of dazzle used for raycast tests
const char * RADIUS_STRING = "Radius";
/*
; DAZZLE.INI example
[Lensflares_List]
0=DEFAULT_LENSFLARE
[Dazzles_List]
0=DEFAULT
;========================================== LENSFLARE DEFINITIONS =================
[DEFAULT_LENSFLARE]
TextureName=dazzle_secondary.jpg
FlareCount=5
FlareLocation1=0.1
FlareLocation2=0.5
FlareLocation3=1.1
FlareLocation4=1.5
FlareLocation5=-0.4
FlareSize1=0.1
FlareSize2=0.05
FlareSize3=0.08
FlareSize4=0.15
FlareSize5=0.10
FlareColor1=1.0,0.5,0.5
FlareColor2=0.5,1.0,0.5
FlareColor3=0.5,0.5,1.0
FlareColor4=0.5,0.5,1.0
FlareColor5=0.5,0.5,1.0
;========================================== DAZZLE DEFINITIONS ====================
[DEFAULT]
HaloIntensity=1.0
HaloIntensityPow=0.95
HaloSizePow=0.95
HaloArea=1.0
HaloScaleX=0.2
HaloScaleY=0.2
DazzleArea=0.05
DazzleDirectionArea=0
DazzleDirection=0,1,1
DazzleSizePow=0.9
DazzleIntensityPow=0.9
DazzleIntensity=50
DazzleScaleX=1.0
DazzleScaleY=1.0
FadeoutStart=30.0
FadeoutEnd=40.0
SizeOptimizationLimit=0.05
HistoryWeight=0.975
UseCameraTranslation=1
DazzleTextureName=dazzle_primary.jpg
HaloTextureName=dazzle_secondary.jpg
DazzleColor=1,1,1
HaloColor=0,0,1
DazzleTestColor=1,1,1
LensflareName=DEFAULT_LENSFLARE
*/
// Global instance of a dazzle loader
DazzleLoaderClass _DazzleLoader;
static SimpleVecClass<DazzleRenderObjClass*> temp_ptrs;
static DazzleTypeClass** types;
static unsigned type_count;
// Current dazzle layer - must be set before rendering
static DazzleLayerClass * current_dazzle_layer = NULL;
static LensflareTypeClass** lensflares;
static unsigned lensflare_count;
static ShaderClass default_dazzle_shader;
static ShaderClass default_halo_shader;
static ShaderClass vis_shader;
static ShaderClass debug_shader;
// static instance of a default dazzle visibility handler
static DazzleVisibilityClass _DefaultVisibilityHandler;
static const DazzleVisibilityClass * _VisibilityHandler = &_DefaultVisibilityHandler;
bool DazzleRenderObjClass::_dazzle_rendering_enabled = true;
static void Init_Shaders()
{
default_dazzle_shader.Set_Cull_Mode( ShaderClass::CULL_MODE_DISABLE );
default_dazzle_shader.Set_Depth_Mask( ShaderClass::DEPTH_WRITE_DISABLE );
default_dazzle_shader.Set_Depth_Compare( ShaderClass::PASS_ALWAYS );
default_dazzle_shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ONE );
default_dazzle_shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE );
default_dazzle_shader.Set_Fog_Func( ShaderClass::FOG_DISABLE );
default_dazzle_shader.Set_Primary_Gradient( ShaderClass::GRADIENT_MODULATE );
default_dazzle_shader.Set_Texturing( ShaderClass::TEXTURING_ENABLE );
default_halo_shader.Set_Cull_Mode( ShaderClass::CULL_MODE_DISABLE );
default_halo_shader.Set_Depth_Mask( ShaderClass::DEPTH_WRITE_DISABLE );
default_halo_shader.Set_Depth_Compare( ShaderClass::PASS_LEQUAL );
default_halo_shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ONE );
default_halo_shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE );
default_halo_shader.Set_Fog_Func( ShaderClass::FOG_DISABLE );
default_halo_shader.Set_Primary_Gradient( ShaderClass::GRADIENT_MODULATE );
default_halo_shader.Set_Texturing( ShaderClass::TEXTURING_ENABLE );
vis_shader.Set_Cull_Mode( ShaderClass::CULL_MODE_DISABLE );
vis_shader.Set_Depth_Mask( ShaderClass::DEPTH_WRITE_DISABLE );
vis_shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_ZERO );
vis_shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE );
vis_shader.Set_Fog_Func( ShaderClass::FOG_DISABLE );
vis_shader.Set_Primary_Gradient( ShaderClass::GRADIENT_MODULATE );
vis_shader.Set_Texturing( ShaderClass::TEXTURING_DISABLE );
debug_shader.Set_Cull_Mode( ShaderClass::CULL_MODE_DISABLE );
debug_shader.Set_Depth_Mask( ShaderClass::DEPTH_WRITE_DISABLE );
debug_shader.Set_Dst_Blend_Func( ShaderClass::DSTBLEND_SRC_ALPHA );
debug_shader.Set_Src_Blend_Func( ShaderClass::SRCBLEND_ONE );
debug_shader.Set_Fog_Func( ShaderClass::FOG_DISABLE );
debug_shader.Set_Primary_Gradient( ShaderClass::GRADIENT_MODULATE );
debug_shader.Set_Texturing( ShaderClass::TEXTURING_DISABLE );
}
/*
** Derived INI to support Vector4
*/
class DazzleINIClass : public INIClass {
public:
DazzleINIClass(FileClass & file) : INIClass(file) {}
const Vector2 Get_Vector2(char const *section, char const *entry, const Vector2 & defvalue = Vector2(0,0) );
const Vector3 Get_Vector3(char const *section, char const *entry, const Vector3 & defvalue = Vector3(0,0,0) );
const Vector4 Get_Vector4(char const *section, char const *entry, const Vector4 & defvalue = Vector4(0,0,0,0) ) const;
};
const Vector2 DazzleINIClass::Get_Vector2(char const *section, char const *entry, const Vector2 & defvalue)
{
if (section != NULL && entry != NULL) {
INIEntry * entryptr = Find_Entry(section, entry);
if (entryptr && entryptr->Value != NULL) {
Vector2 ret;
if ( sscanf( entryptr->Value, "%f,%f", &ret[0], &ret[1], &ret[2] ) == 2 ) {
return ret;
}
}
}
return defvalue;
}
const Vector3 DazzleINIClass::Get_Vector3(char const *section, char const * entry, const Vector3 & defvalue )
{
if (section != NULL && entry != NULL) {
INIEntry * entryptr = Find_Entry(section, entry);
if (entryptr && entryptr->Value != NULL) {
Vector3 ret;
if ( sscanf( entryptr->Value, "%f,%f,%f", &ret[0], &ret[1], &ret[2] ) == 3 ) {
return ret;
}
}
}
return defvalue;
}
const Vector4 DazzleINIClass::Get_Vector4(char const *section, char const *entry, const Vector4 & defvalue) const
{
if (section != NULL && entry != NULL) {
INIEntry * entryptr = Find_Entry(section, entry);
if (entryptr && entryptr->Value != NULL) {
Vector4 ret;
if ( sscanf( entryptr->Value, "%f,%f,%f,%f", &ret[0], &ret[1], &ret[2], &ret[3] ) == 4 ) {
return ret;
}
}
}
return defvalue;
}
// ----------------------------------------------------------------------------
LensflareTypeClass::LensflareTypeClass(const LensflareInitClass& is)
:
lic(is),
texture(NULL)
{
}
LensflareTypeClass::~LensflareTypeClass()
{
REF_PTR_RELEASE(texture);
}
TextureClass* LensflareTypeClass::Get_Texture()
{
if (!texture) {
texture = WW3DAssetManager::Get_Instance()->Get_Texture(lic.texture_name);
SET_REF_OWNER(texture);
}
return texture;
}
void LensflareTypeClass::Generate_Vertex_Buffers(
VertexFormatXYZNDUV2* vertex,
int& vertex_count,
float screen_x_scale,
float screen_y_scale,
float dazzle_intensity,
const Vector4& transformed_location)
{
// Lensflares are placed on a line 2D that goes through the lightsource and the center of the screen
// float scale=sqrt(transformed_location[0]*transformed_location[0]+transformed_location[1]*transformed_location[1]);
float z=transformed_location[2];
float distance_multiplier=sqrt(transformed_location[0]*transformed_location[0]+transformed_location[1]*transformed_location[1])+1.0f;
for (int a=0;a<lic.flare_count;++a) {
float x=lic.flare_locations[a]*transformed_location[0];
float y=lic.flare_locations[a]*transformed_location[1];
float size=lic.flare_sizes[a]*distance_multiplier;
float ix=size*screen_x_scale;
float iy=size*screen_y_scale;
Vector3 col=lic.flare_colors[a]*dazzle_intensity;
if (col[0]>1.0f) col[0]=1.0f;
if (col[1]>1.0f) col[1]=1.0f;
if (col[2]>1.0f) col[2]=1.0f;
unsigned color=DX8Wrapper::Convert_Color(col,1.0f);
vertex->x=x+ix;
vertex->y=y-iy;
vertex->z=z;
vertex->u1=lic.flare_uv[a][0];
vertex->v1=lic.flare_uv[a][1];
vertex->diffuse=color;
vertex++;
vertex->x=x+ix;
vertex->y=y+iy;
vertex->z=z;
vertex->u1=lic.flare_uv[a][2];
vertex->v1=lic.flare_uv[a][1];
vertex->diffuse=color;
vertex++;
vertex->x=x-ix;
vertex->y=y+iy;
vertex->z=z;
vertex->u1=lic.flare_uv[a][2];
vertex->v1=lic.flare_uv[a][3];
vertex->diffuse=color;
vertex++;
vertex->x=x-ix;
vertex->y=y-iy;
vertex->z=z;
vertex->u1=lic.flare_uv[a][0];
vertex->v1=lic.flare_uv[a][3];
vertex->diffuse=color;
vertex++;
vertex_count+=4;
}
}
// ----------------------------------------------------------------------------
DazzleTypeClass::DazzleTypeClass(const DazzleInitClass& is)
:
ic(is),
dazzle_shader(default_dazzle_shader),
halo_shader(default_halo_shader),
primary_texture(NULL),
secondary_texture(NULL),
lensflare_id(DazzleRenderObjClass::Get_Lensflare_ID(is.lensflare_name)),
radius(is.radius)
{
fadeout_end_sqr=ic.fadeout_end*ic.fadeout_end;
fadeout_start_sqr=ic.fadeout_start*ic.fadeout_start;
dazzle_test_color_integer=
0xff000000|
(unsigned(255.0f*ic.dazzle_test_color[2])<<16)|
(unsigned(255.0f*ic.dazzle_test_color[1])<<8)|
(unsigned(255.0f*ic.dazzle_test_color[0]));
dazzle_test_mask_integer=dazzle_test_color_integer&0xf8f8f8f8;
}
DazzleTypeClass::~DazzleTypeClass()
{
REF_PTR_RELEASE(primary_texture);
REF_PTR_RELEASE(secondary_texture);
}
// ----------------------------------------------------------------------------
void DazzleTypeClass::Set_Dazzle_Shader(const ShaderClass& s) // Set shader for the dazzle type
{
dazzle_shader=s;
}
// ----------------------------------------------------------------------------
void DazzleTypeClass::Set_Halo_Shader(const ShaderClass& s) // Set shader for the dazzle type
{
halo_shader=s;
}
// ----------------------------------------------------------------------------
TextureClass* DazzleTypeClass::Get_Dazzle_Texture()
{
if (!primary_texture) {
primary_texture = WW3DAssetManager::Get_Instance()->Get_Texture(ic.primary_texture_name);
if ( primary_texture ) {
SET_REF_OWNER(primary_texture);
}
}
return primary_texture;
}
// ----------------------------------------------------------------------------
TextureClass* DazzleTypeClass::Get_Halo_Texture()
{
if (!secondary_texture) {
secondary_texture = WW3DAssetManager::Get_Instance()->Get_Texture(ic.secondary_texture_name);
if ( secondary_texture ) {
SET_REF_OWNER(secondary_texture);
}
}
return secondary_texture;
}
// ----------------------------------------------------------------------------
void DazzleTypeClass::Calculate_Intensities(
float& dazzle_intensity,
float& dazzle_size,
float& halo_intensity,
const Vector3& camera_dir,
const Vector3& dazzle_dir,
float distance) const
{
if (ic.use_camera_translation && distance>(fadeout_end_sqr)) {
dazzle_intensity=0.0f;
return;
}
dazzle_intensity-=1.0f-ic.dazzle_area;
dazzle_intensity/=ic.dazzle_area;
dazzle_intensity=WWMath::Clamp(dazzle_intensity);
if (ic.dazzle_direction_area>0.0f) {
float angle=-Vector3::Dot_Product(camera_dir,dazzle_dir);
angle-=1.0f-ic.dazzle_direction_area;
angle/=ic.dazzle_direction_area;
angle=WWMath::Clamp(angle);
dazzle_intensity*=angle;
}
if (dazzle_intensity>0.0f) {
dazzle_size=pow(dazzle_intensity,ic.dazzle_size_pow);
dazzle_intensity=pow(dazzle_intensity,ic.dazzle_intensity_pow);
}
else {
dazzle_intensity=0.0f;
}
dazzle_intensity*=ic.dazzle_intensity;
halo_intensity*=ic.halo_intensity;
// Flare fadeout distance - fade it out...
if (ic.use_camera_translation) {
if (distance>(fadeout_start_sqr)) {
distance=sqrt(distance);
distance-=ic.fadeout_start;
distance/=ic.fadeout_end-ic.fadeout_start;
dazzle_intensity*=1.0f-distance; // Scale down intensity
halo_intensity*=1.0f-distance; // Scale down intensity
}
}
return;
}
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Init_From_INI(const INIClass* ini)
{
if (!ini) return;
if (ini->Section_Count()==0) return;
Init_Shaders();
unsigned count=ini->Entry_Count( LENSFLARE_LIST_STRING );
unsigned entry;
for ( entry = 0; entry < count; entry++ ) {
char section_name[80];
ini->Get_String(
LENSFLARE_LIST_STRING,
ini->Get_Entry( LENSFLARE_LIST_STRING, entry),
"",
section_name,
sizeof( section_name ));
LensflareInitClass lic;
ini->Get_String(lic.texture_name,section_name,LENSFLARE_TEXTURE_STRING);
lic.flare_count=ini->Get_Int(section_name,FLARE_COUNT_STRING,0);
if (lic.flare_count) {
lic.flare_locations=new float[lic.flare_count]; // Flare location is 1D
lic.flare_sizes=new float[lic.flare_count];
lic.flare_colors=new Vector3[lic.flare_count];
lic.flare_uv=new Vector4[lic.flare_count];
}
else {
lic.flare_locations=NULL;
lic.flare_sizes=NULL;
lic.flare_colors=NULL;
}
for (int flare=0;flare<lic.flare_count;++flare) {
// Flare location
StringClass tmp_name(true);
tmp_name.Format("%s%d",FLARE_LOCATION_STRING,flare+1);
lic.flare_locations[flare]=ini->Get_Float(section_name,tmp_name,0.0f);
// Flare size
tmp_name.Format("%s%d",FLARE_SIZE_STRING,flare+1);
lic.flare_sizes[flare]=ini->Get_Float(section_name,tmp_name,1.0f);
// Flare color
tmp_name.Format("%s%d",FLARE_COLOR_STRING,flare+1);
TPoint3D<float> tp=ini->Get_Point(section_name,tmp_name,TPoint3D<float>(1.0f,1.0f,1.0f));
lic.flare_colors[flare]=reinterpret_cast<const Vector3&>(tp);
// Flare uv
const DazzleINIClass* dini=reinterpret_cast<const DazzleINIClass*>(ini);
tmp_name.Format("%s%d",FLARE_UV_STRING,flare+1);
lic.flare_uv[flare]=dini->Get_Vector4(section_name,tmp_name,Vector4(0.0f,0.0f,1.0f,1.0f));
}
lic.type=entry;
Init_Lensflare(lic);
lensflares[entry]->name=section_name;
}
count=ini->Entry_Count( DAZZLE_LIST_STRING );
for ( entry = 0; entry < count; entry++ ) {
char section_name[80];
ini->Get_String(
DAZZLE_LIST_STRING,
ini->Get_Entry( DAZZLE_LIST_STRING, entry),
"",
section_name,
sizeof( section_name ));
DazzleInitClass dic;
ini->Get_String(dic.primary_texture_name,section_name,DAZZLE_TEXTURE_STRING);
ini->Get_String(dic.secondary_texture_name,section_name,HALO_TEXTURE_STRING);
dic.halo_intensity=ini->Get_Float(section_name,HALO_INTENSITY_STRING,0.95f);
dic.halo_scale_x=ini->Get_Float(section_name,HALO_SCALE_X_STRING,2.0f);
dic.halo_scale_y=ini->Get_Float(section_name,HALO_SCALE_Y_STRING,2.0f);
dic.dazzle_area=ini->Get_Float(section_name,DAZZLE_AREA_STRING,0.05f);
dic.dazzle_direction_area=ini->Get_Float(section_name,DAZZLE_DIRECTION_AREA_STRING,0.50f);
dic.dazzle_intensity=ini->Get_Float(section_name,DAZZLE_INTENSITY_STRING,0.90f);
dic.dazzle_intensity_pow=ini->Get_Float(section_name,DAZZLE_INTENSITY_POW_STRING,0.90f);
dic.dazzle_size_pow=ini->Get_Float(section_name,DAZZLE_SIZE_POW_STRING,0.90f);
dic.dazzle_scale_x=ini->Get_Float(section_name,DAZZLE_SCALE_X_STRING,100.0f);
dic.dazzle_scale_y=ini->Get_Float(section_name,DAZZLE_SCALE_Y_STRING,25.0f);
dic.fadeout_start=ini->Get_Float(section_name,FADEOUT_START_STRING,25.0f);
dic.fadeout_end=ini->Get_Float(section_name,FADEOUT_END_STRING,50.0f);
dic.size_optimization_limit=ini->Get_Float(section_name,SIZE_OPTIMIZATION_LIMIT_STRING,0.05f);
dic.history_weight=ini->Get_Float(section_name,HISTORY_WEIGHT_STRING,0.5f);
dic.use_camera_translation=!!ini->Get_Int(section_name,USE_CAMERA_TRANSLATION,1);
ini->Get_String(dic.lensflare_name,section_name,DAZZLE_LENSFLARE_STRING);
dic.type=entry;
TPoint3D<float> tp=ini->Get_Point(section_name,DAZZLE_DIRECTION_STRING,TPoint3D<float>(0.0f,0.0f,0.0f));
tp.Normalize();
dic.dazzle_direction=reinterpret_cast<const Vector3&>(tp);
tp=ini->Get_Point(section_name,DAZZLE_TEST_COLOR_STRING,TPoint3D<float>(1.0f,1.0f,1.0f));
dic.dazzle_test_color=reinterpret_cast<const Vector3&>(tp);
tp=ini->Get_Point(section_name,DAZZLE_COLOR_STRING,TPoint3D<float>(1.0f,1.0f,1.0f));
dic.dazzle_color=reinterpret_cast<const Vector3&>(tp);
tp=ini->Get_Point(section_name,HALO_COLOR_STRING,TPoint3D<float>(1.0f,1.0f,1.0f));
dic.halo_color=reinterpret_cast<const Vector3&>(tp);
dic.radius=ini->Get_Float(section_name,RADIUS_STRING,1.0f);
dic.blink_period=ini->Get_Float(section_name,BLINK_PERIOD_STRING,0.0f);
dic.blink_on_time=ini->Get_Float(section_name,BLINK_ON_TIME_STRING,0.0f);
Init_Type(dic);
types[entry]->name=section_name;
}
}
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Init_Type(const DazzleInitClass& i)
{
Init_Shaders();
if (i.type>=type_count) {
unsigned new_count=i.type+1;
DazzleTypeClass** new_types=new DazzleTypeClass*[new_count];
for (unsigned a=0;a<type_count;++a) {
new_types[a]=types[a];
}
for (;a<new_count;++a) {
new_types[a]=0;
}
delete[] types;
types=new_types;
type_count=new_count;
}
delete types[i.type];
types[i.type]=new DazzleTypeClass(i);
}
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Init_Lensflare(const LensflareInitClass& i)
{
Init_Shaders();
if (i.type>=lensflare_count) {
unsigned new_count=i.type+1;
LensflareTypeClass** new_lensflares=new LensflareTypeClass*[new_count];
for (unsigned a=0;a<lensflare_count;++a) {
new_lensflares[a]=lensflares[a];
}
for (;a<new_count;++a) {
new_lensflares[a]=0;
}
delete[] lensflares;
lensflares=new_lensflares;
lensflare_count=new_count;
}
delete lensflares[i.type];
lensflares[i.type]=new LensflareTypeClass(i);
}
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Deinit()
{
// Deinit dazzle types
if (types) {
for (unsigned a=0;a<type_count;++a) {
delete types[a];
}
delete[] types;
}
types=NULL;
type_count=0;
// Deinit lensflare types
if (lensflares) {
for (unsigned a=0;a<lensflare_count;++a) {
delete lensflares[a];
}
delete[] lensflares;
}
lensflares=NULL;
lensflare_count=0;
}
void DazzleRenderObjClass::Install_Dazzle_Visibility_Handler(const DazzleVisibilityClass * visibility_handler)
{
if (visibility_handler == NULL) {
_VisibilityHandler = &_DefaultVisibilityHandler;
} else {
_VisibilityHandler = visibility_handler;
}
}
// ----------------------------------------------------------------------------
//
// The parameter t defines the dazzle type. t has to be a valid type id in order
// for the dazzle to work.
//
// ----------------------------------------------------------------------------
DazzleRenderObjClass::DazzleRenderObjClass(unsigned t)
:
succ(NULL),
type(t),
current_dazzle_intensity(0.0f),
current_dazzle_size(0.0f),
dazzle_color(1.0f,1.0f,1.0f),
halo_color(1.0f,1.0f,1.0f),
lensflare_intensity(1.0f),
on_list(false),
visibility(0.0f)
{
if (types && types[t]) {
radius = types[t]->radius;
} else {
radius = 0.0f;
}
creation_time = WW3D::Get_Sync_Time();
}
// ----------------------------------------------------------------------------
//
// Creating a dazzle with its type name is a bit slower (due to scanning) but
// works equally to the creation with id.
//
// ----------------------------------------------------------------------------
DazzleRenderObjClass::DazzleRenderObjClass(const char * type_name)
:
succ(NULL),
type(Get_Type_ID(type_name)),
current_dazzle_intensity(0.0f),
current_dazzle_size(0.0f),
dazzle_color(1.0f,1.0f,1.0f),
halo_color(1.0f,1.0f,1.0f),
lensflare_intensity(1.0f),
on_list(false),
visibility(0.0f)
{
int id = Get_Type_ID(type_name);
if (types && types[id]) {
radius = types[id]->radius;
} else {
radius = 0.0f;
}
creation_time = WW3D::Get_Sync_Time();
}
// ----------------------------------------------------------------------------
//
// Copy constructor creates an exact copy of the object, except for the visibility
// information, which is initialised with default values.
//
// ----------------------------------------------------------------------------
DazzleRenderObjClass::DazzleRenderObjClass(const DazzleRenderObjClass & src)
:
succ(NULL),
type(src.type),
current_dazzle_intensity(src.current_dazzle_intensity),
current_dazzle_size(src.current_dazzle_size),
current_dir(src.current_dir),
dazzle_color(src.dazzle_color),
halo_color(src.halo_color),
lensflare_intensity(src.lensflare_intensity),
on_list(false),
visibility(src.visibility),
radius(src.radius)
{
creation_time = WW3D::Get_Sync_Time();
}
DazzleRenderObjClass& DazzleRenderObjClass::operator = (const DazzleRenderObjClass & src)
{
type=src.type;
current_dir=src.current_dir;
current_dazzle_intensity=src.current_dazzle_intensity;
current_dazzle_size=src.current_dazzle_size;
dazzle_color=src.dazzle_color;
halo_color=src.halo_color;
lensflare_intensity=src.lensflare_intensity;
visibility=src.visibility;
radius=src.radius;
creation_time = WW3D::Get_Sync_Time();
return *this;
}
void DazzleRenderObjClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
{
sphere.Center.Set(0,0,0);
sphere.Radius = radius;
}
void DazzleRenderObjClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
{
box.Center.Set(0,0,0);
box.Extent.Set(radius,radius,radius);
}
void DazzleRenderObjClass::Set_Layer(DazzleLayerClass *layer)
{
// Never insert a dazzle into a list if it already is on one - this caould create infinite
// loops in the dazzle list.
if (on_list) return;
// This function sets the dazzle to be visible in the given layer.
if (!layer) {
WWASSERT(0);
return;
}
if (type>=type_count) return; // If the type doesn't exist the visibility can't be changed
// Insert at the head of the layer's visible list
succ = layer->visible_lists[type];
layer->visible_lists[type] = this;
on_list = true;
Add_Ref();
}
void DazzleRenderObjClass::Set_Current_Dazzle_Layer(DazzleLayerClass *layer)
{
current_dazzle_layer = layer;
}
/////////////////////////////////////////////////////////////////////////////
// Render Object Interface
/////////////////////////////////////////////////////////////////////////////
RenderObjClass* DazzleRenderObjClass::Clone(void) const
{
return NEW_REF(DazzleRenderObjClass, (*this));
}
// ----------------------------------------------------------------------------
//
// DazzleRenderObjClass's Render() function doesn't actually render the dazzle
// immediatelly but just sets the dazzle visible. This is due to the way the
// dazzle system works (the dazzles need to be rendered after everything else).
// Having the Render() function flag the visibility offers us the visibility
// functionality of the scene graph.
//
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Render(RenderInfoClass & rinfo)
{
WWPROFILE("Dazzle::Render");
if ( Is_Not_Hidden_At_All() &&
_dazzle_rendering_enabled &&
!DX8Wrapper::Is_Render_To_Texture() )
{
// First check if the dazzle is blinking and is "off"
bool is_on = true;
DazzleInitClass & ic = types[type]->ic;
if (ic.blink_period > 0.0f) {
float elapsed_time = ((float)(WW3D::Get_Sync_Time() - creation_time)) / 1000.0f;
float wrapped_time = fmodf(elapsed_time,ic.blink_period);
if (wrapped_time > ic.blink_on_time) {
is_on = false;
}
}
// Next, check visibility
visibility = 1.0f;
if (is_on == false) {
visibility = 0.0f;
} else {
// Vector3 position;
// Get_Transform().Get_Translation(&position);
// visibility = _VisibilityHandler->Compute_Dazzle_Visibility(rinfo,this,position);
Matrix4 view_transform,projection_transform;
DX8Wrapper::Get_Transform(D3DTS_VIEW,view_transform);
DX8Wrapper::Get_Transform(D3DTS_PROJECTION,projection_transform);
Vector3 camera_loc(rinfo.Camera.Get_Position());
Vector3 camera_dir(-view_transform[2][0],-view_transform[2][1],-view_transform[2][2]);
// Matrix3D cam(rinfo.Camera.Get_Transform());
// Vector3 camera_dir(-cam[2][0],-cam[2][1],-cam[2][2]);
// camera_dir.Normalize();
Vector3 loc=Get_Position();
transformed_loc=view_transform*loc;
transformed_loc=projection_transform*transformed_loc;
transformed_loc[0]/=transformed_loc[3];
transformed_loc[1]/=transformed_loc[3];
transformed_loc[2]/=transformed_loc[3];
transformed_loc[3]=1.0f;
current_vloc=Vector3(transformed_loc[0],transformed_loc[1],transformed_loc[2]);
float dazzle_intensity;
Vector3 dir;
dir=camera_loc-loc;
current_distance=dir.Length2();
dir.Normalize();
dazzle_intensity=-Vector3::Dot_Product(dir,camera_dir);
// dazzle_intensity*=visibility;
float dazzle_size;
current_halo_intensity=1.0f;
const DazzleTypeClass* params=types[type];
params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,current_distance);
unsigned time_ms=WW3D::Get_Frame_Time();
if (time_ms==0) time_ms=1;
float weight=pow(params->ic.history_weight,time_ms);
if (dazzle_intensity>0.0f) {
visibility = _VisibilityHandler->Compute_Dazzle_Visibility(rinfo,this,loc);
//visibility=1.0f;
dazzle_intensity*=visibility;
}
else {
visibility=0.0f;
}
if (visibility == 0.0f) {
float i=dazzle_intensity*(1.0f-weight)+current_dazzle_intensity*weight;
current_dazzle_intensity=i;
if (current_dazzle_intensity<0.05f) current_dazzle_intensity=0.0f;
dazzle_intensity=i;
float s=dazzle_size*(1.0f-weight)+current_dazzle_size*weight;
current_dazzle_size=s;
dazzle_size=s;
} else {
current_dazzle_intensity = dazzle_intensity;
current_dazzle_size = dazzle_size;
}
}
// If this dazzle is visible or it is currently fading, submit it for rendering
if (/*visibility > 0.0f ||*/ current_dazzle_intensity>0.0f || current_halo_intensity>0.0f) {
WWASSERT(types[type]);
Set_Layer(current_dazzle_layer);
}
}
else {
visibility=0.0f;
}
}
void DazzleRenderObjClass::Render_Dazzle(CameraClass* camera)
{
WWPROFILE("Dazzle::Render");
Matrix4 old_view_transform;
Matrix4 old_world_transform;
Matrix4 old_projection_transform;
Matrix4 view_transform;
Matrix4 world_transform;
Matrix4 projection_transform;
DX8Wrapper::Get_Transform(D3DTS_VIEW,view_transform);
DX8Wrapper::Get_Transform(D3DTS_WORLD,world_transform);
DX8Wrapper::Get_Transform(D3DTS_PROJECTION,projection_transform);
old_view_transform=view_transform;
old_world_transform=world_transform;
old_projection_transform=projection_transform;
Vector3 camera_loc(camera->Get_Position());
Vector3 camera_dir(-view_transform[2][0],-view_transform[2][1],-view_transform[2][2]);
int display_width,display_height,display_bits;
bool windowed;
WW3D::Get_Device_Resolution(display_width,display_height,display_bits,windowed);
float w=float(display_width);
float h=float(display_height);
float screen_x_scale=1.0f;
float screen_y_scale=1.0f;
if (w>h) {
screen_y_scale=w/h;
}
else {
screen_x_scale=h/w;
}
// unsigned time_ms=WW3D::Get_Frame_Time();
// if (time_ms==0) time_ms=1;
float halo_scale_x=types[type]->ic.halo_scale_x;
float halo_scale_y=types[type]->ic.halo_scale_y;
float dazzle_scale_x=types[type]->ic.dazzle_scale_x;
float dazzle_scale_y=types[type]->ic.dazzle_scale_y;
// Allocate some arrays for the dazzle rendering
int vertex_count=4;
const DazzleTypeClass* params=types[type];
int halo_vertex_count=0;
int dazzle_vertex_count=0;
int lensflare_vertex_count=0;
Vector3 dl;
int lens_max_verts=0;
LensflareTypeClass* lensflare = DazzleRenderObjClass::Get_Lensflare_Class(types[type]->lensflare_id);
if (lensflare) {
lens_max_verts=4*lensflare->lic.flare_count;
}
DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,vertex_count*2+lens_max_verts);
{
DynamicVBAccessClass::WriteLockClass lock(&vb_access);
VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array();
float halo_size=1.0f;
Vector3 dazzle_dxt(screen_x_scale,0.0f,0.0f);
Vector3 halo_dxt=dazzle_dxt*halo_scale_x;
dazzle_dxt*=dazzle_scale_x;
Vector3 dazzle_dyt(0.0f,screen_y_scale,0.0f);
Vector3 halo_dyt=dazzle_dyt*halo_scale_y;
dazzle_dyt*=dazzle_scale_y;
if (current_dazzle_intensity>0.0f) {
VertexFormatXYZNDUV2* vertex=verts;
dazzle_vertex_count+=4;
Vector3 col(
dazzle_color[0]*params->ic.dazzle_color[0],
dazzle_color[1]*params->ic.dazzle_color[1],
dazzle_color[2]*params->ic.dazzle_color[2]);
col*=current_dazzle_intensity;
if (col[0]>1.0f) col[0]=1.0f;
if (col[1]>1.0f) col[1]=1.0f;
if (col[2]>1.0f) col[2]=1.0f;
unsigned color=DX8Wrapper::Convert_Color(col,1.0f);
dl=current_vloc+(dazzle_dxt-dazzle_dyt)*current_dazzle_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=0.0f;
vertex->v1=0.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc+(dazzle_dxt+dazzle_dyt)*current_dazzle_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=1.0f;
vertex->v1=0.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc-(dazzle_dxt-dazzle_dyt)*current_dazzle_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=1.0f;
vertex->v1=1.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc-(dazzle_dxt+dazzle_dyt)*current_dazzle_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=0.0f;
vertex->v1=1.0f;
vertex->diffuse=color;
}
if (current_halo_intensity) {
VertexFormatXYZNDUV2* vertex=verts+dazzle_vertex_count;
halo_vertex_count+=4;
Vector3 col(
halo_color[0]*params->ic.halo_color[0],
halo_color[1]*params->ic.halo_color[1],
halo_color[2]*params->ic.halo_color[2]);
col*=current_halo_intensity;
if (col[0]>1.0f) col[0]=1.0f;
if (col[1]>1.0f) col[1]=1.0f;
if (col[2]>1.0f) col[2]=1.0f;
unsigned color=DX8Wrapper::Convert_Color(col,1.0f);
dl=current_vloc+(halo_dxt-halo_dyt)*halo_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=0.0f;
vertex->v1=0.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc+(halo_dxt+halo_dyt)*halo_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=1.0f;
vertex->v1=0.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc-(halo_dxt-halo_dyt)*halo_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=1.0f;
vertex->v1=1.0f;
vertex->diffuse=color;
vertex++;
dl=current_vloc-(halo_dxt+halo_dyt)*halo_size;
reinterpret_cast<Vector3&>(vertex->x)=dl;
vertex->u1=0.0f;
vertex->v1=1.0f;
vertex->diffuse=color;
}
if (lensflare && current_dazzle_intensity>0.0f) {
VertexFormatXYZNDUV2* vertex=verts+halo_vertex_count+dazzle_vertex_count;
lensflare->Generate_Vertex_Buffers(
vertex,
lensflare_vertex_count,
screen_x_scale,
screen_y_scale,
current_dazzle_intensity * lensflare_intensity,
transformed_loc);
vertex_count+=lensflare_vertex_count;
}
}
int dazzle_poly_count=dazzle_vertex_count>>1;
int halo_poly_count=halo_vertex_count>>1;
int lensflare_poly_count=lensflare_vertex_count>>1;
int poly_count=halo_poly_count>dazzle_poly_count ? halo_poly_count : dazzle_poly_count;
if (lensflare_poly_count>poly_count) poly_count=lensflare_poly_count;
if (!poly_count) {
return;
}
DX8Wrapper::Set_Vertex_Buffer(vb_access);
DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,poly_count*3);
{
DynamicIBAccessClass::WriteLockClass lock(&ib_access);
unsigned short* inds=lock.Get_Index_Array();
// Proceed two polygons at a time
for (int a=0;a<poly_count/2;a++) {
*inds++=short(4*a);
*inds++=short(4*a+1);
*inds++=short(4*a+2);
*inds++=short(4*a);
*inds++=short(4*a+2);
*inds++=short(4*a+3);
}
}
DX8Wrapper::Set_World_Identity();
DX8Wrapper::Set_View_Identity();
DX8Wrapper::Set_Transform(D3DTS_PROJECTION,Matrix4(true));
if (halo_poly_count) {
DX8Wrapper::Set_Index_Buffer(ib_access,dazzle_vertex_count);
DX8Wrapper::Set_Shader(default_halo_shader);
DX8Wrapper::Set_Texture(0,types[type]->Get_Halo_Texture());
SphereClass sphere(Get_Position(),0.1f);
DX8Wrapper::Draw_Triangles(0,halo_poly_count,0,vertex_count);
}
if (dazzle_poly_count) {
DX8Wrapper::Set_Index_Buffer(ib_access,0);
DX8Wrapper::Set_Shader(default_dazzle_shader);
DX8Wrapper::Set_Texture(0,types[type]->Get_Dazzle_Texture());
SphereClass sphere(Vector3(0.0f,0.0f,0.0f),0.0f);
DX8Wrapper::Draw_Triangles(0,dazzle_poly_count,0,vertex_count);
}
if (lensflare_poly_count) {
DX8Wrapper::Set_Index_Buffer(ib_access,dazzle_vertex_count+halo_vertex_count);
DX8Wrapper::Set_Shader(default_dazzle_shader);
DX8Wrapper::Set_Texture(0,lensflare->Get_Texture());
SphereClass sphere(Vector3(0.0f,0.0f,0.0f),0.0f);
DX8Wrapper::Draw_Triangles(0,lensflare_poly_count,0,vertex_count);
}
DX8Wrapper::Set_Transform(D3DTS_PROJECTION,old_projection_transform);
DX8Wrapper::Set_Transform(D3DTS_VIEW,old_view_transform);
DX8Wrapper::Set_Transform(D3DTS_WORLD,old_world_transform);
}
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::Set_Transform(const Matrix3D &m)
{
RenderObjClass::Set_Transform(m);
if (type<type_count) {
Matrix3D::Rotate_Vector(m,types[type]->ic.dazzle_direction,&current_dir);
}
}
// ----------------------------------------------------------------------------
//
// Return the type id of a dazzle class with given name. If such type is not
// found, return UINT_MAX.
//
// ----------------------------------------------------------------------------
unsigned DazzleRenderObjClass::Get_Type_ID(const char* name)
{
for (unsigned a=0;a<type_count;++a) {
if (types[a] && types[a]->name==name) return a;
}
return UINT_MAX;
}
// ----------------------------------------------------------------------------
//
// Return the type name of a dazzle class with given id. If the id is out
// of range, return "DEFAULT" which by convention is always defined and is
// id 0.
//
// ----------------------------------------------------------------------------
const char * DazzleRenderObjClass::Get_Type_Name(unsigned id)
{
if ((id < type_count) && (id >= 0)) {
return types[id]->name;
} else {
return "DEFAULT";
}
}
// ----------------------------------------------------------------------------
//
// Return pointer to DazzleTypeClass object with given id. If the id is out
// of range (usually UINT_MAX, in can the id was obtained with invalid name
// string) return NULL.
//
// ----------------------------------------------------------------------------
DazzleTypeClass* DazzleRenderObjClass::Get_Type_Class(unsigned id) // Return dazzle type class pointer, or NULL if not found
{
if (id>=type_count) return NULL;
return types[id];
}
// ----------------------------------------------------------------------------
//
// Return the type id of a lensflare type class with given name. If such type is
// not found, return UINT_MAX.
//
// ----------------------------------------------------------------------------
unsigned DazzleRenderObjClass::Get_Lensflare_ID(const char* name)
{
for (unsigned a=0;a<lensflare_count;++a) {
if (lensflares[a] && lensflares[a]->name==name) return a;
}
return UINT_MAX;
}
// ----------------------------------------------------------------------------
//
// Return pointer to LensflareTypeClass object with given id. If the id is out
// of range (usually UINT_MAX, in can the id was obtained with invalid name
// string) return NULL.
//
// ----------------------------------------------------------------------------
LensflareTypeClass* DazzleRenderObjClass::Get_Lensflare_Class(unsigned id) // Return lensflare type class pointer, or NULL if not found
{
if (id>=lensflare_count) return NULL;
return lensflares[id];
}
// ----------------------------------------------------------------------------
//
// Should static dazzles require vis information, here's a function that renders
// a quad at the location of the dazzle
//
// ----------------------------------------------------------------------------
void DazzleRenderObjClass::vis_render_dazzle(SpecialRenderInfoClass & rinfo)
{
WWASSERT(rinfo.VisRasterizer != NULL);
rinfo.VisRasterizer->Enable_Two_Sided_Rendering(true);
/*
** Create a transform which is facing the camera
*/
Vector3 cam_point = rinfo.VisRasterizer->Peek_Camera()->Get_Transform().Get_Translation();
Vector3 daz_point = Get_Transform().Get_Translation();
Matrix3D tm;
tm.Look_At(daz_point,cam_point,0.0f);
rinfo.VisRasterizer->Set_Model_Transform(tm);
/*
** Now, generate a single triangle on the X-Y plane
*/
Vector3 verts[4];
TriIndex polys[2];
polys[0] = TriIndex(0,1,2);
polys[1] = TriIndex(0,2,3);
Vector2 view_min,view_max;
rinfo.VisRasterizer->Peek_Camera()->Get_View_Plane(view_min,view_max);
float scale_x=types[type]->ic.halo_scale_x;
if ((scale_x < 0.001f) && (types[type]->ic.dazzle_scale_x > scale_x)) {
scale_x = types[type]->ic.dazzle_scale_x;
}
float scale_y=types[type]->ic.halo_scale_y;
if ((scale_y < 0.001f) && (types[type]->ic.dazzle_scale_y > scale_y)) {
scale_y = types[type]->ic.dazzle_scale_y;
}
float dist = (daz_point - cam_point).Length();
Vector3 dxt(dist * scale_x / (view_max.X - view_min.X),0.0f,0.0f);
Vector3 dyt(0.0f,dist * scale_y / (view_max.Y - view_min.Y),0.0f);
verts[0].Set(dxt+dyt);
verts[1].Set(dxt-dyt);
verts[2].Set(-dxt-dyt);
verts[3].Set(-dxt+dyt);
AABoxClass bounds;
float extent = 1.1f * (dxt+dyt).Length();
bounds.Center = daz_point; //making up a conservative bounding box
bounds.Extent.Set(extent,extent,extent);
/*
** Render
*/
rinfo.VisRasterizer->Enable_Two_Sided_Rendering(true);
rinfo.VisRasterizer->Render_Triangles(verts,4,polys,2,bounds);
rinfo.VisRasterizer->Enable_Two_Sided_Rendering(false);
}
void DazzleRenderObjClass::Special_Render(SpecialRenderInfoClass & rinfo)
{
if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_VIS) {
vis_render_dazzle(rinfo);
}
}
/****************************************************************************************
DazzleRenderObjClass - Persistant object support.
Dazzles are going to save their type and their transform and simply
re-create another dazzle of the same type when loaded.
****************************************************************************************/
class DazzlePersistFactoryClass : public PersistFactoryClass
{
virtual uint32 Chunk_ID(void) const;
virtual PersistClass * Load(ChunkLoadClass & cload) const;
virtual void Save(ChunkSaveClass & csave,PersistClass * obj) const;
enum
{
DAZZLEFACTORY_CHUNKID_VARIABLES = 1212000336,
DAZZLEFACTORY_VARIABLE_OBJPOINTER = 0x00,
OBSOLETE_DAZZLEFACTORY_VARIABLE_TYPE,
DAZZLEFACTORY_VARIABLE_TRANSFORM,
DAZZLEFACTORY_VARIABLE_TYPENAME,
};
};
static DazzlePersistFactoryClass _DazzleFactory;
uint32 DazzlePersistFactoryClass::Chunk_ID(void) const
{
return WW3D_PERSIST_CHUNKID_DAZZLE;
}
PersistClass * DazzlePersistFactoryClass::Load(ChunkLoadClass & cload) const
{
DazzleRenderObjClass * old_obj = NULL;
Matrix3D tm(1);
char dazzle_type[256];
dazzle_type[0] = 0;
/*
** Load the dazzle parameters
*/
while (cload.Open_Chunk()) {
switch (cload.Cur_Chunk_ID()) {
case DAZZLEFACTORY_CHUNKID_VARIABLES:
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_MICRO_CHUNK(cload,DAZZLEFACTORY_VARIABLE_OBJPOINTER,old_obj);
READ_MICRO_CHUNK(cload,DAZZLEFACTORY_VARIABLE_TRANSFORM,tm);
READ_MICRO_CHUNK_STRING(cload,DAZZLEFACTORY_VARIABLE_TYPENAME,dazzle_type,sizeof(dazzle_type));
}
cload.Close_Micro_Chunk();
}
break;
default:
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
break;
};
cload.Close_Chunk();
}
/*
** Create a new dazzle object
*/
int type_index = 0;
if (strlen(dazzle_type) > 0) {
type_index = DazzleRenderObjClass::Get_Type_ID(dazzle_type);
}
RenderObjClass * new_obj = NEW_REF(DazzleRenderObjClass,(dazzle_type));
/*
** If we failed to create it, replace it with a NULL
*/
if (new_obj == NULL) {
static int count = 0;
if ( ++count < 10 ) {
WWDEBUG_SAY(("DazzlePersistFactory failed to create dazzle of type: %s!!\r\n",dazzle_type));
WWDEBUG_SAY(("Replacing it with a NULL render object!\r\n"));
}
new_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj("NULL");
}
WWASSERT(new_obj != NULL);
if (new_obj) {
new_obj->Set_Transform(tm);
}
/*
** Register the old pointer for re-mapping to the new pointer
*/
SaveLoadSystemClass::Register_Pointer(old_obj,new_obj);
return new_obj;
}
void DazzlePersistFactoryClass::Save(ChunkSaveClass & csave,PersistClass * obj) const
{
DazzleRenderObjClass * robj = (DazzleRenderObjClass *)obj;
unsigned int dazzle_type = robj->Get_Dazzle_Type();
const char * dazzle_type_name = DazzleRenderObjClass::Get_Type_Name(dazzle_type);
Matrix3D tm = robj->Get_Transform();
csave.Begin_Chunk(DAZZLEFACTORY_CHUNKID_VARIABLES);
WRITE_MICRO_CHUNK(csave,DAZZLEFACTORY_VARIABLE_OBJPOINTER,robj);
WRITE_MICRO_CHUNK(csave,DAZZLEFACTORY_VARIABLE_TRANSFORM,tm);
WRITE_MICRO_CHUNK_STRING(csave,DAZZLEFACTORY_VARIABLE_TYPENAME,dazzle_type_name);
csave.End_Chunk();
}
/*
** DazzleRenderObj save-load.
*/
const PersistFactoryClass & DazzleRenderObjClass::Get_Factory (void) const
{
return _DazzleFactory;
}
/**********************************************************************************************
**
** DazzleLayerClass Implementation
**
**********************************************************************************************/
DazzleLayerClass::DazzleLayerClass(void) :
visible_lists(NULL)
{
if (type_count != 0) {
// Generate an array with one visible list for each type.
// NOTE - this means that this constructor must be called AFTER all types
// are initialized
WWASSERT(type_count);
visible_lists = new DazzleRenderObjClass *[type_count];
for (unsigned int i = 0; i < type_count; i++) {
visible_lists[i] = NULL;
}
}
}
DazzleLayerClass::~DazzleLayerClass(void)
{
// NOTE - this destructor must be called BEFORE DeInit().
WWASSERT(type_count);
for (unsigned int i = 0; i < type_count; i++) {
Clear_Visible_List(i);
}
delete [] visible_lists;
}
void DazzleLayerClass::Render(CameraClass* camera)
{
if (!camera) return;
camera->Apply();
unsigned time_ms=WW3D::Get_Frame_Time();
if (time_ms==0) time_ms=1;
DX8Wrapper::Set_Material(NULL);
for (unsigned type=0;type<type_count;++type) {
if (!types[type]) continue;
int count = Get_Visible_Item_Count(type);
if (!count) continue;
DazzleRenderObjClass* n = visible_lists[type];
while (n) {
n->Render_Dazzle(camera);
n=n->Succ();
}
// Must clear the visible list at the end of each render.
Clear_Visible_List(type);
}
}
// ----------------------------------------------------------------------------
int DazzleLayerClass::Get_Visible_Item_Count(unsigned int type) const
{
if (type >= type_count) {
WWASSERT(0);
return 0;
}
int count=0;
DazzleRenderObjClass* n = visible_lists[type];
while (n) {
count++;
n=n->Succ();
}
return count;
}
// ----------------------------------------------------------------------------
void DazzleLayerClass::Clear_Visible_List(unsigned int type)
{
if (type >= type_count) {
WWASSERT(0);
return;
}
DazzleRenderObjClass* n = visible_lists[type];
while (n) {
n->Release_Ref();
n->on_list = false;
n=n->Succ();
}
visible_lists[type] = NULL;
}
/**********************************************************************************************
**
** DazzleVisibilityClass Implementation
** The default dazzle visibility handler asks the scene to determine whether the dazzle
** is occluded.
**
**********************************************************************************************/
float DazzleVisibilityClass::Compute_Dazzle_Visibility
(
RenderInfoClass & rinfo,
DazzleRenderObjClass * dazzle,
const Vector3 & point
) const
{
/*
** Look up the scene this dazzle is in
*/
SceneClass * scene = dazzle->Get_Scene();
RenderObjClass * container = dazzle->Get_Container();
while ((scene == NULL) && (container != NULL)) {
scene = container->Get_Scene();
container = container->Get_Container();
}
/*
** If we found the scene (we SHOULD!) then ask it to compute the visibility
*/
if (scene != NULL) {
float value = scene->Compute_Point_Visibility(rinfo,point);
scene->Release_Ref();
return value;
} else {
return 1.0f;
}
}
/**********************************************************************************************
**
** DazzlePrototypeClass Implementation
**
**********************************************************************************************/
RenderObjClass * DazzlePrototypeClass::Create(void)
{
return NEW_REF(DazzleRenderObjClass,(DazzleType));
}
WW3DErrorType DazzlePrototypeClass::Load_W3D(ChunkLoadClass & cload)
{
StringClass dazzle_type;
while (cload.Open_Chunk()) {
switch (cload.Cur_Chunk_ID())
{
READ_WWSTRING_CHUNK(cload,W3D_CHUNK_DAZZLE_NAME,Name);
READ_WWSTRING_CHUNK(cload,W3D_CHUNK_DAZZLE_TYPENAME,dazzle_type);
default:
break;
}
cload.Close_Chunk();
}
DazzleType = DazzleRenderObjClass::Get_Type_ID(dazzle_type);
if (DazzleType == UINT_MAX) {
DazzleType = 0;
}
return WW3D_ERROR_OK;
}
/**********************************************************************************************
**
** DazzleLoaderClass Implementation
**
**********************************************************************************************/
PrototypeClass * DazzleLoaderClass::Load_W3D(ChunkLoadClass & cload)
{
DazzlePrototypeClass * new_proto = new DazzlePrototypeClass;
new_proto->Load_W3D(cload);
return new_proto;
}