1282 lines
57 KiB
C
1282 lines
57 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 : WWPhys *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/wwphys/pscene.h $*
|
||
|
* *
|
||
|
* Author:: Greg Hjelstrom *
|
||
|
* *
|
||
|
* $Modtime:: 2/28/02 11:48a $*
|
||
|
* *
|
||
|
* $Revision:: 125 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
|
||
|
#if defined(_MSC_VER)
|
||
|
#pragma once
|
||
|
#endif
|
||
|
|
||
|
#ifndef PSCENE_H
|
||
|
#define PSCENE_H
|
||
|
|
||
|
#include "always.h"
|
||
|
#include "scene.h"
|
||
|
#include "widgetuser.h"
|
||
|
#include "physlist.h"
|
||
|
#include "aabtreecull.h"
|
||
|
#include "gridcull.h"
|
||
|
#include "vector.h"
|
||
|
#include "shader.h"
|
||
|
#include "vissample.h"
|
||
|
#include "vistablemgr.h"
|
||
|
#include "phystexproject.h"
|
||
|
#include "simplevec.h"
|
||
|
#include "vissectorstats.h"
|
||
|
|
||
|
class Matrix3D;
|
||
|
class ChunkLoadClass;
|
||
|
class ChunkSaveClass;
|
||
|
class PhysClass;
|
||
|
class LightPhysClass;
|
||
|
class LightClass;
|
||
|
class StaticPhysClass;
|
||
|
class RenderInfoClass;
|
||
|
class SpecialRenderInfoClass;
|
||
|
class VisRenderContextClass;
|
||
|
class VisOptimizationContextClass;
|
||
|
class AABoxClass;
|
||
|
class VertexMaterialClass;
|
||
|
class PathfindClass;
|
||
|
class PhysDecalSysClass;
|
||
|
class MeshClass;
|
||
|
class VisOptProgressClass;
|
||
|
class CameraShakeSystemClass;
|
||
|
class LightEnvironmentClass;
|
||
|
class StaticAnimPhysClass;
|
||
|
class StringClass;
|
||
|
|
||
|
// forward referencing the collision detection queries
|
||
|
class PhysRayCollisionTestClass;
|
||
|
class PhysAABoxCollisionTestClass;
|
||
|
class PhysOBBoxCollisionTestClass;
|
||
|
class PhysAABoxIntersectionTestClass;
|
||
|
class PhysOBBoxIntersectionTestClass;
|
||
|
class PhysMeshIntersectionTestClass;
|
||
|
|
||
|
// forward referencing the culling system types.
|
||
|
class PhysAABTreeCullClass;
|
||
|
class StaticAABTreeCullClass;
|
||
|
class DynamicAABTreeCullClass;
|
||
|
class PhysGridCullClass;
|
||
|
class StaticLightCullClass;
|
||
|
|
||
|
// Lighting solver
|
||
|
class LightSolveContextClass;
|
||
|
|
||
|
/**
|
||
|
|
||
|
Physics system
|
||
|
|
||
|
All objects in the world which want to interact physically (as opposed to being
|
||
|
simply decorations) will register a "PhysicalObject" with the physics sytem.
|
||
|
The ABC PhysicalObjectClass is used by the physics manager for the following
|
||
|
things:
|
||
|
|
||
|
- checking for collisions between all objects; methods for collision detection
|
||
|
will be pure virtual methods of the base class
|
||
|
- computing forces between any "linked" objects
|
||
|
- applying global gravity and damping to all of the objects
|
||
|
- telling all physical objects to timestep themselves.
|
||
|
|
||
|
Initializing the system
|
||
|
|
||
|
- Physics system will init itself by clearing all of its lists and
|
||
|
tables.
|
||
|
|
||
|
- Each game object asks the physics system to create an instance of a
|
||
|
physics object and specifies all of the important parameters...
|
||
|
|
||
|
- Whenever an object is added to the system, it is added in sorted order
|
||
|
to the x,y, and z "neighbor" lists.
|
||
|
|
||
|
Each frame the following things will happen:
|
||
|
|
||
|
- All game objects will exert their influence over their PhysicalObjects using
|
||
|
methods provided. Game objects will usually know exactly what PhysicalObject
|
||
|
type they have. I.e. a HummVee will know that its physical object is a
|
||
|
Wheel4PhysClass and will be able to directly call methods of that class.
|
||
|
|
||
|
- One at a time, each physical object will take its "move" for the frame. Moves
|
||
|
will be calculated in a framerate-independent way. A single "move" for an object
|
||
|
may consist of rotation and translation.
|
||
|
|
||
|
Each move, the following things will happen:
|
||
|
|
||
|
- The object will rotate in place according to its angular velocity and the
|
||
|
amount of time which has passed for this frame
|
||
|
|
||
|
- Collision detection code will "push" the object into a valid position in the world.
|
||
|
If it is unable to push the object into a valid position, the rotation state will
|
||
|
be reverted.
|
||
|
|
||
|
- The object will then compute a translational move for the frame based on its
|
||
|
velocity and the time which has passed.
|
||
|
|
||
|
- Collision detection code will test the final position for penetration with the world.
|
||
|
If penetration has occured, the object will be pushed out of the polygons it
|
||
|
is penetrating. If this is not possible, we revert to the previous state.
|
||
|
|
||
|
Brainstorming:
|
||
|
|
||
|
- Collision between any pair of objects can be disabled or enabled as desired?
|
||
|
|
||
|
- Multiple different types of collision objects or everything is a box?
|
||
|
Or everything is three different sets of 3d boxes?
|
||
|
|
||
|
- A separate sorted list for the x axis, y axis and z axis will be maintained. It
|
||
|
will be used to optimize the collision detection algorithm. A single, overall
|
||
|
bounding sphere / axis aligned box should be used for this quick rejection.
|
||
|
|
||
|
- How will all of the separate physical object types interact??? The papers all
|
||
|
handle everything as a rigid body, no special cases...
|
||
|
|
||
|
- Different types of objects need to interact whenever a collision occurs. The
|
||
|
physics manager should just detect collisions, then the objects should ask for
|
||
|
any info they need to resolve the collision. Whenever a value is computed for
|
||
|
a particular collision, it should be cached so that if the second object also
|
||
|
needs the same value, it is not re-computed.
|
||
|
|
||
|
- "real" collision resolution requires the velocity of the collision point.
|
||
|
|
||
|
- How do we generalize the dy/dt function for the ODE solver since we have multiple
|
||
|
different types of objects (with different state vectors)
|
||
|
* each object will be responsible for: (1) adding itself to the state vector
|
||
|
(2) getting its new state out of the state vector and (3) adding its
|
||
|
derivatives to the derivative vector. Each of these functions will
|
||
|
return the number of values which were added to the vector. This should
|
||
|
allow us to "dumb-down" the physics for objects which are far away too...
|
||
|
|
||
|
- Can each object be asked for its dy/dt separately?
|
||
|
* yes, each object will add its dy/dt values to a given array.
|
||
|
|
||
|
- All of this copying into the gigantic state vector sounds really in-efficient.
|
||
|
Find a better system. What if we only decide to use Euler's method, it could
|
||
|
be easily hard coded into each object type...
|
||
|
* The giganitic state vector approach is overkill. We will not use it.
|
||
|
|
||
|
12/03/97
|
||
|
|
||
|
- Each object will be "timestepped" individually. Each object type will be
|
||
|
free to use whatever integration method it wants to (again, no monolithic state
|
||
|
vector)
|
||
|
|
||
|
- One at a time, each object will be told to update their state. They will be
|
||
|
given an elapsed time to ensure that we are frame-rate independent.
|
||
|
|
||
|
- The steps a typical physical object will need to take in order to update itself:
|
||
|
|
||
|
- Store its current state so that we can revert if we have to
|
||
|
|
||
|
- Compute a desired state for the end of the timestep. This can be done
|
||
|
using the high-tech integrator and all of the rigid body dynamics equations.
|
||
|
|
||
|
- Do the rotation portion of that move in place.
|
||
|
|
||
|
- "Push" the object into a valid position (world polys and object polys)
|
||
|
If push goes into an infinite loop, revert and kill the angular velocity.
|
||
|
|
||
|
- Subdivide the linear move into steps which are ~half the characteristic
|
||
|
length of the bounding box. Store this vector
|
||
|
|
||
|
- Loop while we haven't eaten the entire translation:
|
||
|
|
||
|
- Add the sub-move vector
|
||
|
|
||
|
- "Push" the object into a valid position, modify velocity by normal of the
|
||
|
polygon collided with. If push goes into an infinite loop, revert to
|
||
|
previous sub-move and exit
|
||
|
|
||
|
|
||
|
Feb 9, 1998
|
||
|
|
||
|
Nope, try again, simplify, simplify, simplify!
|
||
|
|
||
|
- For objects which do not care about rotation causing collision (e.g. characters),
|
||
|
*use a collision object which doesn't care either!* So, for characters and many of the
|
||
|
objects in the game, we will use either Axis-Aligned boxes or cylinders. Since I have
|
||
|
the math for casting an axis-aligned box, I will probably use that. These objects will
|
||
|
rotate within thier box so to the physics system, rotation / orientation will be trivial.
|
||
|
|
||
|
- Jello Physics! For objects like the vehicles which were going to be done with rigid body
|
||
|
dynamics I'm going to try a spring-mass model. There are many problems with rigid body
|
||
|
dynamics. It is very difficult and expensive to compute correct contact forces, and it
|
||
|
is difficult to find contact points. Assuming the bodies are rigid requires collision
|
||
|
detection or at least penetration depth calculations for solids like Oriented Boxes or
|
||
|
Convex Polyhedra. I have solved "volume-sweeping" for oriented boxes but not "volume-
|
||
|
rotation" or the penetration depth calculation. The spring mass model avoids these
|
||
|
problems and it comes down to testing line-segments for intersection with the world
|
||
|
polygons.
|
||
|
|
||
|
- Each object will still be moved one at a time. At the beginning of a move, an object
|
||
|
must be in a valid position. Its move will be "cast" through the world and the object
|
||
|
will only actually move up to the first collision. At that point, the velocity will be
|
||
|
modified to slide along whatever it it (if possible). Repeat until the entire move
|
||
|
vector is eaten or the object is stopped completely.
|
||
|
|
||
|
April 14, 1998
|
||
|
|
||
|
- Finally getting back to the physics system. Month of march was spent converting code
|
||
|
to the new version of surrender. So, not all of the items in the February notes were
|
||
|
implemented. At this point, I have the beginnings of the character collision system. It
|
||
|
relies on the Cast_AABox function which sweeps an axis-aligned box through the world.
|
||
|
currently it only checks for collisions with the terrain polygons. Also, the "move-one-
|
||
|
at-a-time" system was implemented and the old simulation style system removed.
|
||
|
|
||
|
- I have hidden the implementation of the terrain collision from the game engine. Any
|
||
|
terrain implementation must simply support the Cast_Ray, Cast_AABox, Cast_OBBox functions
|
||
|
and be able to give the user a pointer to a render object which can be added to the scene
|
||
|
in which the terrain is to be rendered. This should allow some freedom to experiment with
|
||
|
octrees or bsp trees to speed up the cast functions...
|
||
|
|
||
|
- The next step is to use the existing "partitioned" mesh to implement the rest of the
|
||
|
needed collision detection functionality so that the rest of the team can work with it
|
||
|
while I experiment with more efficient systems.
|
||
|
- Cast_AABox must be made to also check against the objects.
|
||
|
- Cast_Ray should be hooked in and a physics object for projectiles which is based on
|
||
|
Cast_Ray should be created.
|
||
|
- Communication system between the game engine and collision system should be tested.
|
||
|
This is going to be a virtual class which simply defines a virtual callback method,
|
||
|
game objects will multiply inherit this class and get messages from the system
|
||
|
whenever a collision occurs.
|
||
|
|
||
|
June 1, 1998
|
||
|
|
||
|
- Working on collision detection again. Spent the past two weeks or so writing some
|
||
|
bpt code which turns the terrain mesh into a combination bsp/box tree (I simply call it
|
||
|
a Binary Partition Tree). Each node contains a bounding box which bounds all polygons
|
||
|
in the tree below that node. Building an efficient bpt is becoming a priority since
|
||
|
we're getting a lot of splits and also nodes with gobs of polys in them due to the
|
||
|
way our terrains are constructed. Should be easy to take advantage of our grid lines.
|
||
|
|
||
|
- Collision system has been hooked into the game and a very simple projectile physics
|
||
|
class written which uses rays instead of full blown boxes. The collision system communicates
|
||
|
back to the game through multiple inheritance of a "CollisionObserverClass". The projectile
|
||
|
physics work pretty well when you plug in RK4 or Midpoint as the integrator; same trajectory
|
||
|
no matter what the framerate (within reason). (Mar2000 note: this was pretty stupid since you can
|
||
|
directly calculate where the projectile would end up if the only force is gravity!)
|
||
|
|
||
|
- Changing all of the internal collision functions to pass around "collision test classes"
|
||
|
which wrap the primitive, its movement vector, a results structure, and any pre-calculatable
|
||
|
variables into one structure. The main reason for this was just so I have a place to put
|
||
|
the info that can be precalculated and re-used. (e.g. put a min,max along with the AABoxClass)
|
||
|
|
||
|
- Now writing the recursive AABox Cast function which casts the box against the bpt. Once
|
||
|
this is in place, we should start getting a significant speedup from using the bpt.
|
||
|
|
||
|
- Thinking again about using a hybrid between the "every object moves on its own" and
|
||
|
the "every object puts itself into the monolithic state vector" ideas. I do need some objects
|
||
|
to be simulated together if we want to completely avoid being tied to fixed timesteps. For
|
||
|
example, I need to simulate the camera along with the object its tied to... If we do true
|
||
|
contact... all things touching each other will need to be simulated together.
|
||
|
|
||
|
July 13, 1998
|
||
|
|
||
|
- Removing the distinction between physical objects and terrain. New engine idea will use
|
||
|
a combination of a heightfield and tilemap. This means we're going to have multiple "terrains"
|
||
|
and we will also be having meshes which don't move but are collideable such as guard towers, etc.
|
||
|
|
||
|
August 31, 1998
|
||
|
|
||
|
CURRENT SITUATION: several sub-systems need efficient culling:
|
||
|
- rendering system needs to be able to only render objects which are in the view frustum
|
||
|
- collision system needs to quickly narrow down the number of objects checked for each
|
||
|
collision query made.
|
||
|
- AI/Game Logic needs to be able to quickly find "nearby" objects, objects within certain
|
||
|
radii, objects which are in a given cone etc...
|
||
|
|
||
|
PROBLEMS:
|
||
|
- current code has no culling except for the TileMap object which is itself a huge render
|
||
|
object spanning the entire level that performs culling internally in its render call.
|
||
|
- currently, the "SceneClass" is expected to only deal with RenderObj derived classes.
|
||
|
- collision queries and the like must go through physics object interfaces so that some
|
||
|
physics objects can use simple primitives
|
||
|
- deriving physobj from renderobj doesn't make a lot of sense because render obj is a
|
||
|
relatively "heavy" class. I don't want to make another wrapper (and have the associated
|
||
|
duplicated transforms, etc...)
|
||
|
- Render objects can have their transforms changed at the programmers whim, there is
|
||
|
no built-in provision for telling the scene to refresh its culling information
|
||
|
|
||
|
SOLUTION:
|
||
|
- make a physics "SceneClass" with culling datastructures for both static and dynamic culling
|
||
|
- physics scene deals only with physics objects
|
||
|
- therefore all objects in the "game world" will be represented by a physics object
|
||
|
- when a physics object changes position, the culling database can be refreshed
|
||
|
- physobj needs its linkage information built in.
|
||
|
|
||
|
class PhysicsSceneClass : public SceneClass
|
||
|
{
|
||
|
void Add_Render_Obj(...) { assert(0); }
|
||
|
void Remove_Render_Obj(...) { assert(0); }
|
||
|
|
||
|
void Add_Physical_Object(PhysObjClass * pobj,hint = MOVING);
|
||
|
void Remove_Physical_Object(PhysObjClass * pobj);
|
||
|
|
||
|
void Render(CameraClass & cam);
|
||
|
bool Cast_Ray( );
|
||
|
bool Cast_AABox( );
|
||
|
bool Cast_OBBox( );
|
||
|
PhysObjListClass * Get_Spatial_Object_List(pos,radius);
|
||
|
PhysObjListClass * Get_Spatial_Object_List(min,max);
|
||
|
PhysObjListClass * Get_Spatial_Object_List(frustum);
|
||
|
PhysObjListClass * Get_Spatial_Object_List(raytest);
|
||
|
PhysObjListClass * Get_Spatial_Object_List(raytest);
|
||
|
}
|
||
|
|
||
|
September 15, 1998
|
||
|
|
||
|
Finished my work on the initial prototype of the level editor. In the process of writing the
|
||
|
level editor, I implemented the new PhysicsSceneClass which replaces the old classes: PhysicsSystem
|
||
|
PrivatePhysicsSystem and CollisionSystem and also takes over the job of the main 3D game scene
|
||
|
for rendering. This caused some major re-organization and as a result most of WWPhys was #if 0'd...
|
||
|
|
||
|
A new base class PhysClass was implemented along with a derived DecorationPhysClass which can
|
||
|
be inserted into this scene and rendered, collided with, etc. The AABTree culling system for
|
||
|
all of the static meshes was written to be dynamically re-partitionable. The Grid culling system
|
||
|
was only implemented in terms of an interface. Currently it just contains a linked list of
|
||
|
PhysClasses.
|
||
|
|
||
|
Next job is to add all of the functionality of the old system (Phys4, CharPhys, Tilemap, etc) into
|
||
|
this system and get Commando running on top of it.
|
||
|
|
||
|
NOTES:
|
||
|
- New system contains provisions for updating the culling datastructures when an object moves.
|
||
|
I should also add a "safe teleport" function which asks the system if it is ok for an object
|
||
|
to be in a given position and if not, move the object to a safe position. This could get
|
||
|
rid of the possibility of "startbad's" on level load.
|
||
|
|
||
|
- TileMapClass is now obsolete but much of its functionality will have to go into game code.
|
||
|
The PhysicsSceneClass contains an axis-aligned bounding box tree which serves the purpose
|
||
|
that TileMap used to. Other "TerrainPhysClass's" are still going to be single objects though.
|
||
|
|
||
|
November 30, 1998
|
||
|
|
||
|
Just completed another massive port to the latest version of surrender (1.4x). Also had to
|
||
|
rewrite much of the plugin this time.
|
||
|
|
||
|
Adding occlusion culling for all physics objects in the "static" scene. I still have some
|
||
|
questions in my mind as to how this is going to work but the basic idea is that there will
|
||
|
be "vis-sectors". Each vis-sector will contain a bit-vector with one bit for every piece of
|
||
|
static geometry which indicates whether that piece of geometry can be seen from this
|
||
|
"vis-sector". These bit arrays will be created by rendering the scene from each sector
|
||
|
in a way that writes the node's id rather than texturing, lighting, etc, and then reading
|
||
|
the framebuffer to see which nodes were not occluded. Currently I have two questions:
|
||
|
How are these vis sectors defined? and How can I cull dynamic objects using this information?
|
||
|
|
||
|
Now working on the occlusion bit vectors. Currently implementing it with a full bit vector for
|
||
|
each object which contains a bit for every other object. If we compress this, we could at
|
||
|
the start of each frame, decompress the vis bits for the current active node (or even only
|
||
|
decompress it when the active node changes). Only problem is in implementation, editor stuff
|
||
|
will want an uncompressed one that is easily modified; game will want tight compressed vis table.
|
||
|
|
||
|
December 21, 1998
|
||
|
|
||
|
Converted W3D to render directly to the gerd (bypass the sr scene graph). This was the
|
||
|
easiest way to implement the vis-detection stuff and opens the door for us to
|
||
|
hierarchically cull lights. Vis detection is implemented now.
|
||
|
|
||
|
Need to implement a file format for the map.
|
||
|
|
||
|
- What is in the file format?
|
||
|
- Who reads/writes it?
|
||
|
- If pscene just loads stuff directly, how does Byon get ahold of the objects?
|
||
|
- VisBits are independent of culling system! They only depend on the IDs not changing!
|
||
|
- Its a lot simpler if this system *only* contains completely static meshes! (not walls, etc)
|
||
|
+ none of them *need* game logic
|
||
|
+ none of them change or move
|
||
|
+ byon doesn't need a game object wrapped around them
|
||
|
- is there no pre-calculated lighting on the non static stuff?
|
||
|
- want as much as we can get into this since it should be faster and has no size restrictions
|
||
|
|
||
|
File format is going to be chunk based. Parsing of the top-levels of the file will occur
|
||
|
in Commando. Certain chunks will be passed down to the PhysicsSceneClass to be handled.
|
||
|
These chunks will include a chunk which wraps all of the culling data, a chunk which wraps
|
||
|
each static object or dynamic object, chunks for zones and lights, etc.
|
||
|
|
||
|
Jan 15, 1999
|
||
|
|
||
|
Working on the lighting management system. For the static lights in the level, I want
|
||
|
to use an efficient culling system like the AABTree. All of these lights will be entered
|
||
|
into the scene through a custom call in the physics scene. All dynamic lights will be
|
||
|
added through the normal Add_Render_Object function or by being added as sub-objects
|
||
|
of a model in the scene.
|
||
|
|
||
|
Add_Render_Obj and Remove_Render_Obj will be implemented by having the physics scene
|
||
|
automatically create a cullable object for the render object and storing the pointer
|
||
|
to that object in the UserData field. In addition, the cullable object created for them
|
||
|
will need to be a "dirty culler" that assumes its bounding box or transform could change
|
||
|
at any time since the user is obviously working with a render object and could change
|
||
|
the transform underneath us (normally this is a no-no). These will be added to a "dirty
|
||
|
culler" list and caused to re-insert themselves into the dynamic culling system each
|
||
|
frame. These objects will never cause collisions either (just for sanity) they
|
||
|
are only visual...
|
||
|
|
||
|
Render function will look like this:
|
||
|
|
||
|
Render() {
|
||
|
|
||
|
update the "dirty cullers"
|
||
|
collect dynamic objects and vertex processors (dy_obj_list,dy_vp_list)
|
||
|
push dynamic vertex processors
|
||
|
render static terrain
|
||
|
|
||
|
global optimization of LOD levels for the dynamic objects
|
||
|
|
||
|
for each dynamic object
|
||
|
push static lights which may affect it
|
||
|
render
|
||
|
pop static lights that were pushed
|
||
|
|
||
|
pop dynamic vertex processors
|
||
|
|
||
|
May 27, 1999
|
||
|
|
||
|
Moving the Visibility system into PhysicsSceneClass so that it can incorporate
|
||
|
pre-calculated visibility for other things like dynamic objects. Previously it
|
||
|
was pretty nicely encapsulated inside of the static culling system.
|
||
|
|
||
|
October 26, 1999
|
||
|
|
||
|
Adding shadow generation code
|
||
|
|
||
|
Jan 2000
|
||
|
|
||
|
Pluging in the decal system, texture projection system is mostly done except for
|
||
|
optimizations and static projector generation (masses of tree shadows and stuff).
|
||
|
|
||
|
Feb 21, 2000
|
||
|
|
||
|
Decals are done, Animated Static objects with collision are working now (translation
|
||
|
only). Adding code which generates the static projectors (tree shadows, window projections
|
||
|
and things like that). Optimized the view-frustum culling code to propogate the plane
|
||
|
masks and perform trivial acceptance of entire sub-trees.
|
||
|
|
||
|
Junk 28, 1000
|
||
|
|
||
|
Major VIS update. Now the dynamic culling system is a pre-generated AABTree with
|
||
|
precalculated visiblity for each node in the tree. In addition, the static object
|
||
|
culling system contains hierarchical visibility data and each light will have a
|
||
|
pvs for what static objects and dynamic object cells it can "see". The generation
|
||
|
of the dynamic object AAB-Tree is "seeded" with a pathfind solve and a coarse
|
||
|
voxelization of the level. This tree is "optimized" after VIS is computed; redundant
|
||
|
leaves of the tree are deleted and the vis tables collapsed.
|
||
|
|
||
|
Aug 9, 2000
|
||
|
|
||
|
Implementing a new lighting system which collects the lights affecting each object
|
||
|
which is not pre-lit and creates temporary directional lights for them. This should
|
||
|
solve the problem of having a level with thousands of lights but only a few that
|
||
|
actually need to be active. We'll still need to reduce the number of lights in
|
||
|
some levels though. The code for this lighting algorithm can be found in
|
||
|
lightenvironment.cpp.
|
||
|
|
||
|
Sept 24, 2000
|
||
|
|
||
|
Making the lighting system coherent across frames. If an object doesn't move, it
|
||
|
will have its local static lighting environment cached and can just re-use the data.
|
||
|
Whenever physics object move, they invalidate their internal cache and will ask
|
||
|
the physics scene to recompute the lighting environment next time its needed. This
|
||
|
change involved adding the Compute_Static_Lighting function to pscene and the
|
||
|
pair of functions: Invalidate_Static_Lighting_Cache and Get_Static_Lighting_Cache
|
||
|
to PhysClass. These caches must also be invalidated when lights in the scene change
|
||
|
state (such as when the power goes out in a building...)
|
||
|
|
||
|
April 2001
|
||
|
|
||
|
Installed the new vis renderer, it seems to simplify a lot of code! Also converting
|
||
|
the shadow rendering code to work under DX8. I plan to add a new shadow mode which
|
||
|
uses hardware to render-to-texture.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
** PhysicsSceneClass
|
||
|
** Drop all of the objects into the world in here, represented by physics objects, then
|
||
|
** you can do fun things like rendering and collision detection.
|
||
|
*/
|
||
|
class PhysicsSceneClass : public SceneClass , public WidgetUserClass
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
PhysicsSceneClass(void);
|
||
|
virtual ~PhysicsSceneClass(void);
|
||
|
|
||
|
/*
|
||
|
** For now, making the Physics Scene a singleton. If we want the feature of
|
||
|
** instantiating multiple physics scenes, we will need to add a scene pointer
|
||
|
** to the base PhysClass and resolve all cases where we use this function.
|
||
|
*/
|
||
|
static PhysicsSceneClass * Get_Instance(void) { return TheScene; }
|
||
|
|
||
|
/*
|
||
|
** Timestep the world
|
||
|
*/
|
||
|
void Update(float dt,int frameid);
|
||
|
void Pre_Render_Processing(CameraClass & camera);
|
||
|
void Post_Render_Processing(void);
|
||
|
|
||
|
/*
|
||
|
** Methods to add and remove physical objects in the system
|
||
|
*/
|
||
|
void Add_Dynamic_Object(PhysClass * newobj);
|
||
|
void Add_Static_Object(StaticPhysClass * newtile,int cull_node_id = -1);
|
||
|
void Add_Dynamic_Light(LightPhysClass * light);
|
||
|
void Add_Static_Light(LightPhysClass * newlight,int cull_node_id = -1);
|
||
|
|
||
|
void Remove_Object(PhysClass * obj);
|
||
|
void Remove_All(void);
|
||
|
|
||
|
void Delayed_Remove_Object(PhysClass * obj);
|
||
|
void Process_Release_List(void);
|
||
|
|
||
|
bool Contains(PhysClass * obj);
|
||
|
|
||
|
RefPhysListIterator Get_Dynamic_Object_Iterator(void);
|
||
|
RefPhysListIterator Get_Static_Object_Iterator(void);
|
||
|
RefPhysListIterator Get_Static_Anim_Object_Iterator(void);
|
||
|
RefPhysListIterator Get_Static_Light_Iterator(void);
|
||
|
|
||
|
TexProjListIterator Get_Static_Projector_Iterator(void);
|
||
|
TexProjListIterator Get_Dynamic_Projector_Iterator(void);
|
||
|
|
||
|
StaticPhysClass * Get_Static_Object_By_ID(uint32 id);
|
||
|
|
||
|
/*
|
||
|
** Dirty Cull List
|
||
|
**
|
||
|
** The objects in this list update their culling every frame.
|
||
|
** An example of this is a cinematic with an animated bounding
|
||
|
** box.
|
||
|
**
|
||
|
*/
|
||
|
void Add_To_Dirty_Cull_List(PhysClass *obj);
|
||
|
void Remove_From_Dirty_Cull_List(PhysClass *obj);
|
||
|
bool Is_In_Dirty_Cull_List(PhysClass *obj);
|
||
|
|
||
|
/*
|
||
|
** Lighting Controls
|
||
|
**
|
||
|
** Lighting Mode: You can disable all lighting calculations, use the surrender lighting code,
|
||
|
** or use the el-cheapo lighting code which turns all lights into direction lights with no
|
||
|
** per-vertex attenuation or direction calculations.
|
||
|
**
|
||
|
** Scene Ambient Light: The physics scene takes over the ambient light (is also implemented
|
||
|
** in SceneClass) so that I can tweak the ambient light on a per-object basis. This will
|
||
|
** probably be done to make dynamic objects blend in with the light-mapped environment better.
|
||
|
**
|
||
|
** Lighting LOD: Set the cut-off intensity where point light sources are turned into pure
|
||
|
** ambient lights. For example, if this is set to 0.5f, then any light whose intensity
|
||
|
** is less that 0.5 will be converted into a slightly dimmer ball of ambient and thus not
|
||
|
** incur the directional lighting calculation cost. NOTE: this lighting LOD is only
|
||
|
** used when using LIGHTING_MODE_CHEAP lighting model
|
||
|
**
|
||
|
** Sun Light: This controls the direction of the sun. For Renegade, we probably won't ever
|
||
|
** change this in-game. However, if we did not use light-maps and we re-calculated all of
|
||
|
** the static projectors each time the sun moved, we could have a moving sun.
|
||
|
**
|
||
|
** NOTE: elevation is the angle that the sun makes with the horizontal,
|
||
|
** rotation is the angle between the +X axis and the line of the sun projected onto the X-Y plane.
|
||
|
** these variables are chose to match the ones in LightScape.
|
||
|
*/
|
||
|
enum {
|
||
|
LIGHTING_MODE_NONE = 0,
|
||
|
LIGHTING_MODE_SURRENDER,
|
||
|
LIGHTING_MODE_CHEAP
|
||
|
};
|
||
|
|
||
|
int Get_Lighting_Mode(void) { return LightingMode; }
|
||
|
void Set_Lighting_Mode(int mode) { LightingMode = mode; }
|
||
|
|
||
|
virtual void Set_Ambient_Light(const Vector3 & color) { SceneAmbientLight = color; }
|
||
|
virtual const Vector3 & Get_Ambient_Light(void) { return SceneAmbientLight; }
|
||
|
|
||
|
void Set_Lighting_LOD_Cutoff(float intensity);
|
||
|
float Get_Lighting_LOD_Cutoff(void);
|
||
|
|
||
|
bool Is_Sun_Light_Enabled(void);
|
||
|
void Enable_Sun_Light(bool onoff);
|
||
|
LightClass * Get_Sun_Light(void);
|
||
|
void Set_Sun_Light_Orientation(float rotation,float elevation);
|
||
|
void Get_Sun_Light_Orientation(float * set_rotation,float * set_elevation);
|
||
|
void Get_Sun_Light_Vector(Vector3 * set_vector);
|
||
|
|
||
|
void Compute_Static_Lighting(LightEnvironmentClass * light_env,const Vector3 & obj_center,bool use_sun,int vis_object_id);
|
||
|
void Invalidate_Lighting_Caches(const AABoxClass & bounds);
|
||
|
|
||
|
/*
|
||
|
** Collision Detection Methods
|
||
|
** Set_Collision_Region - collects objects in the given region into a list for subsequent collision checks
|
||
|
** this is useful if you're going to do a lot of checks in the same general area (e.g. RigidBody)
|
||
|
** Release_Collision_Region - releases the collision region list
|
||
|
** Cast_Ray - casts a ray into the world, returning information about what was collided and at what point along the ray
|
||
|
** Cast_AABox - casts an axis aligned box, returning information about what was collided and at what point
|
||
|
** Cast_OBBox - casts an oriented box, returning information about what was collided and at what point
|
||
|
** Intersection_Test - tests the given primitive for intersection with anything else in the system
|
||
|
*/
|
||
|
void Set_Collision_Region(const AABoxClass & bounds,int colgroup);
|
||
|
void Release_Collision_Region(void);
|
||
|
|
||
|
bool Cast_Ray(PhysRayCollisionTestClass & raytest,bool use_collision_region = false);
|
||
|
bool Cast_AABox(PhysAABoxCollisionTestClass & boxtest,bool use_collision_region = false);
|
||
|
bool Cast_OBBox(PhysOBBoxCollisionTestClass & boxtest,bool use_collision_region = false);
|
||
|
|
||
|
bool Intersection_Test(PhysAABoxIntersectionTestClass & boxtest,bool use_collision_region = false);
|
||
|
bool Intersection_Test(PhysOBBoxIntersectionTestClass & boxtest,bool use_collision_region = false);
|
||
|
bool Intersection_Test(PhysMeshIntersectionTestClass & meshtest,bool use_collision_region = false);
|
||
|
|
||
|
bool Intersection_Test(const AABoxClass & box,int collision_group,int collision_type,bool use_collision_region = false);
|
||
|
bool Intersection_Test(const OBBoxClass & box,int collision_group,int collision_type,bool use_collision_region = false);
|
||
|
|
||
|
void Force_Dynamic_Objects_Awake(const AABoxClass & box);
|
||
|
|
||
|
/*
|
||
|
** Collection Methods
|
||
|
** Collect lists of objects which meet certain requirements.
|
||
|
** TODO: is this the interface we want? maybe the user can give a callback object?
|
||
|
** maybe more filters over which objects are added to the list?
|
||
|
*/
|
||
|
void Collect_Objects(const Vector3 & point,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Collect_Objects(const AABoxClass & box,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Collect_Objects(const OBBoxClass & box,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Collect_Objects(const FrustumClass & frustum,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
|
||
|
void Collect_Collideable_Objects(const AABoxClass & box,int colgroup,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Collect_Collideable_Objects(const OBBoxClass & box,int colgroup,bool static_objs, bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
|
||
|
void Collect_Lights(const Vector3 & point,bool static_lights,bool dynamic_lights,NonRefPhysListClass * list);
|
||
|
void Collect_Lights(const AABoxClass & bounds,bool static_lights,bool dynamic_lights,NonRefPhysListClass * list);
|
||
|
|
||
|
StaticPhysClass * Find_Static_Object( int instance_id );
|
||
|
|
||
|
/*
|
||
|
** Collision Groups:
|
||
|
**
|
||
|
** Each physical object can be assigned to a collision group. Then
|
||
|
** collision detection between any pair of groups can be enabled or
|
||
|
** disabled. An object will completely ignore objects in collision
|
||
|
** groups that are disabled relative to its collision group.
|
||
|
**
|
||
|
** Collision groups are numbered 0x0 - 0xF
|
||
|
*/
|
||
|
enum {
|
||
|
COLLISION_GROUP_WORLD = 0x0F,
|
||
|
MAX_COLLISION_GROUP = 0x0F,
|
||
|
NUM_COLLISION_FLAGS = 256,
|
||
|
COLLISION_FLAG_SHIFT = 4
|
||
|
};
|
||
|
|
||
|
void Enable_Collision_Detection(int group0,int group1);
|
||
|
void Disable_Collision_Detection(int group0,int group1);
|
||
|
void Enable_All_Collision_Detections(int group);
|
||
|
void Disable_All_Collision_Detections(int group);
|
||
|
bool Do_Groups_Collide(int group0,int group1);
|
||
|
|
||
|
/*
|
||
|
** Cause the culling systems to re-partition themselves. (Typically only done in the EDITOR!)
|
||
|
** The Update_Culling_System_Bounding_Boxes can be used by the EDITOR to refresh the
|
||
|
** boxes in the culling systems without re-partitioning (and losing vis data...)
|
||
|
*/
|
||
|
void Re_Partition_Static_Objects(void);
|
||
|
void Re_Partition_Static_Lights(void);
|
||
|
void Re_Partition_Static_Projectors(void);
|
||
|
void Re_Partition_Dynamic_Culling_System(void);
|
||
|
void Re_Partition_Dynamic_Culling_System(DynamicVectorClass<AABoxClass> & virtual_occludees);
|
||
|
void Update_Culling_System_Bounding_Boxes(void);
|
||
|
bool Verify_Culling_Systems(StringClass & set_error_report);
|
||
|
|
||
|
/*
|
||
|
** Visibility System.
|
||
|
** Enable_Vis - turn the vis system on or off
|
||
|
** Invert_Vis - invert the logic of vis, draw what would be occulded
|
||
|
** Set_Vis_Quick_And_Dirty - when generating, make non-occluders always visible (only used in preprocessing)
|
||
|
** Enable_Vis_Sector_Display - highlight the current vis sector in wireframe
|
||
|
** Enable_Vis_Sector_History_Display - highlight the last few vis sectors
|
||
|
** Disable_Vis_Sector_Fallback - don't fall back to the previous sector when there is no sector for the current position
|
||
|
*/
|
||
|
void Enable_Vis(bool onoff); // on by default
|
||
|
void Invert_Vis(bool onoff); // off by default
|
||
|
void Set_Vis_Quick_And_Dirty(bool onoff); // off by default
|
||
|
void Enable_Vis_Sector_Display(bool onoff); // off by default
|
||
|
void Enable_Vis_Sector_History_Display(bool onoff); // off by default
|
||
|
void Enable_Vis_Sector_Fallback(bool onoff); // on by default
|
||
|
void Enable_Backface_Occluder_Debug(bool onoff);
|
||
|
|
||
|
bool Is_Vis_Enabled(void);
|
||
|
bool Is_Vis_Inverted(void);
|
||
|
bool Is_Vis_Quick_And_Dirty(void);
|
||
|
bool Is_Vis_Sector_Display_Enabled(void);
|
||
|
bool Is_Vis_Sector_History_Display_Enabled(void);
|
||
|
bool Is_Vis_Sector_Missing(void);
|
||
|
bool Is_Vis_Sector_Fallback_Enabled(void);
|
||
|
bool Is_Backface_Occluder_Debug_Enabled(void);
|
||
|
|
||
|
void Lock_Vis_Sample_Point(bool onoff);
|
||
|
bool Is_Vis_Sample_Point_Locked(void);
|
||
|
|
||
|
void Compute_Vis_Sample_Point(const CameraClass & camera,Vector3 * set_point);
|
||
|
VisTableClass * Get_Vis_Table(int vis_sector_id);
|
||
|
VisTableClass * Get_Vis_Table(const Vector3 & point);
|
||
|
VisTableClass * Get_Vis_Table(const CameraClass & camera);
|
||
|
VisTableClass * Get_Vis_Table_For_Rendering(const CameraClass & camera);
|
||
|
|
||
|
virtual void On_Vis_Occluders_Rendered(VisRenderContextClass & context,VisSampleClass & sample) {}
|
||
|
|
||
|
/*
|
||
|
** Dynamic object visibility system debugging. This system is no longer implemented
|
||
|
** as a "grid" but rather an AABTree...
|
||
|
*/
|
||
|
enum {
|
||
|
VIS_GRID_DISPLAY_NONE = 0,
|
||
|
VIS_GRID_DISPLAY_ACTUAL_BOXES,
|
||
|
VIS_GRID_DISPLAY_CENTERS,
|
||
|
VIS_GRID_DISPLAY_OCCUPIED
|
||
|
};
|
||
|
|
||
|
void Set_Vis_Grid_Display_Mode(int mode);
|
||
|
int Get_Vis_Grid_Display_Mode(void);
|
||
|
|
||
|
void Vis_Grid_Debug_Reset_Node(void);
|
||
|
bool Vis_Grid_Debug_Enter_Parent(void);
|
||
|
bool Vis_Grid_Debug_Enter_Sibling(void);
|
||
|
bool Vis_Grid_Debug_Enter_Front_Child(void);
|
||
|
bool Vis_Grid_Debug_Enter_Back_Child(void);
|
||
|
|
||
|
/*
|
||
|
** Dynamic objects look up their vis-ID throught this method. Note that if you pass in a
|
||
|
** pointer to your previous node_id, the lookup will be faster and this variable will be modified
|
||
|
** with the updated node id. The first time this method is called, initialize the node_id to zero.
|
||
|
*/
|
||
|
uint32 Get_Dynamic_Object_Vis_ID(const AABoxClass & obj_bounds,int * node_id = NULL);
|
||
|
void Debug_Display_Dynamic_Vis_Node(int node_id);
|
||
|
|
||
|
/*
|
||
|
** Visibility Pre-Processing System. (Typically only used in the EDITOR!)
|
||
|
** Reset_Vis - marks the visibility data as dirty, to be discarded at the next opportunity
|
||
|
** Validate_Vis - manually validates the visibility data (used after loading for example)
|
||
|
** Allocate_Vis_Object_Id - reserve id(s) for objects whose visibility is to be tracked
|
||
|
** Allocate_Vis_Sector_Id - reserve id(s) for vis sectors (view cells).
|
||
|
** Get_Vis_Table_Size - returns the number of Vis Object ID's reserved
|
||
|
** Get_Vis_Table_Count - returns the number of Vis Sector ID's reserved
|
||
|
** Update_Vis - performs a vis-sample from the given position or camera
|
||
|
** Export_Vis_Data - saves just the visibility data to a file
|
||
|
** Import_Vis_Data - loads the visibility data from a file
|
||
|
** Show_Vis_Window - enable display of the vis render window
|
||
|
** Is_Vis_Window_Visibile - test whether the vis render window is being displayed
|
||
|
** Generate_Vis_Statistics_Report - generates a report giving the amount of polygons and textures
|
||
|
** visible from each sector in the system.
|
||
|
** Optimize_Visibility_Data - compresses vis by removing redundant vis-id's and pruning the dynamic culling
|
||
|
** system. This should only be called *after* all vis samples have been completed.
|
||
|
*/
|
||
|
virtual void Reset_Vis(bool doitnow = false);
|
||
|
void Validate_Vis(void);
|
||
|
int Allocate_Vis_Object_ID(int count = 1);
|
||
|
int Allocate_Vis_Sector_ID(int count = 1);
|
||
|
int Get_Vis_Table_Size(void); // also max vis *object* ID and vis object count.
|
||
|
int Get_Vis_Table_Count(void); // also max vis *sector* ID and vis sector count.
|
||
|
|
||
|
VisSampleClass Update_Vis(const Matrix3D & camera,VisDirBitsType direction_bits = VIS_ALL);
|
||
|
VisSampleClass Update_Vis(const Vector3 & sample_point,const Matrix3D & camera,VisDirBitsType direction_bits = VIS_ALL,CameraClass * alternate_camera = NULL,int user_vis_id = -1);
|
||
|
int Get_Static_Light_Count(void);
|
||
|
void Generate_Vis_For_Light(int light_index);
|
||
|
|
||
|
void Export_Vis_Data(ChunkSaveClass & csave);
|
||
|
void Import_Vis_Data(ChunkLoadClass & cload);
|
||
|
|
||
|
void Show_Vis_Window(bool onoff);
|
||
|
bool Is_Vis_Window_Visible(void);
|
||
|
|
||
|
void Generate_Vis_Statistics_Report(DynamicVectorClass<VisSectorStatsClass> & report);
|
||
|
|
||
|
void Optimize_Visibility_Data(VisOptProgressClass & progress_status);
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Texture Projection System.
|
||
|
*/
|
||
|
void Enable_Static_Projectors(bool onoff);
|
||
|
bool Are_Static_Projectors_Enabled(void);
|
||
|
void Enable_Dynamic_Projectors(bool onoff);
|
||
|
bool Are_Dynamic_Projectors_Enabled(void);
|
||
|
|
||
|
void Add_Static_Texture_Projector(TexProjectClass * newprojector);
|
||
|
void Remove_Static_Texture_Projector(TexProjectClass * projector);
|
||
|
void Add_Dynamic_Texture_Projector(TexProjectClass * newprojector);
|
||
|
void Remove_Dynamic_Texture_Projector(TexProjectClass * projector);
|
||
|
|
||
|
void Remove_Texture_Projector(TexProjectClass * projector);
|
||
|
bool Contains(TexProjectClass * projector);
|
||
|
|
||
|
/*
|
||
|
** Shadow system, built on top of the Texture Projection system.
|
||
|
*/
|
||
|
enum ShadowEnum
|
||
|
{
|
||
|
SHADOW_MODE_NONE = 0, // no shadows at all
|
||
|
SHADOW_MODE_BLOBS, // projected blob shadows
|
||
|
SHADOW_MODE_BLOBS_PLUS, // projected blobs with main character having a rendered shadow
|
||
|
SHADOW_MODE_HARDWARE, // use render-to-texture hardware
|
||
|
SHADOW_MODE_COUNT,
|
||
|
};
|
||
|
|
||
|
void Set_Shadow_Mode(ShadowEnum shadow_mode);
|
||
|
ShadowEnum Get_Shadow_Mode(void);
|
||
|
void Set_Shadow_Attenuation(float znear,float zfar);
|
||
|
void Get_Shadow_Attenuation(float * set_znear,float * set_zfar);
|
||
|
void Set_Shadow_Normal_Intensity(float normal_intensity);
|
||
|
float Get_Shadow_Normal_Intensity(void);
|
||
|
|
||
|
void Set_Shadow_Resolution(unsigned int res);
|
||
|
unsigned int Get_Shadow_Resolution(void);
|
||
|
void Set_Max_Simultaneous_Shadows(unsigned int count);
|
||
|
unsigned int Get_Max_Simultaneous_Shadows(void);
|
||
|
|
||
|
CameraClass * Get_Shadow_Camera(void);
|
||
|
SpecialRenderInfoClass *Get_Shadow_Render_Context(int width,int height);
|
||
|
MaterialPassClass * Get_Shadow_Material_Pass(void);
|
||
|
|
||
|
/*
|
||
|
** Generate (or re-generate) all static shadows. Invalidate must be called before calling Generate.
|
||
|
*/
|
||
|
void Invalidate_Static_Shadow_Projectors(void);
|
||
|
void Generate_Static_Shadow_Projectors(void);
|
||
|
void Setup_Static_Directional_Shadow(StaticAnimPhysClass & obj,const Vector3 & light_dir,TextureClass * render_target);
|
||
|
|
||
|
/*
|
||
|
** Decal system
|
||
|
** Project a decal onto the geometry in the vicinity of the given coordinate system
|
||
|
*/
|
||
|
int Create_Decal( const Matrix3D & tm,
|
||
|
const char * texture_name,
|
||
|
float radius,
|
||
|
bool is_permanent = false,
|
||
|
bool apply_to_translucent_polys = false,
|
||
|
PhysClass * only_this_obj = NULL );
|
||
|
|
||
|
bool Remove_Decal(uint32 id);
|
||
|
|
||
|
/*
|
||
|
** Shatter system
|
||
|
** Shatter a mesh into many pieces and send them flying.
|
||
|
*/
|
||
|
void Shatter_Mesh( MeshClass * mesh,
|
||
|
const Vector3 & impact_point,
|
||
|
const Vector3 & impact_normal,
|
||
|
const Vector3 & impact_velocity );
|
||
|
|
||
|
/*
|
||
|
** Camera Shake System
|
||
|
** Drop in camera shake spheres and any camera in the vicinity will automatically be affected.
|
||
|
** Prior to calling WW3D::Render(scene...) you need to pass your camera into Apply_Camera_Shakes
|
||
|
*/
|
||
|
void Add_Camera_Shake( const Vector3 & position,
|
||
|
float radius = 50.0f,
|
||
|
float duration = 1.5f,
|
||
|
float power = 1.0f );
|
||
|
void Apply_Camera_Shakes( CameraClass & camera );
|
||
|
|
||
|
/*
|
||
|
** Temporary accessors for the level editor.
|
||
|
*/
|
||
|
bool Is_Vis_Reset_Needed (void) const { return VisResetNeeded; }
|
||
|
void Vis_Reset_Needed(bool needed) { VisResetNeeded = needed; }
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Save-Load system. There are three save-load sub-systems in the physics library.
|
||
|
** PhysStaticDataSaveSystem - saves static data like pathfind, vis, and static culling data.
|
||
|
** PhysStaticObjectsSaveSystem - saves static objects like terrain pieces which have no dynamic state.
|
||
|
** PhysDynamicDataSaveSystem - saves dynamic data, settings, and objects in the physics scene
|
||
|
*/
|
||
|
void Save_Level_Static_Data(ChunkSaveClass & csave);
|
||
|
void Load_Level_Static_Data(ChunkLoadClass & cload);
|
||
|
void Post_Load_Level_Static_Data(void);
|
||
|
|
||
|
void Save_Level_Static_Objects(ChunkSaveClass & csave);
|
||
|
void Load_Level_Static_Objects(ChunkLoadClass & cload);
|
||
|
void Post_Load_Level_Static_Objects(void);
|
||
|
|
||
|
void Save_Level_Dynamic_Data(ChunkSaveClass & csave);
|
||
|
void Load_Level_Dynamic_Data(ChunkLoadClass & cload);
|
||
|
void Post_Load_Level_Dynamic_Data(void);
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Control over the polygon budget
|
||
|
*/
|
||
|
void Set_Polygon_Budgets(int static_count,int dynamic_count);
|
||
|
void Get_Polygon_Budgets(int * static_count,int * dynamic_count);
|
||
|
|
||
|
|
||
|
void Set_Update_Only_Visible_Objects(bool b) { UpdateOnlyVisibleObjects=b; }
|
||
|
bool Get_Update_Only_Visible_Objects() { return UpdateOnlyVisibleObjects; }
|
||
|
|
||
|
/*
|
||
|
** Scene Class methods. These should *only* be used when absolutely necessary since
|
||
|
** it is more efficient to operate through the physics interface (I can keep track
|
||
|
** of whether an object has moved and update its culling etc). If you insert a render
|
||
|
** object through this interface, a DecoPhys object will be created for it and added to
|
||
|
** a "Dirty Cullers" list. The "Dirty Cullers" list will assume that those objects
|
||
|
** have changed shape or moved every frame and always re-insert the object into the
|
||
|
** culling system. This code is needed in order to support render objects that
|
||
|
** add other render objects to the scene like particle emitters.
|
||
|
** Still don't support the iterator interface... maybe will some day...
|
||
|
*/
|
||
|
virtual void Add_Render_Object(RenderObjClass * obj);
|
||
|
virtual void Remove_Render_Object(RenderObjClass * obj);
|
||
|
virtual SceneIterator * Create_Iterator(bool /*onlyvisible = false*/) { assert(0); return NULL; }
|
||
|
virtual void Destroy_Iterator(SceneIterator * /*it*/) { assert(0); }
|
||
|
virtual void Register(RenderObjClass * obj,RegType for_what);
|
||
|
virtual void Unregister(RenderObjClass * obj,RegType for_what);
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Accessors
|
||
|
*/
|
||
|
void Get_Level_Extents (Vector3 &min, Vector3 &max);
|
||
|
|
||
|
/*
|
||
|
** Debugging control. Turn on rendering of debug vectors, points, bounding boxes, etc.
|
||
|
*/
|
||
|
void Enable_Debug_Display(bool onoff) { DebugDisplayEnabled = onoff; }
|
||
|
bool Is_Debug_Display_Enabled(void) { return DebugDisplayEnabled; }
|
||
|
void Enable_Projector_Debug_Display(bool onoff) { ProjectorDebugDisplayEnabled = onoff; }
|
||
|
bool Is_Projector_Debug_Display_Enabled(void) { return ProjectorDebugDisplayEnabled; }
|
||
|
void Enable_Dirty_Cull_Debug_Display(bool onoff) { DirtyCullDebugDisplayEnabled = onoff; }
|
||
|
bool Is_Dirty_Cull_Debug_Display_Enabled(void) { return DirtyCullDebugDisplayEnabled; }
|
||
|
void Enable_Lighting_Debug_Display(bool onoff) { LightingDebugDisplayEnabled = onoff; }
|
||
|
bool Is_Lighting_Debug_Display_Enabled(void) { return LightingDebugDisplayEnabled; }
|
||
|
const Vector3 & Get_Last_Camera_Position(void) { return LastCameraPosition; }
|
||
|
|
||
|
/*
|
||
|
** Performance Statistics
|
||
|
*/
|
||
|
struct StatsStruct
|
||
|
{
|
||
|
StatsStruct(void);
|
||
|
void Reset(void);
|
||
|
|
||
|
int FrameCount;
|
||
|
int CullNodeCount;
|
||
|
int CullNodesAccepted;
|
||
|
int CullNodesTriviallyAccepted;
|
||
|
int CullNodesRejected;
|
||
|
|
||
|
};
|
||
|
|
||
|
void Per_Frame_Statistics_Update(void);
|
||
|
const StatsStruct & Get_Statistics(void);
|
||
|
float Compute_Vis_Mesh_Ram(void);
|
||
|
|
||
|
protected:
|
||
|
|
||
|
/*
|
||
|
** Rendering functions
|
||
|
*/
|
||
|
virtual void Customized_Render(RenderInfoClass & rinfo);
|
||
|
void Render_Objects(RenderInfoClass& rinfo,RefPhysListClass * static_ws_list,RefPhysListClass * static_list,RefPhysListClass * dyn_list);
|
||
|
void Render_Object(RenderInfoClass & context,PhysClass * obj);
|
||
|
void Render_Backface_Occluders(RenderInfoClass & context,RefPhysListClass * static_ws_list,RefPhysListClass * static_list);
|
||
|
|
||
|
void Optimize_LODs( CameraClass & camera,
|
||
|
RefPhysListClass * dyn_obj_list,
|
||
|
RefPhysListClass * static_obj_list,
|
||
|
RefPhysListClass * static_ws_mesh_list );
|
||
|
/*
|
||
|
** Internal Vis functions. These are used to generate the VIS data.
|
||
|
*/
|
||
|
void Release_Vis_Resources(void);
|
||
|
virtual void Internal_Vis_Reset(void);
|
||
|
CameraClass * Get_Vis_Camera(void);
|
||
|
void Vis_Render_And_Scan(VisRenderContextClass & context,VisSampleClass & sample);
|
||
|
void Merge_Vis_Sector_IDs(uint32 id0,uint32 id1);
|
||
|
void Merge_Vis_Object_IDs(uint32 id0,uint32 id1);
|
||
|
|
||
|
/*
|
||
|
** Internal texture-projection functions
|
||
|
*/
|
||
|
public:
|
||
|
void Release_Projector_Resources(void);
|
||
|
protected:
|
||
|
void Apply_Projectors(const CameraClass & camera);
|
||
|
void Apply_Projector_To_Objects(TexProjectClass * tex_proj,const CameraClass & camera);
|
||
|
float Compute_Projector_Attenuation(TexProjectClass * dynamic_projector,const Vector3 & view_pos,const Vector3 & view_dir);
|
||
|
|
||
|
/*
|
||
|
** Internal decal functions
|
||
|
*/
|
||
|
void Allocate_Decal_Resources(void);
|
||
|
void Release_Decal_Resources(void);
|
||
|
|
||
|
/*
|
||
|
** Internal save-load code
|
||
|
*/
|
||
|
void Save_LDD_Variables(ChunkSaveClass & csave);
|
||
|
void Save_Static_Objects(ChunkSaveClass & csave);
|
||
|
void Save_Dynamic_Objects(ChunkSaveClass & csave);
|
||
|
void Save_Static_Lights(ChunkSaveClass & csave);
|
||
|
void Save_Static_Object_States(ChunkSaveClass & csave);
|
||
|
|
||
|
void Load_LDD_Variables(ChunkLoadClass & cload);
|
||
|
void Load_Static_Objects(ChunkLoadClass & cload);
|
||
|
void Load_Dynamic_Objects(ChunkLoadClass & cload);
|
||
|
void Load_Static_Lights(ChunkLoadClass & cload);
|
||
|
void Load_Static_Object_States(ChunkLoadClass & cload);
|
||
|
|
||
|
/*
|
||
|
** Misc
|
||
|
*/
|
||
|
void Internal_Add_Dynamic_Object(PhysClass * newobj);
|
||
|
void Internal_Add_Static_Object(StaticPhysClass * newtile);
|
||
|
void Internal_Add_Static_Light(LightPhysClass * newlight);
|
||
|
|
||
|
void Reset_Sun_Light(void);
|
||
|
void Load_Sun_Light(ChunkLoadClass & cload);
|
||
|
void Save_Sun_Light(ChunkSaveClass & csave);
|
||
|
|
||
|
void Add_Collected_Objects_To_List(bool static_objs,bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Add_Collected_Collideable_Objects_To_List(int colgroup,bool static_objs,bool dynamic_objs,NonRefPhysListClass * list);
|
||
|
void Add_Collected_Lights_To_List(bool static_lights,bool dynamic_lights,NonRefPhysListClass * list);
|
||
|
|
||
|
//- Volatile or Constant Member Variables -------------------------------------------------------------
|
||
|
//
|
||
|
// These variables do not need to be saved or loaded for one of the following reasons:
|
||
|
// - They are created/initialized when the physics scene is constructed and never change
|
||
|
// - They are simple flags or variables that just store the last thing the user set
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
|
||
|
/*
|
||
|
** Cached Data during the Pre_Render, Render, and Post_Render sequence
|
||
|
*/
|
||
|
RefPhysListClass VisibleStaticObjectList;
|
||
|
RefPhysListClass VisibleWSMeshList;
|
||
|
RefPhysListClass VisibleDynamicObjectList;
|
||
|
TexProjListClass ActiveTextureProjectors;
|
||
|
|
||
|
/*
|
||
|
** Current frame number, last camera position, etc
|
||
|
*/
|
||
|
int FrameNum;
|
||
|
Vector3 LastCameraPosition;
|
||
|
int LastValidVisId; // id of the last valid vis sector
|
||
|
bool DebugDisplayEnabled;
|
||
|
bool ProjectorDebugDisplayEnabled;
|
||
|
bool DirtyCullDebugDisplayEnabled;
|
||
|
bool LightingDebugDisplayEnabled;
|
||
|
StatsStruct LastValidStats; // last complete statistics sample
|
||
|
StatsStruct CurrentStats; // currently accumulating statistics sample
|
||
|
bool StaticProjectorsDirty;
|
||
|
|
||
|
/*
|
||
|
** Visibility system variables
|
||
|
*/
|
||
|
enum
|
||
|
{
|
||
|
VIS_RENDER_WIDTH = 256, // resolution width for the vis render window
|
||
|
VIS_RENDER_HEIGHT = 256 // resolution height for the vis render window
|
||
|
};
|
||
|
|
||
|
bool VisEnabled; // use vis data if present? (default true)
|
||
|
bool VisInverted; // invert vis data if present? (default false)
|
||
|
bool VisQuickAndDirty; // ignore non-occluders in generating vis? (quick-n-dirty vis)
|
||
|
bool VisResetNeeded; // indicates that the vis system is to be reset
|
||
|
|
||
|
bool VisSectorDisplayEnabled;// debugging, highlight the vis sector mesh
|
||
|
bool VisSectorHistoryEnabled;// debugging, highlight the previous 3 vis sectors.
|
||
|
int VisGridDisplayMode; // debugging, display the visible grid cells
|
||
|
bool VisSectorMissing; // debugging, true when no vis sector was found!
|
||
|
bool VisSectorFallbackEnabled; // Use the last valid vis sector when no sector is found
|
||
|
bool BackfaceDebugEnabled; // is backface debugging enabled.
|
||
|
bool VisSamplePointLocked; // is the sample point for vis being over-ridden?
|
||
|
Vector3 LockedVisSamplePoint; // position to sample vis from when locked/overridden.
|
||
|
|
||
|
CameraClass * VisCamera; // camera set up for vis-rendering
|
||
|
VisTableClass * CurrentVisTable; // current active vis table
|
||
|
|
||
|
/*
|
||
|
** Shadow system variables
|
||
|
*/
|
||
|
bool StaticProjectorsEnabled; // toggle static shadows (shadows cast by static objs onto dynamic objs)
|
||
|
bool DynamicProjectorsEnabled; // toggle dynamic shadows (shadows cast by dynamic objs onto everything)
|
||
|
ShadowEnum ShadowMode; // current shadow mode
|
||
|
float ShadowAttenStart; // distance to start of shadow attenuation
|
||
|
float ShadowAttenEnd; // distance to end of shadow attenuation
|
||
|
float ShadowNormalIntensity; // "normal" non attenuated shadow intensity
|
||
|
TextureClass * ShadowBlobTexture; // texture to use for fake "blob" shadows
|
||
|
|
||
|
SpecialRenderInfoClass *ShadowRenderContext; // render context for shadows
|
||
|
CameraClass * ShadowCamera; // camera for rendering shadow textures
|
||
|
MaterialPassClass * ShadowMaterialPass; // material pass for shadows
|
||
|
int ShadowResWidth;
|
||
|
int ShadowResHeight;
|
||
|
|
||
|
/*
|
||
|
** Decal System
|
||
|
*/
|
||
|
PhysDecalSysClass * DecalSystem;
|
||
|
|
||
|
/*
|
||
|
** Pathfinding
|
||
|
*/
|
||
|
PathfindClass * Pathfinder;
|
||
|
|
||
|
/*
|
||
|
** Camera Shaking
|
||
|
*/
|
||
|
CameraShakeSystemClass *CameraShakeSystem;
|
||
|
|
||
|
/*
|
||
|
** Render objects processing lists
|
||
|
*/
|
||
|
RefRenderObjListClass UpdateList;
|
||
|
RefRenderObjListClass VertexProcList;
|
||
|
RefPhysListClass ReleaseList;
|
||
|
|
||
|
/*
|
||
|
** Miscellaneous resources
|
||
|
*/
|
||
|
MaterialPassClass * HighlightMaterialPass;
|
||
|
|
||
|
|
||
|
//- Level Static Data ---------------------------------------------------------------------------------
|
||
|
//
|
||
|
// This data is constant throughout the course of a level and therefore is stored in the
|
||
|
// LSD (L)evel (S)tatic (D)ata file.
|
||
|
// - The structure of the Static Object AABTree
|
||
|
// - The structure of the Static Light AABTree
|
||
|
// - The structure of the Dynamic Object culling grid
|
||
|
// - All of the StaticPhysClasses and StaticLightClasses (in StaticObjList and StaticLightList)
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
|
||
|
/*
|
||
|
** Culling systems. These will have a structure which is based on the
|
||
|
** static terrain for the level and do not change during the course of a level (though
|
||
|
** the objects may link and unlink from them)
|
||
|
*/
|
||
|
StaticAABTreeCullClass * StaticCullingSystem;
|
||
|
StaticLightCullClass * StaticLightingSystem;
|
||
|
PhysGridCullClass * DynamicCullingSystem;
|
||
|
DynamicAABTreeCullClass * DynamicObjVisSystem;
|
||
|
|
||
|
TypedAABTreeCullSystemClass<TexProjectClass> * StaticProjectorCullingSystem;
|
||
|
TypedGridCullSystemClass<TexProjectClass> * DynamicProjectorCullingSystem;
|
||
|
|
||
|
/*
|
||
|
** Visibility Tables
|
||
|
*/
|
||
|
VisTableMgrClass VisTableManager;
|
||
|
|
||
|
/*
|
||
|
** Lighting:
|
||
|
** Sun Light. The sun is special cased to generate shadows and a lens
|
||
|
** flare. It should not be changed unless you are in the level editor.
|
||
|
*/
|
||
|
int LightingMode;
|
||
|
Vector3 SceneAmbientLight;
|
||
|
bool UseSun;
|
||
|
float SunPitch;
|
||
|
float SunYaw;
|
||
|
LightClass * SunLight;
|
||
|
|
||
|
|
||
|
//- Level Dynamic Data --------------------------------------------------------------------------------
|
||
|
//
|
||
|
// This is the dynamic data/objects which all need to be saved in either the LDD file or SAV file.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------------------------------
|
||
|
|
||
|
/*
|
||
|
** Collision group tables
|
||
|
*/
|
||
|
static bool AllowCollisionFlags[NUM_COLLISION_FLAGS];
|
||
|
|
||
|
/*
|
||
|
** Polygon budget for the LOD system
|
||
|
*/
|
||
|
int DynamicPolyBudget;
|
||
|
int StaticPolyBudget;
|
||
|
|
||
|
/*
|
||
|
** Master lists of the objects in the system. Each object will be in *one* of the
|
||
|
** following lists.
|
||
|
*/
|
||
|
RefPhysListClass ObjList;
|
||
|
RefPhysListClass StaticObjList;
|
||
|
RefPhysListClass StaticLightList;
|
||
|
TexProjListClass StaticProjectorList;
|
||
|
TexProjListClass DynamicProjectorList;
|
||
|
|
||
|
/*
|
||
|
** Auxiliary lists. These lists are used to perform certain special
|
||
|
** processing on certain objects or to avoid performing certain operations
|
||
|
** on objects. A given object can be in any or all of these lists...
|
||
|
*/
|
||
|
RefPhysListClass DirtyCullList; // objects that have 'dirty culling' must be re-inserted each frame...
|
||
|
RefPhysListClass TimestepList; // objects which need to be time-stepped go in here
|
||
|
RefPhysListClass StaticAnimList; // list of the StaticAnim objects, these can cast shadows, change states, etc
|
||
|
NonRefPhysListClass CollisionRegionList; // cached list of objects in the current collision region
|
||
|
|
||
|
bool UpdateOnlyVisibleObjects;
|
||
|
unsigned CurrentFrameNumber;
|
||
|
|
||
|
private:
|
||
|
|
||
|
/*
|
||
|
** The physics scene is a singleton. If we want to support multiple
|
||
|
** physics scenes, we would need to add a scene pointer to each physics object
|
||
|
** and everywhere they are calling Get_Instance() they can just use their pointer
|
||
|
*/
|
||
|
static PhysicsSceneClass * TheScene;
|
||
|
|
||
|
/*
|
||
|
** WW3D is a friend because we let it call our protected Render function (which no
|
||
|
** one else is allowed to call... trying to "contain" surrender :-)
|
||
|
*/
|
||
|
friend class WW3D;
|
||
|
|
||
|
/*
|
||
|
** VisOptimizationContextClass is a friend so that it can merge vis-id's.
|
||
|
*/
|
||
|
friend class VisOptimizationContextClass;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif
|