mirror of
https://github.com/electronicarts/CnC_Generals_Zero_Hour.git
synced 2025-12-18 08:31:40 -05:00
Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
4
Generals/Code/Libraries/Source/WWVegas/Miles6/.gitignore
vendored
Normal file
4
Generals/Code/Libraries/Source/WWVegas/Miles6/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -0,0 +1,25 @@
|
||||
This document is going to be a place to put descriptions of our reasoning for any "confusing" design decisions made during the conversion to DX8.
|
||||
|
||||
TODO: WRITE PROPER DESCRIPTIONS FOR ALL OF THE FOLLOWING!!!
|
||||
|
||||
Lighting
|
||||
--------
|
||||
The user has two choices regarding lighting. SimpleSceneClass will just install the first four LightClasses
|
||||
into DX8 and let them affect all objects. Otherwise, you need to implement a SceneClass which wraps each
|
||||
top-level render object and associates a LightEnvironmentClass with it. In your 'Customized_Render' function
|
||||
you need to update each object's LightEnvironment object from the lights around it.
|
||||
|
||||
Mesh Rendering System
|
||||
---------------------
|
||||
Grouped by FVF format and material settings. Many meshes can share a single VB and IB...
|
||||
|
||||
MeshModel Sharing
|
||||
-----------------
|
||||
It would be nice if MeshClass just Add_Ref'd the same mesh model whenever we re-use a mesh. The problems with
|
||||
this are:
|
||||
- the transform which is used during deffered rendering and during decal rendering
|
||||
- instance specific light environment pointer is in the mesh model class
|
||||
- lots of other stuff <-- FILL THIS IN!
|
||||
|
||||
|
||||
|
||||
274
Generals/Code/Libraries/Source/WWVegas/WW3D2/DX8 Status.txt
Normal file
274
Generals/Code/Libraries/Source/WWVegas/WW3D2/DX8 Status.txt
Normal file
@@ -0,0 +1,274 @@
|
||||
|
||||
|
||||
Now we've got WW3D up and running with the skeleton app. Here is a somewhat more detailed/organized
|
||||
list of what is left to do:
|
||||
|
||||
LIMITATIONS/POTENTIAL PROBLEMS:
|
||||
- Skins need to use a limited set of rendering features?
|
||||
- Polys going into the alpha system must use a limited set of rendering features.
|
||||
- Additional procedural material passes cannot be applied to alpha blended meshes (no multi-pass alpha)
|
||||
- Meshes only get two vertex color arrays. Their vertex materials must be configured properly to enable them.
|
||||
- HY: Simplescene supports only four global lights
|
||||
- HY: WW3D Spoltlights have an approximate inverse linear attentuation instead of max linear attentuation
|
||||
|
||||
|
||||
UPDATED TODO LIST:
|
||||
agg_def:
|
||||
- Texture replacement feature needs to be implemented
|
||||
assetmgr:
|
||||
- Texture cache,
|
||||
- Dazzle loader,
|
||||
bmp2d
|
||||
- works. Code for setting aspect ratio was added but not used due to legacy - HY
|
||||
boxrobj
|
||||
- Alpha blending support needed
|
||||
- Vis rendering code needed
|
||||
camera
|
||||
- *** CameraClass projection convention changed to -1<x<1... Fix all code in commando and E&B!
|
||||
- Also convert all uses of CameraClass::Un_Project!
|
||||
cullablematpass
|
||||
- collapsed into matpass
|
||||
dazzle
|
||||
- Fully commented out
|
||||
decalmsh
|
||||
- works
|
||||
decalsys
|
||||
- DistAlphaVP to be converted (renegade)
|
||||
dx8wrapper
|
||||
- Toggle_Windowed function commented out
|
||||
- One-time init functions commented out (TextureLoader,SegmentedLine,Dazzle)
|
||||
dynamesh
|
||||
- works except for alpha support
|
||||
font3d
|
||||
- works
|
||||
intersec
|
||||
- Compiles but not tested,
|
||||
- Probably contains a lot of un-used functions because all intersect calls are now routing through Cast_Ray!
|
||||
line3d
|
||||
- works except for alpha sorting
|
||||
mapper
|
||||
- All mappers need to properly handle the u-v array index
|
||||
- Animating1DMapper commented out
|
||||
- Axial mapper commented out
|
||||
- Silhouette mapper commented out
|
||||
matrixmapper
|
||||
- All mappers need to properly handle the u-v array index
|
||||
matinfo
|
||||
- Texture reduction factor access commented out
|
||||
matpass
|
||||
- works except for skins and culling
|
||||
mesh
|
||||
- static sort list code commented out
|
||||
- vis rendering code commented out
|
||||
- ORIENTED and ALIGNED features broken
|
||||
- dependencies code commented out
|
||||
meshmdl
|
||||
- shadow rendering
|
||||
- vis rendering
|
||||
- get_deformed_screenspace_vertices commented out (Can we delete this? skins are working...)
|
||||
- get_deformed_eyespace_vertices commented out (Can we delete this? skins are working...)
|
||||
- Render_Prelit
|
||||
- needs to use the dynamic index buffer when rendering cullable material passes
|
||||
meshmdlio
|
||||
- animated texture loading not implemented
|
||||
- use mesh TWOSIDED flag to set shaders on loading (and take out Jani's temp code to do this on the fly)
|
||||
metalmap
|
||||
- fully commented out
|
||||
pointgr
|
||||
- works except for alpha support
|
||||
r3dobj
|
||||
- fully commented out - may be able to DELETE
|
||||
render2d
|
||||
- works
|
||||
rendobj
|
||||
- texture_reduction feature commented out - may not be needed (only have a global texture reduction factor?)
|
||||
rinfo
|
||||
- surrender-specific vis code
|
||||
ringobj
|
||||
- works
|
||||
- no alpha support
|
||||
- vis rendering code commented out
|
||||
scene
|
||||
- static sort list code commented out
|
||||
segline
|
||||
- material handling code commented out
|
||||
- rendering code commented out
|
||||
shattersystem
|
||||
- works, but might not for multi-texturing.
|
||||
- Naty check if dynamesh supports multi-texturing. you changed the interface
|
||||
- a bit. HY
|
||||
sphereobj
|
||||
- works
|
||||
- no alpha support
|
||||
- no viz
|
||||
- might have bug in sphere generation when sphere is too big
|
||||
sr_util
|
||||
- DELETED!
|
||||
statistics
|
||||
- fully commented out
|
||||
texfcach
|
||||
- fully commented out
|
||||
texproject
|
||||
- works except for the second stage stuff (is this generally broken?).
|
||||
textdraw
|
||||
- works. This is a legacy font system to be removed from Renegade.
|
||||
texture
|
||||
- lots of miscellaneous missing features here
|
||||
- NoLOD flag to be supported for UI textures
|
||||
texturefile
|
||||
- fully commented out
|
||||
textureloader
|
||||
- fully commented out, this is the background loading system
|
||||
txt.cpp
|
||||
- works. This is a legacy font system to be removed from E&B.
|
||||
txt2d.cpp
|
||||
- works. This is a legacy font system to be removed from E&B.
|
||||
vertmaterial
|
||||
- all uses of VertexMaterialClass may need to configure the UV-array source index.
|
||||
- all users of VMC must properly enable/disable lighting
|
||||
- all users of VMC must configure the diffuse and emissive color source if they want per-vertex arrays...
|
||||
- changed so the default is visible - HY
|
||||
- TODO: Make Get_Preset const so no one can modify the static presets
|
||||
ww3d
|
||||
- TextureLoader support commented out of Begin_Render
|
||||
- Statistics code commented out
|
||||
- Read_Gerd_Render_Device_Description commented out (?)
|
||||
- Set/Get_Texture_Reduction commented out
|
||||
- Flush_Texture_Cache function commented out
|
||||
- Detect_Drivers commented out
|
||||
- On_Activate/Deactivate_App commented out
|
||||
- Update_Pixel_Center commented out
|
||||
General:
|
||||
- Add support for multiple texture stages
|
||||
- Create sort system
|
||||
- Add support for exclusion masks. The way this works is that we support exclusion masks differently at the top-level object level and the low-level rendering object level (note that this means that the mid-levels will get skipped over unless we collapse the container bits together with the low-level object bits. However we probably cannot do this, since the subobjects bits may be more permissive than the container's bits. Should we worry about this?). At the top level, when the light environment is constructed, we filter the light's exclusion bits vs. the light environments' exclusion bits (passed into the construct call, stored in the light environment at creation, or something). If it does not pass, it is not inserted into the light environment. When we insert a light into the light environment, we also store its exclusion bits (perhaps we only do this if "light aggregation" is turned off - see below). Then the low-level code for applying the current light environment receives the low-level robj's exclusion bits, compares them, and decides whether to actually set the light into D3D. For this to work properly, we need a flag to prevent lights which are rejected from the light environment because it is full of more-important lights from contributing to the ambient.
|
||||
- Change the "Get_Texture_Array" functions in MeshMatDescClass to private, change name to PEEK!
|
||||
- have texture category sorting functions take account of both texture stages
|
||||
|
||||
NOTE: We have three enums/#defines/consts for the number of texture stages:
|
||||
RENDERER_MAX_TEX_STAGES, MeshMatDescClass::MAX_TEX_STAGES, MeshBuilderClass::MAX_STAGES.
|
||||
We are even explicitly comparing two of them and asserting if they are different in
|
||||
dx8renderer.cpp. There is a similar situation with DX8FVFCategoryContainer::MAX_PASSES,
|
||||
MeshMatDescClass::MAX_PASSES and MeshBuilderClass::MAX_PASSES. We need to clean this up!
|
||||
|
||||
Features we are removing support for (will need application changes):
|
||||
- indirect textures (we will provide a (slow) function to swap textures)
|
||||
|
||||
|
||||
Ok, the WW3D2 skeleton program compiles and links now with no references to SR. Some files I took more care on, others I blocked out the entire file for later. Every piece of code is wrapped with #ifdef WW3D_DX8 with a matching #endif and comment, there should be no typo's in the #ifdef's because I used a macro to insert them all (so we can do searches and safely assume that we see all of them).
|
||||
Here are some (raw) notes I took while commenting out all references to SR:
|
||||
|
||||
X - VertexMaterialClass - need to separate from sr (SOON)
|
||||
X - Basic texture functionality (loading from files, etc)
|
||||
- More advanced texture handling code needs to be re-implemented, but try to maintain our current interfaces as much as possible. Many issues here: background thread loader, texture file cache, texture LOD, indirect textures ?... (SOON)
|
||||
X - ShaderClass - just convert to our own, mimicing the bitfield that SR used for now (SOON)
|
||||
- Exclusion masks - this is not supported but some application code is probably using it. We need to decide what to do here.
|
||||
- Camera aligned and camera oriented meshes - the way we used to do them required the mesh push transform code to change the camera matrix, which doesn't work well with our current scheme. We need to think how to support this stuff.
|
||||
X - MaterialInfo Class - can un-comment when we have the above material systems in place, evaluate where this is used?
|
||||
- sr_util - all of these functions un-needed? (no more As_srVector3 :-)
|
||||
- agg_def.cpp - all texture features commented out
|
||||
X - box render objects completely commented out - materials, gerd
|
||||
- texturefcache - commented out
|
||||
- TextureFileClass - commented out
|
||||
X - DynaMeshClass - commented out, need materials, gerd replacement, new rendering interface before we can bring this back. A *lot* of stuff uses DynaMeshClass... (shatter system, text systems, etc)
|
||||
- Dazzles - commented out, gerd, materials
|
||||
- streaming textures - commented out, new texture code needed
|
||||
- texture creation functions in assetmanager commented out
|
||||
X - Bitmap2DObjClass - commented out, do we need this any more? - depends on dynamesh
|
||||
X - BW Render, used for shadow rendering, uses some srVectorProcessor stuff
|
||||
X - Camera - internals commented out
|
||||
X - MatPass, CullableMatPass - all procedural material passes commented out, design new, low-level rendering interface, then port these to it.
|
||||
X - passdata.h - no sure what this is for, it is commented out
|
||||
X - meshmodel - all material functions commented out, will also probably re-write the guts of meshmodel to store "sub-meshes" rather than material arrays. depends on design of new low-level rendering system. (SOON)
|
||||
X - decal system - all material handling commented out, rendering commented out, depends on new low-level rendering system
|
||||
X - matrix mapper - this is used to generate u-v coordinates in a surrender vertex processor, new system needs to support this functionality, then we can port this (well, it will use DX8 features to do the same thing in HW...)
|
||||
X - intersec.h - commented out, Eric Cosky's collision code, do we need this any more?
|
||||
X - dx8renderer - uses srVectorProcessor
|
||||
X - dx8wrapper - uses Gerd
|
||||
X - fog.cpp - all fog objects commented out, probably won't implement fog with a render object, just have fog settings be stored in the scene
|
||||
X - font3d - surface loading! textures
|
||||
X - lightclass - hmmmm, re-consider lighting...
|
||||
X - lightenv - uses lightclass as input.
|
||||
X - line3d - uses srModeller, srMeshModel. Do we need this any more?
|
||||
X - mapper.cpp - srVertexProcessor, need to convert to HW form (DELETED)
|
||||
X - mesh - materials, gerd transforms, meshmodel
|
||||
X - meshgeometry - uses srVectorProcessor in a couple of places
|
||||
X - meshmdl - lots of material and gerd stuff, re-design?
|
||||
- metalmap - uses vectorprocessor, textures
|
||||
X - pointgroups - surrender types, gerd rendering, materials
|
||||
X - particle buffer - needs point group
|
||||
X - particle emitter - materials, particle buffer
|
||||
X - particle loader - needs particle classes, materials
|
||||
X - polyinfo - don't know what this is?
|
||||
X - projector - built on top of matrix mapper, used for projected textures
|
||||
X - r3dobj - image3dobj, can we delete this?
|
||||
X - render2d - textures, gerd calls
|
||||
X - rendertype - lots of GERD stuff, Jani is this an "obsolete" optimization?
|
||||
- rinfo - material passes, gerd stuff, vis commands which use ext-functions for the surrender software rasterizer.
|
||||
X - ring render object - materials, gerd rendering calls
|
||||
X - scene - fog settings, don't use FogClass any more, just plug fog settings into the new low-level interface...
|
||||
- scene - ensure that the scene ambient light value gets added into the light environment's effective ambient (E&B uses the scene ambient and currently it doesn't do anything)
|
||||
- segline - custom gerd pipeline, materials
|
||||
X - shatter system - dynamic meshes, materials.
|
||||
X - sphere - materials, gerd rendering calls
|
||||
- statistics - Jani's texture stats, new texture system must support this.
|
||||
- texfcache - completely commented out
|
||||
X - texproject - needs procedural material pass interface, vertex processor...
|
||||
X - textdraw - textures, dynamic meshes
|
||||
- texture loader - is this the backround thread loader? commented out
|
||||
X - txt.cpp - uses textures
|
||||
X - txt2d.cpp - uses txt, dynameshes
|
||||
X - vertexbuffer.cpp - not sure what this is, uses srVectorProcessor
|
||||
- ww3d - lots of gerd calls, surrender types, screen capture, movie capture, texture reduction, statistics
|
||||
- Investigate cost of BeginScene-EndScene, set viewport has to occur right after beginScene... Should we minimize our viewport changes? If the cost is high, we might need to separate the viewport definition from the camera...
|
||||
- Silhouette mapper un-implemented
|
||||
- Axial mapper un-implemented
|
||||
- How should handle the extra render states for dealing with TexGen? If we apply these states, there is nothing to remove them!
|
||||
-- HY render states for texgen and texmaterial are encapsulated in vertex material & mapper
|
||||
-- if the vertex material detects a null mapper the defaults are set.
|
||||
- Make Dynamesh support Cast_Ray so that the E&B intersection code works!
|
||||
|
||||
|
||||
Shaders have been converted to Shader->Apply() and the state is being tracked by the shader class.
|
||||
Materials have been converted to Material->Apply() which calls Mapper->Apply()
|
||||
|
||||
Now, some big issues we need to think about are (in no particular order):
|
||||
|
||||
SOME GOALS - Maintain as many existing class interfaces as we can so that our apps don't have much re-coding!
|
||||
Input data is existing W3D files, no format changes or new tools! (for now anyway :-)
|
||||
Incorporate the ideas in Jani's DX8 code, grouping small meshes together in larger VBs, etc
|
||||
|
||||
GERD Replacement - our new low-level rendering interface needs to be the replacement for everywhere we are using the GERD. It needs to supply all of the features that we are using in the GERD currently while allowing us to use Jani's mesh optimizations. There is a lot to think about here and almost everything depends on us doing this right. It also might need to serve as an abstraction layer so that I can implement a software VIS-renderer behind it.
|
||||
SOLUTION: No GERD replacement, no abstraction layer. DX8Wrapper will be a thin insulation layer though.
|
||||
|
||||
VIS - I'll have to re-implement the rendering code for VIS. It will be a 32bit, solid fill, zbuffering software rasterizer. Not too hard but still a bit of work. Needs to be done in a way that all render objects can be rendered through it easily.
|
||||
SOLUTION: Vis rendering will branch at the render object level to a new custom vis rasterizer possibly based on the bw shadow code
|
||||
|
||||
TEXTURES - there are many features in the textures system, the "file cache", background loading, LOD, tga loading, global texture reduction factor, etc.
|
||||
SOLUTION: Naty is working on this system.
|
||||
|
||||
MESHMODEL - I think we'll need to do some load-time conversion of all of our mesh-models into a form similar to Jani's dx8 mesh code. More thought needs to be put into this.
|
||||
|
||||
ALPHA SORTING - This issue becomes especially complex when you think about mixing different types of render objects. This issue will influence how we design the low level rendering interface.
|
||||
SOLUTION: There will be a custom alpha sorting/rendering system. RenderObjects will be allowed to talk to either DX8 or this system.
|
||||
|
||||
UNIX - It looks like Neal has put some effort into making ww3d compile under Unix. We will probably make life very difficult for him if there are DX8 calls all over the place :-)
|
||||
SOLUTION: UNIX version of E&B will not use WW3D2. It only needs collision detection so we'll implement a custom solution.
|
||||
|
||||
|
||||
Optimizations:
|
||||
==============
|
||||
* Currently we search a linear list for textures with the same name every time we ask
|
||||
the asset manager for a new texture. We should probably use the hashtable template
|
||||
for this instead.
|
||||
* The VectorProcessorClass stuff is completely unoptimized - we might want to
|
||||
optimize this in future.
|
||||
|
||||
|
||||
********* NEW STUFF ************
|
||||
DX8 Features which we currently do not support and might want to in future:
|
||||
* Different modes than clamp and wrap - DX8 exposes all kinds of cool modes like mirror, mirror once - do we expose these in our tools? How well are they supported in hardware? If they are not universally supported then we probably don't want to expose them...
|
||||
* Cube and volume textures - support via inheriting from shared base class with TextureClass?
|
||||
* Anisotropic filtering: currently trilinear is enabled in the TextureClass but not in our tools. There are issues to think about for both trilinear and anisotropic like: not all hardware supports it, some hardware supports it if there is just one texture but not otherwise, or with a slowdown etc. - this is probably not something we want the artist to specify directly: perhaps the artist can mark those meshes which would benefit from "advanced filtering", and we turn it on selectively depending on hardware?
|
||||
|
||||
We can do fancy texture matrix operations "for free" now. (Only on Hardware T&L cards!)
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
- Detect skins that are using materials that are too complex (max of two uv channels, one pass???)
|
||||
- Remove Translucency from max plugin
|
||||
- Editor has to resolve all of the cases where it is rendering to secondary windows
|
||||
- VIS system needs a new z-buffering software renderer
|
||||
- WWConfig needs to be updated
|
||||
- Classic environment mapper and env mapper are the same thing now...
|
||||
191
Generals/Code/Libraries/Source/WWVegas/WW3D2/FramGrab.cpp
Normal file
191
Generals/Code/Libraries/Source/WWVegas/WW3D2/FramGrab.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
// FramGrab.cpp: implementation of the FrameGrabClass class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "framgrab.h"
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
//#include <errno.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
FrameGrabClass::FrameGrabClass(const char *filename, MODE mode, int width, int height, int bitcount, float framerate)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
Mode = mode;
|
||||
Filename = filename;
|
||||
FrameRate = framerate;
|
||||
Counter = 0;
|
||||
|
||||
Stream = 0;
|
||||
AVIFile = 0;
|
||||
|
||||
if(Mode != AVI) return;
|
||||
|
||||
AVIFileInit(); // opens AVIFile library
|
||||
|
||||
// find the first free file with this prefix
|
||||
int counter = 0;
|
||||
int result;
|
||||
char file[256];
|
||||
do {
|
||||
sprintf(file, "%s%d.AVI", filename, counter++);
|
||||
result = _access(file, 0);
|
||||
} while(result != -1);
|
||||
|
||||
// Create new AVI file using AVIFileOpen.
|
||||
hr = AVIFileOpen(&AVIFile, file, OF_WRITE | OF_CREATE, NULL);
|
||||
if (hr != 0) {
|
||||
char buf[256];
|
||||
sprintf(buf, "Unable to open %s\n", Filename);
|
||||
OutputDebugString(buf);
|
||||
CleanupAVI();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create a stream using AVIFileCreateStream.
|
||||
AVIStreamInfo.fccType = streamtypeVIDEO;
|
||||
AVIStreamInfo.fccHandler = mmioFOURCC('M','S','V','C');
|
||||
AVIStreamInfo.dwFlags = 0;
|
||||
AVIStreamInfo.dwCaps = 0;
|
||||
AVIStreamInfo.wPriority = 0;
|
||||
AVIStreamInfo.wLanguage = 0;
|
||||
AVIStreamInfo.dwScale = 1;
|
||||
AVIStreamInfo.dwRate = (int)FrameRate;
|
||||
AVIStreamInfo.dwStart = 0;
|
||||
AVIStreamInfo.dwLength = 0;
|
||||
AVIStreamInfo.dwInitialFrames = 0;
|
||||
AVIStreamInfo.dwSuggestedBufferSize = 0;
|
||||
AVIStreamInfo.dwQuality = 0;
|
||||
AVIStreamInfo.dwSampleSize = 0;
|
||||
SetRect(&AVIStreamInfo.rcFrame, 0, 0, width, height);
|
||||
AVIStreamInfo.dwEditCount = 0;
|
||||
AVIStreamInfo.dwFormatChangeCount = 0;
|
||||
sprintf(AVIStreamInfo.szName,"G");
|
||||
|
||||
hr = AVIFileCreateStream(AVIFile, &Stream, &AVIStreamInfo);
|
||||
if (hr != 0) {
|
||||
CleanupAVI();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set format of new stream
|
||||
BitmapInfoHeader.biWidth = width;
|
||||
BitmapInfoHeader.biHeight = height;
|
||||
BitmapInfoHeader.biBitCount = (unsigned short)bitcount;
|
||||
BitmapInfoHeader.biSizeImage = ((((UINT)BitmapInfoHeader.biBitCount * BitmapInfoHeader.biWidth + 31) & ~31) / 8) * BitmapInfoHeader.biHeight;
|
||||
BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // size of structure
|
||||
BitmapInfoHeader.biPlanes = 1; // must be set to 1
|
||||
BitmapInfoHeader.biCompression = BI_RGB; // uncompressed
|
||||
BitmapInfoHeader.biXPelsPerMeter = 1; // not used
|
||||
BitmapInfoHeader.biYPelsPerMeter = 1; // not used
|
||||
BitmapInfoHeader.biClrUsed = 0; // all colors are used
|
||||
BitmapInfoHeader.biClrImportant = 0; // all colors are important
|
||||
|
||||
hr = AVIStreamSetFormat(Stream, 0, &BitmapInfoHeader, sizeof(BitmapInfoHeader));
|
||||
if (hr != 0) {
|
||||
CleanupAVI();
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap = (long *) GlobalAllocPtr(GMEM_MOVEABLE, BitmapInfoHeader.biSizeImage);
|
||||
}
|
||||
|
||||
FrameGrabClass::~FrameGrabClass()
|
||||
{
|
||||
if(Mode == AVI) {
|
||||
CleanupAVI();
|
||||
}
|
||||
}
|
||||
|
||||
void FrameGrabClass::CleanupAVI() {
|
||||
if(Bitmap != 0) { GlobalFreePtr(Bitmap); Bitmap = 0; }
|
||||
if(Stream != 0) { AVIStreamRelease(Stream); Stream = 0; }
|
||||
if(AVIFile != 0) { AVIFileRelease(AVIFile); AVIFile = 0; }
|
||||
|
||||
AVIFileExit();
|
||||
Mode = RAW;
|
||||
}
|
||||
|
||||
void FrameGrabClass::GrabAVI(void *BitmapPointer)
|
||||
{
|
||||
// CompressDIB(&bi, lpOld, &biNew, lpNew);
|
||||
|
||||
// Save the compressed data using AVIStreamWrite.
|
||||
HRESULT hr = AVIStreamWrite(Stream, Counter++, 1, BitmapPointer, BitmapInfoHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL);
|
||||
if(hr != 0) {
|
||||
char buf[256];
|
||||
sprintf(buf, "avi write error %x/%d\n", hr, hr);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameGrabClass::GrabRawFrame(void * /*BitmapPointer*/)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FrameGrabClass::ConvertGrab(void *BitmapPointer)
|
||||
{
|
||||
ConvertFrame(BitmapPointer);
|
||||
Grab( Bitmap );
|
||||
}
|
||||
|
||||
|
||||
void FrameGrabClass::Grab(void *BitmapPointer)
|
||||
{
|
||||
if(Mode == AVI)
|
||||
GrabAVI(BitmapPointer);
|
||||
else
|
||||
GrabRawFrame(BitmapPointer);
|
||||
}
|
||||
|
||||
|
||||
void FrameGrabClass::ConvertFrame(void *BitmapPointer)
|
||||
{
|
||||
|
||||
int width = BitmapInfoHeader.biWidth;
|
||||
int height = BitmapInfoHeader.biHeight;
|
||||
long *image = (long *) BitmapPointer;
|
||||
|
||||
// copy the data, doing a vertical flip & byte re-ordering of the pixel longwords
|
||||
int y = height;
|
||||
while(y--) {
|
||||
int x = width;
|
||||
int yoffset = y * width;
|
||||
int yoffset2 = (height - y) * width;
|
||||
while(x--) {
|
||||
long *source = &image[yoffset + x];
|
||||
long *dest = &Bitmap[yoffset2 + x];
|
||||
*dest = *source;
|
||||
unsigned char *c = (unsigned char *) dest;
|
||||
c[3] = c[0];
|
||||
c[0] = c[2];
|
||||
c[2] = c[3];
|
||||
c[3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
148
Generals/Code/Libraries/Source/WWVegas/WW3D2/MAPPERS.TXT
Normal file
148
Generals/Code/Libraries/Source/WWVegas/WW3D2/MAPPERS.TXT
Normal file
@@ -0,0 +1,148 @@
|
||||
MAPPER_NAME
|
||||
Description:
|
||||
What the mapper does
|
||||
Params:
|
||||
What to type in the argument space
|
||||
<Argument Name> = (type) <default value>
|
||||
e.g. if it says
|
||||
UPerSec=(float) 0.0;
|
||||
it means you have to type in
|
||||
UPerSec=1.0;
|
||||
to get your U coordinate scrolling at one unit per second and it has to be a float. If you don't type anything the
|
||||
default value is 0.0.
|
||||
|
||||
Types:
|
||||
(float) - any real number
|
||||
(int) - any integer
|
||||
(bool) - either TRUE or FALSE
|
||||
|
||||
|
||||
LINEAR_OFFSET
|
||||
Description:
|
||||
Makes the texture scroll at the speed specified
|
||||
Params:
|
||||
UPerSec=(float) 0.0;
|
||||
VPerSec=(float) 0.0;
|
||||
UScale=(float) 1.0;
|
||||
VScale=(float) 1.0;
|
||||
|
||||
CLASSIC_ENVIRONMENT
|
||||
Description:
|
||||
Uses the Normals to look up the environment map
|
||||
|
||||
ENVIRONMENT
|
||||
Description:
|
||||
Uses the Reflection direction to look up the environment map
|
||||
|
||||
SCREEN
|
||||
Description:
|
||||
Projects takes the screen coordinate as the UV coordinate
|
||||
Params:
|
||||
UScale=(float) 1.0f;
|
||||
VScale=(float) 1.0f;
|
||||
|
||||
SILHOUETTE
|
||||
Description: Obsolete, not supported
|
||||
|
||||
SCALE
|
||||
Description:
|
||||
Scales the UV coordinates. Useful for detail mapping.
|
||||
Params:
|
||||
UScale=(float) 1.0f;
|
||||
VScale=(float) 1.0f;
|
||||
|
||||
GRID
|
||||
Description:
|
||||
Given a texture that is divided up in to a grid, it animates the texture by looking
|
||||
up the texture from the topleft to the bottom right, going left to right and then
|
||||
top to bottom (the same way you would read English text). The texture map must be divided
|
||||
up evenly.
|
||||
Params:
|
||||
FPS=(float) 1.0f; The frames per second
|
||||
Log2Width=(int) 1; So 0=width 1, 1=width 2, 2=width 4. The default means animate using a texture divided up into quarters.
|
||||
Last=(int) GridWidth*GridWidth; The last frame to use
|
||||
|
||||
ROTATE
|
||||
Description:
|
||||
Rotates a texture map counterclockwise about a specified center then scales the texture
|
||||
Params:
|
||||
Speed=(float) 0.1f; In Hertz. 1 = 1 rotate per second
|
||||
UCenter=(float) 0.0f;
|
||||
VCenter=(float) 0.0f;
|
||||
UScale=(float) 1.0;
|
||||
VScale=(float) 1.0;
|
||||
|
||||
SINE_LINEAR_OFFSET
|
||||
Description:
|
||||
Moves the texture map in the shape of a Lissajous figure.
|
||||
Params:
|
||||
UAmp=(float) 1.0f;
|
||||
UFreq=(float) 1.0f;
|
||||
UPhase=(float) 0.0f;
|
||||
VAmp=(float) 1.0f;
|
||||
VFreq=(float) 1.0f;
|
||||
VPhase=(float) 0.0f;
|
||||
|
||||
STEP_LINEAR_OFFSET
|
||||
Description:
|
||||
Similar to Linear Offset but moves stuff around in discrete steps
|
||||
Params:
|
||||
UStep=(float) 0.0f;
|
||||
VStep=(float) 0.0f;
|
||||
SPS=(float) 0.0f; Steps per second
|
||||
|
||||
ZIGZAG_LINEAR_OFFSET
|
||||
Description:
|
||||
Similar to Linear Offset but reverses direction periodically.
|
||||
Params:
|
||||
UPerSec=(float) 0.0f;
|
||||
VPerSec=(float) 0.0f;
|
||||
Period=(float) 0.0f; Time it takes to make a zigzag in seconds
|
||||
|
||||
WS_CLASSIC_ENVIRONMENT
|
||||
Description:
|
||||
World space normal environment map
|
||||
|
||||
WS_ENVIRONMENT
|
||||
Description:
|
||||
World space reflection environment map
|
||||
|
||||
GRID_CLASSIC_ENVIRONMENT
|
||||
Description:
|
||||
Animated normal environment map
|
||||
|
||||
GRID_ENVIRONMENT
|
||||
Description:
|
||||
Animated reflection environtment map
|
||||
|
||||
RANDOM
|
||||
Description: Randomly rotates and translates a texture with linear offset
|
||||
FPS=(float) 0.0f; Frames per second
|
||||
UPerSec=(float) 0.0;
|
||||
VPerSec=(float) 0.0;
|
||||
|
||||
EDGE
|
||||
Description: Uses the Z-coordinate of the reflection or normal vector to access the U coordinate
|
||||
The V-coordinate is linear offset
|
||||
VPerSec=(float) 0.0
|
||||
UseReflect=FALSE
|
||||
VStart=(float) 0.0
|
||||
|
||||
BUMPENV
|
||||
Description: Sets up and possibly animates the bump matrix, also has the LinearOffset features
|
||||
NOTE: even if you don't want to animate the bump matrix, you should use this mapper
|
||||
so that the matrix gets set up with the identity settings.
|
||||
BumpRotation = (float) 0.1f; In Hertz. 1 = 1 rotate per second (DEFAULT = 0.0)
|
||||
BumpScale = scale factor applied to the bumps (DEFAULT = 1.0)
|
||||
UPerSec=(float) 0.0;
|
||||
VPerSec=(float) 0.0;
|
||||
UScale=(float) 1.0;
|
||||
VScale=(float) 1.0;
|
||||
|
||||
|
||||
-----------
|
||||
TODO:
|
||||
-the ability to affect the period of the zigzag in only one direction (V) while the other (U) continues to offset undisturbed in the original linear fashion.
|
||||
-groovy scaling
|
||||
-scale random
|
||||
-random mapper random time
|
||||
@@ -0,0 +1,25 @@
|
||||
HY 2/14/01 Created.
|
||||
|
||||
Polygons are rendered via:
|
||||
A. The Mesh packet renderer
|
||||
B. Render object's render method
|
||||
C. Alpha sorting pipeline
|
||||
|
||||
NB. Shaders and Vertex Mateirals have presets that you can use to set state
|
||||
|
||||
Guidelines for B type polygons:
|
||||
|
||||
1. Always set the World matrix
|
||||
2. Always use a Shader (Shader.Apply())
|
||||
3. Always use a VertexMaterial (VertexMaterial.Apply())
|
||||
4. If there is a Texture, use Texture.Apply()
|
||||
|
||||
For any other render state, save the initial state, set your state, render then
|
||||
restore the original state.
|
||||
|
||||
e.g. save the VIEW matrix if you're nuking it, then restore it after you're done.
|
||||
|
||||
Guidelines for C type polygons:
|
||||
|
||||
1. All vertices submitted must be in View Coordinates
|
||||
2. All states submitted must be entirely contained in Shader,VertexMaterial & Texture
|
||||
Binary file not shown.
@@ -0,0 +1,161 @@
|
||||
;---------------------------------------------------------------------------------------------------------------------
|
||||
;
|
||||
; DAZZLE.INI
|
||||
|
||||
; This file is a sample DAZZLE.INI file, indicating how to set up dazzles and lens
|
||||
; flares for an application. PLEASE USE THIS FOR REFERENCE ONLY. You should consult the
|
||||
; asset manager of your project in order to find the location of the actual DAZZLE.INI
|
||||
; file that is specific to your project.
|
||||
;
|
||||
; PLEASE NOTE: some of the tools and library code assume that the dazzle type 'DEFAULT'
|
||||
; exists and is the first dazzle type.
|
||||
;
|
||||
;
|
||||
; DAZZLE DEFINITION PARAMETERS:
|
||||
;-------------------------------
|
||||
; 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.
|
||||
;
|
||||
; HaloIntensityPow - 1.0 would be linear fadeout, smaller than that will steepen the curve (smaller hotspot)
|
||||
; HaloSizePow - 1.0 would be linear fadeout, smaller than that will steepen the curve (smaller hotspot)
|
||||
; DazzleIntensityPow
|
||||
; DazzleSizePow
|
||||
; HaloArea
|
||||
; DazzleArea - Something like 0.05 is a good starting point for a dazzle...
|
||||
; HaloScaleX - X scale factor for the halo
|
||||
; HaloScaleY - Y scale factor for the halo
|
||||
; DazzleScaleX - X scale factor for the dazzle
|
||||
; DazzleScaleY - Y scale factor for the dazzle
|
||||
; HaloIntensity - base intensity of the halo
|
||||
; DazzleIntensity - base intensity of the dazzle
|
||||
;
|
||||
; 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.
|
||||
;
|
||||
; DazzleDirectionArea - Something like 0.5 might be a good test value
|
||||
; DazzleDirection - direction vector (gth - we should lock this paramter to 0,0,1)
|
||||
; FadeoutStart - distance in meters where the halo and dazzle start to fade out
|
||||
; FadeoutEnd - distance in meters where the halo and dazzle are completely faded out
|
||||
; SizeOptimizationLimit- NOT FINISHED
|
||||
; HistoryWeight - 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!)
|
||||
; DazzleTextureName - texture filename for the dazzle
|
||||
; HaloTextureName - texture filename for the halo
|
||||
; UseCameraTranslation - 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.
|
||||
; HaloColor - color of the halo
|
||||
; DazzleColor - color of the dazzle
|
||||
;
|
||||
; DazzleTestColor - Dazzle test color could be white in many cases but if the level has a lot of
|
||||
; white then another color can be defined.
|
||||
; LensflareName - Dazzle can use a lensflare by defining a name of lensflare in the ini
|
||||
;
|
||||
;
|
||||
; LENSFLARE DEFINITION PARAMETERS:
|
||||
;----------------------------------
|
||||
;
|
||||
; TextureName - Texture to be used by the lensflare
|
||||
; FlareCount - 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.
|
||||
; FlareLocation - 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.
|
||||
; FlareSize - Normalized flare sizes
|
||||
; FlareColor - Colors for each flare sprite
|
||||
; FlareUV - 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.
|
||||
;
|
||||
;---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
[Dazzles_List]
|
||||
0=DEFAULT
|
||||
1=SUN
|
||||
|
||||
[Lensflares_List]
|
||||
0=SUN_LENSFLARE
|
||||
|
||||
|
||||
;========================================== 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
|
||||
HaloTextureName=SunHalo.tga
|
||||
DazzleTextureName=SunDazzle.tga
|
||||
DazzleColor=1,1,1
|
||||
HaloColor=1,1,1
|
||||
DazzleTestColor=1,1,1
|
||||
|
||||
[SUN]
|
||||
HaloSizePow=1.0
|
||||
HaloIntensityPow=1.0
|
||||
HaloArea=1.0
|
||||
HaloScaleX=0.25
|
||||
HaloScaleY=0.25
|
||||
DazzleArea=0.04
|
||||
DazzleDirectionArea=0
|
||||
DazzleDirection=0,1,1
|
||||
DazzleSizePow=1.0
|
||||
DazzleIntensityPow=1.0
|
||||
DazzleIntensity=1.0
|
||||
DazzleScaleX=4.0
|
||||
DazzleScaleY=4.0
|
||||
FadeoutStart=20.0
|
||||
FadeoutEnd=30.0
|
||||
SizeOptimizationLimit=0.05
|
||||
HistoryWeight=0.1
|
||||
UseCameraTranslation=0
|
||||
HaloTextureName=SunHalo.tga
|
||||
DazzleTextureName=SunDazzle.tga
|
||||
DazzleColor=1.0,1.0,1.0
|
||||
LensflareName=SUN_LENSFLARE
|
||||
|
||||
|
||||
;========================================== LENSFLARE DEFINITIONS =================
|
||||
|
||||
[SUN_LENSFLARE]
|
||||
TextureName=SunLensFlare.tga
|
||||
FlareCount=6
|
||||
FlareLocation1=1.3
|
||||
FlareLocation2=0.4
|
||||
FlareLocation3=-0.1
|
||||
FlareLocation4=-0.6
|
||||
FlareLocation5=-0.9
|
||||
FlareLocation6=-1.2
|
||||
FlareSize1=0.06
|
||||
FlareSize2=0.04
|
||||
FlareSize3=0.03
|
||||
FlareSize4=0.15
|
||||
FlareSize5=0.20
|
||||
FlareSize6=0.30
|
||||
FlareUV1=0.000,0.000,0.118,0.238
|
||||
FlareUV2=0.134,0.048,0.204,0.190
|
||||
FlareUV3=0.228,0.079,0.276,0.175
|
||||
FlareUV4=0.000,0.619,0.165,1.000
|
||||
FlareUV5=0.181,0.365,0.488,1.000
|
||||
FlareUV6=0.496,0.000,1.000,1.000
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,173 @@
|
||||
State Management Responsibilities
|
||||
|
||||
Key:
|
||||
G - Global
|
||||
DX8W - DX8 Wrapper
|
||||
LE - Wrapper::Set Light Environment
|
||||
DX8R - DX8 Renderer (affects meshes only)
|
||||
Shader - ShaderClass
|
||||
VM - VertexMaterial
|
||||
Map - Mapper (part of VertexMaterial)
|
||||
Texture - TextureClass
|
||||
WW3D
|
||||
|
||||
_D3DRENDERSTATETYPE {
|
||||
ZENABLE = 7,
|
||||
FILLMODE = 8, WW3D
|
||||
SHADEMODE = 9,
|
||||
LINEPATTERN = 10,
|
||||
ZWRITEENABLE = 14, Shader
|
||||
ALPHATESTENABLE = 15, Shader
|
||||
LASTPIXEL = 16,
|
||||
SRCBLEND = 19, Shader
|
||||
DESTBLEND = 20, Shader
|
||||
CULLMODE = 22, Shader
|
||||
ZFUNC = 23, Shader
|
||||
ALPHAREF = 24, Shader
|
||||
ALPHAFUNC = 25, Shader
|
||||
DITHERENABLE = 26, G
|
||||
ALPHABLENDENABLE = 27, Shader
|
||||
FOGENABLE = 28, Shader
|
||||
SPECULARENABLE = 29, Shader
|
||||
ZVISIBLE = 30,
|
||||
FOGCOLOR = 34, Shader
|
||||
FOGTABLEMODE = 35, G
|
||||
FOGSTART = 36, Scene
|
||||
FOGEND = 37, Scene
|
||||
FOGDENSITY = 38,
|
||||
EDGEANTIALIAS = 40,
|
||||
ZBIAS = 47, G (set to zero after device is initted)
|
||||
RANGEFOGENABLE = 48, G
|
||||
|
||||
STENCILENABLE = 52,
|
||||
STENCILFAIL = 53,
|
||||
STENCILZFAIL = 54,
|
||||
STENCILPASS = 55,
|
||||
STENCILFUNC = 56,
|
||||
STENCILREF = 57,
|
||||
STENCILMASK = 58,
|
||||
STENCILWRITEMASK = 59,
|
||||
TEXTUREFACTOR = 60,
|
||||
|
||||
WRAP0 = 128,
|
||||
WRAP1 = 129,
|
||||
WRAP2 = 130,
|
||||
WRAP3 = 131,
|
||||
WRAP4 = 132,
|
||||
WRAP5 = 133,
|
||||
WRAP6 = 134,
|
||||
WRAP7 = 135,
|
||||
CLIPPING = 136,
|
||||
LIGHTING = 137, VM
|
||||
AMBIENT = 139, LE
|
||||
FOGVERTEXMODE = 140, G
|
||||
COLORVERTEX = 141, G
|
||||
LOCALVIEWER = 142,
|
||||
NORMALIZENORMALS = 143,
|
||||
DIFFUSEMATERIALSOURCE = 145, VM
|
||||
SPECULARMATERIALSOURCE = 146, G
|
||||
AMBIENTMATERIALSOURCE = 147, VM, set to same setting as diffuse material source
|
||||
EMISSIVEMATERIALSOURCE = 148, VM
|
||||
VERTEXBLEND = 151,
|
||||
CLIPPLANEENABLE = 152,
|
||||
|
||||
SOFTWAREVERTEXPROCESSING = 153, G
|
||||
|
||||
POINTSIZE = 154,
|
||||
POINTSIZE_MIN = 155,
|
||||
POINTSPRITEENABLE = 156,
|
||||
|
||||
POINTSCALEENABLE = 157,
|
||||
POINTSCALE_A = 158,
|
||||
POINTSCALE_B = 159,
|
||||
POINTSCALE_C = 160,
|
||||
|
||||
MULTISAMPLEANTIALIAS = 161,
|
||||
MULTISAMPLEMASK = 162,
|
||||
|
||||
PATCHEDGESTYLE = 163,
|
||||
PATCHSEGMENTS = 164,
|
||||
|
||||
DEBUGMONITORTOKEN = 165,
|
||||
POINTSIZE_MAX = 166,
|
||||
INDEXEDVERTEXBLENDENABLE = 167,
|
||||
COLORWRITEENABLE = 168,
|
||||
TWEENFACTOR = 170,
|
||||
BLENDOP = 171,
|
||||
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
} D3DRENDERSTATETYPE;
|
||||
|
||||
_D3DTEXTURESTAGESTATETYPE {
|
||||
COLOROP = 1, Shader stages 0,1 only
|
||||
COLORARG1 = 2, Shader stages 0,1 only
|
||||
COLORARG2 = 3, Shader stages 0,1 only
|
||||
ALPHAOP = 4, Shader stages 0,1 only
|
||||
ALPHAARG1 = 5, Shader stages 0,1 only
|
||||
ALPHAARG2 = 6, Shader stages 0,1 only
|
||||
BUMPENVMAT00 = 7,
|
||||
BUMPENVMAT01 = 8,
|
||||
BUMPENVMAT10 = 9,
|
||||
BUMPENVMAT11 = 10,
|
||||
TEXCOORDINDEX = 11, DX8R, Map
|
||||
ADDRESSU = 13, Texture
|
||||
ADDRESSV = 14, Texture
|
||||
BORDERCOLOR = 15,
|
||||
MAGFILTER = 16, Texture
|
||||
MINFILTER = 17, Texture
|
||||
MIPFILTER = 18, Texture
|
||||
MIPMAPLODBIAS = 19,
|
||||
MAXMIPLEVEL = 20,
|
||||
MAXANISOTROPY = 21,
|
||||
BUMPENVLSCALE = 22,
|
||||
BUMPENVLOFFSET = 23,
|
||||
TEXTURETRANSFORMFLAGS = 24, Map
|
||||
ADDRESSW = 25,
|
||||
COLORARG0 = 26,
|
||||
ALPHAARG0 = 27,
|
||||
RESULTARG = 28,
|
||||
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
} D3DTEXTURESTAGESTATETYPE;
|
||||
|
||||
Variables
|
||||
|
||||
_D3DTRANSFORMSTATETYPE {
|
||||
D3DTS_VIEW = 2, Pointgroup (restores), Camera
|
||||
D3DTS_PROJECTION = 3, Camera
|
||||
D3DTS_TEXTURE0 = 16,
|
||||
D3DTS_TEXTURE1 = 17,
|
||||
D3DTS_TEXTURE2 = 18,
|
||||
D3DTS_TEXTURE3 = 19,
|
||||
D3DTS_TEXTURE4 = 20,
|
||||
D3DTS_TEXTURE5 = 21,
|
||||
D3DTS_TEXTURE6 = 22,
|
||||
D3DTS_TEXTURE7 = 23,
|
||||
|
||||
D3DTS_FORCE_DWORD = 0x7fffffff
|
||||
|
||||
D3DTS_WORLDMATRIX(0) = box, pointgroup, camera
|
||||
} D3DTRANSFORMSTATETYPE;
|
||||
|
||||
Clip Planes =
|
||||
Clip Status =
|
||||
Current Texture Palette =
|
||||
Cursor Position =
|
||||
Cursor Properties =
|
||||
Gamma Ramp =
|
||||
Indices = DX8W
|
||||
Light = LE
|
||||
Material = VM
|
||||
Palette Entries =
|
||||
Pixel Shader =
|
||||
Pixel Shader Const =
|
||||
Render Target =
|
||||
Stream Source = DX8W
|
||||
Texture = DX8W
|
||||
WORLD Transform = box, DX8R, pointgr
|
||||
VIEW Transform = pointgr
|
||||
PROJECTION Transform = camera
|
||||
TEXTURE Transform = Map
|
||||
Vertex Shader = DX8W
|
||||
Vertex Shader Const =
|
||||
Viewport = Camera, WW3D
|
||||
1217
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtree.cpp
Normal file
1217
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtree.cpp
Normal file
File diff suppressed because it is too large
Load Diff
347
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtree.h
Normal file
347
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtree.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/aabtree.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/14/01 9:42a $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef AABTREE_H
|
||||
#define AABTREE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "refcount.h"
|
||||
#include "simplevec.h"
|
||||
#include "vector3.h"
|
||||
#include "vector3i.h"
|
||||
#include "aaplane.h"
|
||||
#include "bittype.h"
|
||||
#include "colmath.h"
|
||||
#include "wwdebug.h"
|
||||
#include "aabtreebuilder.h"
|
||||
#include "obbox.h"
|
||||
#include <tri.h>
|
||||
#include <float.h>
|
||||
|
||||
|
||||
class MeshClass;
|
||||
class CameraClass;
|
||||
class RayCollisionTestClass;
|
||||
class AABoxCollisionTestClass;
|
||||
class OBBoxCollisionTestClass;
|
||||
class OBBoxIntersectionTestClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class MeshGeometryClass;
|
||||
class OBBoxClass;
|
||||
class ChunkLoadClass;
|
||||
|
||||
struct BoxRayAPTContextStruct;
|
||||
|
||||
#define AABTREE_LEAF_FLAG 0x80000000
|
||||
|
||||
|
||||
/*
|
||||
** AABTreeClass
|
||||
** This class encapsulates an Axis-Aligned Bounding Box Tree for a mesh. This tree
|
||||
** can be used to perform hierarchical culling for collision detection. Note that
|
||||
** this class is constructed using the AABTreeBuilderClass; these two classes are
|
||||
** very tightly coupled. Pretty much the only code which needs to know about the AABTreeClass
|
||||
** is in MeshGeometryClass. I moved these out into a separate file just to reduce the
|
||||
** size of meshmdl.cpp.
|
||||
*/
|
||||
class AABTreeClass : public W3DMPO, public RefCountClass
|
||||
{
|
||||
W3DMPO_GLUE(AABTreeClass)
|
||||
public:
|
||||
|
||||
AABTreeClass(void);
|
||||
AABTreeClass(AABTreeBuilderClass * builder);
|
||||
AABTreeClass(const AABTreeClass & that);
|
||||
~AABTreeClass(void);
|
||||
|
||||
void Load_W3D(ChunkLoadClass & cload);
|
||||
|
||||
int Get_Node_Count(void) { return NodeCount; }
|
||||
int Get_Poly_Count(void) { return PolyCount; }
|
||||
int Compute_Ram_Size(void);
|
||||
void Generate_APT(const OBBoxClass & box,SimpleDynVecClass<uint32> & apt);
|
||||
void Generate_APT(const OBBoxClass & box,const Vector3 & viewdir,SimpleDynVecClass<uint32> & apt);
|
||||
|
||||
bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
int Cast_Semi_Infinite_Axis_Aligned_Ray(const Vector3 & start_point,
|
||||
int axis_dir, unsigned char & flags);
|
||||
bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
private:
|
||||
|
||||
AABTreeClass & operator = (const AABTreeClass & that);
|
||||
|
||||
void Read_Poly_Indices(ChunkLoadClass & cload);
|
||||
void Read_Nodes(ChunkLoadClass & cload);
|
||||
|
||||
void Build_Tree_Recursive(AABTreeBuilderClass::CullNodeStruct * node,int &curpolyindex);
|
||||
void Reset(void);
|
||||
void Set_Mesh(MeshGeometryClass * mesh);
|
||||
void Update_Bounding_Boxes(void);
|
||||
void Update_Min_Max(int index,Vector3 & min,Vector3 & max);
|
||||
|
||||
/*
|
||||
** CullNodeStruct - the culling tree is built out of an array of these structures
|
||||
** They contain the extents of an axis-aligned box, indices to children nodes,
|
||||
** and indices into the polygon array
|
||||
** (05/22/2000 gth - changed this structure to support either child nodes -or-
|
||||
** a polygon array but not both at the same time. Also switched to 32bit indices
|
||||
** so that the code doesn't become useless as quickly )
|
||||
*/
|
||||
struct CullNodeStruct
|
||||
{
|
||||
Vector3 Min;
|
||||
Vector3 Max;
|
||||
|
||||
uint32 FrontOrPoly0;
|
||||
uint32 BackOrPolyCount;
|
||||
|
||||
// accessors
|
||||
inline bool Is_Leaf(void);
|
||||
|
||||
inline int Get_Back_Child(void); // returns index of back child (only call for non-LEAFs!!!)
|
||||
inline int Get_Front_Child(void); // returns index of front child (only call for non-LEAFs!!!)
|
||||
inline int Get_Poly0(void); // returns index of first polygon (only call on LEAFs)
|
||||
inline int Get_Poly_Count(void); // returns polygon count (only call on LEAFs)
|
||||
|
||||
// initialization
|
||||
inline void Set_Front_Child(uint32 index);
|
||||
inline void Set_Back_Child(uint32 index);
|
||||
inline void Set_Poly0(uint32 index);
|
||||
inline void Set_Poly_Count(uint32 count);
|
||||
};
|
||||
|
||||
/*
|
||||
** OBBoxAPTContextStruct - this is a temporary datastructure used in building
|
||||
** an APT by culling the mesh to an oriented bounding box.
|
||||
*/
|
||||
struct OBBoxAPTContextStruct
|
||||
{
|
||||
OBBoxAPTContextStruct(const OBBoxClass & box,SimpleDynVecClass<uint32> & apt) :
|
||||
Box(box), APT(apt)
|
||||
{ }
|
||||
|
||||
OBBoxClass Box;
|
||||
SimpleDynVecClass<uint32> & APT;
|
||||
};
|
||||
|
||||
/**
|
||||
** OBBoxRayAPTContextStruct - temporary datastructure used in building an APT
|
||||
** by culling the mesh to a oriented box and eliminating backfaces to a ray.
|
||||
*/
|
||||
struct OBBoxRayAPTContextStruct
|
||||
{
|
||||
OBBoxRayAPTContextStruct(const OBBoxClass & box,const Vector3 & viewdir,SimpleDynVecClass<uint32> & apt) :
|
||||
Box(box),
|
||||
ViewVector(viewdir),
|
||||
APT(apt)
|
||||
{ }
|
||||
|
||||
OBBoxClass Box;
|
||||
Vector3 ViewVector;
|
||||
SimpleDynVecClass<uint32> & APT;
|
||||
};
|
||||
|
||||
void Generate_OBBox_APT_Recursive(CullNodeStruct * node,OBBoxAPTContextStruct & context);
|
||||
void Generate_OBBox_APT_Recursive(CullNodeStruct * node, OBBoxRayAPTContextStruct & context);
|
||||
|
||||
bool Cast_Ray_Recursive(CullNodeStruct * node,RayCollisionTestClass & raytest);
|
||||
int Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive(CullNodeStruct * node, const Vector3 & start_point,
|
||||
int axis_r, int axis_1, int axis_2, int direction, unsigned char & flags);
|
||||
bool Cast_AABox_Recursive(CullNodeStruct * node,AABoxCollisionTestClass & boxtest);
|
||||
bool Cast_OBBox_Recursive(CullNodeStruct * node,OBBoxCollisionTestClass & boxtest);
|
||||
bool Intersect_OBBox_Recursive(CullNodeStruct * node,OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
bool Cast_Ray_To_Polys(CullNodeStruct * node,RayCollisionTestClass & raytest);
|
||||
int Cast_Semi_Infinite_Axis_Aligned_Ray_To_Polys(CullNodeStruct * node, const Vector3 & start_point,
|
||||
int axis_r, int axis_1, int axis_2, int direction, unsigned char & flags);
|
||||
bool Cast_AABox_To_Polys(CullNodeStruct * node,AABoxCollisionTestClass & boxtest);
|
||||
bool Cast_OBBox_To_Polys(CullNodeStruct * node,OBBoxCollisionTestClass & boxtest);
|
||||
bool Intersect_OBBox_With_Polys(CullNodeStruct * node,OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
void Update_Bounding_Boxes_Recursive(CullNodeStruct * node);
|
||||
|
||||
int NodeCount; // number of nodes in the tree
|
||||
CullNodeStruct * Nodes; // array of nodes
|
||||
int PolyCount; // number of polygons in the parent mesh (and the number of indexes in our array)
|
||||
uint32 * PolyIndices; // linear array of polygon indices, nodes index into this array
|
||||
MeshGeometryClass * Mesh; // pointer to the parent mesh (non-ref-counted; we are a member of this mesh)
|
||||
|
||||
friend class MeshClass;
|
||||
friend class MeshGeometryClass;
|
||||
friend class AuxMeshDataClass;
|
||||
friend class AABTreeBuilderClass;
|
||||
|
||||
};
|
||||
|
||||
inline int AABTreeClass::Compute_Ram_Size(void)
|
||||
{
|
||||
return NodeCount * sizeof(CullNodeStruct) +
|
||||
PolyCount * sizeof(int) +
|
||||
sizeof(AABTreeClass);
|
||||
}
|
||||
|
||||
inline bool AABTreeClass::Cast_Ray(RayCollisionTestClass & raytest)
|
||||
{
|
||||
WWASSERT(Nodes != NULL);
|
||||
return Cast_Ray_Recursive(&(Nodes[0]),raytest);
|
||||
}
|
||||
|
||||
inline int AABTreeClass::Cast_Semi_Infinite_Axis_Aligned_Ray(const Vector3 & start_point,
|
||||
int axis_dir, unsigned char & flags)
|
||||
{
|
||||
// These tables translate between the axis_dir representation (which is an integer in which 0
|
||||
// indicates a ray along the positive x axis, 1 along the negative x axis, 2 the positive y
|
||||
// axis, 3 negative y axis, 4 positive z axis, 5 negative z axis) and a four-integer
|
||||
// representation (axis_r is the axis number - 0, 1 or 2 - of the axis along which the ray is
|
||||
// cast; axis_1 and axis_2 are the axis numbers of the other two axes; direction is 0 for
|
||||
// negative and 1 for positive direction of the ray).
|
||||
static const int axis_r[6] = { 0, 0, 1, 1, 2, 2 };
|
||||
static const int axis_1[6] = { 1, 1, 2, 2, 0, 0 };
|
||||
static const int axis_2[6] = { 2, 2, 0, 0, 1, 1 };
|
||||
static const int direction[6] = { 1, 0, 1, 0, 1, 0 };
|
||||
WWASSERT(Nodes != NULL);
|
||||
WWASSERT(axis_dir >= 0);
|
||||
WWASSERT(axis_dir < 6);
|
||||
|
||||
// The functions called after this point will 'or' bits into this variable, so it needs to
|
||||
// be initialized here to TRI_RAYCAST_FLAG_NONE.
|
||||
flags = TRI_RAYCAST_FLAG_NONE;
|
||||
|
||||
return Cast_Semi_Infinite_Axis_Aligned_Ray_Recursive(&(Nodes[0]), start_point,
|
||||
axis_r[axis_dir], axis_1[axis_dir], axis_2[axis_dir], direction[axis_dir], flags);
|
||||
}
|
||||
|
||||
inline bool AABTreeClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
|
||||
{
|
||||
WWASSERT(Nodes != NULL);
|
||||
return Cast_AABox_Recursive(&(Nodes[0]),boxtest);
|
||||
}
|
||||
|
||||
inline bool AABTreeClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
|
||||
{
|
||||
WWASSERT(Nodes != NULL);
|
||||
return Cast_OBBox_Recursive(&(Nodes[0]),boxtest);
|
||||
}
|
||||
|
||||
inline bool AABTreeClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
|
||||
{
|
||||
WWASSERT(Nodes != NULL);
|
||||
return Intersect_OBBox_Recursive(&(Nodes[0]),boxtest);
|
||||
}
|
||||
|
||||
inline void AABTreeClass::Update_Bounding_Boxes(void)
|
||||
{
|
||||
WWASSERT(Nodes != NULL);
|
||||
Update_Bounding_Boxes_Recursive(&(Nodes[0]));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
|
||||
AABTreeClass::CullNodeStruct implementation
|
||||
|
||||
These nodes can be either leaf nodes or non-leaf nodes. If they are leaf nodes, they
|
||||
will contain an index to their first polygon index and a polygon count. If they are
|
||||
non-leafs they will contain indices to their front and back children. Since I'm re-using
|
||||
the same variables for the child indices and the polygon indices, you have to call
|
||||
the Is_Leaf function then only call the appropriate functions. The flag indicating whether
|
||||
this node is a leaf is stored in the MSB of the FrontOrPoly0 variable. It will always
|
||||
be stripped off by these accessor functions
|
||||
|
||||
***********************************************************************************************/
|
||||
|
||||
inline bool AABTreeClass::CullNodeStruct::Is_Leaf(void)
|
||||
{
|
||||
return ((FrontOrPoly0 & AABTREE_LEAF_FLAG) != 0);
|
||||
}
|
||||
|
||||
inline int AABTreeClass::CullNodeStruct::Get_Front_Child(void)
|
||||
{
|
||||
WWASSERT(!Is_Leaf());
|
||||
return FrontOrPoly0; // we shouldn't be calling this on a leaf and the leaf bit should be zero...
|
||||
}
|
||||
|
||||
inline int AABTreeClass::CullNodeStruct::Get_Back_Child(void)
|
||||
{
|
||||
WWASSERT(!Is_Leaf());
|
||||
return BackOrPolyCount;
|
||||
}
|
||||
|
||||
inline int AABTreeClass::CullNodeStruct::Get_Poly0(void)
|
||||
{
|
||||
WWASSERT(Is_Leaf());
|
||||
return (FrontOrPoly0 & ~AABTREE_LEAF_FLAG);
|
||||
}
|
||||
|
||||
inline int AABTreeClass::CullNodeStruct::Get_Poly_Count(void)
|
||||
{
|
||||
WWASSERT(Is_Leaf());
|
||||
return BackOrPolyCount;
|
||||
}
|
||||
|
||||
inline void AABTreeClass::CullNodeStruct::Set_Front_Child(uint32 index)
|
||||
{
|
||||
WWASSERT(index < 0x7FFFFFFF);
|
||||
FrontOrPoly0 = index;
|
||||
}
|
||||
|
||||
inline void AABTreeClass::CullNodeStruct::Set_Back_Child(uint32 index)
|
||||
{
|
||||
WWASSERT(index < 0x7FFFFFFF);
|
||||
BackOrPolyCount = index;
|
||||
}
|
||||
|
||||
inline void AABTreeClass::CullNodeStruct::Set_Poly0(uint32 index)
|
||||
{
|
||||
WWASSERT(index < 0x7FFFFFFF);
|
||||
FrontOrPoly0 = (index | AABTREE_LEAF_FLAG);
|
||||
}
|
||||
|
||||
inline void AABTreeClass::CullNodeStruct::Set_Poly_Count(uint32 count)
|
||||
{
|
||||
WWASSERT(count < 0x7FFFFFFF);
|
||||
BackOrPolyCount = count;
|
||||
}
|
||||
|
||||
#endif
|
||||
930
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtreebuilder.cpp
Normal file
930
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtreebuilder.cpp
Normal file
@@ -0,0 +1,930 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/aabtreebuilder.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* AABTreeBuilderClass::AABTreeBuilderClass -- Constructor *
|
||||
* AABTreeBuilderClass::~AABTreeBuilderClass -- Destructor *
|
||||
* AABTreeBuilderClass::Reset -- reset the builder, delete all arrays *
|
||||
* AABTreeBuilderClass::Build_AABTree -- Build an AABTree for the given mesh. *
|
||||
* AABTreeBuilderClass::Build_Tree -- recursivly builds the culling tree *
|
||||
* AABTreeBuilderClass::Select_Splitting_Plane -- select a partition for the given polys *
|
||||
* AABTreeBuilderClass::Compute_Plane_Score -- evaluate the suitability of a partition plane *
|
||||
* AABTreeBuilderClass::Which_Side -- which side of a plane is the given poly *
|
||||
* AABTreeBuilderClass::Split_Polys -- partition the polys with a plane *
|
||||
* AABTreeBuilderClass::Compute_Bounding_Box -- compute bounding boxes for the cull nodes *
|
||||
* AABTreeBuilderClass::Assign_Index -- assign an array index to each node *
|
||||
* AABTreeBuilderClass::Node_Count -- Count the nodes in the tree *
|
||||
* AABTreeBuilderClass::Poly_Count -- returns number of polys *
|
||||
* AABTreeBuilderClass::Node_Count_Recursive -- internal implementation of Node_Count *
|
||||
* AABTreeBuilderClass::Submit_Tree -- install nodes into an AABTreeClass *
|
||||
* AABTreeBuilderClass::Submit_Tree_Recursive -- internal implementation of Submit_Tree *
|
||||
* AABTreeBuilderClass::Update_Min -- ensure given vector is < min of the poly *
|
||||
* AABTreeBuilderClass::Update_Max -- ensure given vector is > max of poly *
|
||||
* AABTreeBuilderClass::Update_Min_Max -- ensure given vector is in min max of poly *
|
||||
* AABTreeBuilderClass::Export -- Saves this AABTree into a W3D chunk *
|
||||
* AABTreeBuilderClass::Build_W3D_AABTree_Recursive -- Build array of indices and W3dMeshAAB *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "aabtreebuilder.h"
|
||||
#include "chunkio.h"
|
||||
#include "w3d_file.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define WWASSERT assert // can't use WWASSERT because we use this module in the MAX plugin...
|
||||
const float COINCIDENCE_EPSILON = 0.001f;
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::AABTreeBuilderClass -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
AABTreeBuilderClass::AABTreeBuilderClass(void) :
|
||||
Root(NULL),
|
||||
CurPolyIndex(0),
|
||||
PolyCount(0),
|
||||
Polys(NULL),
|
||||
VertCount(0),
|
||||
Verts(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::~AABTreeBuilderClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/19/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
AABTreeBuilderClass::~AABTreeBuilderClass(void)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Reset -- reset the builder, delete all arrays *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/19/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Reset(void)
|
||||
{
|
||||
if (Root) {
|
||||
delete Root; Root = NULL;
|
||||
}
|
||||
|
||||
if (Verts != NULL) {
|
||||
delete[] Verts;
|
||||
Verts = NULL;
|
||||
}
|
||||
|
||||
if (Polys != NULL) {
|
||||
delete[] Polys;
|
||||
Polys = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Build_AABTree -- Build an AABTree for the given mesh. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Build_AABTree(int polycount,Vector3i * polys,int vertcount,Vector3 * verts)
|
||||
{
|
||||
WWASSERT(polycount > 0);
|
||||
WWASSERT(vertcount > 0);
|
||||
WWASSERT(polys != NULL);
|
||||
WWASSERT(verts != NULL);
|
||||
|
||||
/*
|
||||
** If we already have allocated data, release it
|
||||
*/
|
||||
Reset();
|
||||
|
||||
/*
|
||||
** Copy the mesh data
|
||||
*/
|
||||
VertCount = vertcount;
|
||||
PolyCount = polycount;
|
||||
Verts = W3DNEWARRAY Vector3[VertCount];
|
||||
Polys = W3DNEWARRAY Vector3i[PolyCount];
|
||||
|
||||
for (int vi=0; vi<VertCount; vi++) {
|
||||
Verts[vi] = verts[vi];
|
||||
}
|
||||
for (int pi=0; pi<PolyCount; pi++) {
|
||||
Polys[pi] = polys[pi];
|
||||
}
|
||||
|
||||
/*
|
||||
** First, create a list of all of the poly indices
|
||||
*/
|
||||
int * polyindices = W3DNEWARRAY int[PolyCount];
|
||||
for (int i=0; i<PolyCount; i++) {
|
||||
polyindices[i] = i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Build the tree, note that the array of poly indices will be
|
||||
** deleted by the Build_Tree function.
|
||||
*/
|
||||
Root = W3DNEW CullNodeStruct;
|
||||
Build_Tree(Root,PolyCount,polyindices);
|
||||
polyindices = NULL;
|
||||
|
||||
/*
|
||||
** fill in the remaining information needed in the tree:
|
||||
** for example: bounding boxes, index assignments
|
||||
*/
|
||||
Compute_Bounding_Box(Root);
|
||||
Assign_Index(Root,0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Build_Tree -- recursivly builds the culling tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Build_Tree(CullNodeStruct * node,int polycount,int * polyindices)
|
||||
{
|
||||
/*
|
||||
** First, if there are only a few polys left, just terminate the tree
|
||||
*/
|
||||
if (polycount <= MIN_POLYS_PER_NODE) {
|
||||
node->PolyCount = polycount;
|
||||
node->PolyIndices = polyindices;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to find a suitable partitioning plane.
|
||||
*/
|
||||
SplitChoiceStruct sc;
|
||||
|
||||
sc = Select_Splitting_Plane(polycount,polyindices);
|
||||
|
||||
/*
|
||||
** If the algorithm could not separate any polys, just install the polys
|
||||
** in this node and terminate. TODO: explore how this happens.
|
||||
*/
|
||||
if (sc.FrontCount + sc.BackCount != polycount) {
|
||||
node->PolyCount = polycount;
|
||||
node->PolyIndices = polyindices;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decide whether to actually partition this node. If the partitioning
|
||||
** will not gain us anything, just install the polys in this node and terminate
|
||||
** the tree.
|
||||
*/
|
||||
#if 0
|
||||
if (sc.Cost == MAX_COST) {
|
||||
node->PolyCount = polycount;
|
||||
node->PolyIndices = polyindices;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Ok, split the polys
|
||||
*/
|
||||
SplitArraysStruct arrays;
|
||||
Split_Polys(polycount,polyindices,sc,&arrays);
|
||||
|
||||
/*
|
||||
** Free the memory in use by the input tile-list
|
||||
*/
|
||||
delete[] polyindices;
|
||||
|
||||
/*
|
||||
** Build a front tree if necessary. Remember that the Build function
|
||||
** deletes the poly array.
|
||||
*/
|
||||
if (arrays.FrontCount) {
|
||||
WWASSERT(arrays.FrontPolys != NULL);
|
||||
node->Front = W3DNEW CullNodeStruct;
|
||||
Build_Tree(node->Front,arrays.FrontCount,arrays.FrontPolys);
|
||||
arrays.FrontPolys = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Build a back tree if necessary. Remember that the build function
|
||||
** deletes the tile array.
|
||||
*/
|
||||
if (arrays.BackCount) {
|
||||
WWASSERT(arrays.BackPolys != NULL);
|
||||
|
||||
node->Back = W3DNEW CullNodeStruct;
|
||||
Build_Tree(node->Back,arrays.BackCount,arrays.BackPolys);
|
||||
arrays.BackPolys = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Select_Splitting_Plane -- select a partition for the given polys *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
AABTreeBuilderClass::SplitChoiceStruct
|
||||
AABTreeBuilderClass::Select_Splitting_Plane(int polycount,int * polyindices)
|
||||
{
|
||||
WWASSERT(polyindices != NULL);
|
||||
|
||||
const int NUM_TRYS = 50;
|
||||
|
||||
SplitChoiceStruct best_plane_stats;
|
||||
SplitChoiceStruct considered_plane_stats;
|
||||
|
||||
/*
|
||||
** Try putting axis-aligned planes through some random vertices
|
||||
*/
|
||||
for (int trys = 0; trys < MIN(NUM_TRYS,polycount); trys++) {
|
||||
|
||||
AAPlaneClass plane;
|
||||
|
||||
/*
|
||||
** Select a random poly and vertex index;
|
||||
*/
|
||||
int poly_index = polyindices[rand() % polycount];
|
||||
int vert_index = rand() % 3;
|
||||
const Vector3i * polyverts = Polys + poly_index;
|
||||
const Vector3 * vert = Verts + (*polyverts)[vert_index];
|
||||
|
||||
/*
|
||||
** Select a random plane
|
||||
*/
|
||||
switch(rand() % 3) {
|
||||
case 0: plane.Set(AAPlaneClass::XNORMAL,vert->X); break;
|
||||
case 1: plane.Set(AAPlaneClass::YNORMAL,vert->Y); break;
|
||||
case 2: plane.Set(AAPlaneClass::ZNORMAL,vert->Z); break;
|
||||
};
|
||||
|
||||
/*
|
||||
** Get the score for this plane
|
||||
*/
|
||||
considered_plane_stats = Compute_Plane_Score(polycount,polyindices,plane);
|
||||
|
||||
if (considered_plane_stats.Cost < best_plane_stats.Cost) {
|
||||
best_plane_stats = considered_plane_stats;
|
||||
}
|
||||
}
|
||||
|
||||
return best_plane_stats;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Compute_Plane_Score -- evaluate the suitability of a partition plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
AABTreeBuilderClass::SplitChoiceStruct
|
||||
AABTreeBuilderClass::Compute_Plane_Score(int polycount,int * polyindices,const AAPlaneClass & plane)
|
||||
{
|
||||
/*
|
||||
** The score of a splitting plane is based on the following factors:
|
||||
** - the volumes of the resulting two children volumes,
|
||||
** - the number of polys in each child volume
|
||||
*/
|
||||
SplitChoiceStruct sc;
|
||||
sc.Plane = plane;
|
||||
|
||||
for (int i=0; i<polycount; i++) {
|
||||
|
||||
switch(Which_Side(plane,polyindices[i])) {
|
||||
|
||||
case FRONT:
|
||||
case ON:
|
||||
case BOTH:
|
||||
{
|
||||
sc.FrontCount++;
|
||||
Update_Min_Max(polyindices[i],sc.FMin,sc.FMax );
|
||||
break;
|
||||
}
|
||||
|
||||
case BACK:
|
||||
{
|
||||
sc.BackCount++;
|
||||
Update_Min_Max(polyindices[i],sc.BMin,sc.BMax );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Inflate the box a tiny amount so that we never
|
||||
** get volumes of zero!
|
||||
*/
|
||||
sc.BMin -= Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
|
||||
sc.BMax += Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
|
||||
|
||||
/*
|
||||
** Compute the cost.
|
||||
*/
|
||||
float back_cost = (sc.BMax.X - sc.BMin.X) * (sc.BMax.Y - sc.BMin.Y) * (sc.BMax.Z - sc.BMin.Z) * sc.BackCount;
|
||||
float front_cost = (sc.FMax.X - sc.FMin.X) * (sc.FMax.Y - sc.FMin.Y) * (sc.FMax.Z - sc.FMin.Z) * sc.FrontCount;
|
||||
sc.Cost = front_cost + back_cost;
|
||||
|
||||
if ((sc.FrontCount == 0) || (sc.BackCount == 0)) {
|
||||
sc.Cost = FLT_MAX;
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Which_Side -- which side of a plane is the given poly *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
AABTreeBuilderClass::OverlapType
|
||||
AABTreeBuilderClass::Which_Side(const AAPlaneClass & plane,int poly_index)
|
||||
{
|
||||
/*
|
||||
** Check each vertex to see if it is in front, behind or on the plane
|
||||
*/
|
||||
int mask = 0;
|
||||
for (int vi=0; vi<3; vi++) {
|
||||
|
||||
const Vector3 & point = Verts[ Polys[poly_index][vi] ];
|
||||
float delta = point[plane.Normal] - plane.Dist;
|
||||
|
||||
if (delta > COINCIDENCE_EPSILON) {
|
||||
mask |= POS;
|
||||
}
|
||||
if (delta < -COINCIDENCE_EPSILON) {
|
||||
mask |= NEG;
|
||||
}
|
||||
mask |= ON;
|
||||
}
|
||||
|
||||
/*
|
||||
** Now evaluate the status of all of the verts to determine whether the
|
||||
** triangle is in front, behind, on or overlapping the plane
|
||||
*/
|
||||
|
||||
/*
|
||||
** If all verts were ON the plane, the triangle is ON the plane
|
||||
*/
|
||||
if (mask == ON) {
|
||||
return ON;
|
||||
}
|
||||
|
||||
/*
|
||||
** If all verts were POS or ON, the triangle is POS (IN_FRONT)
|
||||
*/
|
||||
if ((mask & ~(POS | ON)) == 0) {
|
||||
return POS;
|
||||
}
|
||||
|
||||
/*
|
||||
** If all verts were NEG or ON, the triangle is NEG (BEHIND)
|
||||
*/
|
||||
if ((mask & ~(NEG | ON)) == 0) {
|
||||
return NEG;
|
||||
}
|
||||
|
||||
/*
|
||||
** Otherwise, the triangle spans the plane
|
||||
*/
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Split_Polys -- partition the polys with a plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Split_Polys
|
||||
(
|
||||
int polycount,
|
||||
int * polyindices,
|
||||
const SplitChoiceStruct & sc,
|
||||
SplitArraysStruct * arrays
|
||||
)
|
||||
{
|
||||
/*
|
||||
** Note that this routine arrays of polygons. The caller is then responsible for keeping
|
||||
** track of the memory this routine allocates.
|
||||
*/
|
||||
if (sc.FrontCount > 0) {
|
||||
arrays->FrontPolys = W3DNEWARRAY int[sc.FrontCount];
|
||||
}
|
||||
|
||||
if (sc.BackCount > 0) {
|
||||
arrays->BackPolys = W3DNEWARRAY int[sc.BackCount];
|
||||
}
|
||||
|
||||
arrays->FrontCount = 0;
|
||||
arrays->BackCount = 0;
|
||||
|
||||
for (int i=0; i<polycount; i++) {
|
||||
|
||||
switch(Which_Side(sc.Plane,polyindices[i])) {
|
||||
|
||||
case FRONT:
|
||||
case ON:
|
||||
case BOTH:
|
||||
arrays->FrontPolys[arrays->FrontCount++] = polyindices[i];
|
||||
break;
|
||||
|
||||
case BACK:
|
||||
arrays->BackPolys[arrays->BackCount++] = polyindices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** when we are all done, the counts should match.
|
||||
*/
|
||||
WWASSERT(arrays->FrontCount == sc.FrontCount);
|
||||
WWASSERT(arrays->BackCount == sc.BackCount);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Compute_Bounding_Box -- compute bounding boxes for the cull nodes *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Compute_Bounding_Box(CullNodeStruct * node)
|
||||
{
|
||||
/*
|
||||
** compute bounding volumes of the children
|
||||
*/
|
||||
if (node->Front) {
|
||||
Compute_Bounding_Box(node->Front);
|
||||
}
|
||||
|
||||
if (node->Back) {
|
||||
Compute_Bounding_Box(node->Back);
|
||||
}
|
||||
|
||||
/*
|
||||
** compute bounding volume for the polys in this node
|
||||
*/
|
||||
node->Min.Set(100000.0f,100000.0f,100000.0f);
|
||||
node->Max.Set(-100000.0f,-100000.0f,-100000.0f);
|
||||
|
||||
for (int poly_index = 0; poly_index < node->PolyCount; poly_index++) {
|
||||
Update_Min_Max(node->PolyIndices[poly_index],node->Min,node->Max );
|
||||
}
|
||||
|
||||
/*
|
||||
** bound the polys in the front child node
|
||||
*/
|
||||
if (node->Front) {
|
||||
if (node->Front->Min.X < node->Min.X) node->Min.X = node->Front->Min.X;
|
||||
if (node->Front->Max.X > node->Max.X) node->Max.X = node->Front->Max.X;
|
||||
|
||||
if (node->Front->Min.Y < node->Min.Y) node->Min.Y = node->Front->Min.Y;
|
||||
if (node->Front->Max.Y > node->Max.Y) node->Max.Y = node->Front->Max.Y;
|
||||
|
||||
if (node->Front->Min.Z < node->Min.Z) node->Min.Z = node->Front->Min.Z;
|
||||
if (node->Front->Max.Z > node->Max.Z) node->Max.Z = node->Front->Max.Z;
|
||||
}
|
||||
|
||||
/*
|
||||
** bound the polys in the back child node
|
||||
*/
|
||||
if (node->Back) {
|
||||
if (node->Back->Min.X < node->Min.X) node->Min.X = node->Back->Min.X;
|
||||
if (node->Back->Max.X > node->Max.X) node->Max.X = node->Back->Max.X;
|
||||
|
||||
if (node->Back->Min.Y < node->Min.Y) node->Min.Y = node->Back->Min.Y;
|
||||
if (node->Back->Max.Y > node->Max.Y) node->Max.Y = node->Back->Max.Y;
|
||||
|
||||
if (node->Back->Min.Z < node->Min.Z) node->Min.Z = node->Back->Min.Z;
|
||||
if (node->Back->Max.Z > node->Max.Z) node->Max.Z = node->Back->Max.Z;
|
||||
}
|
||||
|
||||
WWASSERT(node->Min.X != 100000.0f);
|
||||
WWASSERT(node->Min.Y != 100000.0f);
|
||||
WWASSERT(node->Min.Z != 100000.0f);
|
||||
WWASSERT(node->Max.X != -100000.0f);
|
||||
WWASSERT(node->Max.Y != -100000.0f);
|
||||
WWASSERT(node->Max.Z != -100000.0f);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Assign_Index -- assign an array index to each node *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
int AABTreeBuilderClass::Assign_Index(CullNodeStruct * node,int index)
|
||||
{
|
||||
/*
|
||||
** This function is used to assign a sequential index to
|
||||
** each node in the tree. The AABTree stores its nodes in
|
||||
** an array so this index is used to determine which slot
|
||||
** in the array to put each node into.
|
||||
*/
|
||||
WWASSERT(node);
|
||||
node->Index = index;
|
||||
index++;
|
||||
|
||||
if (node->Front) {
|
||||
index = Assign_Index(node->Front,index);
|
||||
}
|
||||
|
||||
if (node->Back) {
|
||||
index = Assign_Index(node->Back,index);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Node_Count -- Count the nodes in the tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
int AABTreeBuilderClass::Node_Count(void)
|
||||
{
|
||||
if (Root) {
|
||||
return Node_Count_Recursive(Root,0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Poly_Count -- returns number of polys *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/23/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
int AABTreeBuilderClass::Poly_Count(void)
|
||||
{
|
||||
return PolyCount;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Node_Count_Recursive -- internal implementation of Node_Count *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
int AABTreeBuilderClass::Node_Count_Recursive(CullNodeStruct * node,int curcount)
|
||||
{
|
||||
curcount++;
|
||||
if (node->Front) {
|
||||
curcount = Node_Count_Recursive(node->Front,curcount);
|
||||
}
|
||||
if (node->Back) {
|
||||
curcount = Node_Count_Recursive(node->Back,curcount);
|
||||
}
|
||||
return curcount;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Update_Min -- ensure given vector is < min of the poly *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/22/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Update_Min(int poly_index,Vector3 & min)
|
||||
{
|
||||
for (int vert_index = 0; vert_index < 3; vert_index++) {
|
||||
|
||||
const Vector3i * polyverts = Polys + poly_index;
|
||||
const Vector3 * point = Verts + (*polyverts)[vert_index];
|
||||
|
||||
if (point->X < min.X) min.X = point->X;
|
||||
if (point->Y < min.Y) min.Y = point->Y;
|
||||
if (point->Z < min.Z) min.Z = point->Z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Update_Max -- ensure given vector is > max of poly *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/22/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Update_Max(int poly_index,Vector3 & max)
|
||||
{
|
||||
for (int vert_index = 0; vert_index < 3; vert_index++) {
|
||||
|
||||
const Vector3i * polyverts = Polys + poly_index;
|
||||
const Vector3 * point = Verts + (*polyverts)[vert_index];
|
||||
|
||||
if (point->X > max.X) max.X = point->X;
|
||||
if (point->Y > max.Y) max.Y = point->Y;
|
||||
if (point->Z > max.Z) max.Z = point->Z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Update_Min_Max -- ensure given vector is in min max of poly *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 9/24/98 BMG : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Update_Min_Max(int poly_index, Vector3 & min, Vector3 & max)
|
||||
{
|
||||
for (int vert_index = 0; vert_index < 3; vert_index++) {
|
||||
|
||||
const Vector3i * polyverts = Polys + poly_index;
|
||||
const Vector3 * point = Verts + (*polyverts)[vert_index];
|
||||
|
||||
if (point->X < min.X) min.X = point->X;
|
||||
if (point->Y < min.Y) min.Y = point->Y;
|
||||
if (point->Z < min.Z) min.Z = point->Z;
|
||||
|
||||
if (point->X > max.X) max.X = point->X;
|
||||
if (point->Y > max.Y) max.Y = point->Y;
|
||||
if (point->Z > max.Z) max.Z = point->Z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Export -- Saves this AABTree into a W3D chunk *
|
||||
* *
|
||||
* This function will export the AABTree into a W3D chunk so that it can be loaded by its *
|
||||
* sister class "AABTreeClass" in the WW3D library. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/22/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Export(ChunkSaveClass & csave)
|
||||
{
|
||||
csave.Begin_Chunk(W3D_CHUNK_AABTREE);
|
||||
|
||||
/*
|
||||
** Pack the tree into an array of W3dMeshAABTreeNode's and polygon indices
|
||||
*/
|
||||
W3dMeshAABTreeNode * nodes = W3DNEWARRAY W3dMeshAABTreeNode[Node_Count()];
|
||||
uint32 * poly_indices = W3DNEWARRAY uint32[Poly_Count()];
|
||||
|
||||
int cur_node = 0;
|
||||
int cur_poly = 0;
|
||||
Build_W3D_AABTree_Recursive(Root,nodes,poly_indices,cur_node,cur_poly);
|
||||
|
||||
/*
|
||||
** Write out the header
|
||||
*/
|
||||
csave.Begin_Chunk(W3D_CHUNK_AABTREE_HEADER);
|
||||
W3dMeshAABTreeHeader header;
|
||||
memset(&header,0,sizeof(header));
|
||||
header.NodeCount = Node_Count();
|
||||
header.PolyCount = Poly_Count();
|
||||
csave.Write(&header,sizeof(header));
|
||||
csave.End_Chunk();
|
||||
|
||||
/*
|
||||
** Write out the array of polygon indices
|
||||
*/
|
||||
csave.Begin_Chunk(W3D_CHUNK_AABTREE_POLYINDICES);
|
||||
csave.Write(poly_indices,Poly_Count() * sizeof(uint32));
|
||||
csave.End_Chunk();
|
||||
|
||||
/*
|
||||
** Write out the array of nodes
|
||||
*/
|
||||
csave.Begin_Chunk(W3D_CHUNK_AABTREE_NODES);
|
||||
for (int ni=0; ni<Node_Count(); ni++) {
|
||||
csave.Write(&(nodes[ni]),sizeof(W3dMeshAABTreeNode));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.End_Chunk(); // W3D_CHUNK_AABTREE done
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABTreeBuilderClass::Build_W3D_AABTree_Recursive -- Build array of indices and W3dMeshAABTr *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/22/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABTreeBuilderClass::Build_W3D_AABTree_Recursive
|
||||
(
|
||||
AABTreeBuilderClass::CullNodeStruct * node,
|
||||
W3dMeshAABTreeNode * w3d_nodes,
|
||||
uint32 * poly_indices,
|
||||
int & cur_node,
|
||||
int & cur_poly
|
||||
)
|
||||
{
|
||||
/*
|
||||
** Copy data from the builder's node into our node
|
||||
*/
|
||||
W3dMeshAABTreeNode * newnode = &(w3d_nodes[node->Index]);
|
||||
newnode->Min.X = node->Min.X;
|
||||
newnode->Min.Y = node->Min.Y;
|
||||
newnode->Min.Z = node->Min.Z;
|
||||
newnode->Max.X = node->Max.X;
|
||||
newnode->Max.Y = node->Max.Y;
|
||||
newnode->Max.Z = node->Max.Z;
|
||||
|
||||
/*
|
||||
** If this is a non-leaf node, set up the child indices, otherwise set up the polygon indices
|
||||
*/
|
||||
if (node->Front != NULL) {
|
||||
|
||||
WWASSERT(node->Back != NULL); // if we have one child, we better have both!
|
||||
newnode->FrontOrPoly0 = node->Front->Index;
|
||||
newnode->BackOrPolyCount = node->Back->Index;
|
||||
|
||||
} else {
|
||||
|
||||
newnode->FrontOrPoly0 = cur_poly | 0x80000000;
|
||||
newnode->BackOrPolyCount = node->PolyCount;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the polygon indices for this node into our array
|
||||
*/
|
||||
for (int pcounter = 0; pcounter < node->PolyCount; pcounter++) {
|
||||
poly_indices[cur_poly++] = node->PolyIndices[pcounter];
|
||||
}
|
||||
|
||||
/*
|
||||
** Install the children
|
||||
*/
|
||||
if (node->Front) {
|
||||
Build_W3D_AABTree_Recursive(node->Front,w3d_nodes,poly_indices,cur_node,cur_poly);
|
||||
}
|
||||
if (node->Back) {
|
||||
Build_W3D_AABTree_Recursive(node->Back,w3d_nodes,poly_indices,cur_node,cur_poly);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
209
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtreebuilder.h
Normal file
209
Generals/Code/Libraries/Source/WWVegas/WW3D2/aabtreebuilder.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/aabtreebuilder.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef AABTREEBUILDER_H
|
||||
#define AABTREEBUILDER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "vector3i.h"
|
||||
#include "aaplane.h"
|
||||
#include "bittype.h"
|
||||
#include <float.h>
|
||||
|
||||
class AABTreeClass;
|
||||
class ChunkSaveClass;
|
||||
struct W3dMeshAABTreeNode;
|
||||
|
||||
/*
|
||||
** AABTreeBuilderClass
|
||||
** This class serves simply to build AABTreeClasses. It first builds a tree
|
||||
** which uses an easier to manage data structure (but uses more memory). Then
|
||||
** the tree is converted into the representation used in the AABTreeClass.
|
||||
*/
|
||||
class AABTreeBuilderClass
|
||||
{
|
||||
public:
|
||||
|
||||
AABTreeBuilderClass(void);
|
||||
~AABTreeBuilderClass(void);
|
||||
|
||||
void Build_AABTree(int polycount,Vector3i * polys,int vertcount,Vector3 * verts);
|
||||
void Export(ChunkSaveClass & csave);
|
||||
|
||||
int Node_Count(void);
|
||||
int Poly_Count(void);
|
||||
|
||||
enum
|
||||
{
|
||||
MIN_POLYS_PER_NODE = 4,
|
||||
SMALL_VERTEX = -100000,
|
||||
BIG_VERTEX = 100000
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
** This CullNodeStruct is used in building the AABTree. It is much more
|
||||
** wasteful in terms of memory footprint and number of allocations than the
|
||||
** streamlined version found in the actual AABTreeClass.
|
||||
*/
|
||||
struct CullNodeStruct
|
||||
{
|
||||
CullNodeStruct(void) : Index(0),Min(0,0,0),Max(0,0,0),Front(NULL),Back(NULL),PolyCount(0),PolyIndices(NULL) {}
|
||||
~CullNodeStruct(void)
|
||||
{
|
||||
if (Front) { delete Front; }
|
||||
if (Back) { delete Back; }
|
||||
if (PolyIndices) { delete[] PolyIndices; }
|
||||
}
|
||||
|
||||
int Index;
|
||||
Vector3 Min;
|
||||
Vector3 Max;
|
||||
CullNodeStruct * Front;
|
||||
CullNodeStruct * Back;
|
||||
int PolyCount;
|
||||
int * PolyIndices;
|
||||
};
|
||||
|
||||
/*
|
||||
** SplitChoiceStruct - encapsulates the results of evaluating the suitability of a partition
|
||||
*/
|
||||
struct SplitChoiceStruct
|
||||
{
|
||||
SplitChoiceStruct(void) :
|
||||
Cost(FLT_MAX),
|
||||
FrontCount(0),
|
||||
BackCount(0),
|
||||
BMin(BIG_VERTEX,BIG_VERTEX,BIG_VERTEX),
|
||||
BMax(SMALL_VERTEX,SMALL_VERTEX,SMALL_VERTEX),
|
||||
FMin(BIG_VERTEX,BIG_VERTEX,BIG_VERTEX),
|
||||
FMax(SMALL_VERTEX,SMALL_VERTEX,SMALL_VERTEX),
|
||||
Plane(AAPlaneClass::XNORMAL,0)
|
||||
{
|
||||
}
|
||||
|
||||
float Cost; // try to minimize this!
|
||||
int FrontCount; // number of polys in front of the plane
|
||||
int BackCount; // number of polys behind the plane
|
||||
Vector3 BMin; // min of the bounding box of the "back" child
|
||||
Vector3 BMax; // max of the bounding box of the "back" child
|
||||
Vector3 FMin; // min of the bounding box of the "front" child
|
||||
Vector3 FMax; // max of the bounding box of the "front" child
|
||||
AAPlaneClass Plane; // partitioning plane
|
||||
};
|
||||
|
||||
struct SplitArraysStruct
|
||||
{
|
||||
SplitArraysStruct(void) :
|
||||
FrontCount(0),
|
||||
BackCount(0),
|
||||
FrontPolys(NULL),
|
||||
BackPolys(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
int FrontCount;
|
||||
int BackCount;
|
||||
int * FrontPolys;
|
||||
int * BackPolys;
|
||||
};
|
||||
|
||||
enum OverlapType
|
||||
{
|
||||
POS = 0x01,
|
||||
NEG = 0x02,
|
||||
ON = 0x04,
|
||||
BOTH = 0x08,
|
||||
OUTSIDE = POS,
|
||||
INSIDE = NEG,
|
||||
OVERLAPPED = BOTH,
|
||||
FRONT = POS,
|
||||
BACK = NEG,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Internal functions
|
||||
*/
|
||||
void Reset();
|
||||
void Build_Tree(CullNodeStruct * node,int polycount,int * polyindices);
|
||||
SplitChoiceStruct Select_Splitting_Plane(int polycount,int * polyindices);
|
||||
SplitChoiceStruct Compute_Plane_Score(int polycont,int * polyindices,const AAPlaneClass & plane);
|
||||
void Split_Polys(int polycount,int * polyindices,const SplitChoiceStruct & sc,SplitArraysStruct * arrays);
|
||||
OverlapType Which_Side(const AAPlaneClass & plane,int poly_index);
|
||||
void Compute_Bounding_Box(CullNodeStruct * node);
|
||||
int Assign_Index(CullNodeStruct * node,int index);
|
||||
int Node_Count_Recursive(CullNodeStruct * node,int curcount);
|
||||
void Update_Min(int poly_index,Vector3 & set_min);
|
||||
void Update_Max(int poly_index,Vector3 & set_max);
|
||||
void Update_Min_Max(int poly_index, Vector3 & set_min, Vector3 & set_max);
|
||||
|
||||
void Build_W3D_AABTree_Recursive(CullNodeStruct * node,
|
||||
W3dMeshAABTreeNode * w3dnodes,
|
||||
uint32 * poly_indices,
|
||||
int & cur_node,
|
||||
int & cur_poly);
|
||||
/*
|
||||
** Tree
|
||||
*/
|
||||
CullNodeStruct * Root;
|
||||
int CurPolyIndex;
|
||||
|
||||
/*
|
||||
** Mesh data
|
||||
*/
|
||||
int PolyCount;
|
||||
Vector3i * Polys;
|
||||
int VertCount;
|
||||
Vector3 * Verts;
|
||||
|
||||
friend class AABTreeClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //AABTREEBUILDER_H
|
||||
|
||||
894
Generals/Code/Libraries/Source/WWVegas/WW3D2/agg_def.cpp
Normal file
894
Generals/Code/Libraries/Source/WWVegas/WW3D2/agg_def.cpp
Normal file
@@ -0,0 +1,894 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/agg_def.cpp $*
|
||||
* *
|
||||
* Author:: Patrick Smith
|
||||
* *
|
||||
* $Modtime:: 4/05/01 10:21a $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "agg_def.h"
|
||||
#include "htree.h"
|
||||
#include "w3derr.h"
|
||||
#include "chunkio.h"
|
||||
#include "wwdebug.h"
|
||||
#include "assetmgr.h"
|
||||
#include "matinfo.h"
|
||||
#include "texture.h"
|
||||
#include "wwstring.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Local constants
|
||||
//
|
||||
const char * const EMPTY_STRING = "";
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Global variable initialization
|
||||
//
|
||||
AggregateLoaderClass _AggregateLoader;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregateDefClass
|
||||
//
|
||||
AggregateDefClass::AggregateDefClass (void)
|
||||
: m_pName (NULL)
|
||||
{
|
||||
// Set our member data to default settings
|
||||
::memset (&m_Info, 0, sizeof (m_Info));
|
||||
::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
|
||||
m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregateDefClass
|
||||
//
|
||||
AggregateDefClass::AggregateDefClass (const AggregateDefClass &src)
|
||||
: m_pName (NULL)
|
||||
{
|
||||
// Set our member data to default settings
|
||||
::memset (&m_Info, 0, sizeof (m_Info));
|
||||
::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
|
||||
m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
|
||||
|
||||
// Invoke the assignment operator
|
||||
(*this) = src;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregateDefClass
|
||||
//
|
||||
AggregateDefClass::AggregateDefClass (RenderObjClass &base_model)
|
||||
: m_pName (NULL)
|
||||
{
|
||||
// Set our member data to default settings
|
||||
::memset (&m_Info, 0, sizeof (m_Info));
|
||||
::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
|
||||
m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
|
||||
|
||||
Initialize (base_model);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ~AggregateDefClass
|
||||
//
|
||||
AggregateDefClass::~AggregateDefClass (void)
|
||||
{
|
||||
// Free the name buffer if necessary
|
||||
if (m_pName != NULL) {
|
||||
|
||||
// free() is used because the buffer was allocated with ::_strdup().
|
||||
::free (m_pName);
|
||||
m_pName = NULL;
|
||||
}
|
||||
|
||||
Free_Subobject_List ();
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// operator=
|
||||
//
|
||||
const AggregateDefClass &
|
||||
AggregateDefClass::operator= (const AggregateDefClass &src)
|
||||
{
|
||||
int index;
|
||||
|
||||
// Free the name buffer if necessary
|
||||
if (m_pName != NULL) {
|
||||
::free (m_pName);
|
||||
m_pName = NULL;
|
||||
}
|
||||
|
||||
// Start with a fresh set of data
|
||||
Free_Subobject_List ();
|
||||
|
||||
// Copy the src object's name and info struct
|
||||
Set_Name (src.Get_Name ());
|
||||
::memcpy (&m_Info, &src.m_Info, sizeof (m_Info));
|
||||
::memcpy (&m_MiscInfo, &src.m_MiscInfo, sizeof (m_MiscInfo));
|
||||
m_Version = src.m_Version;
|
||||
|
||||
// Loop through all the entries in the src object's subobj list
|
||||
for (index = 0; index < src.m_SubobjectList.Count (); index ++) {
|
||||
W3dAggregateSubobjectStruct *pinfo = src.m_SubobjectList[index];
|
||||
if (pinfo != NULL) {
|
||||
|
||||
// Copy the src object's info for this subobj
|
||||
W3dAggregateSubobjectStruct *new_info = W3DNEW W3dAggregateSubobjectStruct;
|
||||
::memcpy (new_info, pinfo, sizeof (W3dAggregateSubobjectStruct));
|
||||
|
||||
// Add this subobj to our list
|
||||
m_SubobjectList.Add (new_info);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a reference to ourselves
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Free_Subobject_List
|
||||
//
|
||||
void
|
||||
AggregateDefClass::Free_Subobject_List (void)
|
||||
{
|
||||
// Delete all the stucture pointers contained in the subobject list
|
||||
for (int index = 0; index < m_SubobjectList.Count (); index ++) {
|
||||
W3dAggregateSubobjectStruct *pinfo = m_SubobjectList[index];
|
||||
if (pinfo) {
|
||||
delete pinfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the lists contents
|
||||
m_SubobjectList.Delete_All ();
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Create
|
||||
//
|
||||
RenderObjClass *
|
||||
AggregateDefClass::Create (void)
|
||||
{
|
||||
// Attempt to create an instance of the hierarchy
|
||||
RenderObjClass *pmodel = Create_Render_Object (m_Info.BaseModelName);
|
||||
if (pmodel != NULL) {
|
||||
|
||||
// Perform the aggregation
|
||||
Attach_Subobjects (*pmodel);
|
||||
|
||||
// Let the new object know what its new name and base name are.
|
||||
pmodel->Set_Name (m_pName);
|
||||
pmodel->Set_Base_Model_Name (m_Info.BaseModelName);
|
||||
pmodel->Set_Sub_Objects_Match_LOD ((m_MiscInfo.Flags & W3D_AGGREGATE_FORCE_SUB_OBJ_LOD) == W3D_AGGREGATE_FORCE_SUB_OBJ_LOD);
|
||||
|
||||
} else {
|
||||
WWDEBUG_SAY (("Unable to load aggregate %s.\r\n", m_Info.BaseModelName));
|
||||
}
|
||||
|
||||
// Return a pointer to the new aggregate
|
||||
return pmodel;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Find_Subobject
|
||||
//
|
||||
RenderObjClass *
|
||||
AggregateDefClass::Find_Subobject
|
||||
(
|
||||
RenderObjClass &model,
|
||||
const char mesh_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN],
|
||||
const char bone_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN]
|
||||
)
|
||||
{
|
||||
RenderObjClass *parent_model = &model;
|
||||
parent_model->Add_Ref ();
|
||||
|
||||
// Loop through all the models in our "path" until we've either failed
|
||||
// or found the exact mesh we were looking for...
|
||||
for (int index = 1;
|
||||
(mesh_path[index][0] != 0) && (parent_model != NULL);
|
||||
index ++) {
|
||||
|
||||
// Look one level deeper into the subobject chain...
|
||||
RenderObjClass *sub_obj = NULL;
|
||||
if (bone_path[index][0] == 0) {
|
||||
sub_obj = parent_model->Get_Sub_Object_By_Name (mesh_path[index]);
|
||||
} else {
|
||||
|
||||
int bone_index = parent_model->Get_Bone_Index (bone_path[index]);
|
||||
int subobj_count = parent_model->Get_Num_Sub_Objects_On_Bone (bone_index);
|
||||
|
||||
// Loop through all the subobjects on this bone
|
||||
for (int subobj_index = 0; (subobj_index < subobj_count) && (sub_obj == NULL); subobj_index ++) {
|
||||
|
||||
// Is this the subobject we were looking for?
|
||||
RenderObjClass *ptemp_obj = parent_model->Get_Sub_Object_On_Bone (subobj_index, bone_index);
|
||||
if (::lstrcmpi (ptemp_obj->Get_Name (), mesh_path[index]) == 0) {
|
||||
sub_obj = ptemp_obj;
|
||||
} else {
|
||||
REF_PTR_RELEASE (ptemp_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE (parent_model);
|
||||
|
||||
// The parent for the next iteration is the subobject on this one.
|
||||
parent_model = sub_obj;
|
||||
}
|
||||
|
||||
// Return a pointer to the subobject
|
||||
return parent_model;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Attach_Subobjects
|
||||
//
|
||||
void
|
||||
AggregateDefClass::Attach_Subobjects (RenderObjClass &base_model)
|
||||
{
|
||||
// Now loop through all the subobjects and attach them to the appropriate bone
|
||||
for (int index = 0; index < m_SubobjectList.Count (); index ++) {
|
||||
W3dAggregateSubobjectStruct *psubobj_info = m_SubobjectList[index];
|
||||
if (psubobj_info != NULL) {
|
||||
|
||||
// Now create this subobject and attach it to its bone.
|
||||
RenderObjClass *prender_obj = Create_Render_Object (psubobj_info->SubobjectName);
|
||||
if (prender_obj != NULL) {
|
||||
|
||||
// Attach this object to the requested bone
|
||||
if (base_model.Add_Sub_Object_To_Bone (prender_obj, psubobj_info->BoneName) == false) {
|
||||
WWDEBUG_SAY (("Unable to attach %s to %s.\r\n", psubobj_info->SubobjectName, psubobj_info->BoneName));
|
||||
}
|
||||
|
||||
// Release our hold on this pointer
|
||||
prender_obj->Release_Ref ();
|
||||
} else {
|
||||
WWDEBUG_SAY (("Unable to load aggregate subobject %s.\r\n", psubobj_info->SubobjectName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Create_Render_Object
|
||||
//
|
||||
RenderObjClass *
|
||||
AggregateDefClass::Create_Render_Object (const char *passet_name)
|
||||
{
|
||||
// Assume failure
|
||||
RenderObjClass *prender_obj = NULL;
|
||||
|
||||
// Attempt to get an instance of the render object from the asset manager
|
||||
prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (passet_name);
|
||||
|
||||
// If we couldn't find the render object in the asset manager, then attempt to
|
||||
// load it from file
|
||||
if ((prender_obj == NULL) &&
|
||||
Load_Assets (passet_name)) {
|
||||
|
||||
// It should be in the asset manager now, so attempt to get it again.
|
||||
prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (passet_name);
|
||||
}
|
||||
|
||||
// Return a pointer to the render object
|
||||
return prender_obj;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Load_Assets
|
||||
//
|
||||
bool
|
||||
AggregateDefClass::Load_Assets (const char *passet_name)
|
||||
{
|
||||
// Assume failure
|
||||
bool retval = false;
|
||||
|
||||
// Param OK?
|
||||
if (passet_name != NULL) {
|
||||
|
||||
// Determine what the current working directory is
|
||||
char path[MAX_PATH];
|
||||
::GetCurrentDirectory (sizeof (path), path);
|
||||
|
||||
// Ensure the path is directory delimited
|
||||
if (path[::lstrlen(path)-1] != '\\') {
|
||||
::lstrcat (path, "\\");
|
||||
}
|
||||
|
||||
// Assume the filename is simply the "asset name" + the w3d extension
|
||||
::lstrcat (path, passet_name);
|
||||
::lstrcat (path, ".w3d");
|
||||
|
||||
// If the file exists, then load it into the asset manager.
|
||||
if (::GetFileAttributes (path) != 0xFFFFFFFF) {
|
||||
retval = WW3DAssetManager::Get_Instance()->Load_3D_Assets (path);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the true/false result code
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Initialize
|
||||
//
|
||||
void
|
||||
AggregateDefClass::Initialize (RenderObjClass &base_model)
|
||||
{
|
||||
// Start with fresh lists
|
||||
Free_Subobject_List ();
|
||||
|
||||
// Determine what the render objects original name was.
|
||||
const char *orig_model_name = base_model.Get_Base_Model_Name ();
|
||||
orig_model_name = (orig_model_name == NULL) ? base_model.Get_Name () : orig_model_name;
|
||||
|
||||
// Record information about this base model
|
||||
::lstrcpy (m_Info.BaseModelName, orig_model_name);
|
||||
m_Info.SubobjectCount = 0;
|
||||
m_MiscInfo.OriginalClassID = base_model.Class_ID ();
|
||||
m_MiscInfo.Flags = 0;
|
||||
m_MiscInfo.Flags |= base_model.Is_Sub_Objects_Match_LOD_Enabled () ? W3D_AGGREGATE_FORCE_SUB_OBJ_LOD : 0;
|
||||
|
||||
|
||||
// Pass the aggregate name along
|
||||
Set_Name (base_model.Get_Name ());
|
||||
|
||||
// Create a new instance of the model which we can use
|
||||
// to compare with the supplied model and determine
|
||||
// which 'bones-models' and textures are new.
|
||||
RenderObjClass *pvanilla_model = (RenderObjClass *)Create_Render_Object (orig_model_name);
|
||||
|
||||
// Build lists of changes from the delta between the original model and the provided one
|
||||
Build_Subobject_List (*pvanilla_model, base_model);
|
||||
|
||||
// Release the model if necessary
|
||||
REF_PTR_RELEASE (pvanilla_model);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Build_Subobject_List
|
||||
//
|
||||
void
|
||||
AggregateDefClass::Build_Subobject_List
|
||||
(
|
||||
RenderObjClass &original_model,
|
||||
RenderObjClass &model
|
||||
)
|
||||
{
|
||||
int index;
|
||||
|
||||
// Loop through all the bones in this render obj
|
||||
int bone_count = model.Get_Num_Bones ();
|
||||
for (int bone_index = 0; bone_index < bone_count; bone_index ++) {
|
||||
const char *pbone_name = model.Get_Bone_Name (bone_index);
|
||||
|
||||
// Build a list of nodes that are contained in the vanilla model
|
||||
DynamicVectorClass <RenderObjClass *> orig_node_list;
|
||||
for (index = 0;
|
||||
index < original_model.Get_Num_Sub_Objects_On_Bone (bone_index);
|
||||
index ++) {
|
||||
RenderObjClass *psubobj = original_model.Get_Sub_Object_On_Bone (index, bone_index);
|
||||
if (psubobj != NULL) {
|
||||
orig_node_list.Add (psubobj);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a list of nodes that are contained in this bone
|
||||
DynamicVectorClass <RenderObjClass *> node_list;
|
||||
for (index = 0;
|
||||
index < model.Get_Num_Sub_Objects_On_Bone (bone_index);
|
||||
index ++) {
|
||||
RenderObjClass *psubobj = model.Get_Sub_Object_On_Bone (index, bone_index);
|
||||
if (psubobj != NULL) {
|
||||
node_list.Add (psubobj);
|
||||
}
|
||||
}
|
||||
|
||||
int node_count = node_list.Count ();
|
||||
if (node_count > 0) {
|
||||
|
||||
// Loop through the subobjects and add each one to our internal list
|
||||
W3dAggregateSubobjectStruct subobj_info = { 0 };
|
||||
for (int node_index = 0; node_index < node_count; node_index ++) {
|
||||
RenderObjClass *psubobject = node_list[node_index];
|
||||
WWASSERT (psubobject != NULL);
|
||||
|
||||
// Is this subobject new? (i.e. not in a 'vanilla' instance?)
|
||||
const char *prototype_name = psubobject->Get_Name ();
|
||||
if (psubobject != NULL &&
|
||||
(Is_Object_In_List (prototype_name, orig_node_list) == false)) {
|
||||
|
||||
// Add this subobject to our list
|
||||
::lstrcpy (subobj_info.SubobjectName, prototype_name);
|
||||
::lstrcpy (subobj_info.BoneName, pbone_name);
|
||||
Add_Subobject (subobj_info);
|
||||
m_Info.SubobjectCount ++;
|
||||
|
||||
// Attach this render object to the 'original' model (this is done
|
||||
// so we can do texture compares later)
|
||||
RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance ()->Create_Render_Obj (prototype_name);
|
||||
((RenderObjClass &)original_model).Add_Sub_Object_To_Bone (prender_obj, pbone_name);
|
||||
REF_PTR_RELEASE (prender_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free our hold on the render objs in the original node list
|
||||
for (index = 0; index < orig_node_list.Count (); index ++) {
|
||||
REF_PTR_RELEASE (orig_node_list[index]);
|
||||
}
|
||||
orig_node_list.Delete_All ();
|
||||
|
||||
// Free our hold on the render objs in the node list
|
||||
for (index = 0; index < node_list.Count (); index ++) {
|
||||
REF_PTR_RELEASE (node_list[index]);
|
||||
}
|
||||
node_list.Delete_All ();
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Is_Object_In_List
|
||||
//
|
||||
bool
|
||||
AggregateDefClass::Is_Object_In_List
|
||||
(
|
||||
const char *passet_name,
|
||||
DynamicVectorClass <RenderObjClass *> &node_list
|
||||
)
|
||||
{
|
||||
// Assume failure
|
||||
bool retval = false;
|
||||
|
||||
// Loop through the nodes in the list until we've found the one
|
||||
// were are looking for.
|
||||
for (int node_index = 0; (node_index < node_list.Count ()) && (retval == false); node_index ++) {
|
||||
RenderObjClass *prender_obj = node_list[node_index];
|
||||
|
||||
// Is this the render object we were looking for?
|
||||
if (prender_obj != NULL &&
|
||||
::lstrcmpi (prender_obj->Get_Name (), passet_name) == 0) {
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the true/false result code
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Load
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Load_W3D (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
W3dTextureReplacerHeaderStruct header = { 0 };
|
||||
|
||||
|
||||
while (chunk_load.Open_Chunk()) {
|
||||
|
||||
WW3DErrorType error = WW3D_ERROR_OK;
|
||||
|
||||
switch (chunk_load.Cur_Chunk_ID()) {
|
||||
|
||||
case W3D_CHUNK_AGGREGATE_HEADER:
|
||||
error = Read_Header(chunk_load);
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_AGGREGATE_INFO:
|
||||
error = Read_Info(chunk_load);
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_TEXTURE_REPLACER_INFO:
|
||||
if (chunk_load.Read (&header, sizeof (header)) == sizeof (header)) {
|
||||
if (header.ReplacedTexturesCount > 0) {
|
||||
WWDEBUG_SAY(("Obsolete texture replacement chunk encountered in aggregate: %s\r\n",m_pName));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_AGGREGATE_CLASS_INFO:
|
||||
error = Read_Class_Info(chunk_load);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// Unknown chunk.
|
||||
break;
|
||||
}
|
||||
chunk_load.Close_Chunk();
|
||||
if (error != WW3D_ERROR_OK) return (error);
|
||||
}
|
||||
|
||||
return WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Read_Header
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Read_Header (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
|
||||
|
||||
// Is this the header chunk?
|
||||
W3dAggregateHeaderStruct header = { 0 };
|
||||
if (chunk_load.Read (&header, sizeof (header)) == sizeof (header)) {
|
||||
|
||||
// Copy the name from the header structure
|
||||
m_pName = ::_strdup (header.Name);
|
||||
m_Version = header.Version;
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Read_Info
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Read_Info (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
|
||||
|
||||
// Read the chunk straight into our member structure
|
||||
::memset (&m_Info, 0, sizeof (m_Info));
|
||||
if (chunk_load.Read (&m_Info, sizeof (m_Info)) == sizeof (m_Info)) {
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
|
||||
// Read all the subobjects from the file
|
||||
for (UINT isubobject = 0;
|
||||
(isubobject < m_Info.SubobjectCount) && (ret_val == WW3D_ERROR_OK);
|
||||
isubobject ++) {
|
||||
|
||||
// Read this subobject's definition from the file
|
||||
ret_val = Read_Subobject (chunk_load);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Read_Subobject
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Read_Subobject (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
|
||||
|
||||
// Read the subobject information from the file
|
||||
W3dAggregateSubobjectStruct subobj_info = { 0 };
|
||||
if (chunk_load.Read (&subobj_info, sizeof (subobj_info)) == sizeof (subobj_info)) {
|
||||
|
||||
// Add this subobject to our list
|
||||
Add_Subobject (subobj_info);
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Add_Subobject
|
||||
//
|
||||
void
|
||||
AggregateDefClass::Add_Subobject (const W3dAggregateSubobjectStruct &subobj_info)
|
||||
{
|
||||
// Create a new structure and copy the contents of the src
|
||||
W3dAggregateSubobjectStruct *pnew_entry = W3DNEW W3dAggregateSubobjectStruct;
|
||||
::lstrcpy (pnew_entry->SubobjectName, subobj_info.SubobjectName);
|
||||
::lstrcpy (pnew_entry->BoneName, subobj_info.BoneName);
|
||||
|
||||
// Add this new entry to the list
|
||||
m_SubobjectList.Add (pnew_entry);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Read_Class_Info
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Read_Class_Info (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
|
||||
|
||||
// Read the chunk straight into our header structure
|
||||
::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
|
||||
if (chunk_load.Read (&m_MiscInfo, sizeof (m_MiscInfo)) == sizeof (m_MiscInfo)) {
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Save_W3D (ChunkSaveClass &chunk_save)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
||||
|
||||
// Begin a chunk that identifies an aggregate
|
||||
if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE) == TRUE) {
|
||||
|
||||
// Attempt to save the different sections of the aggregate definition
|
||||
if ((Save_Header (chunk_save) == WW3D_ERROR_OK) &&
|
||||
(Save_Info (chunk_save) == WW3D_ERROR_OK) &&
|
||||
(Save_Class_Info (chunk_save) == WW3D_ERROR_OK)) {
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// Close the aggregate chunk
|
||||
chunk_save.End_Chunk ();
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save_Header
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Save_Header (ChunkSaveClass &chunk_save)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
||||
|
||||
// Begin a chunk that identifies the aggregate
|
||||
if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_HEADER) == TRUE) {
|
||||
|
||||
// Fill the header structure
|
||||
W3dAggregateHeaderStruct header = { 0 };
|
||||
header.Version = W3D_CURRENT_AGGREGATE_VERSION;
|
||||
::lstrcpyn (header.Name, m_pName, sizeof (header.Name));
|
||||
header.Name[sizeof (header.Name) - 1] = 0;
|
||||
|
||||
// Write the header out to the chunk
|
||||
if (chunk_save.Write (&header, sizeof (header)) == sizeof (header)) {
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// End the header chunk
|
||||
chunk_save.End_Chunk ();
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save_Info
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Save_Info (ChunkSaveClass &chunk_save)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
||||
|
||||
// Begin a chunk that identifies the aggregate settings
|
||||
if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_INFO) == TRUE) {
|
||||
|
||||
// Write the settings structure out to the chunk
|
||||
if (chunk_save.Write (&m_Info, sizeof (m_Info)) == sizeof (m_Info)) {
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
|
||||
// Write all the subobjects to the file
|
||||
for (int isubobject = 0;
|
||||
(isubobject < m_SubobjectList.Count ()) && (ret_val == WW3D_ERROR_OK);
|
||||
isubobject ++) {
|
||||
|
||||
// Write this object to the file
|
||||
ret_val = Save_Subobject (chunk_save, m_SubobjectList[isubobject]);
|
||||
}
|
||||
}
|
||||
|
||||
// End the settings chunk
|
||||
chunk_save.End_Chunk ();
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save_Subobject
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Save_Subobject
|
||||
(
|
||||
ChunkSaveClass &chunk_save,
|
||||
W3dAggregateSubobjectStruct *psubobject
|
||||
)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
||||
|
||||
// Write the subobj structure out to the chunk
|
||||
if (chunk_save.Write (psubobject, sizeof (W3dAggregateSubobjectStruct)) == sizeof (W3dAggregateSubobjectStruct)) {
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save_Class_Info
|
||||
//
|
||||
WW3DErrorType
|
||||
AggregateDefClass::Save_Class_Info (ChunkSaveClass &chunk_save)
|
||||
{
|
||||
// Assume error
|
||||
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
||||
|
||||
// Begin a chunk that identifies the texture replacer header
|
||||
if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_CLASS_INFO) == TRUE) {
|
||||
|
||||
// Write the class information structure out to the chunk
|
||||
if (chunk_save.Write (&m_MiscInfo, sizeof (m_MiscInfo)) == sizeof (m_MiscInfo)) {
|
||||
|
||||
// Success!
|
||||
ret_val = WW3D_ERROR_OK;
|
||||
}
|
||||
|
||||
// End the class info chunk
|
||||
chunk_save.End_Chunk ();
|
||||
}
|
||||
|
||||
// Return the WW3D_ERROR_TYPE return code
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Load
|
||||
//
|
||||
PrototypeClass *
|
||||
AggregateLoaderClass::Load_W3D (ChunkLoadClass &chunk_load)
|
||||
{
|
||||
// Assume failure
|
||||
AggregatePrototypeClass *pprototype = NULL;
|
||||
|
||||
// Create a definition object
|
||||
AggregateDefClass *pdefinition = W3DNEW AggregateDefClass;
|
||||
if (pdefinition != NULL) {
|
||||
|
||||
// Ask the definition object to load the aggregate data
|
||||
if (pdefinition->Load_W3D (chunk_load) != WW3D_ERROR_OK) {
|
||||
|
||||
// Error! Free the definition
|
||||
delete pdefinition;
|
||||
pdefinition = NULL;
|
||||
} else {
|
||||
|
||||
// Success! Create a prototype from the definition
|
||||
pprototype = W3DNEW AggregatePrototypeClass (pdefinition);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a pointer to the prototype
|
||||
return pprototype;
|
||||
}
|
||||
|
||||
259
Generals/Code/Libraries/Source/WWVegas/WW3D2/agg_def.h
Normal file
259
Generals/Code/Libraries/Source/WWVegas/WW3D2/agg_def.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/agg_def.h $*
|
||||
* *
|
||||
* Author:: Patrick Smith *
|
||||
* *
|
||||
* $Modtime:: 4/05/01 9:52a $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef AGGREGATE_DEF_H
|
||||
#define AGGREGATE_DEF_H
|
||||
|
||||
#include "proto.h"
|
||||
#include "rendobj.h"
|
||||
#include "w3d_file.h"
|
||||
#include "w3derr.h"
|
||||
#include "vector.h"
|
||||
#include "bittype.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _UNIX
|
||||
#include "osdep.h"
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class IndirectTextureClass;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Macros
|
||||
//
|
||||
#ifndef SAFE_FREE
|
||||
#define SAFE_FREE(pointer) \
|
||||
{ \
|
||||
if (pointer) { \
|
||||
::free (pointer); \
|
||||
pointer = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif //SAFE_FREE
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregateDefClass
|
||||
//
|
||||
// Description of an aggregate object. Used by the asset manager
|
||||
// to construct aggregates. An 'aggregate' is simply a 'shell' that
|
||||
// contains references to a hierarchy model and subobjects to attach to its bones.
|
||||
//
|
||||
class AggregateDefClass
|
||||
{
|
||||
public:
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public constructors/destructors
|
||||
//
|
||||
AggregateDefClass (void);
|
||||
AggregateDefClass (RenderObjClass &base_model);
|
||||
AggregateDefClass (const AggregateDefClass &src);
|
||||
virtual ~AggregateDefClass (void);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public operators
|
||||
//
|
||||
const AggregateDefClass &operator= (const AggregateDefClass &src);
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
virtual WW3DErrorType Load_W3D (ChunkLoadClass &chunk_load);
|
||||
virtual WW3DErrorType Save_W3D (ChunkSaveClass &chunk_save);
|
||||
const char * Get_Name (void) const { return m_pName; }
|
||||
void Set_Name (const char *pname) { SAFE_FREE (m_pName); m_pName = ::_strdup (pname); }
|
||||
RenderObjClass * Create (void);
|
||||
AggregateDefClass * Clone (void) const { return W3DNEW AggregateDefClass (*this); }
|
||||
|
||||
//
|
||||
// Public accessors
|
||||
//
|
||||
ULONG Class_ID (void) const { return m_MiscInfo.OriginalClassID; }
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
void Initialize (RenderObjClass &base_model);
|
||||
|
||||
protected:
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Protected data types
|
||||
//
|
||||
typedef struct _TEXTURE_INFO
|
||||
{
|
||||
W3dTextureReplacerStruct names;
|
||||
IndirectTextureClass * pnew_texture;
|
||||
|
||||
bool operator == (_TEXTURE_INFO &src) { return false; }
|
||||
bool operator != (_TEXTURE_INFO &src) { return true; }
|
||||
} TEXTURE_INFO;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Protected methods
|
||||
//
|
||||
|
||||
//
|
||||
// Loading methods
|
||||
//
|
||||
virtual WW3DErrorType Read_Header (ChunkLoadClass &chunk_load);
|
||||
virtual WW3DErrorType Read_Info (ChunkLoadClass &chunk_load);
|
||||
virtual WW3DErrorType Read_Subobject (ChunkLoadClass &chunk_load);
|
||||
virtual WW3DErrorType Read_Class_Info (ChunkLoadClass &chunk_load);
|
||||
|
||||
//
|
||||
// Saving methods
|
||||
//
|
||||
virtual WW3DErrorType Save_Header (ChunkSaveClass &chunk_save);
|
||||
virtual WW3DErrorType Save_Info (ChunkSaveClass &chunk_save);
|
||||
virtual WW3DErrorType Save_Subobject (ChunkSaveClass &chunk_save, W3dAggregateSubobjectStruct *psubobject);
|
||||
virtual WW3DErrorType Save_Class_Info (ChunkSaveClass &chunk_save);
|
||||
|
||||
//
|
||||
// Creation methods
|
||||
//
|
||||
virtual void Attach_Subobjects (RenderObjClass &base_model);
|
||||
|
||||
//
|
||||
// Search methods
|
||||
//
|
||||
virtual RenderObjClass * Find_Subobject (RenderObjClass &model, const char mesh_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN], const char bone_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN]);
|
||||
|
||||
//
|
||||
// Misc. methods
|
||||
//
|
||||
virtual void Free_Subobject_List (void);
|
||||
virtual void Add_Subobject (const W3dAggregateSubobjectStruct &subobj_info);
|
||||
virtual bool Load_Assets (const char *asset_name);
|
||||
virtual RenderObjClass *Create_Render_Object (const char *passet_name);
|
||||
virtual bool Is_Object_In_List (const char *passet_name, DynamicVectorClass <RenderObjClass *> &node_list);
|
||||
|
||||
virtual void Build_Subobject_List (RenderObjClass &original_model, RenderObjClass &model);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Private member data
|
||||
//
|
||||
DWORD m_Version;
|
||||
DynamicVectorClass<W3dAggregateSubobjectStruct *> m_SubobjectList;
|
||||
W3dAggregateInfoStruct m_Info;
|
||||
W3dAggregateMiscInfo m_MiscInfo;
|
||||
char * m_pName;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregatePrototypeClass
|
||||
//
|
||||
class AggregatePrototypeClass : public W3DMPO, public PrototypeClass
|
||||
{
|
||||
W3DMPO_GLUE(AggregatePrototypeClass)
|
||||
public:
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public constructors/destructors
|
||||
//
|
||||
AggregatePrototypeClass (AggregateDefClass *pdef) { m_pDefinition = pdef; }
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
virtual const char * Get_Name(void) const { return m_pDefinition->Get_Name (); }
|
||||
virtual int Get_Class_ID(void) const { return m_pDefinition->Class_ID (); }
|
||||
virtual RenderObjClass * Create (void) { return m_pDefinition->Create (); }
|
||||
virtual void DeleteSelf() { delete this; }
|
||||
virtual AggregateDefClass * Get_Definition (void) const { return m_pDefinition; }
|
||||
virtual void Set_Definition (AggregateDefClass *pdef) { m_pDefinition = pdef; }
|
||||
|
||||
protected:
|
||||
virtual ~AggregatePrototypeClass (void) { delete m_pDefinition; }
|
||||
|
||||
private:
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Private member data
|
||||
//
|
||||
AggregateDefClass * m_pDefinition;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AggregateLoaderClass
|
||||
//
|
||||
class AggregateLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Chunk_Type (void) { return W3D_CHUNK_AGGREGATE; }
|
||||
virtual PrototypeClass * Load_W3D (ChunkLoadClass &chunk_load);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Global variables
|
||||
//
|
||||
extern AggregateLoaderClass _AggregateLoader;
|
||||
|
||||
|
||||
#endif //__AGGREGATE_DEF_H
|
||||
1048
Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp
Normal file
1048
Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp
Normal file
File diff suppressed because it is too large
Load Diff
326
Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h
Normal file
326
Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/animobj.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 6/26/01 7:01p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Animatable3DObjClass::Base_Update -- animation update function for the base pose *
|
||||
* Animatable3DObjClass::Anim_Update -- Update function for a single animation *
|
||||
* Animatable3DObjClass::Blend_Update -- update function for a blend of two animations *
|
||||
* Animatable3DObjClass::Combo_Update -- Animation update for a combination of anims *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef ANIMOBJ_H
|
||||
#define ANIMOBJ_H
|
||||
|
||||
#include "always.h"
|
||||
#include "composite.h"
|
||||
#include "htree.h"
|
||||
#include "hanim.h"
|
||||
|
||||
class SkinClass;
|
||||
class RenderInfoClass;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** Animatable3DObjClass
|
||||
** This class performs some of the work necessary to implement hierarchical animation.
|
||||
** It implements much of the bone and animation interface of RenderObjClass.
|
||||
*/
|
||||
class Animatable3DObjClass : public CompositeRenderObjClass
|
||||
{
|
||||
public:
|
||||
|
||||
Animatable3DObjClass(const char * htree_name);
|
||||
Animatable3DObjClass(const Animatable3DObjClass & src);
|
||||
Animatable3DObjClass & operator = (const Animatable3DObjClass &);
|
||||
virtual ~Animatable3DObjClass(void);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Rendering
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - "Scene Graph"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Hierarchical Animation
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Animation(void);
|
||||
virtual void Set_Animation( HAnimClass * motion,
|
||||
float frame, int anim_mode = ANIM_MODE_MANUAL);
|
||||
virtual void Set_Animation( HAnimClass * motion0,
|
||||
float frame0,
|
||||
HAnimClass * motion1,
|
||||
float frame1,
|
||||
float percentage);
|
||||
virtual void Set_Animation( HAnimComboClass * anim_combo);
|
||||
|
||||
virtual void Set_Animation_Frame_Rate_Multiplier(float multiplier); // 020607 srj -- added
|
||||
|
||||
virtual HAnimClass * Peek_Animation_And_Info(float& frame, int& numFrames, int& mode, float& mult); // 020710 srj -- added
|
||||
|
||||
virtual HAnimClass * Peek_Animation( void );
|
||||
virtual bool Is_Animation_Complete( void ) const;
|
||||
virtual int Get_Num_Bones(void);
|
||||
virtual const char * Get_Bone_Name(int bone_index);
|
||||
virtual int Get_Bone_Index(const char * bonename);
|
||||
virtual const Matrix3D & Get_Bone_Transform(const char * bonename);
|
||||
virtual const Matrix3D & Get_Bone_Transform(int boneindex);
|
||||
virtual void Capture_Bone(int boneindex);
|
||||
virtual void Release_Bone(int boneindex);
|
||||
virtual bool Is_Bone_Captured(int boneindex) const;
|
||||
virtual void Control_Bone(int bindex,const Matrix3D & objtm,bool world_space_translation = false);
|
||||
virtual const HTreeClass * Get_HTree(void) const { return HTree; }
|
||||
|
||||
//
|
||||
// Simple bone evaluation methods for when the caller doesn't want
|
||||
// to update the heirarchy, but needs to know the transform of
|
||||
// a bone at a given frame.
|
||||
//
|
||||
virtual bool Simple_Evaluate_Bone(int boneindex, Matrix3D *tm) const;
|
||||
virtual bool Simple_Evaluate_Bone(int boneindex, float frame, Matrix3D *tm) const;
|
||||
|
||||
// (gth) TESTING DYNAMICALLY SWAPPING SKELETONS!
|
||||
virtual void Set_HTree(HTreeClass * htree);
|
||||
|
||||
///Generals change so we can set sub-object transforms directly without having them revert to base pose
|
||||
///when marked dirty. DON'T USE THIS UNLESS YOU HAVE A GOOD REASON! -MW
|
||||
void Friend_Set_Hierarchy_Valid(bool onoff) const { IsTreeValid = onoff; }
|
||||
|
||||
protected:
|
||||
|
||||
// internally used to compute the current frame if the object is in ANIM_MODE_MANUAL
|
||||
float Compute_Current_Frame(float *newDirection=NULL) const;
|
||||
|
||||
// Update the sub-object transforms according to the current anim state and root transform.
|
||||
virtual void Update_Sub_Object_Transforms(void);
|
||||
|
||||
// Update the transforms using the base pose only
|
||||
void Base_Update(const Matrix3D & root);
|
||||
|
||||
// Update the transforms using a single frame of motion data
|
||||
void Anim_Update( const Matrix3D & root,
|
||||
HAnimClass * motion,
|
||||
float frame);
|
||||
|
||||
// Update the transforms blending two frames of motion data
|
||||
void Blend_Update( const Matrix3D & root,
|
||||
HAnimClass * motion0,
|
||||
float frame0,
|
||||
HAnimClass * motion1,
|
||||
float frame1,
|
||||
float percentage);
|
||||
|
||||
// Update the transforms with an AnimationCombination
|
||||
void Combo_Update( const Matrix3D & root,
|
||||
HAnimComboClass *anim);
|
||||
|
||||
// flag to kep track of whether the hierarchy tree transforms are currently valid
|
||||
bool Is_Hierarchy_Valid(void) const { return IsTreeValid; }
|
||||
void Set_Hierarchy_Valid(bool onoff) const { IsTreeValid = onoff; }
|
||||
|
||||
// Progress anims for single anim (loop and once)
|
||||
void Single_Anim_Progress( void );
|
||||
|
||||
// Release any anims
|
||||
void Release( void );
|
||||
|
||||
protected:
|
||||
|
||||
// Is the hierarchy tree currently valid
|
||||
mutable bool IsTreeValid;
|
||||
|
||||
// Hierarchy Tree
|
||||
HTreeClass * HTree;
|
||||
|
||||
// Animation state for the next frame. When we add more flexible motion
|
||||
// compositing, add a new state and its associated data to the union below
|
||||
enum {
|
||||
NONE = 0,
|
||||
BASE_POSE,
|
||||
SINGLE_ANIM,
|
||||
DOUBLE_ANIM,
|
||||
MULTIPLE_ANIM,
|
||||
};
|
||||
|
||||
int CurMotionMode;
|
||||
|
||||
union {
|
||||
// CurMotionMode == SINGLE_ANIM
|
||||
struct {
|
||||
HAnimClass * Motion;
|
||||
float Frame;
|
||||
int AnimMode;
|
||||
mutable int LastSyncTime;
|
||||
float animDirection;
|
||||
float frameRateMultiplier; // 020607 srj -- added
|
||||
} ModeAnim;
|
||||
|
||||
// CurMotionMode == DOUBLE_ANIM
|
||||
struct {
|
||||
|
||||
HAnimClass * Motion0;
|
||||
HAnimClass * Motion1;
|
||||
float Frame0;
|
||||
float Frame1;
|
||||
float Percentage;
|
||||
} ModeInterp;
|
||||
|
||||
// CurMotionMode == MULTIPLE_ANIM
|
||||
struct {
|
||||
HAnimComboClass * AnimCombo;
|
||||
} ModeCombo;
|
||||
|
||||
};
|
||||
|
||||
friend class SkinClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Animatable3DObjClass::Base_Update -- animation update function for the base pose *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/2/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void Animatable3DObjClass::Base_Update(const Matrix3D & root)
|
||||
{
|
||||
/*
|
||||
** This method simply puts the meshes in the base pose's configuration
|
||||
*/
|
||||
if (HTree) {
|
||||
HTree->Base_Update(root);
|
||||
}
|
||||
Set_Hierarchy_Valid(true);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Animatable3DObjClass::Anim_Update -- Update function for a single animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/2/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float frame)
|
||||
{
|
||||
/*
|
||||
** Apply motion to the base pose
|
||||
*/
|
||||
if ((motion) && (HTree)) {
|
||||
if (ModeAnim.Motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM)
|
||||
HTree->Anim_Update(Transform,(HRawAnimClass*)ModeAnim.Motion,ModeAnim.Frame);
|
||||
else
|
||||
HTree->Anim_Update(root,motion,frame);
|
||||
}
|
||||
Set_Hierarchy_Valid(true);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Animatable3DObjClass::Blend_Update -- update function for a blend of two animations *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/2/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void Animatable3DObjClass::Blend_Update
|
||||
(
|
||||
const Matrix3D & root,
|
||||
HAnimClass * motion0,
|
||||
float frame0,
|
||||
HAnimClass * motion1,
|
||||
float frame1,
|
||||
float percentage
|
||||
)
|
||||
{
|
||||
/*
|
||||
** Apply motion to the base pose
|
||||
*/
|
||||
if (HTree) {
|
||||
HTree->Blend_Update(root,motion0,frame0,motion1,frame1,percentage);
|
||||
}
|
||||
Set_Hierarchy_Valid(true);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Animatable3DObjClass::Combo_Update -- Animation update for a combination of anims *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/2/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void Animatable3DObjClass::Combo_Update( const Matrix3D & root, HAnimComboClass *anim )
|
||||
{
|
||||
if (HTree) {
|
||||
HTree->Combo_Update(root, anim);
|
||||
}
|
||||
Set_Hierarchy_Valid(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //ANIMOBJ_H
|
||||
1727
Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp
Normal file
1727
Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
441
Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h
Normal file
441
Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/assetmgr.h 15 7/24/01 6:28p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/assetmgr.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 7/17/01 5:52p $*
|
||||
* *
|
||||
* $Revision:: 15 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef ASSETMGR_H
|
||||
#define ASSETMGR_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector.h"
|
||||
#include "htreemgr.h"
|
||||
#include "hanimmgr.h"
|
||||
#include "slist.h"
|
||||
#include "texture.h"
|
||||
#include "hashtemplate.h"
|
||||
#include "simplevec.h"
|
||||
|
||||
class HAnimClass;
|
||||
class HTreeClass;
|
||||
class ChunkLoadClass;
|
||||
|
||||
class FileClass;
|
||||
class FileFactoryClass;
|
||||
class PrototypeLoaderClass;
|
||||
class Font3DDataClass;
|
||||
class Font3DInstanceClass;
|
||||
class FontCharsClass;
|
||||
class RenderObjClass;
|
||||
class HModelClass;
|
||||
class PrototypeClass;
|
||||
class HTreeManagerClass;
|
||||
class HAnimManagerClass;
|
||||
class HAnimIterator;
|
||||
class TextureIterator;
|
||||
class TextureFileCache;
|
||||
class StreamingTextureClass;
|
||||
struct StreamingTextureConfig;
|
||||
class TextureClass;
|
||||
class MetalMapManagerClass;
|
||||
|
||||
/*
|
||||
** AssetIterator
|
||||
** This object can iterate through the 3D assets which
|
||||
** currently exist in the Asset Manager. It tells you the names
|
||||
** of the assets which the manager can create for you.
|
||||
*/
|
||||
class AssetIterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
virtual ~AssetIterator(void) { };
|
||||
virtual void First(void) { Index = 0; }
|
||||
virtual void Next(void) { Index ++; }
|
||||
virtual bool Is_Done(void) = 0;
|
||||
virtual const char * Current_Item_Name(void) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
AssetIterator(void) { Index = 0; }
|
||||
int Index;
|
||||
};
|
||||
|
||||
/*
|
||||
** RenderObjIterator
|
||||
** The render obj iterator simply adds a method for determining
|
||||
** the class id of a render object prototype in the system.
|
||||
*/
|
||||
class RenderObjIterator : public AssetIterator
|
||||
{
|
||||
public:
|
||||
virtual int Current_Item_Class_ID(void) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
|
||||
WW3DAssetManager
|
||||
|
||||
This object is the manager of all of the 3D data. Load your meshes, animations,
|
||||
etc etc using the Load_3D_Assets function.
|
||||
|
||||
WARNING: hierarchy trees should be loaded before the meshes and animations
|
||||
which attach to them.
|
||||
|
||||
-------------------------------------------------------------------------------------
|
||||
Dec 11, 1997, Asset Manager Brainstorming:
|
||||
|
||||
- WW3DAssetManager will be diferentiated from other game data asset managers
|
||||
(sounds, strings, etc) because they behave differently and serve different
|
||||
purposes
|
||||
|
||||
- WW3D creates "clones" from the blueprints it has of render objects whereas
|
||||
Our commando data asset manager will provide the data (file images) for the
|
||||
blueprints. Maybe the CommandoDataManager could deal in MemoryFileClasses.
|
||||
Or void * and then the ww3d manager could convert to MemoryFiles...
|
||||
|
||||
- Future caching: In the case that we want to implement a caching system,
|
||||
assets must be "released" when not in use.
|
||||
|
||||
- CommandoW3d asset manager asks the game data asset manager for assets by name.
|
||||
Game data manager must have a "directory" structure which maps each named
|
||||
asset to data on disk. It then returns an image of the file once it has
|
||||
been loaded into ram.
|
||||
|
||||
- Assets must be individual files, named with the asset name used in code/scripting
|
||||
We will write a tool which chops w3d files up so that all of the individual assets
|
||||
are brought out into their own file and named with the actual w3d name.
|
||||
|
||||
- Data Asset Manager will load the file into ram, give it to us and forget about it
|
||||
W3d will release_ref it or delete it and the file image will go away.
|
||||
|
||||
- Each time the 3d asset manager is requested for an asset, it will look through
|
||||
the render objects it has, if the asset isn't found, it will ask for the asset
|
||||
from the generic data asset manager. When creating the actual render object,
|
||||
the 3d asset manager may find that it needs another asset (such as a hierarchy tree).
|
||||
It will then recurse, and ask for that asset.
|
||||
|
||||
- Copy Mode will go away. It will be internally set based on whether the mesh
|
||||
contains vertex animation. All other render objects will simply "Clone".
|
||||
|
||||
- Commando will derive a Cmdo3DAssetManager which knows about the special chunks
|
||||
required for the terrains.
|
||||
|
||||
-------------------------------------------------------------------------------------
|
||||
July 28, 1998
|
||||
|
||||
- Exposed the prototype system and added prototype loaders (PrototypeClass and
|
||||
PrototypeLoaderClass in proto.h). This now allows the user to install his own
|
||||
loaders for new render object types.
|
||||
|
||||
- Simplified the interface by removing the special purpose creation functions,
|
||||
leaving only the Create_Render_Obj function.
|
||||
|
||||
- In certain cases some users need to know what kind of render object was created
|
||||
so we added a Class_ID mechanism to RenderObjClass.
|
||||
|
||||
- Class_ID for render objects is not enough. Need the asset iterator to be able
|
||||
to tell you the Class_ID of each asset in the asset manager. This also means that
|
||||
the prototype class needs to be able to tell you the class ID. Actually this
|
||||
code only seems to be used by tools such as SView but is needed anyway...
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class WW3DAssetManager
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
** Constructor and destructor
|
||||
*/
|
||||
WW3DAssetManager(void);
|
||||
virtual ~WW3DAssetManager(void);
|
||||
|
||||
/*
|
||||
** Access to the single instance of a WW3DAssetManager. The user
|
||||
** can subclass their own asset manager class but should only
|
||||
** create one instance. (a violation of this will be caught with
|
||||
** a run-time assertion)
|
||||
**
|
||||
** The "official" way to get at the global asset manager is to
|
||||
** use a line of code like this:
|
||||
** WW3DAssetManager::Get_Instance();
|
||||
*/
|
||||
static WW3DAssetManager * Get_Instance(void) { return TheInstance; }
|
||||
static void Delete_This(void) { if (TheInstance) delete TheInstance; }
|
||||
|
||||
/*
|
||||
** Load data from any type of w3d file
|
||||
*/
|
||||
virtual bool Load_3D_Assets( const char * filename);
|
||||
virtual bool Load_3D_Assets(FileClass & assetfile);
|
||||
|
||||
/*
|
||||
** Get rid of all of the currently loaded assets
|
||||
*/
|
||||
virtual void Free_Assets(void);
|
||||
|
||||
/*
|
||||
** Release any assets that only the asset manager has a reference to.
|
||||
*/
|
||||
virtual void Release_Unused_Assets(void);
|
||||
|
||||
/*
|
||||
** Release assets not in the given exclusion list.
|
||||
*/
|
||||
virtual void Free_Assets_With_Exclusion_List(const DynamicVectorClass<StringClass> & model_exclusion_list);
|
||||
virtual void Create_Asset_List(DynamicVectorClass<StringClass> & model_exclusion_list);
|
||||
|
||||
/*
|
||||
** create me an instance of one of the prototype render objects
|
||||
*/
|
||||
virtual RenderObjClass * Create_Render_Obj(const char * name);
|
||||
|
||||
/*
|
||||
** query if there is a render object with the specified name
|
||||
*/
|
||||
virtual bool Render_Obj_Exists(const char * name);
|
||||
|
||||
/*
|
||||
** Iterate through all render objects or through the
|
||||
** sub-categories of render objects. NOTE! the user is responsible
|
||||
** for releasing the iterator when finished with it!
|
||||
*/
|
||||
virtual RenderObjIterator * Create_Render_Obj_Iterator(void);
|
||||
virtual void Release_Render_Obj_Iterator(RenderObjIterator *);
|
||||
|
||||
/*
|
||||
** Access to HAnims, Used by Animatable3DObj's
|
||||
** TODO: make HAnims accessible from the HMODELS (or Animatable3DObj...)
|
||||
*/
|
||||
virtual AssetIterator * Create_HAnim_Iterator(void);
|
||||
virtual HAnimClass * Get_HAnim(const char * name);
|
||||
virtual bool Add_Anim (HAnimClass *new_anim) { return HAnimManager.Add_Anim (new_anim); }
|
||||
|
||||
/*
|
||||
** Access to textures
|
||||
*/
|
||||
// virtual AssetIterator * Create_Texture_Iterator(void);
|
||||
|
||||
HashTemplateClass<StringClass,TextureClass*>& Texture_Hash() { return TextureHash; }
|
||||
|
||||
static void Log_Texture_Statistics();
|
||||
|
||||
virtual TextureClass * Get_Texture(
|
||||
const char * filename,
|
||||
TextureClass::MipCountType mip_level_count=TextureClass::MIP_LEVELS_ALL,
|
||||
WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN,
|
||||
bool allow_compression=true);
|
||||
TextureClass* Get_Bumpmap_Based_On_Texture(TextureClass* texture);
|
||||
|
||||
virtual void Release_All_Textures(void);
|
||||
virtual void Release_Unused_Textures(void);
|
||||
virtual void Release_Texture(TextureClass *);
|
||||
virtual void Load_Procedural_Textures();
|
||||
virtual MetalMapManagerClass* Peek_Metal_Map_Manager() { return MetalManager; }
|
||||
|
||||
/*
|
||||
** Access to Font3DInstances. (These are not saved, we just use the
|
||||
** asset manager as a convienient way to create them.)
|
||||
*/
|
||||
virtual Font3DInstanceClass * Get_Font3DInstance( const char * name);
|
||||
|
||||
/*
|
||||
** Access to FontChars. Used by Render2DSentenceClass
|
||||
*/
|
||||
virtual FontCharsClass * Get_FontChars( const char * name, int point_size, bool is_bold = false );
|
||||
|
||||
/*
|
||||
** Access to HTrees, Used by Animatable3DObj's
|
||||
*/
|
||||
virtual AssetIterator * Create_HTree_Iterator(void);
|
||||
virtual HTreeClass * Get_HTree(const char * name);
|
||||
|
||||
/*
|
||||
** Prototype Loaders, The user can register new loaders here. Note that
|
||||
** a the pointer to your loader will be stored inside the asset manager.
|
||||
** For this reason, your loader should be a static or global object.
|
||||
*/
|
||||
virtual void Register_Prototype_Loader(PrototypeLoaderClass * loader);
|
||||
|
||||
/*
|
||||
** The Add_Prototype is public so that we can add prototypes for procedurally
|
||||
** generated objects to the asset manager.
|
||||
*/
|
||||
void Add_Prototype(PrototypeClass * newproto);
|
||||
void Remove_Prototype(PrototypeClass *proto);
|
||||
void Remove_Prototype(const char *name);
|
||||
PrototypeClass * Find_Prototype(const char * name);
|
||||
|
||||
/*
|
||||
** Load on Demand
|
||||
*/
|
||||
bool Get_WW3D_Load_On_Demand( void ) { return WW3D_Load_On_Demand; }
|
||||
void Set_WW3D_Load_On_Demand( bool on_off ) { WW3D_Load_On_Demand = on_off; }
|
||||
|
||||
/*
|
||||
** Add fog to objects on load
|
||||
*/
|
||||
bool Get_Activate_Fog_On_Load( void ) { return Activate_Fog_On_Load; }
|
||||
void Set_Activate_Fog_On_Load( bool on_off ) { Activate_Fog_On_Load = on_off; }
|
||||
|
||||
// Log texture statistics
|
||||
void Log_All_Textures();
|
||||
protected:
|
||||
|
||||
/*
|
||||
** Access to Font3DData. (These are privately managed/accessed)
|
||||
*/
|
||||
virtual AssetIterator * Create_Font3DData_Iterator(void);
|
||||
virtual void Add_Font3DData(Font3DDataClass * font);
|
||||
virtual void Remove_Font3DData(Font3DDataClass * font);
|
||||
virtual Font3DDataClass * Get_Font3DData(const char * name);
|
||||
virtual void Release_All_Font3DDatas( void);
|
||||
virtual void Release_Unused_Font3DDatas( void);
|
||||
|
||||
virtual void Release_All_FontChars( void );
|
||||
|
||||
void Free(void);
|
||||
|
||||
PrototypeLoaderClass * Find_Prototype_Loader(int chunk_id);
|
||||
bool Load_Prototype(ChunkLoadClass & cload);
|
||||
|
||||
/*
|
||||
** Compile time control over the dynamic arrays:
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PROTOLOADERS_VECTOR_SIZE = 32,
|
||||
PROTOLOADERS_GROWTH_RATE = 16,
|
||||
|
||||
PROTOTYPES_VECTOR_SIZE = 256,
|
||||
PROTOTYPES_GROWTH_RATE = 32,
|
||||
};
|
||||
|
||||
/*
|
||||
** Prototype Loaders
|
||||
** These objects are responsible for importing certain W3D chunk types and turning
|
||||
** them into prototypes.
|
||||
*/
|
||||
DynamicVectorClass < PrototypeLoaderClass * > PrototypeLoaders;
|
||||
|
||||
/*
|
||||
** Prototypes
|
||||
** These objects are abstract factories for named render objects. Prototypes is
|
||||
** a dynamic array of pointers to the currently loaded prototypes.
|
||||
*/
|
||||
DynamicVectorClass < PrototypeClass * > Prototypes;
|
||||
|
||||
/*
|
||||
** Prototype Hash Table
|
||||
** This structure is simply used to speed up the name lookup for prototypes
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PROTOTYPE_HASH_TABLE_SIZE = 4096,
|
||||
PROTOTYPE_HASH_BITS = 12,
|
||||
PROTOTYPE_HASH_MASK = 0x00000FFF
|
||||
};
|
||||
|
||||
PrototypeClass * * PrototypeHashTable;
|
||||
|
||||
/*
|
||||
** managers of HTrees, HAnims, Textures....
|
||||
*/
|
||||
HTreeManagerClass HTreeManager;
|
||||
HAnimManagerClass HAnimManager;
|
||||
|
||||
/*
|
||||
** When enabled, this handles all the caching for the texture class.
|
||||
** If NULL then textures are not being cached.
|
||||
*/
|
||||
TextureFileCache * TextureCache;
|
||||
|
||||
/*
|
||||
** list of Font3DDatas
|
||||
*/
|
||||
SList<Font3DDataClass> Font3DDatas;
|
||||
|
||||
/*
|
||||
** list of FontChars
|
||||
*/
|
||||
SimpleDynVecClass<FontCharsClass*> FontCharsList;
|
||||
|
||||
/*
|
||||
** Should .W3D be loaded if not in memory
|
||||
*/
|
||||
bool WW3D_Load_On_Demand;
|
||||
|
||||
/*
|
||||
** Should we activate fog on objects while loading them
|
||||
*/
|
||||
bool Activate_Fog_On_Load;
|
||||
|
||||
// Metal Map Manager
|
||||
MetalMapManagerClass * MetalManager;
|
||||
|
||||
/*
|
||||
** Texture hash table for quick texture lookups
|
||||
*/
|
||||
HashTemplateClass<StringClass, TextureClass *> TextureHash;
|
||||
|
||||
/*
|
||||
** The 3d asset manager is a singleton, there should be only
|
||||
** one and it is accessible through Get_Instance()
|
||||
*/
|
||||
static WW3DAssetManager * TheInstance;
|
||||
|
||||
/*
|
||||
** the iterator classes are friends
|
||||
*/
|
||||
friend class RObjIterator;
|
||||
friend class HAnimIterator;
|
||||
friend class HTreeIterator;
|
||||
friend class Font3DDataIterator;
|
||||
friend class TextureIterator;
|
||||
|
||||
// Font3DInstance need access to the Font3DData
|
||||
friend class Font3DInstanceClass;
|
||||
};
|
||||
|
||||
#endif
|
||||
382
Generals/Code/Libraries/Source/WWVegas/WW3D2/bitmaphandler.cpp
Normal file
382
Generals/Code/Libraries/Source/WWVegas/WW3D2/bitmaphandler.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#include "bitmaphandler.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
void Bitmap_Assert(bool condition)
|
||||
{
|
||||
WWASSERT(condition);
|
||||
}
|
||||
|
||||
void BitmapHandlerClass::Create_Mipmap_B8G8R8A8(
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_surface_pitch,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_surface_pitch,
|
||||
unsigned width,
|
||||
unsigned height)
|
||||
{
|
||||
unsigned src_pitch=src_surface_pitch/4;
|
||||
for (unsigned y=0;y<height;y+=2) {
|
||||
unsigned* dest=(unsigned*)dest_surface;
|
||||
dest_surface+=dest_surface_pitch;
|
||||
unsigned* src=(unsigned*)src_surface;
|
||||
src_surface+=src_surface_pitch;
|
||||
for (unsigned x=0;x<width;x+=2) {
|
||||
unsigned bgra3=src[src_pitch];
|
||||
unsigned bgra1=*src++;
|
||||
unsigned bgra4=src[src_pitch];
|
||||
unsigned bgra2=*src++;
|
||||
*dest++=Combine_A8R8G8B8(bgra1,bgra2,bgra3,bgra4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapHandlerClass::Copy_Image_Generate_Mipmap(
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_pitch,
|
||||
WW3DFormat dest_format,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_pitch,
|
||||
WW3DFormat src_format,
|
||||
unsigned char* mip_surface,
|
||||
unsigned mip_pitch)
|
||||
{
|
||||
// Optimized loop if source and destination are 32 bit
|
||||
if (src_format==dest_format && src_format==WW3D_FORMAT_A8R8G8B8) {
|
||||
dest_pitch/=4;
|
||||
src_pitch/=4;
|
||||
mip_pitch/=4;
|
||||
for (unsigned y=0;y<height/2;++y) {
|
||||
unsigned* dest_ptr=(unsigned*)dest_surface;
|
||||
dest_ptr+=2*y*dest_pitch;
|
||||
unsigned* src_ptr=(unsigned*)src_surface;
|
||||
src_ptr+=y*2*src_pitch;
|
||||
unsigned* mip_ptr=(unsigned*)mip_surface;
|
||||
mip_ptr+=y*mip_pitch;
|
||||
unsigned b8g8r8a8_00;
|
||||
unsigned b8g8r8a8_01;
|
||||
unsigned b8g8r8a8_10;
|
||||
unsigned b8g8r8a8_11;
|
||||
for (unsigned x=0;x<width/2;x++) {
|
||||
b8g8r8a8_10=src_ptr[src_pitch];
|
||||
dest_ptr[dest_pitch]=b8g8r8a8_10;
|
||||
b8g8r8a8_00=*src_ptr++;
|
||||
*dest_ptr++=b8g8r8a8_00;
|
||||
|
||||
b8g8r8a8_11=src_ptr[src_pitch];
|
||||
dest_ptr[dest_pitch]=b8g8r8a8_11;
|
||||
b8g8r8a8_01=*src_ptr++;
|
||||
*dest_ptr++=b8g8r8a8_01;
|
||||
|
||||
*mip_ptr++=Combine_A8R8G8B8(b8g8r8a8_00,b8g8r8a8_01,b8g8r8a8_10,b8g8r8a8_11);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
WWASSERT(src_format!=WW3D_FORMAT_P8); // This function doesn't support paletted formats
|
||||
unsigned src_bpp=Get_Bytes_Per_Pixel(src_format);
|
||||
unsigned dest_bpp=Get_Bytes_Per_Pixel(dest_format);
|
||||
|
||||
for (unsigned y=0;y<height/2;++y) {
|
||||
unsigned char* dest_ptr=dest_surface+2*y*dest_pitch;
|
||||
unsigned char* src_ptr=src_surface+y*2*src_pitch;
|
||||
unsigned char* mip_ptr=mip_surface+y*mip_pitch;
|
||||
unsigned b8g8r8a8_00;
|
||||
unsigned b8g8r8a8_01;
|
||||
unsigned b8g8r8a8_10;
|
||||
unsigned b8g8r8a8_11;
|
||||
for (unsigned x=0;x<width/2;x++,dest_ptr+=dest_bpp*2,src_ptr+=src_bpp*2,mip_ptr+=dest_bpp) {
|
||||
Read_B8G8R8A8(b8g8r8a8_00,src_ptr,src_format,NULL,0);
|
||||
Write_B8G8R8A8(dest_ptr,dest_format,b8g8r8a8_00);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_01,src_ptr+src_bpp,src_format,NULL,0);
|
||||
Write_B8G8R8A8(dest_ptr+dest_bpp,dest_format,b8g8r8a8_01);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_10,src_ptr+src_pitch,src_format,NULL,0);
|
||||
Write_B8G8R8A8(dest_ptr+dest_pitch,dest_format,b8g8r8a8_10);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_11,src_ptr+src_bpp+src_pitch,src_format,NULL,0);
|
||||
Write_B8G8R8A8(dest_ptr+dest_bpp+dest_pitch,dest_format,b8g8r8a8_11);
|
||||
|
||||
unsigned b8g8r8a8=Combine_A8R8G8B8(b8g8r8a8_00,b8g8r8a8_01,b8g8r8a8_10,b8g8r8a8_11);
|
||||
|
||||
Write_B8G8R8A8(mip_ptr,dest_format,b8g8r8a8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Copy image from source surface to destination surface with stretch and color
|
||||
// space conversion if needed. If 'generate_mip_level' is set, process image
|
||||
// in 2x2 blocks and generate mipmap on top of the original source image while
|
||||
// copying.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void BitmapHandlerClass::Copy_Image(
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_surface_width,
|
||||
unsigned dest_surface_height,
|
||||
unsigned dest_surface_pitch,
|
||||
WW3DFormat dest_surface_format,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_surface_width,
|
||||
unsigned src_surface_height,
|
||||
unsigned src_surface_pitch,
|
||||
WW3DFormat src_surface_format,
|
||||
const unsigned char* src_palette,
|
||||
unsigned src_palette_bpp,
|
||||
bool generate_mip_level)
|
||||
{
|
||||
WWASSERT(dest_surface_width);
|
||||
WWASSERT(dest_surface_height);
|
||||
|
||||
// Bumpmap?
|
||||
if (dest_surface_format==WW3D_FORMAT_U8V8 ||
|
||||
dest_surface_format==WW3D_FORMAT_L6V5U5 ||
|
||||
dest_surface_format==WW3D_FORMAT_X8L8V8U8) {
|
||||
|
||||
unsigned src_bpp=Get_Bytes_Per_Pixel(src_surface_format);
|
||||
|
||||
for( unsigned y=0; y<dest_surface_height; y++ ) {
|
||||
unsigned char* dest_ptr=dest_surface;
|
||||
dest_ptr+=y*dest_surface_pitch;
|
||||
unsigned char* src_ptr_mid=src_surface;
|
||||
src_ptr_mid+=y*src_surface_pitch;
|
||||
unsigned char* src_ptr_next_line = ( src_ptr_mid + src_surface_pitch );
|
||||
unsigned char* src_ptr_prev_line = ( src_ptr_mid - src_surface_pitch );
|
||||
|
||||
if( y == src_surface_height-1 ) // Don't go past the last line
|
||||
src_ptr_next_line = src_ptr_mid;
|
||||
if( y == 0 ) // Don't go before first line
|
||||
src_ptr_prev_line = src_ptr_mid;
|
||||
|
||||
for( unsigned x=0; x<dest_surface_width; x++ ) {
|
||||
unsigned pixel00;
|
||||
unsigned pixel01;
|
||||
unsigned pixelM1;
|
||||
unsigned pixel10;
|
||||
unsigned pixel1M;
|
||||
|
||||
Read_B8G8R8A8(pixel00,src_ptr_mid,src_surface_format,NULL,0);
|
||||
Read_B8G8R8A8(pixel01,src_ptr_mid+src_bpp,src_surface_format,NULL,0);
|
||||
Read_B8G8R8A8(pixelM1,src_ptr_mid-src_bpp,src_surface_format,NULL,0);
|
||||
Read_B8G8R8A8(pixel10,src_ptr_prev_line,src_surface_format,NULL,0);
|
||||
Read_B8G8R8A8(pixel1M,src_ptr_next_line,src_surface_format,NULL,0);
|
||||
|
||||
// Convert to luminance
|
||||
unsigned char bv00;
|
||||
unsigned char bv01;
|
||||
unsigned char bvM1;
|
||||
unsigned char bv10;
|
||||
unsigned char bv1M;
|
||||
Write_B8G8R8A8(&bv00,WW3D_FORMAT_L8,pixel00);
|
||||
Write_B8G8R8A8(&bv01,WW3D_FORMAT_L8,pixel01);
|
||||
Write_B8G8R8A8(&bvM1,WW3D_FORMAT_L8,pixelM1);
|
||||
Write_B8G8R8A8(&bv10,WW3D_FORMAT_L8,pixel10);
|
||||
Write_B8G8R8A8(&bv1M,WW3D_FORMAT_L8,pixel1M);
|
||||
int v00=bv00,v01=bv01,vM1=bvM1,v10=bv10,v1M=bv1M;
|
||||
|
||||
int iDu = (vM1-v01); // The delta-u bump value
|
||||
int iDv = (v1M-v10); // The delta-v bump value
|
||||
|
||||
if( (v00 < vM1) && (v00 < v01) ) { // If we are at valley
|
||||
iDu = vM1-v00; // Choose greater of 1st order diffs
|
||||
if( iDu < v00-v01 )
|
||||
iDu = v00-v01;
|
||||
}
|
||||
|
||||
// The luminance bump value (land masses are less shiny)
|
||||
unsigned short uL = ( v00>1 ) ? 63 : 127;
|
||||
|
||||
switch(dest_surface_format) {
|
||||
case WW3D_FORMAT_U8V8:
|
||||
*dest_ptr++ = (unsigned char)iDu;
|
||||
*dest_ptr++ = (unsigned char)iDv;
|
||||
break;
|
||||
|
||||
case WW3D_FORMAT_L6V5U5:
|
||||
*(unsigned short*)dest_ptr = (unsigned short)( ( (iDu>>3) & 0x1f ) << 0 );
|
||||
*(unsigned short*)dest_ptr |= (unsigned short)( ( (iDv>>3) & 0x1f ) << 5 );
|
||||
*(unsigned short*)dest_ptr |= (unsigned short)( ( ( uL>>2) & 0x3f ) << 10 );
|
||||
dest_ptr += 2;
|
||||
break;
|
||||
|
||||
case WW3D_FORMAT_X8L8V8U8:
|
||||
*dest_ptr++ = (unsigned char)iDu;
|
||||
*dest_ptr++ = (unsigned char)iDv;
|
||||
*dest_ptr++ = (unsigned char)uL;
|
||||
*dest_ptr++ = (unsigned char)0L;
|
||||
break;
|
||||
|
||||
default:
|
||||
WWASSERT(0); // Unknown bumpmap format
|
||||
break;
|
||||
}
|
||||
|
||||
// Move one pixel to the left (src is 32-bpp)
|
||||
src_ptr_mid+=src_bpp;
|
||||
src_ptr_prev_line+=src_bpp;
|
||||
src_ptr_next_line+=src_bpp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (src_surface_format==dest_surface_format && (src_surface_format==WW3D_FORMAT_A8R8G8B8 || src_surface_format==WW3D_FORMAT_X8R8G8B8)) {
|
||||
// One-to-one copy or scaling?
|
||||
dest_surface_pitch/=4;
|
||||
src_surface_pitch/=4;
|
||||
if (dest_surface_width==src_surface_width && dest_surface_height==src_surface_height) {
|
||||
// Generate the next mip level while copying the current surface?
|
||||
if (generate_mip_level) {
|
||||
if (dest_surface_width==1) {
|
||||
*(unsigned*)dest_surface=*(unsigned*)src_surface;
|
||||
}
|
||||
else {
|
||||
for (unsigned y=0;y<dest_surface_height/2;++y) {
|
||||
unsigned* dest_ptr=(unsigned*)dest_surface;
|
||||
dest_ptr+=2*y*dest_surface_pitch;
|
||||
unsigned* src_ptr=(unsigned*)src_surface;
|
||||
unsigned* mip_ptr=src_ptr;
|
||||
src_ptr+=y*2*src_surface_pitch;
|
||||
mip_ptr+=y*src_surface_pitch;
|
||||
unsigned b8g8r8a8_00;
|
||||
unsigned b8g8r8a8_01;
|
||||
unsigned b8g8r8a8_10;
|
||||
unsigned b8g8r8a8_11;
|
||||
for (unsigned x=0;x<dest_surface_width/2;x++) {
|
||||
b8g8r8a8_10=src_ptr[src_surface_pitch];
|
||||
dest_ptr[dest_surface_pitch]=b8g8r8a8_10;
|
||||
b8g8r8a8_00=*src_ptr++;
|
||||
*dest_ptr++=b8g8r8a8_00;
|
||||
|
||||
b8g8r8a8_11=src_ptr[src_surface_pitch];
|
||||
dest_ptr[dest_surface_pitch]=b8g8r8a8_11;
|
||||
b8g8r8a8_01=*src_ptr++;
|
||||
*dest_ptr++=b8g8r8a8_01;
|
||||
|
||||
*mip_ptr++=Combine_A8R8G8B8(b8g8r8a8_00,b8g8r8a8_01,b8g8r8a8_10,b8g8r8a8_11);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned y=0;y<dest_surface_height;++y) {
|
||||
unsigned* dest_ptr=(unsigned*)dest_surface;
|
||||
dest_ptr+=y*dest_surface_pitch;
|
||||
const unsigned* src_ptr=(unsigned*)src_surface;
|
||||
src_ptr+=y*src_surface_pitch;
|
||||
for (unsigned x=0;x<dest_surface_width;++x) {
|
||||
*dest_ptr++=*src_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// For now do only point-sampling
|
||||
for (unsigned y=0;y<dest_surface_height;++y) {
|
||||
unsigned* dest_ptr=(unsigned*)dest_surface;
|
||||
dest_ptr+=y*dest_surface_pitch;
|
||||
unsigned src_y=y*src_surface_height/dest_surface_height;
|
||||
const unsigned* src_ptr=(unsigned*)src_surface;
|
||||
src_ptr+=src_y*src_surface_pitch;
|
||||
for (unsigned x=0;x<dest_surface_width;++x) {
|
||||
unsigned src_x=x*src_surface_width/dest_surface_width;
|
||||
*dest_ptr++=src_ptr[src_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned dest_bpp=Get_Bytes_Per_Pixel(dest_surface_format);
|
||||
unsigned src_bpp=Get_Bytes_Per_Pixel(src_surface_format);
|
||||
|
||||
// One-to-one copy or scaling?
|
||||
if (dest_surface_width==src_surface_width && dest_surface_height==src_surface_height) {
|
||||
// Generate the next mip level while copying the current surface?
|
||||
if (generate_mip_level) {
|
||||
WWASSERT(src_surface_format!=WW3D_FORMAT_P8); // Paletted textures can't be mipmapped
|
||||
if (dest_surface_width==1) {
|
||||
unsigned char* dest_ptr=dest_surface;
|
||||
unsigned char* src_ptr=src_surface;
|
||||
unsigned b8g8r8a8;
|
||||
Read_B8G8R8A8(b8g8r8a8,src_ptr,src_surface_format,src_palette,src_palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr,dest_surface_format,b8g8r8a8);
|
||||
}
|
||||
else {
|
||||
for (unsigned y=0;y<dest_surface_height/2;++y) {
|
||||
unsigned char* dest_ptr=dest_surface+2*y*dest_surface_pitch;
|
||||
unsigned char* src_ptr=src_surface+y*2*src_surface_pitch;
|
||||
unsigned char* mip_ptr=src_surface+y*src_surface_pitch;
|
||||
unsigned b8g8r8a8_00;
|
||||
unsigned b8g8r8a8_01;
|
||||
unsigned b8g8r8a8_10;
|
||||
unsigned b8g8r8a8_11;
|
||||
for (unsigned x=0;x<dest_surface_width/2;x++,dest_ptr+=dest_bpp*2,src_ptr+=src_bpp*2,mip_ptr+=src_bpp) {
|
||||
Read_B8G8R8A8(b8g8r8a8_00,src_ptr,src_surface_format,src_palette,src_palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr,dest_surface_format,b8g8r8a8_00);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_01,src_ptr+src_bpp,src_surface_format,src_palette,src_palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr+dest_bpp,dest_surface_format,b8g8r8a8_01);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_10,src_ptr+src_surface_pitch,src_surface_format,src_palette,src_palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr+dest_surface_pitch,dest_surface_format,b8g8r8a8_10);
|
||||
|
||||
Read_B8G8R8A8(b8g8r8a8_11,src_ptr+src_bpp+src_surface_pitch,src_surface_format,src_palette,src_palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr+dest_bpp+dest_surface_pitch,dest_surface_format,b8g8r8a8_11);
|
||||
|
||||
unsigned b8g8r8a8=Combine_A8R8G8B8(b8g8r8a8_00,b8g8r8a8_01,b8g8r8a8_10,b8g8r8a8_11);
|
||||
|
||||
Write_B8G8R8A8(mip_ptr,src_surface_format,b8g8r8a8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned y=0;y<dest_surface_height;++y) {
|
||||
unsigned char* dest_ptr=dest_surface+y*dest_surface_pitch;
|
||||
const unsigned char* src_ptr=src_surface+y*src_surface_pitch;
|
||||
for (unsigned x=0;x<dest_surface_width;++x,dest_ptr+=dest_bpp,src_ptr+=src_bpp) {
|
||||
Copy_Pixel(dest_ptr,dest_surface_format,src_ptr,src_surface_format,src_palette,src_palette_bpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// For now do only point-sampling
|
||||
for (unsigned y=0;y<dest_surface_height;++y) {
|
||||
unsigned char* dest_ptr=dest_surface+y*dest_surface_pitch;
|
||||
unsigned src_y=y*src_surface_height/dest_surface_height;
|
||||
const unsigned char* src_ptr=src_surface+src_y*src_surface_pitch;
|
||||
for (unsigned x=0;x<dest_surface_width;++x,dest_ptr+=dest_bpp) {
|
||||
unsigned src_x=x*src_surface_width/dest_surface_width;
|
||||
src_x*=src_bpp;
|
||||
Copy_Pixel(dest_ptr,dest_surface_format,src_ptr+src_x,src_surface_format,src_palette,src_palette_bpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
390
Generals/Code/Libraries/Source/WWVegas/WW3D2/bitmaphandler.h
Normal file
390
Generals/Code/Libraries/Source/WWVegas/WW3D2/bitmaphandler.h
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BITMAPHANDLER_H
|
||||
#define BITMAPHANDLER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "ww3dformat.h"
|
||||
|
||||
void Bitmap_Assert(bool condition);
|
||||
|
||||
class BitmapHandlerClass
|
||||
{
|
||||
public:
|
||||
WWINLINE static void Read_B8G8R8A8(
|
||||
unsigned char* argb,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp);
|
||||
|
||||
WWINLINE static void Read_B8G8R8A8(
|
||||
unsigned& argb,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp);
|
||||
|
||||
WWINLINE static void Write_B8G8R8A8(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned char* argb);
|
||||
|
||||
WWINLINE static void Write_B8G8R8A8(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned& argb);
|
||||
|
||||
WWINLINE static void Copy_Pixel(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp);
|
||||
|
||||
WWINLINE static unsigned Combine_A8R8G8B8(
|
||||
unsigned bgra1,
|
||||
unsigned bgra2,
|
||||
unsigned bgra3,
|
||||
unsigned bgra4);
|
||||
|
||||
static void Create_Mipmap_B8G8R8A8(
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_surface_pitch,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_surface_pitch,
|
||||
unsigned width,
|
||||
unsigned height);
|
||||
|
||||
static void Copy_Image_Generate_Mipmap(
|
||||
unsigned width,
|
||||
unsigned height,
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_pitch,
|
||||
WW3DFormat dest_format,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_pitch,
|
||||
WW3DFormat src_format,
|
||||
unsigned char* mip_surface,
|
||||
unsigned mip_pitch);
|
||||
|
||||
static void Copy_Image(
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_surface_width,
|
||||
unsigned dest_surface_height,
|
||||
unsigned dest_surface_pitch,
|
||||
WW3DFormat dest_surface_format,
|
||||
unsigned char* src_surface,
|
||||
unsigned src_surface_width,
|
||||
unsigned src_surface_height,
|
||||
unsigned src_surface_pitch,
|
||||
WW3DFormat src_surface_format,
|
||||
const unsigned char* src_palette,
|
||||
unsigned src_palette_bpp,
|
||||
bool generate_mip_level);
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Read color value of given type in BGRA (D3D) byte order. Regarless
|
||||
// of the source format the color value is converted to 32-bit format.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE void BitmapHandlerClass::Read_B8G8R8A8(
|
||||
unsigned char* argb,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp)
|
||||
{
|
||||
switch (src_format) {
|
||||
case WW3D_FORMAT_A8R8G8B8:
|
||||
case WW3D_FORMAT_X8R8G8B8:
|
||||
*(unsigned*)argb=*(unsigned*)src_ptr;
|
||||
break;
|
||||
case WW3D_FORMAT_R8G8B8:
|
||||
*argb++=src_ptr[0];
|
||||
*argb++=src_ptr[1];
|
||||
*argb++=src_ptr[2];
|
||||
*argb++=0;
|
||||
break;
|
||||
case WW3D_FORMAT_A4R4G4B4:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=*(unsigned short*)src_ptr;
|
||||
*argb++=((tmp&0x000f)<<4);
|
||||
*argb++=((tmp&0x00f0));
|
||||
*argb++=((tmp&0x0f00)>>4);
|
||||
*argb++=((tmp&0xf000)>>8);
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_A1R5G5B5:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=*(unsigned short*)src_ptr;
|
||||
argb[3]=tmp&0x8000 ? 0xff : 0x0;
|
||||
argb[2]=(tmp>>7)&0xf8;
|
||||
argb[1]=(tmp>>2)&0xf8;
|
||||
argb[0]=(tmp<<3)&0xf8;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_R5G6B5:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=*(unsigned short*)src_ptr;
|
||||
argb[3]=0;
|
||||
argb[2]=(tmp>>8)&0xf8;
|
||||
argb[1]=(tmp>>3)&0xfc;
|
||||
argb[0]=(tmp<<3)&0xf8;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_L8:
|
||||
{
|
||||
unsigned char tmp=*src_ptr++;
|
||||
*argb++=tmp;
|
||||
*argb++=tmp;
|
||||
*argb++=tmp;
|
||||
*argb++=0x0;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_A8:
|
||||
{
|
||||
*argb++=0;
|
||||
*argb++=0;
|
||||
*argb++=0;
|
||||
*argb++=*src_ptr++;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_P8:
|
||||
{
|
||||
unsigned char index=*src_ptr++;
|
||||
switch (palette_bpp) {
|
||||
case 4:
|
||||
*argb++=palette[palette_bpp*index+3];
|
||||
*argb++=palette[palette_bpp*index+2];
|
||||
*argb++=palette[palette_bpp*index+1];
|
||||
*argb++=palette[palette_bpp*index+0];
|
||||
break;
|
||||
case 3:
|
||||
*argb++=palette[palette_bpp*index+2];
|
||||
*argb++=palette[palette_bpp*index+1];
|
||||
*argb++=palette[palette_bpp*index+0];
|
||||
*argb++=0x0;
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
default:
|
||||
Bitmap_Assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_DXT1:
|
||||
case WW3D_FORMAT_DXT2:
|
||||
case WW3D_FORMAT_DXT3:
|
||||
case WW3D_FORMAT_DXT4:
|
||||
case WW3D_FORMAT_DXT5:
|
||||
default: Bitmap_Assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE void BitmapHandlerClass::Read_B8G8R8A8(
|
||||
unsigned& argb,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp)
|
||||
{
|
||||
Read_B8G8R8A8((unsigned char*)&argb,src_ptr,src_format,palette,palette_bpp);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Write color value of given type in BGRA (D3D) byte order. The source value
|
||||
// is always 32 bit and it is converted to defined destination format.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE void BitmapHandlerClass::Write_B8G8R8A8(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned char* argb)
|
||||
{
|
||||
switch (dest_format) {
|
||||
case WW3D_FORMAT_A8R8G8B8:
|
||||
case WW3D_FORMAT_X8R8G8B8:
|
||||
*(unsigned*)dest_ptr=*(unsigned*)argb;
|
||||
break;
|
||||
case WW3D_FORMAT_R8G8B8:
|
||||
*dest_ptr++=*argb++;
|
||||
*dest_ptr++=*argb++;
|
||||
*dest_ptr++=*argb++;
|
||||
break;
|
||||
case WW3D_FORMAT_A4R4G4B4:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=((argb[3])&0xf0)<<8;
|
||||
tmp|=((argb[2])&0xf0)<<4;
|
||||
tmp|=((argb[1])&0xf0);
|
||||
tmp|=((argb[0])&0xf0)>>4;
|
||||
*(unsigned short*)dest_ptr=tmp;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_A1R5G5B5:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=argb[3] ? 0x8000 : 0x0;
|
||||
tmp|=((argb[2])&0xf8)<<7;
|
||||
tmp|=((argb[1])&0xf8)<<2;
|
||||
tmp|=((argb[0])&0xf8)>>3;
|
||||
*(unsigned short*)dest_ptr=tmp;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_R5G6B5:
|
||||
{
|
||||
unsigned short tmp;
|
||||
tmp=((argb[2])&0xf8)<<8;
|
||||
tmp|=((argb[1])&0xfc)<<3;
|
||||
tmp|=((argb[0])&0xf8)>>3;
|
||||
*(unsigned short*)dest_ptr=tmp;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_L8:
|
||||
{
|
||||
// CIE Req. 709: Y709 = 0.2125R + 0.7154G + 0.0721B
|
||||
unsigned char tmp = (unsigned char) ( (
|
||||
((unsigned int)argb[0] * (unsigned int)0x1275) + // 0.0721B
|
||||
((unsigned int)argb[1] * (unsigned int)0xB725) + // 0.7154G (rounded up so FF, FF, FF becomes FF)
|
||||
((unsigned int)argb[2] * (unsigned int)0x3666) // 0.2125R
|
||||
) >> 16);
|
||||
*dest_ptr++=tmp;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_A8:
|
||||
{
|
||||
*dest_ptr++=*argb++;
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_DXT1:
|
||||
case WW3D_FORMAT_DXT2:
|
||||
case WW3D_FORMAT_DXT3:
|
||||
case WW3D_FORMAT_DXT4:
|
||||
case WW3D_FORMAT_DXT5:
|
||||
case WW3D_FORMAT_P8: // Paletted destination not supported
|
||||
default: Bitmap_Assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE void BitmapHandlerClass::Write_B8G8R8A8(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned& argb)
|
||||
{
|
||||
Write_B8G8R8A8(dest_ptr,dest_format,(unsigned char*)&argb);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Copy pixel. Perform color space conversion if needed. The source and
|
||||
// destination are always D3D-style BGRA.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE void BitmapHandlerClass::Copy_Pixel(
|
||||
unsigned char* dest_ptr,
|
||||
WW3DFormat dest_format,
|
||||
const unsigned char* src_ptr,
|
||||
WW3DFormat src_format,
|
||||
const unsigned char* palette,
|
||||
unsigned palette_bpp)
|
||||
{
|
||||
// Color space conversion needed?
|
||||
|
||||
if (dest_format==src_format) {
|
||||
switch (dest_format) {
|
||||
case WW3D_FORMAT_A8R8G8B8:
|
||||
case WW3D_FORMAT_X8R8G8B8:
|
||||
*(unsigned*)dest_ptr=*(unsigned*)src_ptr;
|
||||
break;
|
||||
case WW3D_FORMAT_R8G8B8:
|
||||
*dest_ptr++=src_ptr[0];
|
||||
*dest_ptr++=src_ptr[1];
|
||||
*dest_ptr++=src_ptr[2];
|
||||
break;
|
||||
case WW3D_FORMAT_A4R4G4B4:
|
||||
{
|
||||
unsigned short tmp=*(unsigned short*)src_ptr;
|
||||
*(unsigned short*)dest_ptr=((tmp&0x000f)<<12)|((tmp&0x00f0)<<4)|((tmp&0x0f00)>>4)|((tmp&0xf000)>>12);
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_A1R5G5B5:
|
||||
{
|
||||
unsigned short tmp=*(unsigned short*)src_ptr;
|
||||
*(unsigned short*)dest_ptr=((tmp&0x001f)<<11)|((tmp&0x03e0)<<1)|((tmp&0x7c00)>>9)|((tmp&0x8000)>>15);
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_R5G6B5:
|
||||
{
|
||||
unsigned short tmp=*(unsigned short*)src_ptr;
|
||||
*(unsigned short*)dest_ptr=((tmp&0x001f)<<11)|(tmp&0x07e0)|((tmp&0xf800)>>11);
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_L8:
|
||||
case WW3D_FORMAT_A8: *dest_ptr++=*src_ptr++;
|
||||
break;
|
||||
case WW3D_FORMAT_P8: // Paletted destinations not supported
|
||||
default: Bitmap_Assert(0); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned b8g8r8a8;
|
||||
Read_B8G8R8A8(b8g8r8a8,src_ptr,src_format,palette,palette_bpp);
|
||||
Write_B8G8R8A8(dest_ptr,dest_format,b8g8r8a8);
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE unsigned BitmapHandlerClass::Combine_A8R8G8B8(
|
||||
unsigned bgra1,
|
||||
unsigned bgra2,
|
||||
unsigned bgra3,
|
||||
unsigned bgra4)
|
||||
{
|
||||
bgra1&=0xfcfcfcfc;
|
||||
bgra2&=0xfcfcfcfc;
|
||||
bgra3&=0xfcfcfcfc;
|
||||
bgra4&=0xfcfcfcfc;
|
||||
bgra1>>=2;
|
||||
bgra2>>=2;
|
||||
bgra3>>=2;
|
||||
bgra4>>=2;
|
||||
bgra1+=bgra2;
|
||||
bgra3+=bgra4;
|
||||
bgra1+=bgra3;
|
||||
return bgra1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
281
Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp
Normal file
281
Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Commando/G *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/bmp2d.cpp $*
|
||||
* *
|
||||
* $Author:: Naty_h $*
|
||||
* *
|
||||
* $Modtime:: 4/13/01 1:37p $*
|
||||
* *
|
||||
* $Revision:: 10 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "bmp2d.h"
|
||||
#include "pot.h"
|
||||
#include "ww3d.h"
|
||||
#include "texture.h"
|
||||
#include "surfaceclass.h"
|
||||
|
||||
Bitmap2DObjClass::Bitmap2DObjClass
|
||||
(
|
||||
const char *filename,
|
||||
float screen_x,
|
||||
float screen_y,
|
||||
bool center,
|
||||
bool additive,
|
||||
bool colorizable,
|
||||
int usable_width,
|
||||
int usable_height,
|
||||
bool ignore_alpha
|
||||
)
|
||||
: DynamicScreenMeshClass(2, 4)
|
||||
{
|
||||
|
||||
int resw, resh, resbits;
|
||||
bool windowed;
|
||||
|
||||
// find the resolution (for centering and pixel to pixel translation)
|
||||
WW3D::Get_Device_Resolution(resw, resh, resbits, windowed);
|
||||
// This should be the correct way to do things
|
||||
// but other code expects an aspect ratio of 1.0
|
||||
// Hector Yee 2/22/01
|
||||
// Set_Aspect(resh/(float)resw);
|
||||
|
||||
|
||||
// load up the surfaces file name
|
||||
SurfaceClass *surface=NEW_REF(SurfaceClass,(filename));
|
||||
|
||||
SurfaceClass::SurfaceDescription sd;
|
||||
surface->Get_Description(sd);
|
||||
|
||||
if (usable_width == -1)
|
||||
usable_width = sd.Width;
|
||||
if (usable_height == -1)
|
||||
usable_height = sd.Height;
|
||||
|
||||
// if we requested the image to be centered around a point adjust the
|
||||
// coordinates accordingly.
|
||||
if (center) {
|
||||
screen_x -= ((float)usable_width / resw) / 2;
|
||||
screen_y -= ((float)usable_height / resh) / 2;
|
||||
}
|
||||
|
||||
// The image will be broken down into square textures. The size of these
|
||||
// textures will be the smallest POT (power of two) which is equal or
|
||||
// greater than the smaller dimension of the image. Also, the pieces can
|
||||
// never be larger than 256 texels because some rendering devices don't
|
||||
// support textures larger than that.
|
||||
int surf_w = usable_width;
|
||||
int surf_h = usable_height;
|
||||
int piece = Find_POT(MIN(surf_w, surf_h));
|
||||
piece = MIN(piece, 256);
|
||||
|
||||
// now take the image in question and break it down into
|
||||
// "piece"x"piece"-pixel polygons and calculate the number of textures
|
||||
// based from those calculations.
|
||||
int mw = (surf_w & (piece - 1)) ? (surf_w / piece)+1 : (surf_w /piece);
|
||||
int mh = (surf_h & (piece - 1)) ? (surf_h / piece)+1 : (surf_h /piece);
|
||||
|
||||
// for every square texture it takes four vertexes to express the two
|
||||
// polygons.
|
||||
Resize(mw * mh *2, mw * mh * 4);
|
||||
|
||||
// Set shader to additive if requested, else alpha or opaque depending on
|
||||
// whether the texture has an alpha channel. Sorting is always set so that
|
||||
// sortbias can be used to determine occlusion between the various 2D
|
||||
// elements.
|
||||
ShaderClass shader;
|
||||
|
||||
if (additive) {
|
||||
shader = ShaderClass::_PresetAdditive2DShader;
|
||||
} else {
|
||||
if (ignore_alpha == false && Has_Alpha(sd.Format)) {
|
||||
shader = ShaderClass::_PresetAlpha2DShader;
|
||||
} else {
|
||||
shader = ShaderClass::_PresetOpaque2DShader;
|
||||
}
|
||||
}
|
||||
|
||||
Enable_Sort();
|
||||
|
||||
|
||||
// If we want to be able to colorize this bitmap later (by setting
|
||||
// emissive color for the vertex material, or via a vertex emissive color
|
||||
// array) we need to enable the primary gradient in the shader (it is
|
||||
// disabled in the 2D presets), and set an appropriate vertex material.
|
||||
if (colorizable) {
|
||||
shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE);
|
||||
VertexMaterialClass *vertex_material = NEW_REF( VertexMaterialClass, ());
|
||||
vertex_material->Set_Ambient(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Diffuse(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Specular(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Emissive(1.0f, 1.0f, 1.0f);
|
||||
Set_Vertex_Material(vertex_material, true);
|
||||
vertex_material->Release_Ref();
|
||||
}
|
||||
|
||||
// Set desired shader.
|
||||
Set_Shader(shader);
|
||||
|
||||
// loop through the rows and columns of the image and make valid
|
||||
// textures from the pieces.
|
||||
for (int lpy = 0, tlpy=0; lpy < mh; lpy++, tlpy += piece) {
|
||||
for (int lpx = 0, tlpx = 0; lpx < mw; lpx++, tlpx += piece) {
|
||||
|
||||
// figure the desired width and height of the texture (max "piece")
|
||||
int iw = MIN(piece, usable_width - (tlpx));
|
||||
int ih = MIN(piece, usable_height - (tlpy));
|
||||
int pot = MAX(Find_POT(iw), Find_POT(ih));
|
||||
|
||||
// create the texture and turn MIP-mapping off.
|
||||
SurfaceClass *piece_surface=NEW_REF(SurfaceClass,(pot,pot,sd.Format));
|
||||
piece_surface->Copy(0,0,tlpx,tlpy,pot,pot,surface);
|
||||
TextureClass *piece_texture =NEW_REF(TextureClass,(piece_surface,TextureClass::MIP_LEVELS_1));
|
||||
piece_texture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
|
||||
piece_texture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
|
||||
REF_PTR_RELEASE(piece_surface);
|
||||
|
||||
// calculate our actual texture coordinates based on the difference between
|
||||
// the width and height of the texture and the width and height the font
|
||||
// occupys.
|
||||
float tw = (float)iw / (float)pot;
|
||||
float th = (float)ih / (float)pot;
|
||||
|
||||
// convert image width and image height to normalized values
|
||||
float vw = (float)iw / (float)resw;
|
||||
float vh = (float)ih / (float)resh;
|
||||
|
||||
// figure out the screen space x and y positions of the object in question.
|
||||
float x = screen_x + (((float)tlpx) / (float)resw);
|
||||
float y = screen_y + (((float)tlpy) / (float)resh);
|
||||
|
||||
Set_Texture(piece_texture);
|
||||
Begin_Tri_Strip();
|
||||
Vertex( x, y, 0, 0, 0);
|
||||
Vertex( x + vw, y, 0, tw, 0);
|
||||
Vertex( x, y + vh, 0, 0, th);
|
||||
Vertex( x + vw, y + vh, 0, tw, th);
|
||||
End_Tri_Strip();
|
||||
|
||||
// release our reference to the texture
|
||||
REF_PTR_RELEASE(piece_texture);
|
||||
}
|
||||
}
|
||||
REF_PTR_RELEASE(surface);
|
||||
|
||||
Set_Dirty();
|
||||
}
|
||||
|
||||
Bitmap2DObjClass::Bitmap2DObjClass
|
||||
(
|
||||
TextureClass *texture,
|
||||
float screen_x,
|
||||
float screen_y,
|
||||
bool center,
|
||||
bool additive,
|
||||
bool colorizable,
|
||||
bool ignore_alpha
|
||||
)
|
||||
: DynamicScreenMeshClass(2, 4)
|
||||
{
|
||||
int resw, resh, resbits;
|
||||
bool windowed;
|
||||
|
||||
// find the resolution (for centering and pixel to pixel translation)
|
||||
WW3D::Get_Device_Resolution(resw, resh, resbits, windowed);
|
||||
// This should be the correct way to do things
|
||||
// but other code expects an aspect ratio of 1.0
|
||||
// Hector Yee 2/22/01
|
||||
//Set_Aspect(resh/(float)resw);
|
||||
|
||||
// Find the dimensions of the texture:
|
||||
SurfaceClass::SurfaceDescription sd;
|
||||
texture->Get_Level_Description(sd);
|
||||
|
||||
// convert image width and image height to normalized values
|
||||
float vw = (float) sd.Width / (float)resw;
|
||||
float vh = (float) sd.Height / (float)resh;
|
||||
|
||||
// if we requested the image to be centered around a point adjust the
|
||||
// coordinates accordingly.
|
||||
if (center) {
|
||||
screen_x -= vw / 2;
|
||||
screen_y -= vh / 2;
|
||||
}
|
||||
|
||||
// Set shader to additive if requested, else alpha or opaque depending on whether the texture
|
||||
// has an alpha channel. Sorting is never set - if you wish to sort these types of objects you
|
||||
// should use static sort levels (note that static sort levels are not implemented for these
|
||||
// objects yet, but it should be very simple to do).
|
||||
ShaderClass shader;
|
||||
|
||||
if (additive) {
|
||||
shader = ShaderClass::_PresetAdditive2DShader;
|
||||
} else {
|
||||
if (ignore_alpha == false && Has_Alpha(sd.Format)) {
|
||||
shader = ShaderClass::_PresetAlpha2DShader;
|
||||
} else {
|
||||
shader = ShaderClass::_PresetOpaque2DShader;
|
||||
}
|
||||
}
|
||||
Disable_Sort();
|
||||
|
||||
// If we want to be able to colorize this bitmap later (by setting
|
||||
// emissive color for the vertex material, or via a vertex emissive color
|
||||
// array) we need to enable the primary gradient in the shader (it is
|
||||
// disabled in the 2D presets), and set an appropriate vertex material.
|
||||
if (colorizable) {
|
||||
shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE);
|
||||
VertexMaterialClass *vertex_material = NEW_REF( VertexMaterialClass, ());
|
||||
vertex_material->Set_Ambient(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Diffuse(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Specular(0.0f, 0.0f, 0.0f);
|
||||
vertex_material->Set_Emissive(1.0f, 1.0f, 1.0f);
|
||||
Set_Vertex_Material(vertex_material, true);
|
||||
vertex_material->Release_Ref();
|
||||
}
|
||||
|
||||
// Set desired shader.
|
||||
Set_Shader(shader);
|
||||
|
||||
// Set texture to requested texture:
|
||||
Set_Texture(texture);
|
||||
|
||||
Begin_Tri_Strip();
|
||||
Vertex( screen_x, screen_y, 0, 0, 0);
|
||||
Vertex( screen_x + vw, screen_y, 0, 1.0, 0);
|
||||
Vertex( screen_x, screen_y + vh, 0, 0, 1.0);
|
||||
Vertex( screen_x + vw, screen_y + vh, 0, 1.0, 1.0);
|
||||
End_Tri_Strip();
|
||||
|
||||
Set_Dirty();
|
||||
}
|
||||
|
||||
RenderObjClass * Bitmap2DObjClass::Clone(void) const
|
||||
{
|
||||
return NEW_REF( Bitmap2DObjClass, (*this));
|
||||
}
|
||||
59
Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h
Normal file
59
Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Commando/G *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/bmp2d.h $*
|
||||
* *
|
||||
* $Author:: Hector_y $*
|
||||
* *
|
||||
* $Modtime:: 2/21/01 1:31p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BMP2D_H
|
||||
#define BMP2D_H
|
||||
|
||||
#include "dynamesh.h"
|
||||
|
||||
class Bitmap2DObjClass : public DynamicScreenMeshClass
|
||||
{
|
||||
public:
|
||||
Bitmap2DObjClass(const char *filename, float norm_x, float norm_y,
|
||||
bool center, bool additive, bool colorizable = false, int width = -1, int height = -1, bool ignore_alpha = false);
|
||||
Bitmap2DObjClass(TextureClass *texture, float norm_x, float norm_y,
|
||||
bool center, bool additive, bool colorizable = false, bool ignore_alpha = false);
|
||||
Bitmap2DObjClass( const Bitmap2DObjClass & src) : DynamicScreenMeshClass(src) {}
|
||||
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const { return CLASSID_BITMAP2D; }
|
||||
};
|
||||
|
||||
#endif
|
||||
1375
Generals/Code/Libraries/Source/WWVegas/WW3D2/boxrobj.cpp
Normal file
1375
Generals/Code/Libraries/Source/WWVegas/WW3D2/boxrobj.cpp
Normal file
File diff suppressed because it is too large
Load Diff
265
Generals/Code/Libraries/Source/WWVegas/WW3D2/boxrobj.h
Normal file
265
Generals/Code/Libraries/Source/WWVegas/WW3D2/boxrobj.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/boxrobj.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 2/19/01 1:11p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOXROBJ_H
|
||||
#define BOXROBJ_H
|
||||
|
||||
#include "always.h"
|
||||
#include "rendobj.h"
|
||||
#include "w3d_file.h"
|
||||
#include "shader.h"
|
||||
#include "proto.h"
|
||||
#include "obbox.h"
|
||||
|
||||
class VertexMaterialClass;
|
||||
|
||||
|
||||
/**
|
||||
** BoxRenderObjClass: base class for AABox and OBBox collision boxes
|
||||
**
|
||||
** NOTE: these render objects were designed from the start to be used for
|
||||
** collision boxes. They are designed to normally never render unless you
|
||||
** set the display mask and then, all boxes of that type will render.
|
||||
** The display mask is 'AND'ed with the collision bits in the base render
|
||||
** object class to determine if the box should be rendered. WW3D provides
|
||||
** an interface for setting this mask in your app.
|
||||
**
|
||||
** NOTE2: AABoxRenderObjClass is an axis-aligned box which will be positioned
|
||||
** at a world-space offset (its local center) from the origin of the transform.
|
||||
** This is done because AABoxes are used for rotationally invariant collision
|
||||
** detection so we don't want the boxes to move around as the object rotates.
|
||||
** For this reason, any AABoxes you use in a hierarchical model should be attached
|
||||
** to the root and be constructed symmetrically...
|
||||
**
|
||||
** NOTE3: OBBoxRenderObjClass is an oriented box which is aligned with its transform
|
||||
** but can have a center point that is offest from the transform's origin.
|
||||
**
|
||||
*/
|
||||
class BoxRenderObjClass : public RenderObjClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
BoxRenderObjClass(void);
|
||||
BoxRenderObjClass(const W3dBoxStruct & def);
|
||||
BoxRenderObjClass(const BoxRenderObjClass & src);
|
||||
BoxRenderObjClass & operator = (const BoxRenderObjClass &);
|
||||
|
||||
virtual int Get_Num_Polys(void) const;
|
||||
virtual const char * Get_Name(void) const;
|
||||
virtual void Set_Name(const char * name);
|
||||
void Set_Color(const Vector3 & color);
|
||||
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
|
||||
static void Set_Box_Display_Mask(int mask);
|
||||
static int Get_Box_Display_Mask(void);
|
||||
|
||||
void Set_Local_Center_Extent(const Vector3 & center,const Vector3 & extent);
|
||||
void Set_Local_Min_Max(const Vector3 & min,const Vector3 & max);
|
||||
|
||||
const Vector3 & Get_Local_Center(void) { return ObjSpaceCenter; }
|
||||
const Vector3 & Get_Local_Extent(void) { return ObjSpaceExtent; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void update_cached_box(void) = 0;
|
||||
void render_box(RenderInfoClass & rinfo,const Vector3 & center,const Vector3 & extent);
|
||||
void vis_render_box(SpecialRenderInfoClass & rinfo,const Vector3 & center,const Vector3 & extent);
|
||||
|
||||
char Name[2*W3D_NAME_LEN];
|
||||
Vector3 Color;
|
||||
Vector3 ObjSpaceCenter;
|
||||
Vector3 ObjSpaceExtent;
|
||||
|
||||
static bool IsInitted;
|
||||
static int DisplayMask;
|
||||
};
|
||||
|
||||
inline void BoxRenderObjClass::Set_Local_Center_Extent(const Vector3 & center,const Vector3 & extent)
|
||||
{
|
||||
ObjSpaceCenter = center;
|
||||
ObjSpaceExtent = extent;
|
||||
update_cached_box();
|
||||
}
|
||||
|
||||
inline void BoxRenderObjClass::Set_Local_Min_Max(const Vector3 & min,const Vector3 & max)
|
||||
{
|
||||
ObjSpaceCenter = (max + min) / 2.0f;
|
||||
ObjSpaceExtent = (max - min) / 2.0f;
|
||||
update_cached_box();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** AABoxRenderObjClass -- RenderObject for axis-aligned collision boxes.
|
||||
*/
|
||||
class AABoxRenderObjClass : public W3DMPO, public BoxRenderObjClass
|
||||
{
|
||||
W3DMPO_GLUE(AABoxRenderObjClass)
|
||||
public:
|
||||
|
||||
AABoxRenderObjClass(void);
|
||||
AABoxRenderObjClass(const W3dBoxStruct & def);
|
||||
AABoxRenderObjClass(const AABoxRenderObjClass & src);
|
||||
AABoxRenderObjClass(const AABoxClass & box);
|
||||
AABoxRenderObjClass & operator = (const AABoxRenderObjClass &);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const;
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
virtual bool Intersect_AABox(AABoxIntersectionTestClass & boxtest);
|
||||
virtual bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// AABoxRenderObjClass Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
const AABoxClass & Get_Box(void);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void update_cached_box(void);
|
||||
|
||||
AABoxClass CachedBox;
|
||||
|
||||
};
|
||||
|
||||
inline const AABoxClass & AABoxRenderObjClass::Get_Box(void)
|
||||
{
|
||||
Validate_Transform();
|
||||
update_cached_box();
|
||||
return CachedBox;
|
||||
}
|
||||
|
||||
/*
|
||||
** OBBoxRenderObjClass - render object for oriented collision boxes
|
||||
*/
|
||||
class OBBoxRenderObjClass : public W3DMPO, public BoxRenderObjClass
|
||||
{
|
||||
W3DMPO_GLUE(OBBoxRenderObjClass)
|
||||
public:
|
||||
|
||||
OBBoxRenderObjClass(void);
|
||||
OBBoxRenderObjClass(const W3dBoxStruct & def);
|
||||
OBBoxRenderObjClass(const OBBoxRenderObjClass & src);
|
||||
OBBoxRenderObjClass(const OBBoxClass & box);
|
||||
OBBoxRenderObjClass & operator = (const OBBoxRenderObjClass &);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const;
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
virtual bool Intersect_AABox(AABoxIntersectionTestClass & boxtest);
|
||||
virtual bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// OBBoxRenderObjClass Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
OBBoxClass & Get_Box(void);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void update_cached_box(void);
|
||||
|
||||
OBBoxClass CachedBox;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Loader for boxes
|
||||
*/
|
||||
class BoxLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
virtual int Chunk_Type (void) { return W3D_CHUNK_BOX; }
|
||||
virtual PrototypeClass * Load_W3D(ChunkLoadClass & cload);
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/*
|
||||
** Prototype for Box objects
|
||||
*/
|
||||
class BoxPrototypeClass : public W3DMPO, public PrototypeClass
|
||||
{
|
||||
W3DMPO_GLUE(BoxPrototypeClass)
|
||||
public:
|
||||
BoxPrototypeClass(W3dBoxStruct box);
|
||||
virtual const char * Get_Name(void) const;
|
||||
virtual int Get_Class_ID(void) const;
|
||||
virtual RenderObjClass * Create(void);
|
||||
virtual void DeleteSelf() { delete this; }
|
||||
private:
|
||||
W3dBoxStruct Definition;
|
||||
};
|
||||
|
||||
/*
|
||||
** Instance of the loader which the asset manager installs
|
||||
*/
|
||||
extern BoxLoaderClass _BoxLoader;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
241
Generals/Code/Libraries/Source/WWVegas/WW3D2/bw_render.cpp
Normal file
241
Generals/Code/Libraries/Source/WWVegas/WW3D2/bw_render.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/BW_Render.cpp $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 2/06/01 10:57a $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "bw_render.h"
|
||||
#include "vp.h"
|
||||
#include <string.h>
|
||||
|
||||
BW_Render::Buffer::Buffer(unsigned char* buffer_, int scale_)
|
||||
:
|
||||
buffer(buffer_),
|
||||
scale(scale_),
|
||||
minv(3),
|
||||
maxv(scale_-3)
|
||||
{
|
||||
}
|
||||
|
||||
BW_Render::Buffer::~Buffer()
|
||||
{
|
||||
}
|
||||
|
||||
void BW_Render::Buffer::Set_H_Line(int start_x, int end_x, int y)
|
||||
{
|
||||
if (y<minv || y>=maxv || end_x<minv || start_x>=maxv) return;
|
||||
if (start_x<minv) start_x=minv;
|
||||
if (end_x>=maxv) end_x=maxv-1;
|
||||
unsigned char* ptr=buffer+scale*y+start_x;
|
||||
int w=end_x-start_x;
|
||||
if (w) {
|
||||
::memset(ptr,0x00,w);
|
||||
|
||||
/* // Blurring (test)
|
||||
*(ptr-1)&=0x80;
|
||||
*(ptr-2)&=0xc0;
|
||||
*(ptr+w)&=0x80;
|
||||
*(ptr+w+1)&=0xc0;
|
||||
for (int a=0;a<w;++a) {
|
||||
*(ptr-scale+a)&=0xc0;
|
||||
*(ptr+scale+a)&=0xc0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void BW_Render::Buffer::Fill(unsigned char c)
|
||||
{
|
||||
memset(buffer,c,scale*scale);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
BW_Render::BW_Render(unsigned char* buffer, int buffer_scale)
|
||||
:
|
||||
pixel_buffer(buffer,buffer_scale)
|
||||
{
|
||||
}
|
||||
|
||||
BW_Render::~BW_Render()
|
||||
{
|
||||
}
|
||||
|
||||
void BW_Render::Fill(unsigned char c)
|
||||
{
|
||||
pixel_buffer.Fill(c);
|
||||
}
|
||||
|
||||
// Sets the vertex coordinate buffer location and scales the vertex locations to the kjkj
|
||||
void BW_Render::Set_Vertex_Locations(Vector2* vertices_,int count)
|
||||
{
|
||||
vertices=vertices_;
|
||||
|
||||
float half_scale=pixel_buffer.Scale()*0.5f;
|
||||
VectorProcessorClass::MulAdd(
|
||||
reinterpret_cast<float*>(vertices),
|
||||
half_scale,
|
||||
half_scale,
|
||||
count*2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static inline bool Cull(
|
||||
const Vector2& c1,
|
||||
const Vector2& c2,
|
||||
const Vector2& c3)
|
||||
{
|
||||
float x1=c2[0]-c1[0];
|
||||
float y1=c2[1]-c1[1];
|
||||
float x2=c3[0]-c1[0];
|
||||
float y2=c3[1]-c1[1];
|
||||
float r=x1*y2-x2*y1;
|
||||
if (r<0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BW_Render::Render_Triangle_Strip(const unsigned long* indices,int index_count)
|
||||
{
|
||||
index_count-=2;
|
||||
bool b=false;
|
||||
for (int n=0;n<index_count;++n) {
|
||||
b=!b;
|
||||
int idx_1=indices[0];
|
||||
int idx_2=indices[1];
|
||||
int idx_3=indices[2];
|
||||
indices++;
|
||||
|
||||
if (Cull(vertices[idx_1],vertices[idx_2],vertices[idx_3])==b) continue;
|
||||
|
||||
Vector2 corner_1(vertices[idx_1][0],vertices[idx_1][1]);
|
||||
Vector2 corner_2(vertices[idx_2][0],vertices[idx_2][1]);
|
||||
Vector2 corner_3(vertices[idx_3][0],vertices[idx_3][1]);
|
||||
|
||||
// Sort the corners on y axis
|
||||
|
||||
if (corner_2[1]<corner_1[1]) Swap(corner_1,corner_2);
|
||||
if (corner_3[1]<corner_1[1]) Swap(corner_1,corner_3);
|
||||
if (corner_3[1]<corner_2[1]) Swap(corner_2,corner_3);
|
||||
|
||||
Vector3i yci(WWMath::Float_To_Long(corner_1[1]),WWMath::Float_To_Long(corner_2[1]),WWMath::Float_To_Long(corner_3[1]));
|
||||
Vector3 xcf(corner_1[0],corner_2[0],corner_3[0]);
|
||||
|
||||
Render_Preprocessed_Triangle(xcf,yci);
|
||||
}
|
||||
}
|
||||
|
||||
void BW_Render::Render_Triangles(const unsigned long* indices,int index_count)
|
||||
{
|
||||
index_count/=3;
|
||||
for (int n=0;n<index_count;++n) {
|
||||
int idx_1=*indices++;
|
||||
int idx_2=*indices++;
|
||||
int idx_3=*indices++;
|
||||
|
||||
if (Cull(vertices[idx_1],vertices[idx_2],vertices[idx_3])) continue;
|
||||
|
||||
Vector2 corner_1(vertices[idx_1][0],vertices[idx_1][1]);
|
||||
Vector2 corner_2(vertices[idx_2][0],vertices[idx_2][1]);
|
||||
Vector2 corner_3(vertices[idx_3][0],vertices[idx_3][1]);
|
||||
|
||||
// Sort the corners on y axis
|
||||
|
||||
if (corner_2[1]<corner_1[1]) Swap(corner_1,corner_2);
|
||||
if (corner_3[1]<corner_1[1]) Swap(corner_1,corner_3);
|
||||
if (corner_3[1]<corner_2[1]) Swap(corner_2,corner_3);
|
||||
|
||||
Vector3i yci(WWMath::Float_To_Long(corner_1[1]),WWMath::Float_To_Long(corner_2[1]),WWMath::Float_To_Long(corner_3[1]));
|
||||
Vector3 xcf(corner_1[0],corner_2[0],corner_3[0]);
|
||||
|
||||
Render_Preprocessed_Triangle(xcf,yci);
|
||||
}
|
||||
}
|
||||
|
||||
void BW_Render::Render_Preprocessed_Triangle(Vector3& xcf,Vector3i& yci)
|
||||
{
|
||||
float x_left=xcf[0];
|
||||
float x_right=x_left;
|
||||
int ycnt=yci[1]-yci[0];
|
||||
int y=yci[0];
|
||||
if (ycnt) {
|
||||
float x_step_1=(xcf[1]-xcf[0])/float(ycnt);
|
||||
float x_step_2=(xcf[2]-xcf[0])/float(yci[2]-y);
|
||||
if (x_step_1>x_step_2) {
|
||||
float t=x_step_1;
|
||||
x_step_1=x_step_2;
|
||||
x_step_2=t;
|
||||
}
|
||||
|
||||
while (ycnt>0) {
|
||||
pixel_buffer.Set_H_Line(WWMath::Float_To_Long(x_left),WWMath::Float_To_Long(x_right),y);
|
||||
|
||||
x_left+=x_step_1;
|
||||
x_right+=x_step_2;
|
||||
ycnt--;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (xcf[0]<xcf[1]) {
|
||||
x_left=xcf[0];
|
||||
x_right=xcf[1];
|
||||
}
|
||||
else {
|
||||
x_right=xcf[0];
|
||||
x_left=xcf[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ycnt=yci[2]-yci[1];
|
||||
y=yci[1];
|
||||
|
||||
if (ycnt) {
|
||||
float one_per_ycnt=1.0f/float(ycnt);
|
||||
float x_step_1=(xcf[2]-x_left)*one_per_ycnt;
|
||||
float x_step_2=(xcf[2]-x_right)*one_per_ycnt;
|
||||
while (ycnt>0) {
|
||||
pixel_buffer.Set_H_Line(WWMath::Float_To_Long(x_left),WWMath::Float_To_Long(x_right),y);
|
||||
x_left+=x_step_1;
|
||||
x_right+=x_step_2;
|
||||
ycnt--;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
85
Generals/Code/Libraries/Source/WWVegas/WW3D2/bw_render.h
Normal file
85
Generals/Code/Libraries/Source/WWVegas/WW3D2/bw_render.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/bw_render.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 3/26/01 4:53p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BW_RENDER_H__
|
||||
#define BW_RENDER_H__
|
||||
|
||||
#include "always.h"
|
||||
#include "vector2.h"
|
||||
#include "vector3.h"
|
||||
#include "vector3i.h"
|
||||
|
||||
class BW_Render
|
||||
{
|
||||
// Internal pixel buffer used by the triangle renderer
|
||||
// The buffer is not allocated or freed by this class.
|
||||
class Buffer
|
||||
{
|
||||
unsigned char* buffer;
|
||||
int scale;
|
||||
int minv;
|
||||
int maxv;
|
||||
public:
|
||||
Buffer(unsigned char* buffer, int scale);
|
||||
~Buffer();
|
||||
|
||||
void Set_H_Line(int start_x, int end_x, int y);
|
||||
void Fill(unsigned char c);
|
||||
inline int Scale() const { return scale; }
|
||||
} pixel_buffer;
|
||||
|
||||
Vector2* vertices;
|
||||
|
||||
void Render_Preprocessed_Triangle(Vector3& xcf,Vector3i& yci);
|
||||
|
||||
public:
|
||||
BW_Render(unsigned char* buffer, int scale);
|
||||
~BW_Render();
|
||||
|
||||
void Fill(unsigned char c);
|
||||
void Set_Vertex_Locations(Vector2* vertices,int count); // Warning! Contents are modified!
|
||||
void Render_Triangles(const unsigned long* indices,int index_count);
|
||||
void Render_Triangle_Strip(const unsigned long* indices,int index_count);
|
||||
};
|
||||
|
||||
|
||||
#endif // BW_RENDER_H__
|
||||
242
Generals/Code/Libraries/Source/WWVegas/WW3D2/bwrender.cpp
Normal file
242
Generals/Code/Libraries/Source/WWVegas/WW3D2/bwrender.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : ww3d2 *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/bwrender.cpp $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 4/04/01 10:14a $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "bwrender.h"
|
||||
#include "vp.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
BWRenderClass::Buffer::Buffer(unsigned char* buffer_, int scale_)
|
||||
:
|
||||
buffer(buffer_),
|
||||
scale(scale_),
|
||||
minv(3),
|
||||
maxv(scale_-3)
|
||||
{
|
||||
}
|
||||
|
||||
BWRenderClass::Buffer::~Buffer()
|
||||
{
|
||||
}
|
||||
|
||||
void BWRenderClass::Buffer::Set_H_Line(int start_x, int end_x, int y)
|
||||
{
|
||||
if (y<minv || y>=maxv || end_x<minv || start_x>=maxv) return;
|
||||
if (start_x<minv) start_x=minv;
|
||||
if (end_x>=maxv) end_x=maxv-1;
|
||||
unsigned char* ptr=buffer+scale*y+start_x;
|
||||
int w=end_x-start_x;
|
||||
if (w) {
|
||||
::memset(ptr,0x00,w);
|
||||
|
||||
/* // Blurring (test)
|
||||
*(ptr-1)&=0x80;
|
||||
*(ptr-2)&=0xc0;
|
||||
*(ptr+w)&=0x80;
|
||||
*(ptr+w+1)&=0xc0;
|
||||
for (int a=0;a<w;++a) {
|
||||
*(ptr-scale+a)&=0xc0;
|
||||
*(ptr+scale+a)&=0xc0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void BWRenderClass::Buffer::Fill(unsigned char c)
|
||||
{
|
||||
memset(buffer,c,scale*scale);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
BWRenderClass::BWRenderClass(unsigned char* buffer, int buffer_scale)
|
||||
:
|
||||
pixel_buffer(buffer,buffer_scale)
|
||||
{
|
||||
}
|
||||
|
||||
BWRenderClass::~BWRenderClass()
|
||||
{
|
||||
}
|
||||
|
||||
void BWRenderClass::Fill(unsigned char c)
|
||||
{
|
||||
pixel_buffer.Fill(c);
|
||||
}
|
||||
|
||||
// Sets the vertex coordinate buffer location and scales the vertex locations to the kjkj
|
||||
void BWRenderClass::Set_Vertex_Locations(Vector2* vertices_,int count)
|
||||
{
|
||||
vertices=vertices_;
|
||||
|
||||
float half_scale=pixel_buffer.Scale()*0.5f;
|
||||
VectorProcessorClass::MulAdd(
|
||||
reinterpret_cast<float*>(vertices),
|
||||
half_scale,
|
||||
half_scale,
|
||||
count*2);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static inline bool Cull(
|
||||
const Vector2& c1,
|
||||
const Vector2& c2,
|
||||
const Vector2& c3)
|
||||
{
|
||||
float x1=c2[0]-c1[0];
|
||||
float y1=c2[1]-c1[1];
|
||||
float x2=c3[0]-c1[0];
|
||||
float y2=c3[1]-c1[1];
|
||||
float r=x1*y2-x2*y1;
|
||||
if (r<0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BWRenderClass::Render_Triangle_Strip(const unsigned long* indices,int index_count)
|
||||
{
|
||||
index_count-=2;
|
||||
bool b=false;
|
||||
for (int n=0;n<index_count;++n) {
|
||||
b=!b;
|
||||
int idx_1=indices[0];
|
||||
int idx_2=indices[1];
|
||||
int idx_3=indices[2];
|
||||
indices++;
|
||||
|
||||
if (Cull(vertices[idx_1],vertices[idx_2],vertices[idx_3])==b) continue;
|
||||
|
||||
Vector2 corner_1(vertices[idx_1][0],vertices[idx_1][1]);
|
||||
Vector2 corner_2(vertices[idx_2][0],vertices[idx_2][1]);
|
||||
Vector2 corner_3(vertices[idx_3][0],vertices[idx_3][1]);
|
||||
|
||||
// Sort the corners on y axis
|
||||
|
||||
if (corner_2[1]<corner_1[1]) Swap(corner_1,corner_2);
|
||||
if (corner_3[1]<corner_1[1]) Swap(corner_1,corner_3);
|
||||
if (corner_3[1]<corner_2[1]) Swap(corner_2,corner_3);
|
||||
|
||||
Vector3i yci(WWMath::Float_To_Long(corner_1[1]),WWMath::Float_To_Long(corner_2[1]),WWMath::Float_To_Long(corner_3[1]));
|
||||
Vector3 xcf(corner_1[0],corner_2[0],corner_3[0]);
|
||||
|
||||
Render_Preprocessed_Triangle(xcf,yci);
|
||||
}
|
||||
}
|
||||
|
||||
void BWRenderClass::Render_Triangles(const unsigned long* indices,int index_count)
|
||||
{
|
||||
index_count/=3;
|
||||
for (int n=0;n<index_count;++n) {
|
||||
int idx_1=*indices++;
|
||||
int idx_2=*indices++;
|
||||
int idx_3=*indices++;
|
||||
|
||||
if (Cull(vertices[idx_1],vertices[idx_2],vertices[idx_3])) continue;
|
||||
|
||||
Vector2 corner_1(vertices[idx_1][0],vertices[idx_1][1]);
|
||||
Vector2 corner_2(vertices[idx_2][0],vertices[idx_2][1]);
|
||||
Vector2 corner_3(vertices[idx_3][0],vertices[idx_3][1]);
|
||||
|
||||
// Sort the corners on y axis
|
||||
|
||||
if (corner_2[1]<corner_1[1]) Swap(corner_1,corner_2);
|
||||
if (corner_3[1]<corner_1[1]) Swap(corner_1,corner_3);
|
||||
if (corner_3[1]<corner_2[1]) Swap(corner_2,corner_3);
|
||||
|
||||
Vector3i yci(WWMath::Float_To_Long(corner_1[1]),WWMath::Float_To_Long(corner_2[1]),WWMath::Float_To_Long(corner_3[1]));
|
||||
Vector3 xcf(corner_1[0],corner_2[0],corner_3[0]);
|
||||
|
||||
Render_Preprocessed_Triangle(xcf,yci);
|
||||
}
|
||||
}
|
||||
|
||||
void BWRenderClass::Render_Preprocessed_Triangle(Vector3& xcf,Vector3i& yci)
|
||||
{
|
||||
float x_left=xcf[0];
|
||||
float x_right=x_left;
|
||||
int ycnt=yci[1]-yci[0];
|
||||
int y=yci[0];
|
||||
if (ycnt) {
|
||||
float x_step_1=(xcf[1]-xcf[0])/float(ycnt);
|
||||
float x_step_2=(xcf[2]-xcf[0])/float(yci[2]-y);
|
||||
if (x_step_1>x_step_2) {
|
||||
float t=x_step_1;
|
||||
x_step_1=x_step_2;
|
||||
x_step_2=t;
|
||||
}
|
||||
|
||||
while (ycnt>0) {
|
||||
pixel_buffer.Set_H_Line(WWMath::Float_To_Long(x_left),WWMath::Float_To_Long(x_right),y);
|
||||
|
||||
x_left+=x_step_1;
|
||||
x_right+=x_step_2;
|
||||
ycnt--;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (xcf[0]<xcf[1]) {
|
||||
x_left=xcf[0];
|
||||
x_right=xcf[1];
|
||||
}
|
||||
else {
|
||||
x_right=xcf[0];
|
||||
x_left=xcf[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ycnt=yci[2]-yci[1];
|
||||
y=yci[1];
|
||||
|
||||
if (ycnt) {
|
||||
float one_per_ycnt=1.0f/float(ycnt);
|
||||
float x_step_1=(xcf[2]-x_left)*one_per_ycnt;
|
||||
float x_step_2=(xcf[2]-x_right)*one_per_ycnt;
|
||||
while (ycnt>0) {
|
||||
pixel_buffer.Set_H_Line(WWMath::Float_To_Long(x_left),WWMath::Float_To_Long(x_right),y);
|
||||
x_left+=x_step_1;
|
||||
x_right+=x_step_2;
|
||||
ycnt--;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
96
Generals/Code/Libraries/Source/WWVegas/WW3D2/bwrender.h
Normal file
96
Generals/Code/Libraries/Source/WWVegas/WW3D2/bwrender.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : ww3d2 *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/bwrender.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 4/04/01 10:36a $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BWRENDER_H
|
||||
#define BWRENDER_H
|
||||
|
||||
|
||||
#include "always.h"
|
||||
#include "vector2.h"
|
||||
#include "vector3.h"
|
||||
#include "vector3i.h"
|
||||
|
||||
/**
|
||||
** BWRenderClass
|
||||
** This class implements a simple black-and-white triangle rasterizer which
|
||||
** can be used to generate shadow textures. It is faster than a general purpose
|
||||
** software renderer due to the fact that no z-buffering or sorting is needed and
|
||||
** texturing isn't supported.
|
||||
** (gth) 04/02/2001 - I'm going to add render-to-texture code to Renegade so this
|
||||
** class may be obsolete.
|
||||
*/
|
||||
class BWRenderClass
|
||||
{
|
||||
// Internal pixel buffer used by the triangle renderer
|
||||
// The buffer is not allocated or freed by this class.
|
||||
class Buffer
|
||||
{
|
||||
unsigned char* buffer;
|
||||
int scale;
|
||||
int minv;
|
||||
int maxv;
|
||||
public:
|
||||
Buffer(unsigned char* buffer, int scale);
|
||||
~Buffer();
|
||||
|
||||
void Set_H_Line(int start_x, int end_x, int y);
|
||||
void Fill(unsigned char c);
|
||||
inline int Scale() const { return scale; }
|
||||
} pixel_buffer;
|
||||
|
||||
Vector2* vertices;
|
||||
|
||||
void Render_Preprocessed_Triangle(Vector3& xcf,Vector3i& yci);
|
||||
|
||||
public:
|
||||
BWRenderClass(unsigned char* buffer, int scale);
|
||||
~BWRenderClass();
|
||||
|
||||
void Fill(unsigned char c);
|
||||
void Set_Vertex_Locations(Vector2* vertices,int count); // Warning! Contents are modified!
|
||||
void Render_Triangles(const unsigned long* indices,int index_count);
|
||||
void Render_Triangle_Strip(const unsigned long* indices,int index_count);
|
||||
};
|
||||
|
||||
|
||||
#endif //BWRENDER_H
|
||||
|
||||
826
Generals/Code/Libraries/Source/WWVegas/WW3D2/camera.cpp
Normal file
826
Generals/Code/Libraries/Source/WWVegas/WW3D2/camera.cpp
Normal file
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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:: /VSS_Sync/ww3d2/camera.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 8/29/01 7:29p $*
|
||||
* *
|
||||
* $Revision:: 22 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CameraClass::CameraClass -- constructor *
|
||||
* CameraClass::CameraClass -- copy constructor *
|
||||
* CameraClass::operator == -- assignment operator *
|
||||
* CameraClass::~CameraClass -- destructor *
|
||||
* CameraClass::Clone -- virtual copy constructor *
|
||||
* CameraClass::Add -- add the camera to the world? *
|
||||
* CameraClass::Remove -- Remove the camera from the world? *
|
||||
* CameraClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere *
|
||||
* CameraClass::Get_Object_Space_Bounding_Box -- returns the object space bounding box *
|
||||
* CameraClass::Set_Transform -- set the transform of the camera *
|
||||
* CameraClass::Set_Position -- Set the position of the camera *
|
||||
* CameraClass::Set_Animation -- set the animation state of the camera *
|
||||
* CameraClass::Set_Animation -- Set the animation state of the camera *
|
||||
* CameraClass::Set_Animation -- set the animation state of the camera *
|
||||
* CameraClass::Set_Animation -- set the animation state of the camera *
|
||||
* CameraClass::Set_View_Plane -- control over the view plane *
|
||||
* CameraClass::Set_View_Plane -- set the viewplane using fov angles *
|
||||
* CameraClass::Set_Focal_Length -- set the view plane using focal length and aspect ratio *
|
||||
* CameraClass::Get_View_Plane -- get the corners of the current view plane *
|
||||
* CameraClass::Project -- project a point from ws to the view plane *
|
||||
* CameraClass::Project_Camera_Space_Point -- Project a point that is already in camera spac *
|
||||
* CameraClass::Un_Project -- "unproject" a point from the view plane to world space *
|
||||
* CameraClass::Transform_To_View_Space -- transforms the given world space point to camera *
|
||||
* CameraClass::Rotate_To_View_Space -- rotates the given world space vector to camera space *
|
||||
* CameraClass::Get_Near_Clip_Bounding_Box -- returns an obb that contains near clip plane *
|
||||
* CameraCLass::Update_Frustum -- updates the frustum parameters *
|
||||
* CameraClass::Cull_Box -- tests whether the given box can be culled *
|
||||
* CameraClass::Device_To_View_Space -- converts the given device coordinate to view space *
|
||||
* CameraClass::Device_To_World_Space -- converts given device coord to world space *
|
||||
* CameraClass::Camera_Push -- pushes the camera's parameters into the given GERD *
|
||||
* CameraClass::Camera_Pop -- pops the camera's parameters from the given GERD *
|
||||
* CameraClass::Set_Aspect_Ratio -- sets the aspect ratio of the camera *
|
||||
* CameraClass::Apply_D3D_State -- sets the D3D states controlled by the camera *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "camera.h"
|
||||
#include "ww3d.h"
|
||||
#include "matrix4.h"
|
||||
#include "dx8wrapper.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::CameraClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
CameraClass::CameraClass(void) :
|
||||
Projection(PERSPECTIVE),
|
||||
Viewport(Vector2(0,0),Vector2(1,1)), // pixel viewport to render into
|
||||
AspectRatio(4.0f/3.0f),
|
||||
ZNear(1.0f), // near clip plane distance
|
||||
ZFar(1000.0f), // far clip plane distance
|
||||
ZBufferMin(0.0f), // smallest value we'll write into the z-buffer
|
||||
ZBufferMax(1.0f), // largest value we'll write into the z-buffer
|
||||
FrustumValid(false)
|
||||
{
|
||||
Set_Transform(Matrix3D(1));
|
||||
Set_View_Plane(DEG_TO_RADF(50.0f));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::CameraClass -- copy constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
* 4/13/2001 hy : added in copy code for new member functions *
|
||||
*=============================================================================================*/
|
||||
CameraClass::CameraClass(const CameraClass & src) :
|
||||
RenderObjClass(src),
|
||||
Projection(src.Projection),
|
||||
Viewport(src.Viewport),
|
||||
ViewPlane(src.ViewPlane),
|
||||
ZNear(src.ZNear),
|
||||
ZFar(src.ZFar),
|
||||
FrustumValid(src.FrustumValid),
|
||||
Frustum(src.Frustum),
|
||||
NearClipBBox(src.NearClipBBox),
|
||||
ProjectionTransform(src.ProjectionTransform),
|
||||
CameraInvTransform(src.CameraInvTransform),
|
||||
AspectRatio(src.AspectRatio),
|
||||
ZBufferMin(src.ZBufferMin),
|
||||
ZBufferMax(src.ZBufferMax)
|
||||
{
|
||||
// just being paraniod in case any parent class doesn't completely copy the entire state...
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::operator == -- assignment operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
CameraClass & CameraClass::operator = (const CameraClass & that)
|
||||
{
|
||||
if (this != &that) {
|
||||
RenderObjClass::operator = (that);
|
||||
|
||||
Projection = that.Projection;
|
||||
Viewport = that.Viewport;
|
||||
ViewPlane = that.ViewPlane;
|
||||
ZNear = that.ZNear;
|
||||
ZFar = that.ZFar;
|
||||
FrustumValid = that.FrustumValid;
|
||||
Frustum = that.Frustum;
|
||||
NearClipBBox = that.NearClipBBox;
|
||||
ProjectionTransform = that.ProjectionTransform;
|
||||
CameraInvTransform = that.CameraInvTransform;
|
||||
|
||||
// just being paraniod in case any parent class doesn't completely copy the entire state...
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
return * this;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::~CameraClass -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
CameraClass::~CameraClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Clone -- virtual copy constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
RenderObjClass * CameraClass::Clone(void) const
|
||||
{
|
||||
return NEW_REF( CameraClass, (*this) );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 9/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{
|
||||
sphere.Center.Set(0,0,0);
|
||||
sphere.Radius = ZFar; // could optimize this but its not really used.
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Object_Space_Bounding_Box -- returns the object space bounding box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 9/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
box.Center.Set(0,0,0);
|
||||
box.Extent.Set(ZFar,ZFar,ZFar); // could optimize this but its not really used.
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Set_Transform -- set the transform of the camera *
|
||||
* *
|
||||
* This is over-ridden to invalidate the cached frustum parameters *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Set_Transform(const Matrix3D &m)
|
||||
{
|
||||
RenderObjClass::Set_Transform(m);
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Set_Position -- Set the position of the camera *
|
||||
* *
|
||||
* This is overriden to invalidate the cached frustum parameters *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Set_Position(const Vector3 &v)
|
||||
{
|
||||
RenderObjClass::Set_Position(v);
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Set_View_Plane -- control over the view plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* min - x,y of the upper left corner of the view rectangle (dist is assumed to be 1.0) *
|
||||
* max - x,y of the lower right corner of the view rectangle *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Set_View_Plane(const Vector2 & vmin,const Vector2 & vmax)
|
||||
{
|
||||
ViewPlane.Min = vmin;
|
||||
ViewPlane.Max = vmax;
|
||||
AspectRatio = (vmax.X - vmin.X) / (vmax.Y - vmin.Y);
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Set_View_Plane -- set the viewplane using fov angles *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Set_View_Plane(float hfov,float vfov)
|
||||
{
|
||||
|
||||
float width_half = tan(hfov/2.0);
|
||||
float height_half = 0.0f;
|
||||
|
||||
if (vfov == -1) {
|
||||
height_half = (1.0f / AspectRatio) * width_half; // use the aspect ratio
|
||||
} else {
|
||||
height_half = tan(vfov/2.0);
|
||||
AspectRatio = width_half / height_half; // or, initialize the aspect ratio
|
||||
}
|
||||
|
||||
ViewPlane.Min.Set(-width_half,-height_half);
|
||||
ViewPlane.Max.Set(width_half,height_half);
|
||||
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Set_Aspect_Ratio -- sets the aspect ratio of the camera *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/29/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Set_Aspect_Ratio(float width_to_height)
|
||||
{
|
||||
AspectRatio = width_to_height;
|
||||
ViewPlane.Min.Y = ViewPlane.Min.X / AspectRatio;
|
||||
ViewPlane.Max.Y = ViewPlane.Max.X / AspectRatio;
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_View_Plane -- get the corners of the current view plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Get_View_Plane(Vector2 & set_min,Vector2 & set_max) const
|
||||
{
|
||||
set_min = ViewPlane.Min;
|
||||
set_max = ViewPlane.Max;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Project -- project a point from ws to the view plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* dest - will be set to a point on the normalized view plane. x,y, and z range from -1 to 1 *
|
||||
* ws_point - input point in world space *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* ProjectionResType indicating whether the point was in the frustum *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* When the input is behind the near clip plane, 0,0,0 is returned. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
CameraClass::ProjectionResType CameraClass::Project(Vector3 & dest,const Vector3 & ws_point) const
|
||||
{
|
||||
Update_Frustum();
|
||||
|
||||
Vector3 cam_point;
|
||||
Matrix3D::Transform_Vector(CameraInvTransform,ws_point,&cam_point);
|
||||
|
||||
if (cam_point.Z > -ZNear) {
|
||||
dest.Set(0,0,0);
|
||||
return OUTSIDE_NEAR_CLIP;
|
||||
}
|
||||
|
||||
Vector4 view_point = ProjectionTransform * cam_point;
|
||||
float oow = 1.0f / view_point.W;
|
||||
dest.X = view_point.X * oow;
|
||||
dest.Y = view_point.Y * oow;
|
||||
dest.Z = view_point.Z * oow;
|
||||
|
||||
if (dest.Z > 1.0f) {
|
||||
return OUTSIDE_FAR_CLIP;
|
||||
}
|
||||
|
||||
if ((dest.X < -1.0f) || (dest.X > 1.0f) || (dest.Y < -1.0f) || (dest.Y > 1.0f)) {
|
||||
return OUTSIDE_FRUSTUM;
|
||||
}
|
||||
|
||||
return INSIDE_FRUSTUM;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Project_Camera_Space_Point -- Project a point that is already in camera space *
|
||||
* *
|
||||
* INPUT: *
|
||||
* dest - will be set to a point on the normalized view plane. x,y, and z range from -1 to 1 *
|
||||
* cam_point - input point in camera space *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* ProjectionResType indicating whether the point was in the frustum *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* When the input is behind the near clip plane, 0,0,0 is returned. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/17/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CameraClass::ProjectionResType
|
||||
CameraClass::Project_Camera_Space_Point(Vector3 & dest,const Vector3 & cam_point) const
|
||||
{
|
||||
Update_Frustum();
|
||||
|
||||
if ( cam_point.Z > -ZNear + WWMATH_EPSILON) {
|
||||
dest.Set(0,0,0);
|
||||
return OUTSIDE_NEAR_CLIP;
|
||||
}
|
||||
|
||||
Vector4 view_point = ProjectionTransform * cam_point;
|
||||
float oow = 1.0f / view_point.W;
|
||||
dest.X = view_point.X * oow;
|
||||
dest.Y = view_point.Y * oow;
|
||||
dest.Z = view_point.Z * oow;
|
||||
|
||||
if (dest.Z > 1.0f) {
|
||||
return OUTSIDE_FAR_CLIP;
|
||||
}
|
||||
|
||||
if ((dest.X < -1.0f) || (dest.X > 1.0f) || (dest.Y < -1.0f) || (dest.Y > 1.0f)) {
|
||||
return OUTSIDE_FRUSTUM;
|
||||
}
|
||||
|
||||
return INSIDE_FRUSTUM;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Un_Project -- "unproject" a point from the view plane to world space *
|
||||
* *
|
||||
* The given point is assumed to be on the view_plane at z=-1. The 3D world space point that *
|
||||
* this represents will be returned in dest. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* dest - will be filled in with the 3D world space point that the given point represents *
|
||||
* view_point - point on the view_plane to be un-projected *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Un_Project(Vector3 & dest,const Vector2 & view_point) const
|
||||
{
|
||||
/*
|
||||
** map view_point.X from -1..1 to ViewPlaneMin.X..ViewPlaneMax.X
|
||||
** map view_point.Y from -1..1 to ViewPlaneMin.X..ViewPlaneMax.X
|
||||
*/
|
||||
float vpdx = ViewPlane.Max.X - ViewPlane.Min.X;
|
||||
float vpdy = ViewPlane.Max.Y - ViewPlane.Min.Y;
|
||||
|
||||
Vector3 point;
|
||||
point.X = ViewPlane.Min.X + vpdx * (view_point.X + 1.0f) * 0.5f;
|
||||
point.Y = ViewPlane.Min.Y + vpdy * (view_point.Y + 1.0f) * 0.5f;
|
||||
point.Z = -1.0f;
|
||||
|
||||
Matrix3D::Transform_Vector(Transform,point,&dest);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Transform_To_View_Space -- transforms the given world space point to camera sp *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/22/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Transform_To_View_Space(Vector3 & dest,const Vector3 & ws_point) const
|
||||
{
|
||||
Update_Frustum();
|
||||
Matrix3D::Transform_Vector(CameraInvTransform,ws_point,&dest);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Rotate_To_View_Space -- rotates the given world space vector to camera space *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/22/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Rotate_To_View_Space(Vector3 & dest,const Vector3 & ws_vector) const
|
||||
{
|
||||
Update_Frustum();
|
||||
Matrix3D::Rotate_Vector(CameraInvTransform,ws_vector,&dest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Near_Clip_Bounding_Box -- returns an obb that contains near clip plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/25/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
const OBBoxClass & CameraClass::Get_Near_Clip_Bounding_Box(void) const
|
||||
{
|
||||
Update_Frustum();
|
||||
return NearClipBBox;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Cull_Box -- tests whether the given box can be culled *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/8/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CameraClass::Cull_Box(const AABoxClass & box) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_Frustum();
|
||||
return CollisionMath::Overlap_Test(frustum,box) == CollisionMath::OUTSIDE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Update_Frustum -- updates the frustum parameters *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Update_Frustum(void) const
|
||||
{
|
||||
if (FrustumValid) return;
|
||||
|
||||
Vector2 vpmin,vpmax;
|
||||
float znear,zfar;
|
||||
float znear_dist,zfar_dist;
|
||||
|
||||
Matrix3D cam_mat = Get_Transform();
|
||||
Get_View_Plane(vpmin, vpmax); // Normalized view plane at a depth of 1.0
|
||||
Get_Clip_Planes(znear_dist, zfar_dist);
|
||||
|
||||
// Forward is negative Z in our viewspace coordinate system.
|
||||
znear = -znear_dist;
|
||||
zfar = -zfar_dist;
|
||||
|
||||
// Update the frustum
|
||||
FrustumValid = true;
|
||||
Frustum.Init(cam_mat,vpmin,vpmax,znear,zfar);
|
||||
ViewSpaceFrustum.Init(Matrix3D(1),vpmin,vpmax,znear,zfar);
|
||||
|
||||
// Update the OBB around the near clip rectangle
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
NearClipBBox.Center = cam_mat * Vector3(0,0,znear);
|
||||
#else
|
||||
cam_mat.mulVector3(Vector3(0,0,znear), NearClipBBox.Center);
|
||||
#endif
|
||||
NearClipBBox.Extent.X = (vpmax.X - vpmin.X) * (-znear) * 0.5f; // (near_clip_x / |znear|) == (vpmin.X / 1.0f)...
|
||||
NearClipBBox.Extent.Y = (vpmax.Y - vpmin.Y) * (-znear) * 0.5f;
|
||||
NearClipBBox.Extent.Z = 0.01f;
|
||||
NearClipBBox.Basis.Set(cam_mat);
|
||||
|
||||
// Update the inverse camera matrix
|
||||
Transform.Get_Inverse(CameraInvTransform);
|
||||
|
||||
// Update the projection matrix
|
||||
if (Projection == PERSPECTIVE) {
|
||||
|
||||
ProjectionTransform.Init_Perspective( vpmin.X*znear_dist, vpmax.X*znear_dist,
|
||||
vpmin.Y*znear_dist, vpmax.Y*znear_dist,
|
||||
znear_dist, zfar_dist );
|
||||
|
||||
} else {
|
||||
|
||||
ProjectionTransform.Init_Ortho( vpmin.X,vpmax.X,vpmin.Y,vpmax.Y,znear_dist,zfar_dist);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Device_To_View_Space -- converts the given device coordinate to view space *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/8/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Device_To_View_Space(const Vector2 & device_coord,Vector3 * set_view)
|
||||
{
|
||||
int res_width;
|
||||
int res_height;
|
||||
int res_bits;
|
||||
bool windowed;
|
||||
|
||||
WW3D::Get_Render_Target_Resolution(res_width,res_height,res_bits,windowed);
|
||||
|
||||
// convert the device coordinates into normalized device coordinates:
|
||||
Vector2 ndev;
|
||||
ndev.X = device_coord.X / (float)res_width;
|
||||
ndev.Y = device_coord.Y / (float)res_height;
|
||||
|
||||
// view space rectangle which corresponds to the viewport
|
||||
Vector2 vs_min;
|
||||
Vector2 vs_max;
|
||||
Get_View_Plane(vs_min,vs_max);
|
||||
|
||||
// mapping from the viewport coordinates to view space coordinates
|
||||
set_view->X = vs_min.X + (ndev.X - Viewport.Min.X) * (vs_max.X - vs_min.X) / (Viewport.Width());
|
||||
set_view->Y = vs_max.Y - (ndev.Y - Viewport.Min.Y) * (vs_max.Y - vs_min.Y) / (Viewport.Height());
|
||||
set_view->Z = -1.0f;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Device_To_World_Space -- converts given device coord to world space *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/8/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Device_To_World_Space(const Vector2 & device_coord,Vector3 * world_coord)
|
||||
{
|
||||
Vector3 vs;
|
||||
Device_To_View_Space(device_coord,&vs);
|
||||
Matrix3D::Transform_Vector(Transform,vs,world_coord);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Apply -- sets the D3D states controlled by the camera *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/29/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CameraClass::Apply(void)
|
||||
{
|
||||
Update_Frustum();
|
||||
|
||||
int width,height,bits;
|
||||
bool windowed;
|
||||
WW3D::Get_Render_Target_Resolution(width,height,bits,windowed);
|
||||
|
||||
D3DVIEWPORT8 vp;
|
||||
vp.X = (DWORD)(Viewport.Min.X * (float)width);
|
||||
vp.Y = (DWORD)(Viewport.Min.Y * (float)height);
|
||||
vp.Width = (DWORD)((Viewport.Max.X - Viewport.Min.X) * (float)width);
|
||||
vp.Height = (DWORD)((Viewport.Max.Y - Viewport.Min.Y) * (float)height);
|
||||
vp.MinZ = ZBufferMin;
|
||||
vp.MaxZ = ZBufferMax;
|
||||
DX8Wrapper::Set_Viewport(&vp);
|
||||
|
||||
Matrix4 d3dprojection;
|
||||
Get_D3D_Projection_Matrix(&d3dprojection);
|
||||
DX8Wrapper::Set_Transform(D3DTS_PROJECTION,d3dprojection);
|
||||
DX8Wrapper::Set_Transform(D3DTS_VIEW,CameraInvTransform);
|
||||
}
|
||||
|
||||
void CameraClass::Set_Clip_Planes(float znear,float zfar)
|
||||
{
|
||||
FrustumValid = false;
|
||||
ZNear = znear;
|
||||
ZFar = zfar;
|
||||
}
|
||||
|
||||
void CameraClass::Get_Clip_Planes(float & znear,float & zfar) const
|
||||
{
|
||||
znear = ZNear;
|
||||
zfar = ZFar;
|
||||
}
|
||||
|
||||
float CameraClass::Get_Horizontal_FOV(void) const
|
||||
{
|
||||
float width = ViewPlane.Max.X - ViewPlane.Min.X;
|
||||
return 2*WWMath::Atan2(width,2.0);
|
||||
}
|
||||
|
||||
float CameraClass::Get_Vertical_FOV(void) const
|
||||
{
|
||||
float height = ViewPlane.Max.Y - ViewPlane.Min.Y;
|
||||
return 2*WWMath::Atan2(height,2.0);
|
||||
}
|
||||
|
||||
float CameraClass::Get_Aspect_Ratio(void) const
|
||||
{
|
||||
return AspectRatio;
|
||||
}
|
||||
|
||||
void CameraClass::Get_Projection_Matrix(Matrix4 * set_tm)
|
||||
{
|
||||
WWASSERT(set_tm != NULL);
|
||||
|
||||
Update_Frustum();
|
||||
*set_tm = ProjectionTransform;
|
||||
}
|
||||
|
||||
void CameraClass::Get_D3D_Projection_Matrix(Matrix4 * set_tm)
|
||||
{
|
||||
WWASSERT(set_tm != NULL);
|
||||
Update_Frustum();
|
||||
*set_tm = ProjectionTransform;
|
||||
|
||||
/*
|
||||
** We need to flip the handed-ness of the projection matrix and
|
||||
** move the z-range to 0<z<1 rather than -1<z<1
|
||||
*/
|
||||
float oozdiff = 1.0 / (ZFar - ZNear);
|
||||
if (Projection == PERSPECTIVE) {
|
||||
(*set_tm)[2][2] = -(ZFar) * oozdiff;
|
||||
(*set_tm)[2][3] = -(ZFar*ZNear) * oozdiff;
|
||||
} else {
|
||||
(*set_tm)[2][2] = -oozdiff;
|
||||
(*set_tm)[2][3] = -ZNear * oozdiff;
|
||||
}
|
||||
}
|
||||
|
||||
void CameraClass::Get_View_Matrix(Matrix3D * set_tm)
|
||||
{
|
||||
WWASSERT(set_tm != NULL);
|
||||
Update_Frustum();
|
||||
*set_tm = CameraInvTransform;
|
||||
}
|
||||
|
||||
const Matrix4 & CameraClass::Get_Projection_Matrix(void)
|
||||
{
|
||||
Update_Frustum();
|
||||
return ProjectionTransform;
|
||||
}
|
||||
|
||||
const Matrix3D & CameraClass::Get_View_Matrix(void)
|
||||
{
|
||||
Update_Frustum();
|
||||
return CameraInvTransform;
|
||||
}
|
||||
|
||||
void CameraClass::Convert_Old(Vector3 &pos)
|
||||
{
|
||||
pos.X=(pos.X+1)/2;
|
||||
pos.Y=(pos.Y+1)/2;
|
||||
}
|
||||
|
||||
float CameraClass::Compute_Projected_Sphere_Radius(float dist,float radius)
|
||||
{
|
||||
Vector4 result = ProjectionTransform * Vector4(radius,0.0f,dist,1.0f);
|
||||
return result.X / result.W;
|
||||
}
|
||||
453
Generals/Code/Libraries/Source/WWVegas/WW3D2/camera.h
Normal file
453
Generals/Code/Libraries/Source/WWVegas/WW3D2/camera.h
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/camera.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 7/31/01 10:52a $*
|
||||
* *
|
||||
* $Revision:: 13 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CameraClass::Get_Frustum -- returns the frustum of the camera *
|
||||
* CameraClass::Get_Frustum_Planes -- returns pointer to the array of frustum planes *
|
||||
* CameraClass::Get_Frustum_Corners -- returns pointer to the array of frustum corners *
|
||||
* CameraClass::Get_View_Space_Frustum -- returns the view-space frustum for this camera *
|
||||
* CameraClass::Get_View_Space_Frustum_Planes -- returns the view space clip planes for this *
|
||||
* CameraClass::Get_View_Space_Frustum_Corners -- returns the corners of the view space frus *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "always.h"
|
||||
#include "rendobj.h"
|
||||
#include "plane.h"
|
||||
#include "frustum.h"
|
||||
#include "obbox.h"
|
||||
#include "vector2.h"
|
||||
#include "matrix4.h"
|
||||
#include "colmath.h"
|
||||
|
||||
class RenderInfoClass;
|
||||
|
||||
/**
|
||||
** ViewportClass
|
||||
** This class is used to define a "normalized" screen space rectangle for the
|
||||
** camera to render into. A viewport which filled the entire screen would be
|
||||
** (0,0) - (1,1) with 0,0 being the upper left and 1,1 being the lower right.
|
||||
*/
|
||||
class ViewportClass
|
||||
{
|
||||
public:
|
||||
ViewportClass(void) : Min(0,0), Max(1,1) { }
|
||||
ViewportClass(const Vector2 & min,const Vector2 & max) : Min(min), Max(max) { }
|
||||
ViewportClass(const ViewportClass & vp) : Min(vp.Min), Max(vp.Max) { }
|
||||
|
||||
float Width(void) const { return Max.X - Min.X; }
|
||||
float Height(void) const { return Max.Y - Min.Y; }
|
||||
|
||||
Vector2 Min;
|
||||
Vector2 Max;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** CameraClass
|
||||
** This object controls how vertices are transformed from world-space to view
|
||||
** space, the parameters of the perspective projection, and the viewport
|
||||
** on screen that the result is mapped into.
|
||||
**
|
||||
** Cameras are not "rendered" and do not need to be "added" to a scene. A
|
||||
** CameraClass is passed into the WW3D::Render(...) function. The reason
|
||||
** they are render objects is so that they can be inserted onto the bone of
|
||||
** some animation and move with the animation...
|
||||
**
|
||||
** For all of the projection functions (Matrix4, ProjectorClass (used by
|
||||
** decals and texture projections), and CameraClass) I followed the OpenGL
|
||||
** convention of passing positive distances for your clip planes even though
|
||||
** in a right-handed coordinate system your z values are negative after
|
||||
** transformation to camera space. So Set_Clip_Planes expects positive distances
|
||||
** to your near and far clip planes.
|
||||
**
|
||||
** (gth) We should probably separate CameraClass from RenderObjClass... In the
|
||||
** case where a camera is using a transform from an animation; the programmer
|
||||
** is usually requesting the transform and plugging it into the camera anyway.
|
||||
*/
|
||||
class CameraClass : public RenderObjClass
|
||||
{
|
||||
public:
|
||||
|
||||
enum ProjectionType
|
||||
{
|
||||
PERSPECTIVE = 0,
|
||||
ORTHO
|
||||
};
|
||||
|
||||
enum ProjectionResType
|
||||
{
|
||||
INSIDE_FRUSTUM,
|
||||
OUTSIDE_FRUSTUM,
|
||||
OUTSIDE_NEAR_CLIP,
|
||||
OUTSIDE_FAR_CLIP,
|
||||
};
|
||||
|
||||
CameraClass(void);
|
||||
CameraClass(const CameraClass & src);
|
||||
CameraClass & operator = (const CameraClass &);
|
||||
virtual ~CameraClass(void);
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const { return CLASSID_CAMERA; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Rendering, cameras don't "render"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Render(RenderInfoClass & rinfo) { }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - "Scene Graph"
|
||||
// Cameras cache their frustum description, this is invalidated whenever
|
||||
// the transform/position is changed
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Bounding Volumes
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Camera parameter control
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Depth of the scene.
|
||||
float Get_Depth(void) const;
|
||||
|
||||
// Setting the projection type
|
||||
void Set_Projection_Type(ProjectionType ptype);
|
||||
ProjectionType Get_Projection_Type(void);
|
||||
|
||||
// Setting the clipping ranges in world space distances
|
||||
void Set_Clip_Planes(float znear,float zfar);
|
||||
void Get_Clip_Planes(float & znear,float & zfar) const;
|
||||
|
||||
// Setting the zbuffer range used during rendering. (Added to allow subdividing the z-buffer. -MW).
|
||||
void Set_Zbuffer_Range(float znear,float zfar) {ZBufferMin = znear;ZBufferMax=zfar;}
|
||||
void Get_Zbuffer_Range(float & znear,float & zfar) const {znear=ZBufferMin;zfar=ZBufferMax;}
|
||||
|
||||
// Methods for setting the View Plane.
|
||||
// NOTE: View plane is always at a distance of 1.0 from the eye.
|
||||
void Set_View_Plane(const Vector2 & min,const Vector2 & max);
|
||||
void Set_View_Plane(float hfov,float vfov = -1);
|
||||
void Set_Aspect_Ratio(float width_to_height);
|
||||
|
||||
// Methods for querying the View Plane settings.
|
||||
void Get_View_Plane(Vector2 & set_min,Vector2 & set_max) const;
|
||||
float Get_Horizontal_FOV(void) const;
|
||||
float Get_Vertical_FOV(void) const;
|
||||
float Get_Aspect_Ratio(void) const;
|
||||
|
||||
// Access to the projection matrices for this camera
|
||||
void Get_Projection_Matrix(Matrix4 * set_tm);
|
||||
void Get_D3D_Projection_Matrix(Matrix4 * set_tm);
|
||||
void Get_View_Matrix(Matrix3D * set_tm);
|
||||
const Matrix4 & Get_Projection_Matrix(void);
|
||||
const Matrix3D & Get_View_Matrix(void);
|
||||
|
||||
// Projecting and Un-Projecting a point
|
||||
ProjectionResType Project(Vector3 & dest,const Vector3 & ws_point) const;
|
||||
ProjectionResType Project_Camera_Space_Point(Vector3 & dest,const Vector3 & cam_point) const;
|
||||
void Un_Project(Vector3 & dest,const Vector2 & view_point) const;
|
||||
void Transform_To_View_Space(Vector3 & dest,const Vector3 & ws_point) const;
|
||||
void Rotate_To_View_Space(Vector3 & dest,const Vector3 & ws_vector) const;
|
||||
|
||||
// Viewport control
|
||||
void Set_Viewport(const Vector2 & min,const Vector2 & max);
|
||||
void Get_Viewport(Vector2 & set_min,Vector2 & set_max) const;
|
||||
const ViewportClass & Get_Viewport(void) const;
|
||||
|
||||
void Set_Depth_Range(float zstart = 0.0f,float zend = 1.0f);
|
||||
void Get_Depth_Range(float * set_zstart,float * set_zend) const;
|
||||
|
||||
// Culling for various bounding volumes. These functions will return true if the
|
||||
// given primitive is culled (i.e. it is *outside* the view frustum)
|
||||
bool Cull_Sphere(const SphereClass & sphere) const;
|
||||
bool Cull_Sphere_On_Frustum_Sides(const SphereClass & sphere) const;
|
||||
bool Cull_Box(const AABoxClass & box) const;
|
||||
|
||||
// Various properties of the camera's frustum: These funcitons return a
|
||||
// pointer to the internal storage of the descriptions. there will be
|
||||
// 6 frustum planes, 8 corner points, see the implementations of these
|
||||
// functions for definitions on which points/planes are associated with
|
||||
// each index. Better yet, just use the Frustum object.
|
||||
const FrustumClass & Get_Frustum(void) const;
|
||||
const PlaneClass * Get_Frustum_Planes(void) const;
|
||||
const Vector3 * Get_Frustum_Corners(void) const;
|
||||
const FrustumClass & Get_View_Space_Frustum(void) const;
|
||||
const PlaneClass * Get_View_Space_Frustum_Planes(void) const;
|
||||
const Vector3 * Get_View_Space_Frustum_Corners(void) const;
|
||||
const OBBoxClass & Get_Near_Clip_Bounding_Box(void) const;
|
||||
|
||||
// Methods for transforming/projecting points between various coordinate systems
|
||||
// associated with this camera.
|
||||
// "Device Space" - pixel coordinate
|
||||
// "View Space" - 3D space where the view point is at 0,0,0 and the view plane is at z=-1.0
|
||||
// "World Space" - 3D world coordinate system.
|
||||
void Device_To_View_Space(const Vector2 & device_coord,Vector3 * view_coord);
|
||||
void Device_To_World_Space(const Vector2 & device_coord,Vector3 * world_coord);
|
||||
float Compute_Projected_Sphere_Radius(float dist,float radius);
|
||||
|
||||
// apply this camera's settings into d3d.
|
||||
void Apply(void);
|
||||
|
||||
// utility class to convert to old space of 0..1
|
||||
static void Convert_Old(Vector3 &pos);
|
||||
|
||||
protected:
|
||||
|
||||
void Update_Frustum(void) const;
|
||||
|
||||
ProjectionType Projection; // projection type, orthographic or perspective
|
||||
ViewportClass Viewport; // pixel viewport to render into
|
||||
ViewportClass ViewPlane; // corners of a slice through the frustum at z=-1.0
|
||||
float AspectRatio; // aspect ratio of the camera, width / height
|
||||
float ZNear; // near clip plane distance
|
||||
float ZFar; // far clip plane distance
|
||||
float ZBufferMin; // smallest value we'll write into the z-buffer (usually 0.0)
|
||||
float ZBufferMax; // largest value we'll write into the z-buffer (usually 1.0)
|
||||
|
||||
mutable bool FrustumValid;
|
||||
mutable FrustumClass Frustum; // world-space frustum and clip planes
|
||||
mutable FrustumClass ViewSpaceFrustum; // view-space frustum and clip planes
|
||||
mutable OBBoxClass NearClipBBox; // obbox which bounds the near clip plane
|
||||
mutable Matrix4 ProjectionTransform;
|
||||
mutable Matrix3D CameraInvTransform;
|
||||
};
|
||||
|
||||
|
||||
inline float CameraClass::Get_Depth(void) const
|
||||
{
|
||||
return ZFar;
|
||||
}
|
||||
|
||||
inline void CameraClass::Set_Projection_Type(ProjectionType ptype)
|
||||
{
|
||||
FrustumValid = false;
|
||||
Projection = ptype;
|
||||
}
|
||||
|
||||
inline CameraClass::ProjectionType CameraClass::Get_Projection_Type(void)
|
||||
{
|
||||
return Projection;
|
||||
}
|
||||
|
||||
inline void CameraClass::Set_Viewport(const Vector2 & min,const Vector2 & max)
|
||||
{
|
||||
Viewport.Min = min; Viewport.Max = max;
|
||||
FrustumValid = false;
|
||||
}
|
||||
|
||||
inline void CameraClass::Get_Viewport(Vector2 & set_min,Vector2 & set_max) const
|
||||
{
|
||||
set_min = Viewport.Min;
|
||||
set_max = Viewport.Max;
|
||||
}
|
||||
|
||||
inline void CameraClass::Set_Depth_Range(float zmin,float zmax)
|
||||
{
|
||||
ZBufferMin = zmin;
|
||||
ZBufferMax = zmax;
|
||||
}
|
||||
|
||||
inline void CameraClass::Get_Depth_Range(float * set_zmin,float * set_zmax) const
|
||||
{
|
||||
if (set_zmin != NULL) {
|
||||
*set_zmin = ZBufferMin;
|
||||
}
|
||||
if (set_zmax != NULL) {
|
||||
*set_zmax = ZBufferMax;
|
||||
}
|
||||
}
|
||||
|
||||
inline const ViewportClass & CameraClass::Get_Viewport(void) const
|
||||
{
|
||||
return Viewport;
|
||||
}
|
||||
|
||||
inline bool CameraClass::Cull_Sphere(const SphereClass & sphere) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_Frustum();
|
||||
return CollisionMath::Overlap_Test(frustum,sphere) == CollisionMath::OUTSIDE;
|
||||
}
|
||||
|
||||
inline bool CameraClass::Cull_Sphere_On_Frustum_Sides(const SphereClass & sphere) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_Frustum();
|
||||
const PlaneClass * planes = frustum.Planes;
|
||||
bool is_visible = true;
|
||||
for (int i = 1; i < 5; i++) {
|
||||
is_visible = is_visible && (CollisionMath::Overlap_Test(planes[i],sphere) & (CollisionMath::INSIDE|CollisionMath::BOTH));
|
||||
}
|
||||
return !is_visible;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Frustum -- returns the frustum of the camera *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/24/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const FrustumClass &
|
||||
CameraClass::Get_Frustum(void) const
|
||||
{
|
||||
Update_Frustum();
|
||||
return Frustum;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Frustum_Planes -- returns pointer to the array of frustum planes *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const PlaneClass *
|
||||
CameraClass::Get_Frustum_Planes(void) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_Frustum();
|
||||
return frustum.Planes;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_Frustum_Corners -- returns pointer to the array of frustum corners *
|
||||
* *
|
||||
* The camera frustum corner FrustumCorners are defined in the following order *
|
||||
* The first four points lie on the near clipping plane: *
|
||||
* upper left 0, upper right 1, lower left 2, lower right 3. *
|
||||
* The last four points lie on the far clipping plane, numbered analogous fashion. *
|
||||
* upper left 4, upper right 5, lower left 6, lower right 7. *
|
||||
* (remember: the camera space has x going to the right, y up and z backwards). *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/29/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const Vector3 *
|
||||
CameraClass::Get_Frustum_Corners(void) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_Frustum();
|
||||
return frustum.Corners;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_View_Space_Frustum -- returns the view-space frustum for this camera *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/16/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const FrustumClass & CameraClass::Get_View_Space_Frustum(void) const
|
||||
{
|
||||
Update_Frustum();
|
||||
return ViewSpaceFrustum;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_View_Space_Frustum_Planes -- returns the view space clip planes for this c *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/16/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const PlaneClass * CameraClass::Get_View_Space_Frustum_Planes(void) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_View_Space_Frustum();
|
||||
return frustum.Planes;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CameraClass::Get_View_Space_Frustum_Corners -- returns the corners of the view space frustu *
|
||||
* *
|
||||
* The camera frustum corner FrustumCorners are defined in the following order *
|
||||
* The first four points lie on the near clipping plane: *
|
||||
* upper left 0, upper right 1, lower left 2, lower right 3. *
|
||||
* The last four points lie on the far clipping plane, numbered analogous fashion. *
|
||||
* upper left 4, upper right 5, lower left 6, lower right 7. *
|
||||
* (remember: camera space has x going to the right, y up and z backwards). *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/16/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline const Vector3 * CameraClass::Get_View_Space_Frustum_Corners(void) const
|
||||
{
|
||||
const FrustumClass & frustum = Get_View_Space_Frustum();
|
||||
return frustum.Corners;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
65
Generals/Code/Libraries/Source/WWVegas/WW3D2/classid.h
Normal file
65
Generals/Code/Libraries/Source/WWVegas/WW3D2/classid.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Commando *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/classid.h $*
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 3/29/01 1:13a $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CLASSID_H
|
||||
#define CLASSID_H
|
||||
|
||||
#include "always.h"
|
||||
|
||||
/*
|
||||
** enum of all the WW3D class IDs.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
ID_INDIRECT_TEXTURE_CLASS = 0x10000, // IndirectTextureClass "texture.h"
|
||||
ID_VARIABLE_TEXTURE_CLASS, // VariableTextureClass "texture.h"
|
||||
ID_FILE_LIST_TEXTURE_CLASS, // FileListTextureClass "texture.h"
|
||||
ID_RESIZEABLE_TEXTURE_INSTANCE_CLASS, // ResizeableTextureInstanceClass "texture.h"
|
||||
ID_ANIM_TEXTURE_INSTANCE_CLASS, // AnimTextureInstanceClass "texture.h"
|
||||
ID_MANUAL_ANIM_TEXTURE_INSTANCE_CLASS, // ManualAnimTextureInstanceClass "texture.h"
|
||||
ID_TIME_ANIM_TEXTURE_INSTANCE_CLASS, // TimeAnimTextureInstanceClass "texture.h"
|
||||
ID_POINT_GROUP_CLASS, // PointGroupClass "pointgr.h"
|
||||
ID_MESH_MODEL_CLASS, // MeshModelClass "mesh.cpp"
|
||||
ID_CACHED_TEXTURE_FILE_CLASS, // CachedTextureFileClass "assetmgr.cpp"
|
||||
ID_STREAMING_TEXTURE_CLASS, // StreamingTextureClass "texture.h"
|
||||
ID_STREAMING_TEXTURE_INSTANCE_CLASS, // StreamingTextureInstanceClass "texture.h"
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
1109
Generals/Code/Libraries/Source/WWVegas/WW3D2/collect.cpp
Normal file
1109
Generals/Code/Libraries/Source/WWVegas/WW3D2/collect.cpp
Normal file
File diff suppressed because it is too large
Load Diff
149
Generals/Code/Libraries/Source/WWVegas/WW3D2/collect.h
Normal file
149
Generals/Code/Libraries/Source/WWVegas/WW3D2/collect.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/collect.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLLECT_H
|
||||
#define COLLECT_H
|
||||
|
||||
#include "rendobj.h"
|
||||
#include "composite.h"
|
||||
#include "vector.h"
|
||||
#include "proto.h"
|
||||
#include "w3d_file.h"
|
||||
#include "wwstring.h"
|
||||
#include "proxy.h"
|
||||
|
||||
class CollectionDefClass;
|
||||
class SnapPointsClass;
|
||||
|
||||
|
||||
/*
|
||||
** CollectionClass
|
||||
** This is a render object which contains a collection of render objects.
|
||||
*/
|
||||
class CollectionClass : public CompositeRenderObjClass
|
||||
{
|
||||
public:
|
||||
|
||||
CollectionClass(void);
|
||||
CollectionClass(const CollectionDefClass & def);
|
||||
CollectionClass(const CollectionClass & src);
|
||||
CollectionClass & CollectionClass::operator = (const CollectionClass &);
|
||||
virtual ~CollectionClass(void);
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
|
||||
virtual int Class_ID(void) const;
|
||||
virtual int Get_Num_Polys(void) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Proxy interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Get_Proxy_Count (void) const;
|
||||
virtual bool Get_Proxy (int index, ProxyClass &proxy) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Rendering
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - "Scene Graph"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
virtual int Get_Num_Sub_Objects(void) const;
|
||||
virtual RenderObjClass * Get_Sub_Object(int index) const;
|
||||
virtual int Add_Sub_Object(RenderObjClass * subobj);
|
||||
virtual int Remove_Sub_Object(RenderObjClass * robj);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Collision Detection, Ray Tracing
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
virtual bool Intersect_AABox(AABoxIntersectionTestClass & boxtest);
|
||||
virtual bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Bounding Volumes
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Attributes, Options, Properties, etc
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Snap_Point_Count(void);
|
||||
virtual void Get_Snap_Point(int index,Vector3 * set);
|
||||
virtual void Scale(float scale);
|
||||
virtual void Scale(float scalex, float scaley, float scalez);
|
||||
virtual void Update_Obj_Space_Bounding_Volumes(void);
|
||||
|
||||
protected:
|
||||
|
||||
void Free(void);
|
||||
void Update_Sub_Object_Transforms(void);
|
||||
|
||||
DynamicVectorClass <ProxyClass> ProxyList;
|
||||
DynamicVectorClass <RenderObjClass *> SubObjects;
|
||||
SnapPointsClass * SnapPoints;
|
||||
|
||||
SphereClass BoundSphere;
|
||||
AABoxClass BoundBox;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** CollectionLoaderClass
|
||||
** Loader for collection objects
|
||||
*/
|
||||
class CollectionLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Chunk_Type(void) { return W3D_CHUNK_COLLECTION; }
|
||||
virtual PrototypeClass * Load_W3D(ChunkLoadClass & cload);
|
||||
};
|
||||
|
||||
extern CollectionLoaderClass _CollectionLoader;
|
||||
|
||||
#endif
|
||||
153
Generals/Code/Libraries/Source/WWVegas/WW3D2/colorspace.h
Normal file
153
Generals/Code/Libraries/Source/WWVegas/WW3D2/colorspace.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Colorspace *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/ww3d2/colorspace.h $*
|
||||
* *
|
||||
* Original Author:: Hector Yee *
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 8/29/01 9:50p $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLORSPACE_H
|
||||
#define COLORSPACE_H
|
||||
|
||||
#include <wwmath.h>
|
||||
|
||||
void RGB_To_HSV(Vector3 &hsv,const Vector3 &rgb);
|
||||
void HSV_To_RGB(Vector3 &rgb, const Vector3 &hsv);
|
||||
void Recolor(Vector3 &rgb, const Vector3 &hsv_shift);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Color Conversions
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
inline void RGB_To_HSV(Vector3 &hsv,const Vector3 &rgb)
|
||||
// modified from Foley et al. page 592
|
||||
// converts rgb[0..1] to h [0,360), s and v in [0,1]
|
||||
// negative h values are to signify undefined
|
||||
{
|
||||
float max=WWMath::Max(rgb.X,rgb.Y);
|
||||
max=WWMath::Max(max,rgb.Z);
|
||||
float min=WWMath::Min(rgb.X,rgb.Y);
|
||||
min=WWMath::Min(min,rgb.Z);
|
||||
|
||||
// value
|
||||
hsv.Z=max;
|
||||
|
||||
// saturation
|
||||
hsv.Y=(max!=0.0f)?((max-min)/max):0.0f;
|
||||
if (hsv.Y==0.0f) hsv.X=-1.0f;
|
||||
else
|
||||
{
|
||||
float delta=max-min;
|
||||
if (rgb.X==max)
|
||||
hsv.X=(rgb.Y-rgb.Z)/delta;
|
||||
else if (rgb.Y==max)
|
||||
hsv.X=2.0f+ (rgb.Z-rgb.X)/delta;
|
||||
else if (rgb.Z==max)
|
||||
hsv.X=4.0f+ (rgb.X-rgb.Y)/delta;
|
||||
hsv.X*=60.0f;
|
||||
if (hsv.X<0.0f) hsv.X+=360.0f;
|
||||
}
|
||||
}
|
||||
|
||||
inline void HSV_To_RGB(Vector3 &rgb, const Vector3 &hsv)
|
||||
{
|
||||
float h=hsv.X;
|
||||
float s=hsv.Y;
|
||||
float v=hsv.Z;
|
||||
|
||||
if (hsv.Y==0.0f) {
|
||||
rgb.Set(v,v,v);
|
||||
} else {
|
||||
float f,p,q,t;
|
||||
|
||||
int i;
|
||||
|
||||
if (h==360.0f) h=0.0f;
|
||||
|
||||
h/=60.0f;
|
||||
i=WWMath::Floor(h);
|
||||
f=h-i;
|
||||
p=v*(1.0f-s);
|
||||
q=v*(1.0f-(s*f));
|
||||
t=v*(1.0f-(s*(1.0f-f)));
|
||||
switch (i) {
|
||||
case 0:
|
||||
rgb.Set(v,t,p);
|
||||
break;
|
||||
case 1:
|
||||
rgb.Set(q,v,p);
|
||||
break;
|
||||
case 2:
|
||||
rgb.Set(p,v,t);
|
||||
break;
|
||||
case 3:
|
||||
rgb.Set(p,q,v);
|
||||
break;
|
||||
case 4:
|
||||
rgb.Set(t,p,v);
|
||||
break;
|
||||
case 5:
|
||||
rgb.Set(v,p,q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Recolor(Vector3 &rgb, const Vector3 &hsv_shift)
|
||||
{
|
||||
Vector3 hsv;
|
||||
RGB_To_HSV(hsv,rgb);
|
||||
|
||||
// If the Hue has the "undefined flag" (a negative value), this means that the color is pure
|
||||
// monochrome. In this case do not shift the hue (it is undefined) or the saturation (it is 0
|
||||
// so it cannot be decreased, and increasing it would cause the undefined hue to actually
|
||||
// become visible). In this case, we only modify the value.
|
||||
if (hsv.X<0.0f) hsv+=Vector3(0.0f,0.0f,hsv_shift.Z);
|
||||
else hsv+=hsv_shift;
|
||||
|
||||
// angular mod
|
||||
if (hsv.X<0.0f) hsv.X+=360.0f;
|
||||
if (hsv.X>360.0f) hsv.X-=360.0f;
|
||||
// clamp saturation and value
|
||||
hsv.Y=WWMath::Clamp(hsv.Y,0.0f,1.0f);
|
||||
hsv.Z=WWMath::Clamp(hsv.Z,0.0f,1.0f);
|
||||
HSV_To_RGB(rgb,hsv);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
375
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltest.cpp
Normal file
375
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltest.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/coltest.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/07/01 10:26a $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "coltest.h"
|
||||
|
||||
|
||||
AABoxCollisionTestClass::AABoxCollisionTestClass(const AABoxCollisionTestClass & that) :
|
||||
CollisionTestClass(that),
|
||||
Box(that.Box),
|
||||
Move(that.Move),
|
||||
SweepMin(that.SweepMin),
|
||||
SweepMax(that.SweepMax)
|
||||
{
|
||||
}
|
||||
|
||||
AABoxCollisionTestClass::AABoxCollisionTestClass(const AABoxClass & aabox,const Vector3 & move,CastResultStruct * res,int collision_type) :
|
||||
CollisionTestClass(res,collision_type),
|
||||
Box(aabox),
|
||||
Move(move)
|
||||
{
|
||||
SweepMin = Box.Center - Box.Extent;
|
||||
SweepMax = Box.Center + Box.Extent;
|
||||
|
||||
Vector3 endmin = Box.Center + move - Box.Extent;
|
||||
Vector3 endmax = Box.Center + move + Box.Extent;
|
||||
|
||||
if (endmax.X > SweepMax.X) SweepMax.X = endmax.X;
|
||||
if (endmax.Y > SweepMax.Y) SweepMax.Y = endmax.Y;
|
||||
if (endmax.Z > SweepMax.Z) SweepMax.Z = endmax.Z;
|
||||
|
||||
if (endmin.X < SweepMin.X) SweepMin.X = endmin.X;
|
||||
if (endmin.Y < SweepMin.Y) SweepMin.Y = endmin.Y;
|
||||
if (endmin.Z < SweepMin.Z) SweepMin.Z = endmin.Z;
|
||||
}
|
||||
|
||||
|
||||
bool AABoxCollisionTestClass::Cull(const AABoxClass & box)
|
||||
{
|
||||
// const float MOVE_THRESHOLD = 2.0f;
|
||||
// if (WWMath::Fabs(Move.X) + WWMath::Fabs(Move.Y) + WWMath::Fabs(Move.Z) > MOVE_THRESHOLD) {
|
||||
// CastResultStruct res;
|
||||
// return !Box.Cast_To_Box(Move,box,&res);
|
||||
// } else {
|
||||
Vector3 min_corner;
|
||||
Vector3 max_corner;
|
||||
Vector3::Subtract(box.Center,box.Extent,&min_corner);
|
||||
Vector3::Add(box.Center,box.Extent,&max_corner);
|
||||
|
||||
if ((SweepMin.X > max_corner.X) || (SweepMax.X < min_corner.X)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Y > max_corner.Y) || (SweepMax.Y < min_corner.Y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Z > max_corner.Z) || (SweepMax.Z < min_corner.Z)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
void AABoxCollisionTestClass::Rotate(ROTATION_TYPE rotation)
|
||||
{
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
int i;
|
||||
Matrix3D tm(1);
|
||||
switch(rotation) {
|
||||
case ROTATE_NONE:
|
||||
break;
|
||||
case ROTATE_Z90:
|
||||
tm = Matrix3D::RotateZ90;
|
||||
break;
|
||||
case ROTATE_Z180:
|
||||
tm = Matrix3D::RotateZ180;
|
||||
break;
|
||||
case ROTATE_Z270:
|
||||
tm = Matrix3D::RotateZ270;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
Vector3 realcenter = tm * Box.Center;
|
||||
#else
|
||||
Vector3 realcenter;
|
||||
tm.mulVector3(Box.Center, realcenter);
|
||||
#endif
|
||||
|
||||
Vector3 pts[8];
|
||||
Vector3 & min = SweepMin;
|
||||
Vector3 & max = SweepMax;
|
||||
|
||||
pts[0].Set(min.X,min.Y,min.Z);
|
||||
pts[1].Set(min.X,max.Y,min.Z);
|
||||
pts[2].Set(max.X,max.Y,min.Z);
|
||||
pts[3].Set(max.X,min.Y,min.Z);
|
||||
|
||||
pts[4].Set(min.X,min.Y,max.Z);
|
||||
pts[5].Set(min.X,max.Y,max.Z);
|
||||
pts[6].Set(max.X,max.Y,max.Z);
|
||||
pts[7].Set(max.X,min.Y,max.Z);
|
||||
|
||||
// for (i=0; i<8; i++) {
|
||||
// pts[i] = tm * pts[i];
|
||||
// }
|
||||
tm.mulVector3Array(pts, 8);
|
||||
|
||||
Vector3 realmin = pts[0];
|
||||
Vector3 realmax = pts[0];
|
||||
|
||||
for (i=1; i<8; i++) {
|
||||
if (realmin.X >= pts[i].X) realmin.X = pts[i].X;
|
||||
if (realmin.Y >= pts[i].Y) realmin.Y = pts[i].Y;
|
||||
if (realmin.Z >= pts[i].Z) realmin.Z = pts[i].Z;
|
||||
|
||||
if (realmax.X <= pts[i].X) realmax.X = pts[i].X;
|
||||
if (realmax.Y <= pts[i].Y) realmax.Y = pts[i].Y;
|
||||
if (realmax.Z <= pts[i].Z) realmax.Z = pts[i].Z;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// rotate the test by the desired rotation about the Z axis, special cased for
|
||||
// 90 degree rotations about Z. arbitrary rotations cause the axis aligned
|
||||
// box to not be aligned any more :-)
|
||||
float tmp,minx,miny,maxx,maxy;
|
||||
switch(rotation) {
|
||||
case ROTATE_NONE:
|
||||
break;
|
||||
|
||||
case ROTATE_Z90:
|
||||
// rotate the center point and the move vector
|
||||
tmp = Box.Center.X; Box.Center.X = -Box.Center.Y; Box.Center.Y = tmp;
|
||||
tmp = Move.X; Move.X = -Move.Y; Move.Y = tmp;
|
||||
|
||||
// swap x and y for the extent
|
||||
tmp = Box.Extent.X; Box.Extent.X = Box.Extent.Y; Box.Extent.Y = tmp;
|
||||
|
||||
// update sweep bounding box
|
||||
minx = SweepMin.X; miny = SweepMin.Y; maxx = SweepMax.X; maxy = SweepMax.Y;
|
||||
SweepMin.X = -maxy;
|
||||
SweepMin.Y = minx;
|
||||
SweepMax.X = -miny;
|
||||
SweepMax.Y = maxx;
|
||||
break;
|
||||
|
||||
case ROTATE_Z180:
|
||||
// rotate center and move vector
|
||||
Box.Center.X = -Box.Center.X;
|
||||
Box.Center.Y = -Box.Center.Y;
|
||||
Move.X = -Move.X;
|
||||
Move.Y = -Move.Y;
|
||||
|
||||
// update min/max boxes
|
||||
minx = SweepMin.X; miny = SweepMin.Y; maxx = SweepMax.X; maxy = SweepMax.Y;
|
||||
SweepMin.X = -maxx;
|
||||
SweepMin.Y = -maxy;
|
||||
SweepMax.X = -minx;
|
||||
SweepMax.Y = -miny;
|
||||
break;
|
||||
|
||||
case ROTATE_Z270:
|
||||
// rotate center and move.
|
||||
tmp = Box.Center.X; Box.Center.X = Box.Center.Y; Box.Center.Y = -tmp;
|
||||
tmp = Move.X; Move.X = Move.Y; Move.Y = -tmp;
|
||||
|
||||
// update extent (x and y axis swap)
|
||||
tmp = Box.Extent.X; Box.Extent.X = Box.Extent.Y; Box.Extent.Y = tmp;
|
||||
|
||||
// update min/max boxes
|
||||
minx = SweepMin.X; miny = SweepMin.Y; maxx = SweepMax.X; maxy = SweepMax.Y;
|
||||
SweepMin.X = miny;
|
||||
SweepMin.Y = -maxx;
|
||||
SweepMax.X = maxy;
|
||||
SweepMax.Y = -minx;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
assert((Box.Center - realcenter).Length() < 0.001f);
|
||||
assert((SweepMin - realmin).Length() < 0.001f);
|
||||
assert((SweepMax - realmax).Length() < 0.001f);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AABoxCollisionTestClass::Transform(const Matrix3D & tm)
|
||||
{
|
||||
// NOTE: this function will expand the box to enclose the rotated
|
||||
// form of the original box. In practice, this function was only
|
||||
// implemented to double-check the results of the Translate and Rotate
|
||||
// functions.
|
||||
int i;
|
||||
Vector3 tmpcenter = Box.Center;
|
||||
Vector3 tmpextent = Box.Extent;
|
||||
tm.Transform_Center_Extent_AABox(tmpcenter,tmpextent,&Box.Center,&Box.Extent);
|
||||
|
||||
Move = tm.Rotate_Vector(Move);
|
||||
|
||||
Vector3 pts[8];
|
||||
Vector3 & min = SweepMin;
|
||||
Vector3 & max = SweepMax;
|
||||
|
||||
pts[0].Set(min.X,min.Y,min.Z);
|
||||
pts[1].Set(min.X,max.Y,min.Z);
|
||||
pts[2].Set(max.X,max.Y,min.Z);
|
||||
pts[3].Set(max.X,min.Y,min.Z);
|
||||
|
||||
pts[4].Set(min.X,min.Y,max.Z);
|
||||
pts[5].Set(min.X,max.Y,max.Z);
|
||||
pts[6].Set(max.X,max.Y,max.Z);
|
||||
pts[7].Set(max.X,min.Y,max.Z);
|
||||
|
||||
// for (i=0; i<8; i++) {
|
||||
// pts[i] = tm * pts[i];
|
||||
// }
|
||||
tm.mulVector3Array(pts, 8);
|
||||
|
||||
Vector3 realmin = pts[0];
|
||||
Vector3 realmax = pts[0];
|
||||
|
||||
for (i=1; i<8; i++) {
|
||||
if (realmin.X >= pts[i].X) realmin.X = pts[i].X;
|
||||
if (realmin.Y >= pts[i].Y) realmin.Y = pts[i].Y;
|
||||
if (realmin.Z >= pts[i].Z) realmin.Z = pts[i].Z;
|
||||
|
||||
if (realmax.X <= pts[i].X) realmax.X = pts[i].X;
|
||||
if (realmax.Y <= pts[i].Y) realmax.Y = pts[i].Y;
|
||||
if (realmax.Z <= pts[i].Z) realmax.Z = pts[i].Z;
|
||||
}
|
||||
|
||||
SweepMin = realmin;
|
||||
SweepMax = realmax;
|
||||
}
|
||||
|
||||
|
||||
|
||||
OBBoxCollisionTestClass::OBBoxCollisionTestClass
|
||||
(
|
||||
const OBBoxClass & obbox,
|
||||
const Vector3 & move,
|
||||
CastResultStruct * res,
|
||||
int type
|
||||
) :
|
||||
CollisionTestClass(res,type),
|
||||
Box(obbox),
|
||||
Move(move)
|
||||
{
|
||||
Vector3 max_extent;
|
||||
max_extent.X = WWMath::Fabs(Box.Basis[0][0] * Box.Extent.X) +
|
||||
WWMath::Fabs(Box.Basis[0][1] * Box.Extent.Y) +
|
||||
WWMath::Fabs(Box.Basis[0][2] * Box.Extent.Z) + 0.01f;
|
||||
|
||||
max_extent.Y = WWMath::Fabs(Box.Basis[1][0] * Box.Extent.X) +
|
||||
WWMath::Fabs(Box.Basis[1][1] * Box.Extent.Y) +
|
||||
WWMath::Fabs(Box.Basis[1][2] * Box.Extent.Z) + 0.01f;
|
||||
|
||||
max_extent.Z = WWMath::Fabs(Box.Basis[2][0] * Box.Extent.X) +
|
||||
WWMath::Fabs(Box.Basis[2][1] * Box.Extent.Y) +
|
||||
WWMath::Fabs(Box.Basis[2][2] * Box.Extent.Z) + 0.01f;
|
||||
|
||||
SweepMin = Box.Center - max_extent;
|
||||
SweepMax = Box.Center + max_extent;
|
||||
|
||||
Vector3 endmin = Box.Center + move - max_extent;
|
||||
Vector3 endmax = Box.Center + move + max_extent;
|
||||
|
||||
if (endmax.X > SweepMax.X) SweepMax.X = endmax.X;
|
||||
if (endmax.Y > SweepMax.Y) SweepMax.Y = endmax.Y;
|
||||
if (endmax.Z > SweepMax.Z) SweepMax.Z = endmax.Z;
|
||||
|
||||
if (endmin.X < SweepMin.X) SweepMin.X = endmin.X;
|
||||
if (endmin.Y < SweepMin.Y) SweepMin.Y = endmin.Y;
|
||||
if (endmin.Z < SweepMin.Z) SweepMin.Z = endmin.Z;
|
||||
}
|
||||
|
||||
OBBoxCollisionTestClass::OBBoxCollisionTestClass(const OBBoxCollisionTestClass & that) :
|
||||
CollisionTestClass(that),
|
||||
Box(that.Box),
|
||||
Move(that.Move),
|
||||
SweepMin(that.SweepMin),
|
||||
SweepMax(that.SweepMax)
|
||||
{
|
||||
}
|
||||
|
||||
OBBoxCollisionTestClass::OBBoxCollisionTestClass
|
||||
(
|
||||
const OBBoxCollisionTestClass & that,
|
||||
const Matrix3D & tm
|
||||
) :
|
||||
CollisionTestClass(that)
|
||||
{
|
||||
tm.Transform_Min_Max_AABox(that.SweepMin,that.SweepMax,&SweepMin,&SweepMax);
|
||||
Matrix3D::Rotate_Vector(tm,that.Move,&Move);
|
||||
OBBoxClass::Transform(tm,that.Box,&Box);
|
||||
}
|
||||
|
||||
OBBoxCollisionTestClass::OBBoxCollisionTestClass
|
||||
(
|
||||
const AABoxCollisionTestClass & that,
|
||||
const Matrix3D & tm
|
||||
) :
|
||||
CollisionTestClass(that)
|
||||
{
|
||||
tm.Transform_Min_Max_AABox(that.SweepMin,that.SweepMax,&SweepMin,&SweepMax);
|
||||
Matrix3D::Rotate_Vector(tm,that.Move,&Move);
|
||||
Matrix3D::Transform_Vector(tm,that.Box.Center,&(Box.Center));
|
||||
Box.Extent = that.Box.Extent;
|
||||
Box.Basis = tm; // copies the 3x3 rotation portion of the transform
|
||||
}
|
||||
|
||||
|
||||
bool OBBoxCollisionTestClass::Cull(const AABoxClass & box)
|
||||
{
|
||||
Vector3 min_corner;
|
||||
Vector3 max_corner;
|
||||
Vector3::Subtract(box.Center,box.Extent,&min_corner);
|
||||
Vector3::Add(box.Center,box.Extent,&max_corner);
|
||||
|
||||
if ((SweepMin.X > max_corner.X) || (SweepMax.X < min_corner.X)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Y > max_corner.Y) || (SweepMax.Y < min_corner.Y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Z > max_corner.Z) || (SweepMax.Z < min_corner.Z)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
314
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltest.h
Normal file
314
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltest.h
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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:: /VSS_Sync/ww3d2/coltest.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 8/29/01 7:29p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLTEST_H
|
||||
#define COLTEST_H
|
||||
|
||||
#include "always.h"
|
||||
#include "castres.h"
|
||||
#include "lineseg.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "tri.h"
|
||||
#include "colmath.h"
|
||||
#include "coltype.h"
|
||||
|
||||
class RenderObjClass;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CollisionTestClass
|
||||
//
|
||||
// Each type of collision test will have an associated class which
|
||||
// ties together all of the information necessary for the test.
|
||||
// These classes also provide a perfect place to add any information
|
||||
// which can be pre-calculated.
|
||||
//
|
||||
// The base class: CollisionTestClass simply contains a pointer to
|
||||
// the user's CastResultStruct which will contain the results of
|
||||
// the collision test. I store a pointer to a result structure
|
||||
// because in some cases, new CollisionTestClasses are created in
|
||||
// the process of checking (e.g. if the test needs to be transformed
|
||||
// into another coordinate system) and I did not want to be
|
||||
// constantly copying the result structure around. So, the user
|
||||
// must allocate a result structure (usually on the stack) and keep it
|
||||
// until the CollisionTestClass is discarded.
|
||||
//
|
||||
// Every CollisionTestClass should have the following functions:
|
||||
//
|
||||
// bool Cull(const Vector3 & min,const Vector3 & max);
|
||||
// bool Cull(const AABoxClass & box);
|
||||
// bool Cast_To_Triangle(const TriClass & tri);
|
||||
//
|
||||
// These are not virtual because I don't want to pay the price of virtual function
|
||||
// calls at the point in the code where these are used. It may be possible to
|
||||
// write template functions if we use these exact function prototpyes for all
|
||||
// collision test classes though.
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class CollisionTestClass
|
||||
{
|
||||
public:
|
||||
CollisionTestClass(CastResultStruct * res,int collision_type);
|
||||
CollisionTestClass(const CollisionTestClass & that);
|
||||
|
||||
public:
|
||||
CastResultStruct * Result;
|
||||
int CollisionType;
|
||||
RenderObjClass * CollidedRenderObj;
|
||||
};
|
||||
|
||||
|
||||
inline CollisionTestClass::CollisionTestClass(CastResultStruct * res,int collision_type) :
|
||||
Result(res),
|
||||
CollisionType(collision_type),
|
||||
CollidedRenderObj(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
inline CollisionTestClass::CollisionTestClass(const CollisionTestClass & that) :
|
||||
Result(that.Result),
|
||||
CollisionType(that.CollisionType),
|
||||
CollidedRenderObj(that.CollidedRenderObj)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RayCollisionTestClass
|
||||
//
|
||||
// Contains a linesegment to be tested and of course the inherited
|
||||
// pointer to a CollisionStruct for the result
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class RayCollisionTestClass : public CollisionTestClass
|
||||
{
|
||||
public:
|
||||
|
||||
RayCollisionTestClass(const LineSegClass & ray,CastResultStruct * res,int collision_type = COLLISION_TYPE_0,bool check_translucent=false, bool check_hidden=false);
|
||||
RayCollisionTestClass(const RayCollisionTestClass & raytest,const Matrix3D & tm);
|
||||
|
||||
bool Cull(const Vector3 & min,const Vector3 & max);
|
||||
bool Cull(const AABoxClass & box);
|
||||
bool Cast_To_Triangle(const TriClass & tri);
|
||||
|
||||
public:
|
||||
|
||||
LineSegClass Ray;
|
||||
bool CheckTranslucent;
|
||||
bool CheckHidden;
|
||||
|
||||
private:
|
||||
|
||||
// not implemented
|
||||
RayCollisionTestClass(const RayCollisionTestClass &);
|
||||
RayCollisionTestClass & operator = (const RayCollisionTestClass &);
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline RayCollisionTestClass::RayCollisionTestClass(const LineSegClass & ray,CastResultStruct * res,int collision_type,bool check_translucent, bool check_hidden) :
|
||||
CollisionTestClass(res,collision_type),
|
||||
Ray(ray),
|
||||
CheckTranslucent(check_translucent),
|
||||
CheckHidden(check_hidden)
|
||||
{
|
||||
}
|
||||
|
||||
inline RayCollisionTestClass::RayCollisionTestClass(const RayCollisionTestClass & raytest,const Matrix3D & tm) :
|
||||
CollisionTestClass(raytest),
|
||||
Ray(raytest.Ray,tm),
|
||||
CheckTranslucent(raytest.CheckTranslucent),
|
||||
CheckHidden(raytest.CheckHidden)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool RayCollisionTestClass::Cull(const Vector3 & min,const Vector3 & max)
|
||||
{
|
||||
return (CollisionMath::Overlap_Test(min,max,Ray) == CollisionMath::POS);
|
||||
}
|
||||
|
||||
inline bool RayCollisionTestClass::Cull(const AABoxClass & box)
|
||||
{
|
||||
return (CollisionMath::Overlap_Test(box,Ray) == CollisionMath::POS);
|
||||
}
|
||||
|
||||
inline bool RayCollisionTestClass::Cast_To_Triangle(const TriClass & tri)
|
||||
{
|
||||
return CollisionMath::Collide(Ray,tri,Result);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AABoxCollisionTestClass
|
||||
//
|
||||
// Contains an Axis Aligned Box and a movement vector to be tested
|
||||
// for collision. Also adds Min and Max vectors both for the initial
|
||||
// box and for the volume swept out by the box.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class AABoxCollisionTestClass : public CollisionTestClass
|
||||
{
|
||||
public:
|
||||
|
||||
AABoxCollisionTestClass(const AABoxClass & aabox,const Vector3 & move,CastResultStruct * res,int collision_type = COLLISION_TYPE_0);
|
||||
AABoxCollisionTestClass(const AABoxCollisionTestClass & that);
|
||||
|
||||
enum ROTATION_TYPE
|
||||
{
|
||||
ROTATE_NONE = 0,
|
||||
ROTATE_Z90,
|
||||
ROTATE_Z180,
|
||||
ROTATE_Z270
|
||||
};
|
||||
|
||||
bool Cull(const Vector3 & min,const Vector3 & max);
|
||||
bool Cull(const AABoxClass & box);
|
||||
bool Cast_To_Triangle(const TriClass & tri);
|
||||
|
||||
void Translate(const Vector3 & translation);
|
||||
void Rotate(ROTATION_TYPE rotation);
|
||||
void Transform(const Matrix3D & tm);
|
||||
|
||||
public:
|
||||
|
||||
AABoxClass Box;
|
||||
Vector3 Move;
|
||||
|
||||
Vector3 SweepMin;
|
||||
Vector3 SweepMax;
|
||||
|
||||
private:
|
||||
|
||||
// not implemented
|
||||
AABoxCollisionTestClass & operator = (const AABoxCollisionTestClass &);
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline void AABoxCollisionTestClass::Translate(const Vector3 & translation)
|
||||
{
|
||||
// translate the test by the desired translation vector
|
||||
Box.Center += translation;
|
||||
SweepMin += translation;
|
||||
SweepMax += translation;
|
||||
}
|
||||
|
||||
inline bool AABoxCollisionTestClass::Cull(const Vector3 & min,const Vector3 & max)
|
||||
{
|
||||
if ((SweepMin.X > max.X) || (SweepMax.X < min.X)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Y > max.Y) || (SweepMax.Y < min.Y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Z > max.Z) || (SweepMax.Z < min.Z)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool AABoxCollisionTestClass::Cast_To_Triangle(const TriClass & tri)
|
||||
{
|
||||
return CollisionMath::Collide(Box,Move,tri,Result);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// OBBoxCollisionTestClass
|
||||
//
|
||||
// Contains an Oriented Bounding Box and a movement vector to be tested
|
||||
// for collision. Also adds Min and Max vectors (axis aligned box)
|
||||
// both for the initial box and for the volume swept out by the box.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class OBBoxCollisionTestClass : public CollisionTestClass
|
||||
{
|
||||
public:
|
||||
|
||||
OBBoxCollisionTestClass(const OBBoxClass & obbox,const Vector3 & move,CastResultStruct * res,int type = COLLISION_TYPE_0);
|
||||
OBBoxCollisionTestClass(const OBBoxCollisionTestClass & that);
|
||||
OBBoxCollisionTestClass(const OBBoxCollisionTestClass & that,const Matrix3D & tm);
|
||||
OBBoxCollisionTestClass(const AABoxCollisionTestClass & that,const Matrix3D & tm);
|
||||
|
||||
bool Cull(const Vector3 & min,const Vector3 & max);
|
||||
bool Cull(const AABoxClass & box);
|
||||
bool Cast_To_Triangle(const TriClass & tri);
|
||||
|
||||
public:
|
||||
|
||||
OBBoxClass Box;
|
||||
Vector3 Move;
|
||||
Vector3 SweepMin;
|
||||
Vector3 SweepMax;
|
||||
|
||||
private:
|
||||
// not implemented
|
||||
OBBoxCollisionTestClass & operator = (const OBBoxCollisionTestClass &);
|
||||
};
|
||||
|
||||
|
||||
inline bool OBBoxCollisionTestClass::Cull(const Vector3 & min,const Vector3 & max)
|
||||
{
|
||||
if ((SweepMin.X > max.X) || (SweepMax.X < min.X)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Y > max.Y) || (SweepMax.Y < min.Y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((SweepMin.Z > max.Z) || (SweepMax.Z < min.Z)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool OBBoxCollisionTestClass::Cast_To_Triangle(const TriClass & tri)
|
||||
{
|
||||
return CollisionMath::Collide(Box,Move,tri,Vector3(0,0,0),Result);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
93
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltype.h
Normal file
93
Generals/Code/Libraries/Source/WWVegas/WW3D2/coltype.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/coltype.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef COLTYPE_H
|
||||
#define COLTYPE_H
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Collision 'Types'
|
||||
//
|
||||
// This enum defines the collision type bit-field that is used in render object
|
||||
// collision detection.
|
||||
//
|
||||
// The collision type field in a collision or intersection test is used as a
|
||||
// low-level collision mask. It will be 'AND'ed with the collision type of
|
||||
// the render object and will ignore the object unless the result is
|
||||
// non-zero. In Commando, we use this to implement separate collision
|
||||
// representations for "physical" collisions versus "projectile"
|
||||
// collisions. I.e. we use a very simple mesh for the character's
|
||||
// physical collision and a more complex set of meshes for checking whether
|
||||
// a bullet hits a person. This masking system is not meant to be a general
|
||||
// "collision grouping" system. You should use a higher level system for doing
|
||||
// things like making bullets ignore each other, etc.
|
||||
//
|
||||
// One more wrinkle to the system: The collision type in the render obj
|
||||
// will always have the LSB set (COLLISION_TYPE_ALL) so that you can always
|
||||
// do queries against every piece of geometry in a render obj if desired.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
enum
|
||||
{
|
||||
COLLISION_TYPE_ALL = 0x01, // perform this test against *EVERYTHING*
|
||||
COLLISION_TYPE_0 = 0x02, // perform this test against type 0 collision objects
|
||||
COLLISION_TYPE_1 = 0x04, // perform this test against type 1 collision objects
|
||||
COLLISION_TYPE_2 = 0x08,
|
||||
COLLISION_TYPE_3 = 0x10,
|
||||
COLLISION_TYPE_4 = 0x20,
|
||||
COLLISION_TYPE_5 = 0x40,
|
||||
COLLISION_TYPE_6 = 0x80,
|
||||
|
||||
COLLISION_TYPE_PHYSICAL = COLLISION_TYPE_0, // physics collisions
|
||||
COLLISION_TYPE_PROJECTILE = COLLISION_TYPE_1, // projectile collisions
|
||||
COLLISION_TYPE_VIS = COLLISION_TYPE_2, // "vis node" detection
|
||||
COLLISION_TYPE_CAMERA = COLLISION_TYPE_3, // camera collision (99% should match physical setting)
|
||||
COLLISION_TYPE_VEHICLE = COLLISION_TYPE_4, // vehicles will collide with physical and this.
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
567
Generals/Code/Libraries/Source/WWVegas/WW3D2/composite.cpp
Normal file
567
Generals/Code/Libraries/Source/WWVegas/WW3D2/composite.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/composite.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/30/01 2:10p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CompositeRenderObjClass::CompositeRenderObjClass -- Constructor *
|
||||
* CompositeRenderObjClass::CompositeRenderObjClass -- copy constructor *
|
||||
* CompositeRenderObjClass::~CompositeRenderObjClass -- Destructor *
|
||||
* CompositeRenderObjClass::operator -- assignment operator *
|
||||
* CompositeRenderObjClass::Restart -- Recursively call Restart on all sub-objects *
|
||||
* CompositeRenderObjClass::Get_Name -- returns the name of this render object *
|
||||
* CompositeRenderObjClass::Set_Name -- sets the name of this render object *
|
||||
* CompositeRenderObjClass::Set_Base_Model_Name -- sets the "base-model-name" *
|
||||
* CompositeRenderObjClass::Get_Num_Polys -- returns the number of polys *
|
||||
* CompositeRenderObjClass::Notify_Added -- notify all sub-objects that they were added *
|
||||
* CompositeRenderObjClass::Notify_Removed -- notifies all subobjs they were removed from th *
|
||||
* CompositeRenderObjClass::Cast_Ray -- cast a ray against this object *
|
||||
* CompositeRenderObjClass::Cast_AABox -- cast a swept AABox against this object *
|
||||
* CompositeRenderObjClass::Cast_OBBox -- cast a swept OBBox against this object *
|
||||
* CompositeRenderObjClass::Intersect_AABox -- intersect this object with an AABox *
|
||||
* CompositeRenderObjClass::Intersect_OBBox -- intersect this object with an OBBox *
|
||||
* CompositeRenderObjClass::Create_Decal -- create a decal on this object *
|
||||
* CompositeRenderObjClass::Delete_Decal -- remove a logical decal from this object *
|
||||
* CompositeRenderObjClass::Update_Obj_Space_Bounding_Volumes -- updates the object-space BV *
|
||||
* CompositeRenderObjClass::Set_User_Data -- set the userdata pointer *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "composite.h"
|
||||
#include "wwdebug.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::CompositeRenderObjClass -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
CompositeRenderObjClass::CompositeRenderObjClass(void) :
|
||||
Name(NULL),
|
||||
BaseModelName(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::CompositeRenderObjClass -- copy constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CompositeRenderObjClass::CompositeRenderObjClass(const CompositeRenderObjClass & that) :
|
||||
Name(NULL),
|
||||
BaseModelName(NULL)
|
||||
{
|
||||
Set_Name(that.Get_Name());
|
||||
Set_Base_Model_Name(that.Get_Base_Model_Name());
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::~CompositeRenderObjClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CompositeRenderObjClass::~CompositeRenderObjClass(void)
|
||||
{
|
||||
if (Name) free(Name);
|
||||
if (BaseModelName) free(BaseModelName);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::operator -- assignment operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CompositeRenderObjClass & CompositeRenderObjClass::operator = (const CompositeRenderObjClass & that)
|
||||
{
|
||||
Set_Name(that.Get_Name());
|
||||
Set_Base_Model_Name(that.Get_Base_Model_Name());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Restart -- Recursively call Restart on all sub-objects *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/30/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Restart(void)
|
||||
{
|
||||
for (int ni = 0; ni < Get_Num_Sub_Objects(); ni++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(ni);
|
||||
WWASSERT(robj);
|
||||
robj->Restart();
|
||||
robj->Release_Ref();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Get_Name -- returns the name of this render object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
const char * CompositeRenderObjClass::Get_Name(void) const
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Set_Name -- sets the name of this render object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Set_Name(const char * name)
|
||||
{
|
||||
if (Name) {
|
||||
free(Name);
|
||||
Name = NULL;
|
||||
}
|
||||
if (name) {
|
||||
Name = strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Set_Base_Model_Name -- sets the "base-model-name" *
|
||||
* *
|
||||
* The base-model-name was needed by the aggregate code. Ask Patrick Smith about it :-) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Set_Base_Model_Name(const char *name)
|
||||
{
|
||||
if (BaseModelName) {
|
||||
free(BaseModelName);
|
||||
BaseModelName = NULL;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
BaseModelName = ::strdup(name);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Get_Num_Polys -- returns the number of polys *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
int CompositeRenderObjClass::Get_Num_Polys(void) const
|
||||
{
|
||||
int count = 0;
|
||||
for (int ni = 0; ni < Get_Num_Sub_Objects(); ni++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(ni);
|
||||
WWASSERT(robj);
|
||||
count += robj->Get_Num_Polys();
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Notify_Added -- notify all sub-objects that they were added *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Notify_Added(SceneClass * scene)
|
||||
{
|
||||
RenderObjClass::Notify_Added(scene);
|
||||
for (int ni = 0; ni < Get_Num_Sub_Objects(); ni++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(ni);
|
||||
WWASSERT(robj);
|
||||
robj->Notify_Added(scene);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Notify_Removed -- notifies all subobjs they were removed from the *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Notify_Removed(SceneClass * scene)
|
||||
{
|
||||
for (int ni = 0; ni < Get_Num_Sub_Objects(); ni++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(ni);
|
||||
WWASSERT(robj);
|
||||
robj->Notify_Removed(scene);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
RenderObjClass::Notify_Removed(scene);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Cast_Ray -- cast a ray against this object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CompositeRenderObjClass::Cast_Ray(RayCollisionTestClass & raytest)
|
||||
{
|
||||
bool res = false;
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
res |= robj->Cast_Ray(raytest);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Cast_AABox -- cast a swept AABox against this object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CompositeRenderObjClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
|
||||
{
|
||||
bool res = false;
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
res |= robj->Cast_AABox(boxtest);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Cast_OBBox -- cast a swept OBBox against this object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CompositeRenderObjClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
|
||||
{
|
||||
bool res = false;
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
res |= robj->Cast_OBBox(boxtest);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Intersect_AABox -- intersect this object with an AABox *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CompositeRenderObjClass::Intersect_AABox(AABoxIntersectionTestClass & boxtest)
|
||||
{
|
||||
bool res = false;
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
res |= robj->Intersect_AABox(boxtest);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Intersect_OBBox -- intersect this object with an OBBox *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CompositeRenderObjClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
|
||||
{
|
||||
bool res = false;
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
res |= robj->Intersect_OBBox(boxtest);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Create_Decal -- create a decal on this object *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Create_Decal(DecalGeneratorClass * generator)
|
||||
{
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
robj->Create_Decal(generator);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Delete_Decal -- remove a logical decal from this object *
|
||||
* *
|
||||
* This internally removes all decals with the given ID. The ID comes from the generator *
|
||||
* which was used to create the decals. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Delete_Decal(uint32 decal_id)
|
||||
{
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
robj->Delete_Decal(decal_id);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Update_Obj_Space_Bounding_Volumes -- updates the object-space BVs *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Update_Obj_Space_Bounding_Volumes(void)
|
||||
{
|
||||
int i;
|
||||
RenderObjClass * robj = NULL;
|
||||
|
||||
// if we don't have any sub objects, just set default bounds
|
||||
if (Get_Num_Sub_Objects() <= 0) {
|
||||
ObjSphere.Init(Vector3(0,0,0),0);
|
||||
ObjBox.Center.Set(0,0,0);
|
||||
ObjBox.Extent.Set(0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
AABoxClass obj_aabox;
|
||||
MinMaxAABoxClass box;
|
||||
SphereClass sphere;
|
||||
|
||||
// loop through all sub-objects, combining their object-space bounding spheres and boxes.
|
||||
robj = Get_Sub_Object(0);
|
||||
WWASSERT(robj);
|
||||
robj->Get_Obj_Space_Bounding_Sphere(ObjSphere);
|
||||
robj->Get_Obj_Space_Bounding_Box(obj_aabox);
|
||||
robj->Release_Ref();
|
||||
box.Init(obj_aabox);
|
||||
|
||||
for (i=1; i<Get_Num_Sub_Objects(); i++) {
|
||||
|
||||
robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
|
||||
robj->Get_Obj_Space_Bounding_Sphere(sphere);
|
||||
robj->Get_Obj_Space_Bounding_Box(obj_aabox);
|
||||
|
||||
ObjSphere.Add_Sphere(sphere);
|
||||
box.Add_Box(obj_aabox);
|
||||
|
||||
robj->Release_Ref();
|
||||
}
|
||||
|
||||
ObjBox.Init(box);
|
||||
|
||||
Invalidate_Cached_Bounding_Volumes();
|
||||
|
||||
// Now update the object space bounding volumes of this object's container:
|
||||
RenderObjClass *container = Get_Container();
|
||||
if (container) container->Update_Obj_Space_Bounding_Volumes();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CompositeRenderObjClass::Set_User_Data -- set the userdata *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CompositeRenderObjClass::Set_User_Data(void *value, bool recursive)
|
||||
{
|
||||
RenderObjClass::Set_User_Data(value);
|
||||
if (recursive) {
|
||||
for (int i=0; i<Get_Num_Sub_Objects(); i++) {
|
||||
RenderObjClass * robj = Get_Sub_Object(i);
|
||||
WWASSERT(robj);
|
||||
robj->Set_User_Data(value,recursive);
|
||||
robj->Release_Ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
98
Generals/Code/Libraries/Source/WWVegas/WW3D2/composite.h
Normal file
98
Generals/Code/Libraries/Source/WWVegas/WW3D2/composite.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/composite.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/30/01 2:17p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COMPOSITE_H
|
||||
#define COMPOSITE_H
|
||||
|
||||
#include "rendobj.h"
|
||||
|
||||
/*
|
||||
** CompositeRenderObjClass
|
||||
** The sole purpose of this class is to encapsulate some of the chores that all
|
||||
** "composite" (contain sub objects) render objects have to do. Typically all
|
||||
** of the functions are implemented through the existing sub-object interface
|
||||
** so there is still no assumption on how you store/organize your sub-objects.
|
||||
*/
|
||||
class CompositeRenderObjClass : public RenderObjClass
|
||||
{
|
||||
public:
|
||||
|
||||
CompositeRenderObjClass(void);
|
||||
CompositeRenderObjClass(const CompositeRenderObjClass & that);
|
||||
virtual ~CompositeRenderObjClass(void);
|
||||
CompositeRenderObjClass & operator = (const CompositeRenderObjClass & that);
|
||||
|
||||
virtual void Restart(void);
|
||||
|
||||
virtual const char * Get_Name(void) const;
|
||||
virtual void Set_Name(const char * name);
|
||||
virtual const char * Get_Base_Model_Name (void) const { return BaseModelName; }
|
||||
virtual void Set_Base_Model_Name (const char *name);
|
||||
virtual int Get_Num_Polys(void) const;
|
||||
virtual void Notify_Added(SceneClass * scene);
|
||||
virtual void Notify_Removed(SceneClass * scene);
|
||||
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
virtual bool Intersect_AABox(AABoxIntersectionTestClass & boxtest);
|
||||
virtual bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
virtual void Create_Decal(DecalGeneratorClass * generator);
|
||||
virtual void Delete_Decal(uint32 decal_id);
|
||||
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const { sphere = ObjSphere; }
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const { box = ObjBox; }
|
||||
virtual void Update_Obj_Space_Bounding_Volumes(void);
|
||||
|
||||
virtual void Set_User_Data(void *value, bool recursive = false);
|
||||
|
||||
protected:
|
||||
|
||||
char * Name; // name of the render object
|
||||
char * BaseModelName; // name of the original render obj (before aggregation)
|
||||
SphereClass ObjSphere; // object-space bounding sphere
|
||||
AABoxClass ObjBox; // object-space bounding box
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
1625
Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp
Normal file
1625
Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
392
Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.h
Normal file
392
Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DAZZLE_H
|
||||
#define DAZZLE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "matrix3d.h"
|
||||
#include "rendobj.h"
|
||||
#include "wwstring.h"
|
||||
#include "proto.h"
|
||||
#include "w3derr.h"
|
||||
#include "shader.h"
|
||||
#include "matrix4.h"
|
||||
|
||||
class CameraClass;
|
||||
class DazzleVisibilityClass;
|
||||
struct VertexFormatXYZNDUV2;
|
||||
|
||||
class DazzleInitClass
|
||||
{
|
||||
public:
|
||||
unsigned type;
|
||||
bool use_camera_translation;
|
||||
StringClass primary_texture_name;
|
||||
StringClass secondary_texture_name;
|
||||
StringClass lensflare_name;
|
||||
float halo_size_pow;
|
||||
float halo_intensity_pow;
|
||||
float halo_intensity;
|
||||
float halo_area;
|
||||
float halo_scale_x;
|
||||
float halo_scale_y;
|
||||
float dazzle_size_pow;
|
||||
float dazzle_intensity_pow;
|
||||
float dazzle_intensity;
|
||||
float dazzle_area;
|
||||
float dazzle_direction_area;
|
||||
Vector3 dazzle_direction;
|
||||
Vector3 dazzle_test_color;
|
||||
Vector3 dazzle_color;
|
||||
Vector3 halo_color;
|
||||
float dazzle_scale_x;
|
||||
float dazzle_scale_y;
|
||||
float fadeout_start;
|
||||
float fadeout_end;
|
||||
float size_optimization_limit;
|
||||
float history_weight;
|
||||
float radius;
|
||||
float blink_period;
|
||||
float blink_on_time;
|
||||
};
|
||||
|
||||
class LensflareInitClass
|
||||
{
|
||||
public:
|
||||
LensflareInitClass()
|
||||
:
|
||||
flare_locations(0),
|
||||
flare_sizes(0),
|
||||
flare_colors(0),
|
||||
flare_uv(0)
|
||||
{
|
||||
}
|
||||
|
||||
LensflareInitClass(const LensflareInitClass& lic)
|
||||
:
|
||||
type(lic.type),
|
||||
texture_name(lic.texture_name),
|
||||
flare_count(lic.flare_count),
|
||||
flare_locations(0),
|
||||
flare_sizes(0),
|
||||
flare_colors(0),
|
||||
flare_uv(0)
|
||||
{
|
||||
if (flare_count) {
|
||||
flare_locations=W3DNEWARRAY float[flare_count];
|
||||
memcpy(flare_locations,lic.flare_locations,sizeof(float)*flare_count);
|
||||
flare_sizes=W3DNEWARRAY float[flare_count];
|
||||
memcpy(flare_sizes,lic.flare_sizes,sizeof(float)*flare_count);
|
||||
flare_colors=W3DNEWARRAY Vector3[flare_count];
|
||||
memcpy(flare_colors,lic.flare_colors,sizeof(Vector3)*flare_count);
|
||||
flare_uv=W3DNEWARRAY Vector4[flare_count];
|
||||
memcpy(flare_uv,lic.flare_uv,sizeof(Vector4)*flare_count);
|
||||
}
|
||||
}
|
||||
|
||||
~LensflareInitClass()
|
||||
{
|
||||
delete[] flare_locations;
|
||||
delete[] flare_sizes;
|
||||
delete[] flare_colors;
|
||||
delete[] flare_uv;
|
||||
}
|
||||
|
||||
unsigned type;
|
||||
StringClass texture_name;
|
||||
int flare_count;
|
||||
float* flare_locations;
|
||||
float* flare_sizes;
|
||||
Vector3* flare_colors;
|
||||
Vector4* flare_uv;
|
||||
|
||||
};
|
||||
|
||||
class DazzleRenderObjClass;
|
||||
class DazzleLayerClass;
|
||||
class DazzleTypeClass
|
||||
{
|
||||
friend DazzleRenderObjClass;
|
||||
friend DazzleLayerClass;
|
||||
|
||||
TextureClass* primary_texture;
|
||||
TextureClass* secondary_texture;
|
||||
DazzleInitClass ic;
|
||||
float fadeout_end_sqr;
|
||||
float fadeout_start_sqr;
|
||||
StringClass name;
|
||||
unsigned dazzle_test_color_integer;
|
||||
unsigned dazzle_test_mask_integer;
|
||||
unsigned lensflare_id;
|
||||
|
||||
ShaderClass dazzle_shader;
|
||||
ShaderClass halo_shader;
|
||||
|
||||
float radius;
|
||||
|
||||
DazzleTypeClass(const DazzleInitClass& is);
|
||||
virtual ~DazzleTypeClass();
|
||||
public:
|
||||
|
||||
virtual void Calculate_Intensities(
|
||||
float& dazzle_intensity,
|
||||
float& dazzle_size,
|
||||
float& halo_intensity,
|
||||
const Vector3& camera_dir,
|
||||
const Vector3& dazzle_dir,
|
||||
float distance) const;
|
||||
|
||||
void Set_Dazzle_Shader(const ShaderClass& s); // Set shader for the dazzle type
|
||||
void Set_Halo_Shader(const ShaderClass& s); // Set shader for the dazzle type
|
||||
|
||||
TextureClass* Get_Dazzle_Texture();
|
||||
TextureClass* Get_Halo_Texture();
|
||||
|
||||
};
|
||||
|
||||
|
||||
// The DazzleLayerClass is for all the dazzles being rendered with a given
|
||||
// group of camera settings: for example, different scenes may use different
|
||||
// z-buffer settings and in such a case each scene should have a dazzle layer
|
||||
// associated with it. (In some special cases a scene may have more than one
|
||||
// dazzle layer). A dazzle layer contains visible and invisible lists for
|
||||
// each dazzle type. During rendering each dazzle is put on the correct list
|
||||
// (a "current dazzle layer" static variable is set before rendering the
|
||||
// appropriate scenes to ensure this). After all scenes are rendered, the
|
||||
// dazzle layers are rendered one by one with the correct camera settings.
|
||||
// NOTE: dazzle layers must be constructed AFTER all the dazzle types have
|
||||
// been initialized, since the constructor needs to know how many dazzle types
|
||||
// there are.
|
||||
class DazzleLayerClass {
|
||||
|
||||
friend DazzleRenderObjClass;
|
||||
|
||||
public:
|
||||
|
||||
DazzleLayerClass(void);
|
||||
~DazzleLayerClass(void);
|
||||
|
||||
// Render all dazzles in this layer (DazzleRenderObj::Render() only sets visibility)
|
||||
void Render(CameraClass* camera);
|
||||
|
||||
private:
|
||||
|
||||
virtual int Get_Visible_Item_Count(unsigned int type) const; // Return visible item count
|
||||
// virtual void Get_Visible_Item_Locations(unsigned int type, Vector3* locations) const; // Copy locations of visible items to buffer
|
||||
virtual void Clear_Visible_List(unsigned int type);
|
||||
|
||||
// We have an array of visible lists (one for each dazzle type).
|
||||
DazzleRenderObjClass** visible_lists;
|
||||
|
||||
};
|
||||
|
||||
class LensflareTypeClass
|
||||
{
|
||||
friend DazzleLayerClass;
|
||||
friend DazzleRenderObjClass;
|
||||
|
||||
TextureClass* texture;
|
||||
LensflareInitClass lic;
|
||||
StringClass name;
|
||||
|
||||
LensflareTypeClass(const LensflareInitClass& is);
|
||||
virtual ~LensflareTypeClass();
|
||||
public:
|
||||
TextureClass* Get_Texture();
|
||||
|
||||
void Generate_Vertex_Buffers(
|
||||
VertexFormatXYZNDUV2* vertex,
|
||||
int& vertex_count,
|
||||
float screen_x_scale,
|
||||
float screen_y_scale,
|
||||
float dazzle_intensity,
|
||||
const Vector4& transformed_location);
|
||||
|
||||
void Render_Arrays(
|
||||
const Vector4* vertex_coordinates,
|
||||
const Vector2* uv_coordinates,
|
||||
const Vector3* color,
|
||||
int vertex_count,
|
||||
int halo_vertex_count,
|
||||
const Vector2* texture_coordinates);
|
||||
|
||||
};
|
||||
|
||||
class INIClass;
|
||||
|
||||
class DazzleRenderObjClass : public RenderObjClass
|
||||
{
|
||||
friend DazzleLayerClass;
|
||||
|
||||
DazzleRenderObjClass * succ;
|
||||
unsigned type;
|
||||
float current_dazzle_intensity;
|
||||
float current_dazzle_size;
|
||||
float current_halo_intensity;
|
||||
float current_distance;
|
||||
Vector4 transformed_loc;
|
||||
Vector3 current_vloc;
|
||||
Vector3 current_dir;
|
||||
Vector3 dazzle_color;
|
||||
Vector3 halo_color;
|
||||
float lensflare_intensity;
|
||||
float visibility;
|
||||
bool on_list; // This is used to avoid insterting a dazzle into a list twice.
|
||||
float radius; // Used to cast rays against
|
||||
unsigned int creation_time;
|
||||
|
||||
// static void Draw_Debug_Dazzle(int idx);
|
||||
void vis_render_dazzle(SpecialRenderInfoClass & rinfo);
|
||||
|
||||
void Render_Dazzle(CameraClass* camera);
|
||||
|
||||
public:
|
||||
|
||||
DazzleRenderObjClass(unsigned type);
|
||||
DazzleRenderObjClass(const char* type_name);
|
||||
DazzleRenderObjClass(const DazzleRenderObjClass & src);
|
||||
DazzleRenderObjClass & operator = (const DazzleRenderObjClass &);
|
||||
|
||||
DazzleRenderObjClass* Succ() { return succ; }
|
||||
const DazzleRenderObjClass* Succ() const { return succ; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const { return CLASSID_DAZZLE; }
|
||||
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
virtual void Scale(float scale) { radius*=scale; };
|
||||
|
||||
void Set_Dazzle_Color(const Vector3& col) { dazzle_color=col; }
|
||||
void Set_Halo_Color(const Vector3& col) { halo_color=col; }
|
||||
void Set_Lensflare_Intensity (float intensity) {lensflare_intensity=intensity;}
|
||||
|
||||
unsigned int Get_Dazzle_Type(void) { return type; }
|
||||
|
||||
// Usually, a DazzleRenderObj adds itself to the appropriate visible list
|
||||
// (determined by the current layer) when it is rendered. This does not
|
||||
// work for dazzles with "camera transform off", since they are located in
|
||||
// camera space and the standard worldspace visibility algo will give
|
||||
// unpredictable results for them (they may never have a Render() call).
|
||||
// So for these dazzles, you need to call Set_Layer() after constructing
|
||||
// them (this is instead of putting them in a scene). This function adds
|
||||
// the dazzle to the appropriate visible list. NOTE: It is also called
|
||||
// internally by the Render() function.
|
||||
void Set_Layer(DazzleLayerClass *layer);
|
||||
|
||||
// Persistant object save-load interface
|
||||
// Dazzles save their "dazzle-type" and transform
|
||||
virtual const PersistFactoryClass & Get_Factory (void) const;
|
||||
|
||||
// Set the static "current layer" variable. This variable is used in the
|
||||
// Render() call so that the dazzle knows which list to add itself to if
|
||||
// it is visible. This function must be called before rendering the
|
||||
// scene(s) in which the dazzles are present.
|
||||
static void Set_Current_Dazzle_Layer(DazzleLayerClass *layer);
|
||||
|
||||
static void Init_Type(const DazzleInitClass& i);
|
||||
static void Init_Lensflare(const LensflareInitClass& i);
|
||||
static void Init_From_INI(const INIClass* ini);
|
||||
static unsigned Get_Type_ID(const char* name); // Return the ID of type with given name, or INT_MAX if failed
|
||||
static const char * Get_Type_Name(unsigned int id); // Return the name of the type with the given ID
|
||||
static DazzleTypeClass* Get_Type_Class(unsigned id); // Return dazzle type class pointer, or NULL if not found
|
||||
// The pointer is NOT refcounted - all types are deinitialised
|
||||
// when exiting the level.
|
||||
static unsigned Get_Lensflare_ID(const char* name); // Return the ID of lensflare with given name, or INT_MAX if failed
|
||||
static LensflareTypeClass* Get_Lensflare_Class(unsigned id); // Return lensflare type class pointer, or NULL if not found
|
||||
|
||||
static void Deinit();
|
||||
|
||||
// Install a class derived from DazzleVisibilityClass to add app-specific
|
||||
// visibility determination. The default behavior will ask the scene which
|
||||
// the dazzle is a member of to compute its visibility.
|
||||
static void Install_Dazzle_Visibility_Handler(const DazzleVisibilityClass * visibility_handler);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DazzleVisibilityClass
|
||||
** The user should derive a class from DazzleVisibilityClass and implement an app-specific
|
||||
** dazzle visibility test. Renegade will use ray-casting to determine visibility. The
|
||||
** default visibility handler will query the scene which the dazzle is contained in.
|
||||
*/
|
||||
class DazzleVisibilityClass
|
||||
{
|
||||
public:
|
||||
virtual float Compute_Dazzle_Visibility( RenderInfoClass & rinfo,
|
||||
DazzleRenderObjClass * dazzle,
|
||||
const Vector3 & point) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DazzlePrototypeClass
|
||||
** This description object is generated when reading a W3D_CHUNK_DAZZLE. It stores the
|
||||
** information needed to construct a particular instance of a dazzle. Prototypes are
|
||||
** stored in the asset manager and used to construct render objects when needed.
|
||||
*/
|
||||
class DazzlePrototypeClass : public W3DMPO, public PrototypeClass
|
||||
{
|
||||
W3DMPO_GLUE(DazzlePrototypeClass)
|
||||
public:
|
||||
DazzlePrototypeClass(void) : DazzleType(0) { }
|
||||
|
||||
virtual const char * Get_Name(void) const { return Name; }
|
||||
virtual int Get_Class_ID(void) const { return RenderObjClass::CLASSID_DAZZLE; }
|
||||
virtual RenderObjClass * Create(void);
|
||||
virtual void DeleteSelf() { delete this; }
|
||||
|
||||
WW3DErrorType Load_W3D(ChunkLoadClass & cload);
|
||||
|
||||
private:
|
||||
|
||||
StringClass Name;
|
||||
int DazzleType;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DazzleLoaderClass
|
||||
** An instance of this class is registered with the asset manager and handles loading W3D_CHUNK_DAZZLE.
|
||||
** It creates DazzlePrototypes from the data in the chunk.
|
||||
*/
|
||||
class DazzleLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
DazzleLoaderClass(void) { }
|
||||
~DazzleLoaderClass(void) { }
|
||||
|
||||
virtual int Chunk_Type(void) { return W3D_CHUNK_DAZZLE; }
|
||||
virtual PrototypeClass * Load_W3D(ChunkLoadClass & cload);
|
||||
};
|
||||
|
||||
extern DazzleLoaderClass _DazzleLoader;
|
||||
|
||||
#endif
|
||||
712
Generals/Code/Libraries/Source/WWVegas/WW3D2/ddsfile.cpp
Normal file
712
Generals/Code/Libraries/Source/WWVegas/WW3D2/ddsfile.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#include "ddsfile.h"
|
||||
#include "ffactory.h"
|
||||
#include "bufffile.h"
|
||||
#include "formconv.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "bitmaphandler.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DDSFileClass::DDSFileClass(const char* name,unsigned reduction_factor)
|
||||
:
|
||||
Name(name),
|
||||
DDSMemory(NULL),
|
||||
Width(0),
|
||||
Height(0),
|
||||
LevelSizes(NULL),
|
||||
LevelOffsets(NULL),
|
||||
MipLevels(0),
|
||||
ReductionFactor(reduction_factor),
|
||||
Format(WW3D_FORMAT_UNKNOWN)
|
||||
{
|
||||
// The name could be given in .tga or .dds format, so ensure we're opening .dds...
|
||||
int len=strlen(Name);
|
||||
Name[len-3]='d';
|
||||
Name[len-2]='d';
|
||||
Name[len-1]='s';
|
||||
|
||||
file_auto_ptr file(_TheFileFactory,Name);
|
||||
if (!file->Is_Available()) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->Open();
|
||||
char header[4];
|
||||
file->Read(header,4);
|
||||
// Now, we read DDSURFACEDESC2 defining the compressed data
|
||||
unsigned read_bytes=file->Read(&SurfaceDesc,sizeof(LegacyDDSURFACEDESC2));
|
||||
// Verify the structure size matches the read size
|
||||
WWASSERT(read_bytes==SurfaceDesc.Size);
|
||||
|
||||
Format=D3DFormat_To_WW3DFormat((D3DFORMAT)SurfaceDesc.PixelFormat.FourCC);
|
||||
WWASSERT(
|
||||
Format==WW3D_FORMAT_DXT1 ||
|
||||
Format==WW3D_FORMAT_DXT2 ||
|
||||
Format==WW3D_FORMAT_DXT3 ||
|
||||
Format==WW3D_FORMAT_DXT4 ||
|
||||
Format==WW3D_FORMAT_DXT5);
|
||||
|
||||
MipLevels=SurfaceDesc.MipMapCount;
|
||||
if (MipLevels==0) MipLevels=1;
|
||||
|
||||
//Adjust the reduction factor to keep textures above some minimum dimensions
|
||||
if (MipLevels <= WW3D::Get_Texture_Min_Mip_Levels())
|
||||
ReductionFactor=0;
|
||||
else
|
||||
{ int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Mip_Levels();
|
||||
if (ReductionFactor >= mipToDrop)
|
||||
ReductionFactor=mipToDrop;
|
||||
}
|
||||
|
||||
if (MipLevels>ReductionFactor) MipLevels-=ReductionFactor;
|
||||
else {
|
||||
MipLevels=1;
|
||||
ReductionFactor=ReductionFactor-MipLevels;
|
||||
}
|
||||
|
||||
// Drop the two lowest miplevels!
|
||||
if (MipLevels>2) MipLevels-=2;
|
||||
else MipLevels=1;
|
||||
|
||||
Width=SurfaceDesc.Width>>ReductionFactor;
|
||||
Height=SurfaceDesc.Height>>ReductionFactor;
|
||||
|
||||
// MipLevels=SurfaceDesc.dwMipMapCount;
|
||||
// if (MipLevels==0) MipLevels=1;
|
||||
|
||||
unsigned level_size=Calculate_DXTC_Surface_Size(SurfaceDesc.Width,SurfaceDesc.Height,Format);
|
||||
unsigned level_offset=0;
|
||||
|
||||
LevelSizes=W3DNEWARRAY unsigned[MipLevels];
|
||||
LevelOffsets=W3DNEWARRAY unsigned[MipLevels];
|
||||
for (unsigned level=0;level<ReductionFactor;++level) {
|
||||
// level_offset+=level_size;
|
||||
if (level_size>16) { // If surface is bigger than one block (8 or 16 bytes)...
|
||||
level_size/=4;
|
||||
}
|
||||
}
|
||||
for (level=0;level<MipLevels;++level) {
|
||||
LevelSizes[level]=level_size;
|
||||
LevelOffsets[level]=level_offset;
|
||||
level_offset+=level_size;
|
||||
if (level_size>16) { // If surface is bigger than one block (8 or 16 bytes)...
|
||||
level_size/=4;
|
||||
}
|
||||
}
|
||||
// Verify we read through the whole file (not more, not less).
|
||||
#if 0
|
||||
// This code is commented out because it complains for all our files, but it doesn't seem to actually
|
||||
// be a problem. The new version of ddsfile from Vegas actually has removed this check entirely.
|
||||
int expected_size=level_offset+SurfaceDesc.Size+4;
|
||||
if (expected_size!=file->Size()) {
|
||||
WWDEBUG_SAY(("Warning: file % size is not consistent with the data (file size should be %d but was %d)\n",Name,expected_size,file->Size()));
|
||||
}
|
||||
#endif
|
||||
file->Close();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DDSFileClass::~DDSFileClass()
|
||||
{
|
||||
delete[] DDSMemory;
|
||||
delete[] LevelSizes;
|
||||
delete[] LevelOffsets;
|
||||
}
|
||||
|
||||
unsigned DDSFileClass::Get_Width(unsigned level) const
|
||||
{
|
||||
WWASSERT(level<MipLevels);
|
||||
unsigned width=Width>>level;
|
||||
if (width<4) width=4;
|
||||
return width;
|
||||
}
|
||||
|
||||
unsigned DDSFileClass::Get_Height(unsigned level) const
|
||||
{
|
||||
WWASSERT(level<MipLevels);
|
||||
unsigned height=Height>>level;
|
||||
if (height<4) height=4;
|
||||
return height;
|
||||
}
|
||||
|
||||
const unsigned char* DDSFileClass::Get_Memory_Pointer(unsigned level) const
|
||||
{
|
||||
WWASSERT(level<MipLevels);
|
||||
return DDSMemory+LevelOffsets[level];
|
||||
}
|
||||
|
||||
unsigned DDSFileClass::Get_Level_Size(unsigned level) const
|
||||
{
|
||||
WWASSERT(level<MipLevels);
|
||||
return LevelSizes[level];
|
||||
}
|
||||
|
||||
// For some reason DX-Tex tool doesn't fill the surface size field, so we need to calculate it...
|
||||
unsigned DDSFileClass::Calculate_DXTC_Surface_Size(unsigned width, unsigned height, WW3DFormat format)
|
||||
{
|
||||
unsigned level_size=(width/4)*(height/4);
|
||||
switch (format) {
|
||||
case WW3D_FORMAT_DXT1:
|
||||
level_size*=8;
|
||||
break;
|
||||
case WW3D_FORMAT_DXT2:
|
||||
case WW3D_FORMAT_DXT3:
|
||||
case WW3D_FORMAT_DXT4:
|
||||
case WW3D_FORMAT_DXT5:
|
||||
level_size*=16;
|
||||
break;
|
||||
}
|
||||
return level_size;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool DDSFileClass::Load()
|
||||
{
|
||||
if (DDSMemory) return false;
|
||||
if (!LevelSizes || !LevelOffsets) return false;
|
||||
|
||||
file_auto_ptr file(_TheFileFactory,Name);
|
||||
if (!file->Is_Available()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file->Open();
|
||||
// Data size is file size minus the header and info block
|
||||
unsigned size=file->Size()-SurfaceDesc.Size-4;
|
||||
// Skip mip levels if reduction factor is not zero
|
||||
unsigned level_size=Calculate_DXTC_Surface_Size(SurfaceDesc.Width,SurfaceDesc.Height,Format);
|
||||
unsigned skipped_offset=0;
|
||||
for (unsigned i=0;i<ReductionFactor;++i) {
|
||||
skipped_offset+=level_size;
|
||||
size-=level_size;
|
||||
if (level_size>16) { // If surface is bigger than one block (8 or 16 bytes)...
|
||||
level_size/=4;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip the header and info block and possible unused mip levels
|
||||
unsigned seek_size=file->Seek(SurfaceDesc.Size+4+skipped_offset);
|
||||
WWASSERT(seek_size==(SurfaceDesc.Size+4+skipped_offset));
|
||||
|
||||
if (size) {
|
||||
// Allocate memory for the data excluding the headers
|
||||
DDSMemory=MSGW3DNEWARRAY("DDSMemory") unsigned char[size];
|
||||
// Read data
|
||||
unsigned read_size=file->Read(DDSMemory,size);
|
||||
// Verify we got all the data
|
||||
WWASSERT(read_size==size);
|
||||
}
|
||||
file->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Copy mipmap level to D3D surface. The copying is performed using another
|
||||
// Copy_Level_To_Surface function (see below).
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DDSFileClass::Copy_Level_To_Surface(unsigned level,IDirect3DSurface8* d3d_surface)
|
||||
{
|
||||
WWASSERT(d3d_surface);
|
||||
// Verify that the destination surface size matches the source surface size
|
||||
D3DSURFACE_DESC surface_desc;
|
||||
DX8_ErrorCode(d3d_surface->GetDesc(&surface_desc));
|
||||
|
||||
// First lock the surface
|
||||
D3DLOCKED_RECT locked_rect;
|
||||
DX8_ErrorCode(d3d_surface->LockRect(&locked_rect,NULL,0));
|
||||
|
||||
Copy_Level_To_Surface(
|
||||
level,
|
||||
D3DFormat_To_WW3DFormat(surface_desc.Format),
|
||||
surface_desc.Width,
|
||||
surface_desc.Height,
|
||||
reinterpret_cast<unsigned char*>(locked_rect.pBits),
|
||||
locked_rect.Pitch);
|
||||
|
||||
// Finally, unlock the surface
|
||||
DX8_ErrorCode(d3d_surface->UnlockRect());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Copy one mipmap level of texture to a memory surface. Surface type conversion
|
||||
// is performed if the destination is of different format. Scaling will be done
|
||||
// one of these days as well. Conversions between different types of compressed
|
||||
// surfaces are not performed and scaling of compressed surfaces is also not
|
||||
// possible.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DDSFileClass::Copy_Level_To_Surface(
|
||||
unsigned level,
|
||||
WW3DFormat dest_format,
|
||||
unsigned dest_width,
|
||||
unsigned dest_height,
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_pitch)
|
||||
{
|
||||
WWASSERT(DDSMemory);
|
||||
WWASSERT(dest_surface);
|
||||
|
||||
// If the format and size is a match just copy the contents
|
||||
if (dest_format==Format && dest_width==Get_Width(level) && dest_height==Get_Height(level)) {
|
||||
unsigned compressed_size=Get_Level_Size(level);
|
||||
memcpy(dest_surface,Get_Memory_Pointer(level),compressed_size);
|
||||
}
|
||||
else {
|
||||
// If size matches, copy each pixel linearly with color space conversion
|
||||
if (dest_width==Get_Width(level) && dest_height==Get_Height(level)) {
|
||||
// An exception here - if the source format is DXT1 and the destination
|
||||
// is DXT2, just copy the contents and create an empty alpha channel.
|
||||
// This is needed on NVidia cards that have problems with DXT1 compression.
|
||||
if (Format==WW3D_FORMAT_DXT1 && dest_format==WW3D_FORMAT_DXT2) {
|
||||
const unsigned* src_ptr=reinterpret_cast<const unsigned*>(Get_Memory_Pointer(level));
|
||||
unsigned* dest_ptr=reinterpret_cast<unsigned*>(dest_surface);
|
||||
for (unsigned y=0;y<dest_height;y+=4) {
|
||||
for (unsigned x=0;x<dest_width;x+=4) {
|
||||
*dest_ptr++=0xffffffff; // Bytes 1-4 of alpha block
|
||||
*dest_ptr++=0xffffffff; // Bytes 5-8 of alpha block
|
||||
*dest_ptr++=*src_ptr++; // Bytes 1-4 of color block
|
||||
*dest_ptr++=*src_ptr++; // Bytes 5-8 of color block
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
unsigned dest_bpp=Get_Bytes_Per_Pixel(dest_format);
|
||||
|
||||
// Copy 4x4 block at a time
|
||||
bool contains_alpha=false;
|
||||
for (unsigned y=0;y<dest_height;y+=4) {
|
||||
unsigned char* dest_ptr=dest_surface;
|
||||
dest_ptr+=y*dest_pitch;
|
||||
for (unsigned x=0;x<dest_width;x+=4,dest_ptr+=dest_bpp*4) {
|
||||
contains_alpha|=Get_4x4_Block(dest_ptr,dest_pitch,dest_format,level,x,y);
|
||||
}
|
||||
}
|
||||
if (Format==WW3D_FORMAT_DXT1 && contains_alpha) {
|
||||
WWDEBUG_SAY(("Warning: DXT1 format should not contain alpha information - file %s\n",Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Scaling not handled...
|
||||
else {
|
||||
//int a=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE static unsigned RGB565_To_ARGB8888(unsigned short rgb)
|
||||
{
|
||||
unsigned rgba=0;
|
||||
rgba|=unsigned(rgb&0x001f)<<3;
|
||||
rgba|=unsigned(rgb&0x07e0)<<5;
|
||||
rgba|=unsigned(rgb&0xf800)<<8;
|
||||
return rgba;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE static unsigned Combine_Colors(unsigned col1, unsigned col2, unsigned rel)
|
||||
{
|
||||
const unsigned R_B_MASK=0x00ff00ff;
|
||||
const unsigned G_MASK=0x0000ff00;
|
||||
|
||||
unsigned rel2=255-rel;
|
||||
|
||||
unsigned r_b_col1=col1&R_B_MASK;
|
||||
r_b_col1*=rel;
|
||||
unsigned r_b_col2=col2&R_B_MASK;
|
||||
r_b_col2*=rel2;
|
||||
r_b_col1+=r_b_col2;
|
||||
r_b_col1>>=8;
|
||||
r_b_col1&=R_B_MASK;
|
||||
|
||||
|
||||
unsigned g_col1=col1&G_MASK;
|
||||
g_col1*=rel;
|
||||
unsigned g_col2=col2&G_MASK;
|
||||
g_col2*=rel2;
|
||||
g_col1+=g_col2;
|
||||
g_col1>>=8;
|
||||
g_col1&=G_MASK;
|
||||
|
||||
return r_b_col1|g_col1;
|
||||
|
||||
/* float f=float(rel)/256.0f;
|
||||
|
||||
unsigned new_col=0;
|
||||
new_col|=int(float(int(col1&0x00ff0000))*f+float(int(col2&0x00ff0000))*(1.0f-f))&0x00ff0000;
|
||||
new_col|=int(float(int(col1&0x0000ff00))*f+float(int(col2&0x0000ff00))*(1.0f-f))&0x0000ff00;
|
||||
new_col|=int(float(int(col1&0x000000ff))*f+float(int(col2&0x000000ff))*(1.0f-f))&0x000000ff;
|
||||
return new_col;
|
||||
*/
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Note that this is NOT an efficient way of extracting pixels from compressed image - we should implement
|
||||
// faster block-copy method for non-scaled copying.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
unsigned DDSFileClass::Get_Pixel(unsigned level,unsigned x,unsigned y) const
|
||||
{
|
||||
WWASSERT(level<MipLevels);
|
||||
WWASSERT(x<Get_Width(level));
|
||||
WWASSERT(y<Get_Height(level));
|
||||
|
||||
switch (Format) {
|
||||
// Note that we don't currently really support alpha on DXT1 - all alpha textures should use DXT5.
|
||||
// The reason for this is that when converting from DXT1 to 16 bit uncompressed texture we want
|
||||
// to be able to use RGB565 format instead of ARGB4444. As the alpha is encoded in DXT1 per-block
|
||||
// basis there isn't really a way to tell if the surface has an alpha or not so either we use alpha
|
||||
// or we don't.
|
||||
case WW3D_FORMAT_DXT1:
|
||||
{
|
||||
const unsigned char* block_memory=Get_Memory_Pointer(level)+(x/4)*8+((y/4)*(Get_Width(level)/4))*8;
|
||||
|
||||
unsigned col0=RGB565_To_ARGB8888(*(unsigned short*)&block_memory[0]);
|
||||
unsigned col1=RGB565_To_ARGB8888(*(unsigned short*)&block_memory[2]);
|
||||
unsigned char line=block_memory[4+(y%4)];
|
||||
line>>=(x%4)*2;
|
||||
line=(line&3);
|
||||
if (col0>col1) {
|
||||
switch (line) {
|
||||
case 0: return col0|0xff000000;
|
||||
case 1: return col1|0xff000000;
|
||||
case 2: return Combine_Colors(col1,col0,85)|0xff000000;
|
||||
case 3: return Combine_Colors(col0,col1,85)|0xff000000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (line) {
|
||||
case 0: return col0|0xff000000;
|
||||
case 1: return col1|0xff000000;
|
||||
case 2: return Combine_Colors(col1,col0,128)|0xff000000;
|
||||
case 3: return 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_DXT2:
|
||||
return 0xffffffff;
|
||||
case WW3D_FORMAT_DXT3:
|
||||
return 0xffffffff;
|
||||
case WW3D_FORMAT_DXT4:
|
||||
return 0xffffffff;
|
||||
case WW3D_FORMAT_DXT5:
|
||||
{
|
||||
const unsigned char* alpha_block=Get_Memory_Pointer(level)+(x/4)*16+((y/4)*(Get_Width(level)/4))*16;
|
||||
|
||||
unsigned alpha0=alpha_block[0];
|
||||
unsigned alpha1=alpha_block[1];
|
||||
|
||||
unsigned bit_idx=((x%4)+4*(y%4))*3;
|
||||
unsigned byte_idx=bit_idx/8;
|
||||
bit_idx%=8;
|
||||
unsigned alpha_index=0;
|
||||
for (int i=0;i<3;++i) {
|
||||
WWASSERT(byte_idx<6);
|
||||
unsigned alpha_bit=(alpha_block[2+byte_idx]>>(bit_idx))&1;
|
||||
alpha_index|=alpha_bit<<(i);
|
||||
bit_idx++;
|
||||
if (bit_idx>=8) {
|
||||
bit_idx=0;
|
||||
byte_idx++;
|
||||
}
|
||||
}
|
||||
WWASSERT(alpha_index<8);
|
||||
|
||||
// 8-alpha or 6-alpha block?
|
||||
unsigned alpha_value=0;
|
||||
if (alpha0>alpha1) {
|
||||
// 8-alpha block: derive the other six alphas.
|
||||
// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
|
||||
switch (alpha_index) {
|
||||
case 0: alpha_value=alpha0; break;
|
||||
case 1: alpha_value=alpha1; break;
|
||||
case 2: alpha_value=(6*alpha0+1*alpha1+3) / 7; break; // bit code 010
|
||||
case 3: alpha_value=(5*alpha0+2*alpha1+3) / 7; break; // bit code 011
|
||||
case 4: alpha_value=(4*alpha0+3*alpha1+3) / 7; break; // bit code 100
|
||||
case 5: alpha_value=(3*alpha0+4*alpha1+3) / 7; break; // bit code 101
|
||||
case 6: alpha_value=(2*alpha0+5*alpha1+3) / 7; break; // bit code 110
|
||||
case 7: alpha_value=(1*alpha0+6*alpha1+3) / 7; break; // bit code 111
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 6-alpha block.
|
||||
// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
|
||||
switch (alpha_index) {
|
||||
case 0: alpha_value=alpha0; break;
|
||||
case 1: alpha_value=alpha1; break;
|
||||
case 2: alpha_value=(4*alpha0+1*alpha1+2) / 5; break; // Bit code 010
|
||||
case 3: alpha_value=(3*alpha0+2*alpha1+2) / 5; break; // Bit code 011
|
||||
case 4: alpha_value=(2*alpha0+3*alpha1+2) / 5; break; // Bit code 100
|
||||
case 5: alpha_value=(1*alpha0+4*alpha1+2) / 5; break; // Bit code 101
|
||||
case 6: alpha_value=0; break; // Bit code 110
|
||||
case 7: alpha_value=255; break; // Bit code 111
|
||||
}
|
||||
}
|
||||
alpha_value<<=24;
|
||||
|
||||
// Extract color
|
||||
|
||||
const unsigned char* color_block=alpha_block+8;
|
||||
unsigned col0=RGB565_To_ARGB8888(*(unsigned short*)&color_block[0]);
|
||||
unsigned col1=RGB565_To_ARGB8888(*(unsigned short*)&color_block[2]);
|
||||
unsigned char line=color_block[4+(y%4)];
|
||||
line>>=(x%4)*2;
|
||||
line=(line&3);
|
||||
switch (line) {
|
||||
case 0: return col0|alpha_value;
|
||||
case 1: return col1|alpha_value;
|
||||
case 2: return Combine_Colors(col1,col0,85)|alpha_value;
|
||||
case 3: return Combine_Colors(col0,col1,85)|alpha_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Uncompress one 4x4 block from the compressed image.
|
||||
//
|
||||
// Returns: true if block contained alpha, false is not
|
||||
//
|
||||
// Note: Destination can't be DXT or paletted surface!
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool DDSFileClass::Get_4x4_Block(
|
||||
unsigned char* dest_ptr, // Destination surface pointer
|
||||
unsigned dest_pitch, // Destination surface pitch, in bytes
|
||||
WW3DFormat dest_format, // Destination surface format, A8R8G8B8 is fastest
|
||||
unsigned level, // DDS mipmap level to copy from
|
||||
unsigned source_x, // DDS x offset to copy from, must be aligned by 4!
|
||||
unsigned source_y) const // DDS y offset to copy from, must be aligned by 4!
|
||||
{
|
||||
// Verify the block alignment
|
||||
WWASSERT((source_x&3)==0);
|
||||
WWASSERT((source_y&3)==0);
|
||||
// Verify level
|
||||
WWASSERT(level<MipLevels);
|
||||
// Verify coordinate bounds
|
||||
WWASSERT(source_x<Get_Width(level));
|
||||
WWASSERT(source_y<Get_Height(level));
|
||||
|
||||
unsigned dest_bpp=Get_Bytes_Per_Pixel(dest_format);
|
||||
|
||||
switch (Format) {
|
||||
// Note that we don't currently really support alpha on DXT1 - all alpha textures should use DXT5.
|
||||
// The reason for this is that when converting from DXT1 to 16 bit uncompressed texture we want
|
||||
// to be able to use RGB565 format instead of ARGB4444. As the alpha is encoded in DXT1 per-block
|
||||
// basis there isn't really a way to tell if the surface has an alpha or not so either we use alpha
|
||||
// or we don't.
|
||||
case WW3D_FORMAT_DXT1:
|
||||
{
|
||||
const unsigned char* block_memory=Get_Memory_Pointer(level)+(source_x/4)*8+((source_y/4)*(Get_Width(level)/4))*8;
|
||||
|
||||
unsigned col0=RGB565_To_ARGB8888(*(unsigned short*)&block_memory[0]);
|
||||
unsigned col1=RGB565_To_ARGB8888(*(unsigned short*)&block_memory[2]);
|
||||
// Even if we don't support alpha, decompression is different if source has alpha
|
||||
unsigned dest_pixel=0;
|
||||
if (col0>col1) {
|
||||
for (int y=0;y<4;++y) {
|
||||
unsigned char* tmp_dest_ptr=dest_ptr;
|
||||
dest_ptr+=dest_pitch;
|
||||
unsigned char line=block_memory[4+y];
|
||||
for (int x=0;x<4;++x) {
|
||||
switch (line&3) {
|
||||
case 0: dest_pixel=col0|0xff000000; break;
|
||||
case 1: dest_pixel=col1|0xff000000; break;
|
||||
case 2: dest_pixel=Combine_Colors(col1,col0,85)|0xff000000; break;
|
||||
case 3: dest_pixel=Combine_Colors(col0,col1,85)|0xff000000; break;
|
||||
}
|
||||
line>>=2;
|
||||
|
||||
BitmapHandlerClass::Write_B8G8R8A8(tmp_dest_ptr,dest_format,dest_pixel);
|
||||
tmp_dest_ptr+=dest_bpp;
|
||||
}
|
||||
}
|
||||
return false; // No alpha found in the block
|
||||
}
|
||||
else {
|
||||
for (int y=0;y<4;++y) {
|
||||
unsigned char* tmp_dest_ptr=dest_ptr;
|
||||
dest_ptr+=dest_pitch;
|
||||
unsigned char line=block_memory[4+y];
|
||||
for (int x=0;x<4;++x) {
|
||||
switch (line&3) {
|
||||
case 0: dest_pixel=col0|0xff000000; break;
|
||||
case 1: dest_pixel=col1|0xff000000; break;
|
||||
case 2: dest_pixel=Combine_Colors(col1,col0,128)|0xff000000; break;
|
||||
case 3: dest_pixel=0x00000000; break;
|
||||
}
|
||||
line>>=2;
|
||||
|
||||
BitmapHandlerClass::Write_B8G8R8A8(tmp_dest_ptr,dest_format,dest_pixel);
|
||||
tmp_dest_ptr+=dest_bpp;
|
||||
}
|
||||
}
|
||||
return true; // Alpha block...
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WW3D_FORMAT_DXT2:
|
||||
return false;
|
||||
case WW3D_FORMAT_DXT3:
|
||||
return false;
|
||||
case WW3D_FORMAT_DXT4:
|
||||
return false;
|
||||
case WW3D_FORMAT_DXT5:
|
||||
{
|
||||
// Init alphas
|
||||
const unsigned char* alpha_block=Get_Memory_Pointer(level)+(source_x/4)*16+((source_y/4)*(Get_Width(level)/4))*16;
|
||||
|
||||
unsigned alphas[8];
|
||||
alphas[0]=alpha_block[0];
|
||||
alphas[1]=alpha_block[1];
|
||||
|
||||
// 8-alpha or 6-alpha block?
|
||||
if (alphas[0]>alphas[1]) {
|
||||
alphas[2]=(6*alphas[0]+1*alphas[1]+3) / 7; // bit code 010
|
||||
alphas[3]=(5*alphas[0]+2*alphas[1]+3) / 7; // bit code 011
|
||||
alphas[4]=(4*alphas[0]+3*alphas[1]+3) / 7; // bit code 100
|
||||
alphas[5]=(3*alphas[0]+4*alphas[1]+3) / 7; // bit code 101
|
||||
alphas[6]=(2*alphas[0]+5*alphas[1]+3) / 7; // bit code 110
|
||||
alphas[7]=(1*alphas[0]+6*alphas[1]+3) / 7; // bit code 111
|
||||
}
|
||||
else {
|
||||
alphas[2]=(4*alphas[0]+1*alphas[1]+2) / 5; // Bit code 010
|
||||
alphas[3]=(3*alphas[0]+2*alphas[1]+2) / 5; // Bit code 011
|
||||
alphas[4]=(2*alphas[0]+3*alphas[1]+2) / 5; // Bit code 100
|
||||
alphas[5]=(1*alphas[0]+4*alphas[1]+2) / 5; // Bit code 101
|
||||
alphas[6]=0; // Bit code 110
|
||||
alphas[7]=255; // Bit code 111
|
||||
}
|
||||
|
||||
// Init colors
|
||||
const unsigned char* color_block=alpha_block+8;
|
||||
unsigned col0=RGB565_To_ARGB8888(*(unsigned short*)&color_block[0]);
|
||||
unsigned col1=RGB565_To_ARGB8888(*(unsigned short*)&color_block[2]);
|
||||
|
||||
unsigned dest_pixel=0;
|
||||
unsigned bit_idx=0;
|
||||
unsigned contains_alpha=0xff;
|
||||
|
||||
unsigned alpha_indices[16];
|
||||
unsigned* ai_ptr=alpha_indices;
|
||||
for (int a=0;a<2;++a) {
|
||||
ai_ptr[0]=alpha_block[2]&0x7;
|
||||
ai_ptr[1]=(alpha_block[2]>>3)&0x7;
|
||||
ai_ptr[2]=(alpha_block[2]>>6)|((alpha_block[3]&1)<<2);
|
||||
ai_ptr[3]=(alpha_block[3]>>1)&0x7;
|
||||
ai_ptr[4]=(alpha_block[3]>>4)&0x7;
|
||||
ai_ptr[5]=(alpha_block[3]>>7)|((alpha_block[4]&3)<<1);
|
||||
ai_ptr[6]=(alpha_block[4]>>2)&0x7;
|
||||
ai_ptr[7]=(alpha_block[4]>>5);
|
||||
ai_ptr+=8;
|
||||
alpha_block+=3;
|
||||
}
|
||||
|
||||
unsigned aii=0;
|
||||
for (int y=0;y<4;++y) {
|
||||
unsigned char* tmp_dest_ptr=dest_ptr;
|
||||
dest_ptr+=dest_pitch;
|
||||
unsigned char line=color_block[4+y];
|
||||
for (int x=0;x<4;++x,bit_idx+=3) {
|
||||
unsigned alpha_value=alphas[alpha_indices[aii++]];
|
||||
contains_alpha&=alpha_value;
|
||||
alpha_value<<=24;
|
||||
|
||||
// Extract color
|
||||
|
||||
switch (line&3) {
|
||||
case 0: dest_pixel=col0|alpha_value; break;
|
||||
case 1: dest_pixel=col1|alpha_value; break;
|
||||
case 2: dest_pixel=Combine_Colors(col1,col0,85)|alpha_value; break;
|
||||
case 3: dest_pixel=Combine_Colors(col0,col1,85)|alpha_value; break;
|
||||
}
|
||||
line>>=2;
|
||||
|
||||
BitmapHandlerClass::Write_B8G8R8A8(tmp_dest_ptr,dest_format,dest_pixel);
|
||||
tmp_dest_ptr+=dest_bpp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
for (int y=0;y<4;++y) {
|
||||
unsigned char* tmp_dest_ptr=dest_ptr;
|
||||
dest_ptr+=dest_pitch;
|
||||
unsigned char line=color_block[4+y];
|
||||
for (int x=0;x<4;++x,bit_idx+=3) {
|
||||
unsigned byte_idx=bit_idx/8;
|
||||
unsigned tmp_bit_idx=bit_idx&7;
|
||||
unsigned alpha_index=0;
|
||||
for (int i=0;i<3;++i) {
|
||||
WWASSERT(byte_idx<6);
|
||||
unsigned alpha_bit=(alpha_block[2+byte_idx]>>(tmp_bit_idx))&1;
|
||||
alpha_index|=alpha_bit<<(i);
|
||||
tmp_bit_idx++;
|
||||
if (tmp_bit_idx>=8) {
|
||||
tmp_bit_idx=0;
|
||||
byte_idx++;
|
||||
}
|
||||
}
|
||||
WWASSERT(alpha_index<8);
|
||||
unsigned alpha_value=alphas[alpha_index];
|
||||
contains_alpha&=alpha_value;
|
||||
alpha_value<<=24;
|
||||
|
||||
// Extract color
|
||||
|
||||
switch (line&3) {
|
||||
case 0: dest_pixel=col0|alpha_value; break;
|
||||
case 1: dest_pixel=col1|alpha_value; break;
|
||||
case 2: dest_pixel=Combine_Colors(col1,col0,85)|alpha_value; break;
|
||||
case 3: dest_pixel=Combine_Colors(col0,col1,85)|alpha_value; break;
|
||||
}
|
||||
line>>=2;
|
||||
|
||||
BitmapHandlerClass::Write_B8G8R8A8(tmp_dest_ptr,dest_format,dest_pixel);
|
||||
tmp_dest_ptr+=dest_bpp;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return contains_alpha!=0xff; // Alpha block... DXT5 should only be used when the image needs alpha
|
||||
// but for now check anyway...
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
222
Generals/Code/Libraries/Source/WWVegas/WW3D2/ddsfile.h
Normal file
222
Generals/Code/Libraries/Source/WWVegas/WW3D2/ddsfile.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#ifndef DDSFILE_H
|
||||
#define DDSFILE_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "always.h"
|
||||
#include "ww3dformat.h"
|
||||
#include "wwstring.h"
|
||||
|
||||
struct IDirect3DSurface8;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// This structure represents the old DX7 color key structure. It is needed
|
||||
// LegacyDDSURFACEDESC which is needed when loading DDS files. DO NOT MODIFY!
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct LegacyDDCOLORKEY
|
||||
{
|
||||
unsigned ColorSpaceLowValue;
|
||||
unsigned ColorSpaceHighValue;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// This structure represents the old DX7 CAPS2 structure. It is needed
|
||||
// LegacyDDSURFACEDESC which is needed when loading DDS files. DO NOT MODIFY!
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct LegacyDDSCAPS2
|
||||
{
|
||||
unsigned Caps;
|
||||
unsigned Caps2;
|
||||
unsigned Caps3;
|
||||
unsigned Caps4;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// This structure represents the old DX7 pixel format structure. It is needed
|
||||
// LegacyDDSURFACEDESC which is needed when loading DDS files. DO NOT MODIFY!
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct LegacyDDPIXELFORMAT
|
||||
{
|
||||
unsigned Size;
|
||||
unsigned Flags;
|
||||
unsigned FourCC;
|
||||
union
|
||||
{
|
||||
unsigned RGBBitCount;
|
||||
unsigned YUVBitCount;
|
||||
unsigned ZBufferBitDepth;
|
||||
unsigned AlphaBitDepth;
|
||||
unsigned LuminanceBitCount;
|
||||
unsigned BumpBitCount;
|
||||
};
|
||||
union
|
||||
{
|
||||
unsigned RBitMask;
|
||||
unsigned YBitMask;
|
||||
unsigned StencilBitDepth;
|
||||
unsigned LuminanceBitMask;
|
||||
unsigned BumpDuBitMask;
|
||||
};
|
||||
union
|
||||
{
|
||||
unsigned GBitMask;
|
||||
unsigned UBitMask;
|
||||
unsigned ZBitMask;
|
||||
unsigned BumpDvBitMask;
|
||||
};
|
||||
union
|
||||
{
|
||||
unsigned BBitMask;
|
||||
unsigned VBitMask;
|
||||
unsigned StencilBitMask;
|
||||
unsigned BumpLuminanceBitMask;
|
||||
};
|
||||
union
|
||||
{
|
||||
unsigned RGBAlphaBitMask;
|
||||
unsigned YUVAlphaBitMask;
|
||||
unsigned LuminanceAlphaBitMask;
|
||||
unsigned RGBZBitMask;
|
||||
unsigned YUVZBitMask;
|
||||
};
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// This structure represents the old DX7 surface description structure.
|
||||
// It is needed when loading DDS files. DO NOT MODIFY!
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct LegacyDDSURFACEDESC2 {
|
||||
unsigned Size;
|
||||
unsigned Flags;
|
||||
unsigned Height;
|
||||
unsigned Width;
|
||||
union
|
||||
{
|
||||
unsigned Pitch;
|
||||
unsigned LinearSize;
|
||||
};
|
||||
unsigned BackBufferCount;
|
||||
union
|
||||
{
|
||||
unsigned MipMapCount;
|
||||
unsigned RefreshRate;
|
||||
};
|
||||
unsigned AlphaBitDepth;
|
||||
unsigned Reserved;
|
||||
void* Surface;
|
||||
union
|
||||
{
|
||||
LegacyDDCOLORKEY CKDestOverlay;
|
||||
unsigned EmptyFaceColor;
|
||||
};
|
||||
LegacyDDCOLORKEY CKDestBlt;
|
||||
LegacyDDCOLORKEY CKSrcOverlay;
|
||||
LegacyDDCOLORKEY CKSrcBlt;
|
||||
LegacyDDPIXELFORMAT PixelFormat;
|
||||
LegacyDDSCAPS2 Caps;
|
||||
unsigned TextureStage;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Utility class for loading DDS files. Simply create an instance of the class
|
||||
// locally, call Load() and use the copy functions to retrieve the surface.
|
||||
// The class handles conversion of the surface to equal compressed formats
|
||||
// and all non-compressed formats. the compressed DXTn formats can't be cross-
|
||||
// converted except for DXT1 which can be converted to DXT2 (this feature is
|
||||
// needed as the NVidia cards have problems with DXT1).
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class DDSFileClass
|
||||
{
|
||||
unsigned Width;
|
||||
unsigned Height;
|
||||
unsigned MipLevels;
|
||||
unsigned ReductionFactor;
|
||||
unsigned char* DDSMemory;
|
||||
WW3DFormat Format;
|
||||
unsigned* LevelSizes;
|
||||
unsigned* LevelOffsets;
|
||||
LegacyDDSURFACEDESC2 SurfaceDesc;
|
||||
StringClass Name;
|
||||
|
||||
static unsigned Calculate_DXTC_Surface_Size(unsigned width, unsigned height, WW3DFormat format);
|
||||
|
||||
public:
|
||||
// You can pass the name in .tga or .dds format, the class will automatically try and load .dds file.
|
||||
// Note that creating the object will only give you image info - call Load() to load the surfaces.
|
||||
DDSFileClass(const char* name,unsigned reduction_factor);
|
||||
~DDSFileClass();
|
||||
|
||||
unsigned Get_Width(unsigned level) const;
|
||||
unsigned Get_Height(unsigned level) const;
|
||||
|
||||
unsigned Get_Mip_Level_Count() const { return MipLevels; }
|
||||
const unsigned char* Get_Memory_Pointer(unsigned level) const;
|
||||
unsigned Get_Level_Size(unsigned level) const;
|
||||
WW3DFormat Get_Format() const { return Format; }
|
||||
|
||||
// Copy pixels to the destination surface.
|
||||
void Copy_Level_To_Surface(unsigned level,IDirect3DSurface8* d3d_surface);
|
||||
void Copy_Level_To_Surface(
|
||||
unsigned level,
|
||||
WW3DFormat dest_format,
|
||||
unsigned dest_width,
|
||||
unsigned dest_height,
|
||||
unsigned char* dest_surface,
|
||||
unsigned dest_pitch);
|
||||
|
||||
// Get pixel in A8R8G8B8 format. This isn't the fastest possible way of reading data from DDS.
|
||||
unsigned Get_Pixel(unsigned level,unsigned x,unsigned y) const;
|
||||
|
||||
// Uncompress one 4x4 block from the compressed image.
|
||||
// Returns: true if block contained alpha, false is not
|
||||
// Note: Destination can't be DXT or paletted surface!
|
||||
bool Get_4x4_Block(
|
||||
unsigned char* dest_ptr, // Destination surface pointer
|
||||
unsigned dest_pitch, // Destination surface pitch, in bytes
|
||||
WW3DFormat dest_format, // Destination surface format, A8R8G8B8 is fastest
|
||||
unsigned level, // DDS mipmap level to copy from
|
||||
unsigned source_x, // DDS x offset to copy from, must be aligned by 4!
|
||||
unsigned source_y) const; // DDS y offset to copy from, must be aligned by 4!
|
||||
|
||||
bool Load();
|
||||
bool Is_Available() const { return !!LevelSizes; }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
1108
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalmsh.cpp
Normal file
1108
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalmsh.cpp
Normal file
File diff suppressed because it is too large
Load Diff
293
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalmsh.h
Normal file
293
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalmsh.h
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/decalmsh.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 6/14/01 9:32a $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DECALMSH_H
|
||||
#define DECALMSH_H
|
||||
|
||||
#include "always.h"
|
||||
#include "bittype.h"
|
||||
#include "simplevec.h"
|
||||
#include "vector.h"
|
||||
#include "vector2.h"
|
||||
#include "vector3.h"
|
||||
#include "vector3i.h"
|
||||
#include "vector4.h"
|
||||
#include "shader.h"
|
||||
#include "vertmaterial.h"
|
||||
|
||||
class MeshClass;
|
||||
class RenderInfoClass;
|
||||
class DecalGeneratorClass;
|
||||
class DecalSystemClass;
|
||||
class OBBoxClass;
|
||||
class TextureClass;
|
||||
|
||||
/**
|
||||
** DecalMeshClass
|
||||
** This is a "subordinate" class to MeshModel which simply adds "decal" polygons to the mesh.
|
||||
** These polygons will always be exact copies of polygons already in the parent mesh.
|
||||
**
|
||||
** Design Goals:
|
||||
** - Each decal can have its own material settings
|
||||
** - Dynamically growing array of decals
|
||||
** - Each decal is assigned a unique "logical-decal-id" by the decal manager
|
||||
** - A decal mesh may be instructed to remove a specified "logical-decal"
|
||||
**
|
||||
** DecalMeshClass is an abstract base class from which we derive concrete classes.
|
||||
*/
|
||||
|
||||
class DecalMeshClass : public RefCountClass
|
||||
{
|
||||
public:
|
||||
|
||||
DecalMeshClass(MeshClass * parent,DecalSystemClass * system);
|
||||
virtual ~DecalMeshClass(void);
|
||||
|
||||
// world_vertex_locs and world_vertex_norms are dynamically updated worldspace vertex data
|
||||
// which are used by some decal types which cannot use static object geometry (such as decals
|
||||
// for skins, procedurally generated meshes, etc.)
|
||||
|
||||
virtual void Render(void) = 0;
|
||||
|
||||
virtual bool Create_Decal( DecalGeneratorClass * generator,
|
||||
const OBBoxClass & localbox,
|
||||
SimpleDynVecClass<uint32> & apt,
|
||||
const DynamicVectorClass<Vector3> * world_vertex_locs = 0) = 0;
|
||||
|
||||
virtual bool Delete_Decal(uint32 id) = 0;
|
||||
|
||||
virtual int Decal_Count(void) = 0;
|
||||
virtual uint32 Get_Decal_ID(int decal_index) = 0;
|
||||
|
||||
MeshClass * Peek_Parent(void);
|
||||
DecalSystemClass * Peek_System(void);
|
||||
|
||||
DecalMeshClass * Peek_Next_Visible(void) { return NextVisible; }
|
||||
void Set_Next_Visible(DecalMeshClass * mesh) { NextVisible = mesh; }
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** Members
|
||||
*/
|
||||
MeshClass * Parent;
|
||||
DecalSystemClass * DecalSystem;
|
||||
DecalMeshClass * NextVisible;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** RigidDecalMeshClass: a concrete class derived from DecalMeshClass which is
|
||||
** used for decals on rigid (non-skin) meshes.
|
||||
*/
|
||||
|
||||
class RigidDecalMeshClass : public DecalMeshClass
|
||||
{
|
||||
public:
|
||||
|
||||
RigidDecalMeshClass(MeshClass * parent,DecalSystemClass * system);
|
||||
virtual ~RigidDecalMeshClass(void);
|
||||
|
||||
// Rigid decal meshes have static geometry so they do not use world_vertex_locs/norms
|
||||
|
||||
virtual void Render(void);
|
||||
|
||||
virtual bool Create_Decal( DecalGeneratorClass * generator,
|
||||
const OBBoxClass & localbox,
|
||||
SimpleDynVecClass<uint32> & apt,
|
||||
const DynamicVectorClass<Vector3> * world_vertex_locs = 0);
|
||||
|
||||
virtual bool Delete_Decal(uint32 id);
|
||||
|
||||
int Decal_Count(void);
|
||||
uint32 Get_Decal_ID(int decal_index);
|
||||
|
||||
protected:
|
||||
|
||||
int Process_Material_Run(int start_index);
|
||||
|
||||
/*
|
||||
** Connectivity
|
||||
*/
|
||||
SimpleDynVecClass<Vector3i> Polys;
|
||||
|
||||
/*
|
||||
** Geometry
|
||||
*/
|
||||
SimpleDynVecClass<Vector3> Verts;
|
||||
SimpleDynVecClass<Vector3> VertNorms;
|
||||
|
||||
/*
|
||||
** Materials
|
||||
*/
|
||||
SimpleDynVecClass<ShaderClass> Shaders;
|
||||
SimpleDynVecClass<TextureClass *> Textures;
|
||||
SimpleDynVecClass<VertexMaterialClass *> VertexMaterials;
|
||||
SimpleDynVecClass<Vector2> TexCoords;
|
||||
|
||||
/*
|
||||
** Decal Organization
|
||||
*/
|
||||
struct DecalStruct
|
||||
{
|
||||
uint32 DecalID;
|
||||
uint16 VertexStartIndex;
|
||||
uint16 VertexCount;
|
||||
uint16 FaceStartIndex;
|
||||
uint16 FaceCount;
|
||||
};
|
||||
|
||||
SimpleDynVecClass<DecalStruct> Decals;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** SkinDecalMeshClass: a concrete class derived from DecalMeshClass which is
|
||||
** used for decals on skin meshes.
|
||||
*/
|
||||
|
||||
class SkinDecalMeshClass : public DecalMeshClass
|
||||
{
|
||||
public:
|
||||
|
||||
SkinDecalMeshClass(MeshClass * parent,DecalSystemClass * system);
|
||||
virtual ~SkinDecalMeshClass(void);
|
||||
|
||||
// Skin decals use world_vertex_locs/norms since they cannot use static geometry
|
||||
|
||||
virtual void Render(void);
|
||||
|
||||
virtual bool Create_Decal( DecalGeneratorClass * generator,
|
||||
const OBBoxClass & localbox,
|
||||
SimpleDynVecClass<uint32> & apt,
|
||||
const DynamicVectorClass<Vector3> * world_vertex_locs);
|
||||
|
||||
virtual bool Delete_Decal(uint32 id);
|
||||
|
||||
int Decal_Count(void);
|
||||
uint32 Get_Decal_ID(int decal_index);
|
||||
|
||||
protected:
|
||||
|
||||
int Process_Material_Run(int start_index);
|
||||
|
||||
/*
|
||||
** Connectivity
|
||||
*/
|
||||
SimpleDynVecClass<Vector3i> Polys;
|
||||
|
||||
/*
|
||||
** Indirected vertex indices (for copying dynamically updated mesh geometry)
|
||||
*/
|
||||
SimpleDynVecClass<uint32> ParentVertexIndices;
|
||||
|
||||
/*
|
||||
** Materials
|
||||
*/
|
||||
SimpleDynVecClass<ShaderClass> Shaders;
|
||||
SimpleDynVecClass<TextureClass *> Textures;
|
||||
SimpleDynVecClass<VertexMaterialClass *> VertexMaterials;
|
||||
SimpleDynVecClass<Vector2> TexCoords;
|
||||
|
||||
/*
|
||||
** Decal Organization
|
||||
*/
|
||||
struct DecalStruct
|
||||
{
|
||||
uint32 DecalID;
|
||||
uint16 VertexStartIndex;
|
||||
uint16 VertexCount;
|
||||
uint16 FaceStartIndex;
|
||||
uint16 FaceCount;
|
||||
};
|
||||
|
||||
SimpleDynVecClass<DecalStruct> Decals;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** DecalMeshClass inline functions
|
||||
*/
|
||||
|
||||
inline MeshClass * DecalMeshClass::Peek_Parent(void)
|
||||
{
|
||||
return Parent;
|
||||
}
|
||||
|
||||
inline DecalSystemClass * DecalMeshClass::Peek_System(void)
|
||||
{
|
||||
return DecalSystem;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** RigidDecalMeshClass inline functions
|
||||
*/
|
||||
|
||||
inline int RigidDecalMeshClass::Decal_Count(void)
|
||||
{
|
||||
return Decals.Count();
|
||||
}
|
||||
|
||||
inline uint32 RigidDecalMeshClass::Get_Decal_ID(int decal_index)
|
||||
{
|
||||
return Decals[decal_index].DecalID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** SkinDecalMeshClass inline functions
|
||||
*/
|
||||
|
||||
inline int SkinDecalMeshClass::Decal_Count(void)
|
||||
{
|
||||
return Decals.Count();
|
||||
}
|
||||
|
||||
inline uint32 SkinDecalMeshClass::Get_Decal_ID(int decal_index)
|
||||
{
|
||||
return Decals[decal_index].DecalID;
|
||||
}
|
||||
|
||||
|
||||
#endif //DECALMSH_H
|
||||
|
||||
487
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalsys.cpp
Normal file
487
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalsys.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/decalsys.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 6/29/01 11:23a $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* DecalSystemClass::DecalSystemClass -- Constructor *
|
||||
* DecalSystemClass::~DecalSystemClass -- Destructor *
|
||||
* DecalSystemClass::Lock_Decal_Generator -- returns a DecalGenerator *
|
||||
* DecalSystemClass::Unlock_Decal_Generator -- Destroys the decal generator *
|
||||
* DecalSystemClass::Generate_Unique_Global_Decal_Id -- Generates a unique id for a decal *
|
||||
* DecalGeneratorClass::DecalGeneratorClass -- Constructor *
|
||||
* DecalGeneratorClass::~DecalGeneratorClass -- Destructor *
|
||||
* DecalGeneratorClass::Add_Mesh -- Meshes that generate a decal should add themselves *
|
||||
* DecalGeneratorClass::Get_Mesh_List -- returns the list of meshes *
|
||||
* DecalGeneratorClass::Set_Mesh_Transform -- sets the current mesh coordinate system *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "decalsys.h"
|
||||
#include "rendobj.h"
|
||||
#include "mesh.h"
|
||||
#include "decalmsh.h"
|
||||
#include "matrixmapper.h"
|
||||
#include "texture.h"
|
||||
|
||||
|
||||
uint32 DecalSystemClass::DecalIDGenerator = 0;
|
||||
|
||||
|
||||
/*
|
||||
** DecalSystemClass Implementation
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalSystemClass::DecalSystemClass -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
DecalSystemClass::DecalSystemClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalSystemClass::~DecalSystemClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
DecalSystemClass::~DecalSystemClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalSystemClass::Lock_Decal_Generator -- returns a DecalGenerator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
DecalGeneratorClass * DecalSystemClass::Lock_Decal_Generator(void)
|
||||
{
|
||||
DecalGeneratorClass * gen = W3DNEW DecalGeneratorClass(Generate_Decal_Id(), this);
|
||||
return gen;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalSystemClass::Unlock_Decal_Generator -- Destroys the decal generator *
|
||||
* *
|
||||
* Derived classes may take a record of the results of the generator here. Then they can *
|
||||
* put a cap on the total number of decals in the system or whatever... *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void DecalSystemClass::Unlock_Decal_Generator(DecalGeneratorClass * generator)
|
||||
{
|
||||
delete generator;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalSystemClass::Generate_Unique_Global_Decal_Id -- Generates a unique id for a decal *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Hopefully you won't use more than 4 billion decals at one time... *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
uint32 DecalSystemClass::Generate_Unique_Global_Decal_Id(void)
|
||||
{
|
||||
return DecalIDGenerator++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** DecalGeneratorClass Implementation
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalGeneratorClass::DecalGeneratorClass -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
DecalGeneratorClass::DecalGeneratorClass(uint32 id,DecalSystemClass * system) :
|
||||
DecalID(id),
|
||||
System(system),
|
||||
BackfaceVal(0.0f),
|
||||
ApplyToTranslucentMeshes(false),
|
||||
Material(NULL)
|
||||
{
|
||||
Material = NEW_REF(MaterialPassClass,());
|
||||
|
||||
WWASSERT(System != NULL);
|
||||
WWASSERT(Material != NULL);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalGeneratorClass::~DecalGeneratorClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
DecalGeneratorClass::~DecalGeneratorClass(void)
|
||||
{
|
||||
REF_PTR_RELEASE(Material);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalGeneratorClass::Add_Mesh -- Meshes that generate a decal should add themselves *
|
||||
* *
|
||||
* This adds a mesh to the internal list. All meshes that actually add a decal should add *
|
||||
* themselves to this list so that the DecalSystem can keep track of them. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void DecalGeneratorClass::Add_Mesh(RenderObjClass * mesh)
|
||||
{
|
||||
WWASSERT(mesh->Class_ID() == RenderObjClass::CLASSID_MESH);
|
||||
MeshList.Add(mesh);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalGeneratorClass::Get_Mesh_List -- returns the list of meshes *
|
||||
* *
|
||||
* This is the list of meshes which generated decals for this "logical decal" *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
NonRefRenderObjListClass & DecalGeneratorClass::Get_Mesh_List(void)
|
||||
{
|
||||
return MeshList;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DecalGeneratorClass::Set_Mesh_Transform -- sets the current mesh coordinate system *
|
||||
* *
|
||||
* The coordinate system of the mesh is needed in order to compute texture coordinates for *
|
||||
* the decal polygons. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/26/00 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void DecalGeneratorClass::Set_Mesh_Transform(const Matrix3D & mesh_transform)
|
||||
{
|
||||
/*
|
||||
** Mobj-texture = Projection * Mwrld-texture * Mobj-wrld
|
||||
*/
|
||||
Matrix3D world_to_texture;
|
||||
Matrix3D tmp;
|
||||
Matrix4 mesh_to_texture;
|
||||
|
||||
Transform.Get_Orthogonal_Inverse(world_to_texture);
|
||||
Matrix3D::Multiply(world_to_texture,mesh_transform,&tmp);
|
||||
Matrix4::Multiply(Projection,tmp,&mesh_to_texture);
|
||||
|
||||
/*
|
||||
** Plug the matrix and texture size into the mapper
|
||||
*/
|
||||
if (WW3D::Is_Texturing_Enabled()) {
|
||||
float texsize = 64.0f;
|
||||
TextureClass * tex = Material->Peek_Texture();
|
||||
WWASSERT(tex != NULL);
|
||||
if (tex) {
|
||||
SurfaceClass::SurfaceDescription surface_desc;
|
||||
tex->Get_Level_Description(surface_desc);
|
||||
texsize = surface_desc.Width;
|
||||
}
|
||||
|
||||
Mapper->Set_Texture_Transform(mesh_to_texture,texsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** MultiFixedPoolDecalSystemClass implementation
|
||||
*/
|
||||
|
||||
MultiFixedPoolDecalSystemClass::MultiFixedPoolDecalSystemClass(uint32 num_pools, const uint32 *pool_sizes) :
|
||||
Pools(0),
|
||||
PoolCount(num_pools),
|
||||
Generator_PoolID(0),
|
||||
Generator_SlotID(0)
|
||||
{
|
||||
if (PoolCount)
|
||||
{
|
||||
WWASSERT(pool_sizes);
|
||||
Pools = W3DNEWARRAY LogicalDecalPoolClass [PoolCount];
|
||||
}
|
||||
for (uint32 i = 0; i < PoolCount; i++) {
|
||||
assert(pool_sizes[i]);
|
||||
Pools[i].Initialize(pool_sizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
MultiFixedPoolDecalSystemClass::MultiFixedPoolDecalSystemClass(const MultiFixedPoolDecalSystemClass & that) :
|
||||
Pools(0),
|
||||
PoolCount(that.PoolCount),
|
||||
Generator_PoolID(that.Generator_PoolID),
|
||||
Generator_SlotID(that.Generator_SlotID)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
// Allocate arrays (we dont' copy array contents because those are mesh-specific and will be
|
||||
// filled when the state is set anyway)
|
||||
if (PoolCount) Pools = W3DNEWARRAY LogicalDecalPoolClass [PoolCount];
|
||||
for (i = 0; i < PoolCount; i++) {
|
||||
Pools[i].Initialize(that.Pools[i].Size);
|
||||
}
|
||||
}
|
||||
|
||||
MultiFixedPoolDecalSystemClass::~MultiFixedPoolDecalSystemClass(void)
|
||||
{
|
||||
if (Pools) {
|
||||
delete [] Pools;
|
||||
Pools = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This clears the slot in addition to locking the generator, thus preventing any decal id
|
||||
// collisions (since any decal previously in that slot will have the same id as the new one).
|
||||
DecalGeneratorClass * MultiFixedPoolDecalSystemClass::Lock_Decal_Generator(void)
|
||||
{
|
||||
Clear_Decal_Slot(Generator_PoolID, Generator_SlotID);
|
||||
return DecalSystemClass::Lock_Decal_Generator();
|
||||
}
|
||||
|
||||
// This will register the decal in the system in the appropriate pool and slot (determined by
|
||||
// the generator's pool and slot ids), removing any decal which may have been there before.
|
||||
void MultiFixedPoolDecalSystemClass::Unlock_Decal_Generator(DecalGeneratorClass * generator)
|
||||
{
|
||||
find_logical_decal(generator->Get_Decal_ID()).Set(generator);
|
||||
DecalSystemClass::Unlock_Decal_Generator(generator);
|
||||
}
|
||||
|
||||
// This notifies the system that a mesh which has decals on it was destroyed - therefore we
|
||||
// need to remove the mesh from our list to avoid dangling pointers.
|
||||
void MultiFixedPoolDecalSystemClass::Decal_Mesh_Destroyed(uint32 decal_id,DecalMeshClass * mesh)
|
||||
{
|
||||
// We must remove this mesh from all lists where it is present. The method is: for each
|
||||
// decal id present in the decal mesh, find the logical decal and remove the decal mesh from
|
||||
// its list.
|
||||
assert(mesh);
|
||||
MeshClass *parent = mesh->Peek_Parent();
|
||||
find_logical_decal(decal_id).MeshList.Remove(parent);
|
||||
}
|
||||
|
||||
// Not part of the DecalSystemClass interface - this function removes any decal currently in
|
||||
// the given slot in the given pool.
|
||||
void MultiFixedPoolDecalSystemClass::Clear_Decal_Slot(uint32 pool_id, uint32 slot_id)
|
||||
{
|
||||
find_logical_decal(pool_id, slot_id).Clear(encode_decal_id(pool_id, slot_id));
|
||||
}
|
||||
|
||||
// This one removes all decals in a given pool.
|
||||
void MultiFixedPoolDecalSystemClass::Clear_Pool(uint32 pool_id)
|
||||
{
|
||||
LogicalDecalPoolClass & pool = Pools[pool_id];
|
||||
uint32 pool_size = pool.Size;
|
||||
for (uint32 slot_id = 0; slot_id < pool_size; slot_id++) {
|
||||
pool.Array[slot_id].Clear(encode_decal_id(pool_id, slot_id));
|
||||
}
|
||||
}
|
||||
|
||||
// And this one removes all decals in the system.
|
||||
void MultiFixedPoolDecalSystemClass::Clear_All_Decals(void)
|
||||
{
|
||||
for (uint32 pool_id = 0; pool_id < PoolCount; pool_id++) {
|
||||
LogicalDecalPoolClass & pool = Pools[pool_id];
|
||||
uint32 pool_size = pool.Size;
|
||||
for (uint32 slot_id = 0; slot_id < pool_size; slot_id++) {
|
||||
pool.Array[slot_id].Clear(encode_decal_id(pool_id, slot_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a reference to the logical decal at the given pool and slot id (performs range checking)
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalClass & MultiFixedPoolDecalSystemClass::find_logical_decal(uint32 pool_id, uint32 slot_id)
|
||||
{
|
||||
assert(pool_id < PoolCount);
|
||||
pool_id = MIN(pool_id, PoolCount);
|
||||
LogicalDecalPoolClass & pool = Pools[pool_id];
|
||||
assert(slot_id < pool.Size);
|
||||
slot_id = MIN(slot_id, pool.Size);
|
||||
return pool.Array[slot_id];
|
||||
}
|
||||
|
||||
// Get a reference to the logical decal with the given decal id
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalClass & MultiFixedPoolDecalSystemClass::find_logical_decal(uint32 decal_id)
|
||||
{
|
||||
uint32 pool_id, slot_id;
|
||||
decode_decal_id(decal_id, pool_id, slot_id);
|
||||
return find_logical_decal(pool_id, slot_id);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** MultiFixedPoolDecalSystemClass::LogicalDecalClass implementation
|
||||
*/
|
||||
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalClass::LogicalDecalClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalClass::~LogicalDecalClass(void)
|
||||
{
|
||||
// We don't need to do anything here since the mesh list will get removed automatically and
|
||||
// the decals themselves don't neccessarily need to be removed because the logical decal is.
|
||||
// (we don't hold references to the meshes in the mesh list)
|
||||
}
|
||||
|
||||
// Sets the logical decal to the one specified by the given generator (clearing any existing
|
||||
// decal information)
|
||||
void MultiFixedPoolDecalSystemClass::LogicalDecalClass::Set(DecalGeneratorClass * generator)
|
||||
{
|
||||
Clear(generator->Get_Decal_ID());
|
||||
|
||||
/*
|
||||
** Copy the generators' mesh list into our mesh list
|
||||
*/
|
||||
NonRefRenderObjListIterator gen_mesh_it(&(generator->Get_Mesh_List()));
|
||||
for (gen_mesh_it.First(); !gen_mesh_it.Is_Done(); gen_mesh_it.Next()) {
|
||||
MeshList.Add(gen_mesh_it.Get_Obj());
|
||||
}
|
||||
}
|
||||
|
||||
// Just clears any existing logical decal information, leaving the decal empty.
|
||||
void MultiFixedPoolDecalSystemClass::LogicalDecalClass::Clear(uint32 decal_id)
|
||||
{
|
||||
// Remove the decal with this ID from all meshes where it appears
|
||||
NonRefRenderObjListIterator it(&MeshList);
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
it.Get_Obj()->Delete_Decal(decal_id);
|
||||
}
|
||||
|
||||
// Delete list
|
||||
while (!MeshList.Is_Empty()) {
|
||||
MeshList.Remove_Head();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass implementation
|
||||
*/
|
||||
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::LogicalDecalPoolClass(void) :
|
||||
Array(0),
|
||||
Size(0)
|
||||
{
|
||||
}
|
||||
|
||||
MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::~LogicalDecalPoolClass(void)
|
||||
{
|
||||
if (Array) {
|
||||
delete [] Array;
|
||||
Array = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::Initialize(uint32 size)
|
||||
{
|
||||
if (Array) {
|
||||
delete [] Array;
|
||||
Array = 0;
|
||||
}
|
||||
|
||||
Size = size;
|
||||
assert(Size);
|
||||
Array = W3DNEWARRAY LogicalDecalClass[Size];
|
||||
}
|
||||
308
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalsys.h
Normal file
308
Generals/Code/Libraries/Source/WWVegas/WW3D2/decalsys.h
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/decalsys.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 6/29/01 11:30a $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DECALSYS_H
|
||||
#define DECALSYS_H
|
||||
|
||||
#include "always.h"
|
||||
#include "matrix3d.h"
|
||||
#include "matrix4.h"
|
||||
#include "obbox.h"
|
||||
#include "robjlist.h"
|
||||
#include "matpass.h"
|
||||
#include "projector.h"
|
||||
|
||||
class DecalGeneratorClass;
|
||||
class DecalMeshClass;
|
||||
|
||||
/**
|
||||
** DecalSystemClass
|
||||
** This is a class that manages creation and destruction of decals in the system. It is
|
||||
** meant to be over-ridden for game-specific behaviors.
|
||||
**
|
||||
** Sample Code:
|
||||
** 1 - Create the generator. The system gives it a unique id and gives you a clean decal generator
|
||||
**
|
||||
** DecalGeneratorClass * gen = DecalSystem->Lock_Decal_Generator();
|
||||
** gen->Set_Transform(tm);
|
||||
** gen->Set_Projection(proj_tm);
|
||||
** gen->Set_Bounds(OBBox);
|
||||
**
|
||||
** 2 - Apply the generator to any objects that you want it to affect. It wont do anything if it
|
||||
** does not overlap any polygons in those objects
|
||||
**
|
||||
** Scene->Collect_Objects(gen->Get_Bounding_Box(),objectlist);
|
||||
** for (iterator.First(objectlist); !iterator.Is_Done(); iterator.Next()) {
|
||||
** iterator.Peek_Object()->Create_Decal(gen);
|
||||
** }
|
||||
**
|
||||
** 3 - Release the generator back to the system. At this point, the system may record which meshes
|
||||
** actually generated extra decal polygons for future removal. All of this information will be
|
||||
** tied together with the unique 'decal ID' that was assigned to the generator.
|
||||
**
|
||||
** DecalSystem->Unlock_Decal_Generator(gen);
|
||||
**
|
||||
*/
|
||||
class DecalSystemClass
|
||||
{
|
||||
public:
|
||||
DecalSystemClass(void);
|
||||
virtual ~DecalSystemClass(void);
|
||||
|
||||
/*
|
||||
** Create and release DecalGenerators. Note that this is the point at which the
|
||||
** decal system can track "logical" decals. The generator will keep an internal list
|
||||
** of all of the render objects which generated decals which you should copy if you
|
||||
** want to track them (e.g. if you want to cap the maximum number of active decals and
|
||||
** kill the old ones...)
|
||||
*/
|
||||
virtual DecalGeneratorClass * Lock_Decal_Generator(void);
|
||||
virtual void Unlock_Decal_Generator(DecalGeneratorClass * generator);
|
||||
|
||||
/*
|
||||
** When a decal-mesh is destroyed, it must inform the DecalSystem. Otherwise, systems
|
||||
** which track decals can get dangling pointers.
|
||||
*/
|
||||
virtual void Decal_Mesh_Destroyed(uint32 decal_id,DecalMeshClass * mesh) { }
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** This generates the decal ID when a generator is created. This decal system reroutes this
|
||||
** to Generate_Unique_Global_Decal_Id(), but other decal systems may use a different method.
|
||||
*/
|
||||
virtual uint32 Generate_Decal_Id(void) { return Generate_Unique_Global_Decal_Id(); }
|
||||
|
||||
/*
|
||||
** Unique ID generation for decals. Not all decal systems have to use
|
||||
** this method of generating ids. Some may wish to assign the id as the
|
||||
** array index of the logical id or use some other aritrary method.
|
||||
*/
|
||||
static uint32 Generate_Unique_Global_Decal_Id(void);
|
||||
|
||||
static uint32 DecalIDGenerator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DecalGeneratorClass
|
||||
** This class encapsulates the information needed to generate a decal. It also tracks
|
||||
** what meshes actually used it to generate new decal polygons.
|
||||
*/
|
||||
class DecalGeneratorClass : public ProjectorClass
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
** All meshes that actually generate decal polygons should register themselves in the
|
||||
** list. Then when the decal generation is finished, this list can be copied so that
|
||||
** we can come back to those meshes and remove the decals if we want to.
|
||||
*/
|
||||
void Add_Mesh(RenderObjClass * mesh);
|
||||
NonRefRenderObjListClass & Get_Mesh_List(void);
|
||||
|
||||
/*
|
||||
** Decal generator parameters.
|
||||
** see ProjectorClass for control over the coordinate system, projection, etc
|
||||
*/
|
||||
uint32 Get_Decal_ID(void) { return DecalID; }
|
||||
DecalSystemClass * Peek_Decal_System(void) { return System; }
|
||||
|
||||
/*
|
||||
** Backface rejection thresh-hold. The dot-product between the projection vector and
|
||||
** the normal of each polygon is taken, if the result is greater than this value the polygon
|
||||
** is accepted into the decal. Set it to -1 if you want to accept all polygons.
|
||||
*/
|
||||
void Set_Backface_Threshhold(float val) { BackfaceVal = val; }
|
||||
float Get_Backface_Threshhold(void) { return BackfaceVal; }
|
||||
|
||||
/*
|
||||
** Normally, decals are not generated on translucent meshes. This is due to the "floating
|
||||
** decals" that you can get on things like trees. The user can override this behavior
|
||||
** through the following interface.
|
||||
*/
|
||||
void Apply_To_Translucent_Meshes(bool onoff) { ApplyToTranslucentMeshes = onoff; }
|
||||
bool Is_Applied_To_Translucent_Meshes(void) { return ApplyToTranslucentMeshes; }
|
||||
|
||||
/*
|
||||
** Material parameters: just grab a pointer the material pass and modify it.
|
||||
** Remember to release your ref to it when you are done.
|
||||
*/
|
||||
MaterialPassClass * Get_Material(void) { WWASSERT(Material != NULL); Material->Add_Ref(); return Material; }
|
||||
|
||||
/*
|
||||
** Decal generation support. Call Set_Mesh_Transform for the mesh you want to add
|
||||
** a decal to. Then for each vertex, you can call 'Compute_Texture_Coordinate'
|
||||
*/
|
||||
void Set_Mesh_Transform(const Matrix3D & tm);
|
||||
|
||||
protected:
|
||||
|
||||
DecalGeneratorClass(uint32 id,DecalSystemClass * system);
|
||||
~DecalGeneratorClass(void);
|
||||
|
||||
/*
|
||||
** Logical Decal ID, DecalSystem that this generator is tied to
|
||||
*/
|
||||
DecalSystemClass * System;
|
||||
uint32 DecalID; // unique ID generated by the DecalSystem
|
||||
|
||||
/*
|
||||
** Backface Threshhold, Translucent mesh decal enable
|
||||
*/
|
||||
float BackfaceVal;
|
||||
bool ApplyToTranslucentMeshes;
|
||||
|
||||
/*
|
||||
** Material settings
|
||||
*/
|
||||
MaterialPassClass * Material; // material settings for the decal
|
||||
|
||||
/*
|
||||
** Results, list of the meshes which actually generated decal polygons for this logical decal.
|
||||
*/
|
||||
NonRefRenderObjListClass MeshList;
|
||||
|
||||
friend class DecalSystemClass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** MultiFixedPoolDecalSystemClass: This is for decal systems which use several fixed-size decal
|
||||
** pools (If more than one pool is used, it is usually to have separate pools for several
|
||||
** different classes of decals). Note that here the decal IDs are a combination of the pool and
|
||||
** slot ids. (decal ids only have to be unique within a given decal system)
|
||||
*/
|
||||
|
||||
class MultiFixedPoolDecalSystemClass : public DecalSystemClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
MultiFixedPoolDecalSystemClass(uint32 num_pools, const uint32 *pool_sizes);
|
||||
MultiFixedPoolDecalSystemClass(const MultiFixedPoolDecalSystemClass & that);
|
||||
virtual ~MultiFixedPoolDecalSystemClass(void);
|
||||
|
||||
// This clears the slot in addition to locking the generator, thus preventing any decal id
|
||||
// collisions (since any decal previously in that slot will have the same id as the new one).
|
||||
virtual DecalGeneratorClass * Lock_Decal_Generator(void);
|
||||
|
||||
// This will register the decal in the system in the appropriate pool and slot (determined by
|
||||
// the generator's pool and slot ids), removing any decal which may have been there before.
|
||||
virtual void Unlock_Decal_Generator(DecalGeneratorClass * generator);
|
||||
|
||||
// This notifies the system that a mesh which has decals on it was destroyed - therefore we
|
||||
// need to remove the mesh from our list to avoid dangling pointers.
|
||||
virtual void Decal_Mesh_Destroyed(uint32 id,DecalMeshClass * mesh);
|
||||
|
||||
// Not part of the DecalSystemClass interface - this function removes any decal currently in
|
||||
// the given slot in the given pool.
|
||||
void Clear_Decal_Slot(uint32 pool_id, uint32 slot_id);
|
||||
|
||||
// This one removes all decals in a given pool.
|
||||
void Clear_Pool(uint32 pool_id);
|
||||
|
||||
// And this one removes all decals in the system.
|
||||
void Clear_All_Decals(void);
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** This generates the decal ID when a generator is created. This decal system generates the
|
||||
** decal ID from a pool ID and slot ID which are part of the state of the system so someone
|
||||
** can set them before calling Lock_Decal_Generator() (which is where this function is called).
|
||||
** We do it this way to avoid needing to override Lock_Decal_Generator().
|
||||
*/
|
||||
virtual uint32 Generate_Decal_Id(void) { return encode_decal_id(Generator_PoolID, Generator_SlotID); }
|
||||
uint32 Generator_PoolID; // These should be set before calling Lock_Decal_Generator()
|
||||
uint32 Generator_SlotID; // These should be set before calling Lock_Decal_Generator()
|
||||
|
||||
class LogicalDecalClass;
|
||||
|
||||
// Get a reference to the logical decal at the given pool and slot id (performs range chacking)
|
||||
LogicalDecalClass & find_logical_decal(uint32 pool_id, uint32 slot_id);
|
||||
|
||||
// Get a reference to the logical decal with the given decal id
|
||||
LogicalDecalClass & find_logical_decal(uint32 decal_id);
|
||||
|
||||
// The decal ids are formed so that the upper 16 bits are equal to the pool id and the lower
|
||||
// 16 bits are equal to the slot id.
|
||||
static uint32 encode_decal_id(uint32 pool_id, uint32 slot_id) { return (slot_id & 0xFFFF) | (pool_id << 16); }
|
||||
static void decode_decal_id(uint32 decal_id, uint32 & pool_id, uint32 & slot_id) { slot_id = decal_id & 0xFFFF; pool_id = decal_id >> 16; }
|
||||
|
||||
// A class to store the meshes to which the decal has been applied (so that they can be removed when needed)
|
||||
class LogicalDecalClass
|
||||
{
|
||||
public:
|
||||
LogicalDecalClass(void);
|
||||
~LogicalDecalClass(void);
|
||||
|
||||
void Set(DecalGeneratorClass * generator);
|
||||
|
||||
// Just clears any existing logical decal information, leaving the decal empty.
|
||||
void Clear(uint32 decal_id);
|
||||
|
||||
NonRefRenderObjListClass MeshList;
|
||||
};
|
||||
|
||||
class LogicalDecalPoolClass
|
||||
{
|
||||
public:
|
||||
LogicalDecalPoolClass(void);
|
||||
~LogicalDecalPoolClass(void);
|
||||
|
||||
void Initialize(uint32 size);
|
||||
|
||||
LogicalDecalClass * Array;
|
||||
uint32 Size;
|
||||
};
|
||||
|
||||
LogicalDecalPoolClass * Pools;
|
||||
uint32 PoolCount;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //DECALSYS_H
|
||||
|
||||
1165
Generals/Code/Libraries/Source/WWVegas/WW3D2/distlod.cpp
Normal file
1165
Generals/Code/Libraries/Source/WWVegas/WW3D2/distlod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
246
Generals/Code/Libraries/Source/WWVegas/WW3D2/distlod.h
Normal file
246
Generals/Code/Libraries/Source/WWVegas/WW3D2/distlod.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/distlod.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 1/25/01 2:46p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DISTLOD_H
|
||||
#define DISTLOD_H
|
||||
|
||||
#include "proto.h"
|
||||
#include "rendobj.h"
|
||||
#include "composite.h"
|
||||
#include "w3derr.h"
|
||||
|
||||
class ChunkLoadClass;
|
||||
struct DistLODNodeDefStruct;
|
||||
class DistLODDefClass;
|
||||
|
||||
|
||||
/*
|
||||
** DistLODClass
|
||||
** Distance based LOD switching. This is a simple LOD object which switches models
|
||||
** based on the pre-set distances. Note that the models are stored in order of
|
||||
** descending resolution; i.e. the highest res model will be in index 0.
|
||||
** Most functions in this class simply pass the call on to all of the LODs.
|
||||
**
|
||||
** When the level of detail is changed, the LOD which was being used must be
|
||||
** notified that it is being removed from the scene and the new LOD must be
|
||||
** notified that it is being added. This allows us to correctly handle lights
|
||||
** and particle emitters in LODs...
|
||||
*/
|
||||
class DistLODClass : public CompositeRenderObjClass
|
||||
{
|
||||
public:
|
||||
|
||||
DistLODClass(const DistLODDefClass & desc);
|
||||
DistLODClass(const DistLODClass & that);
|
||||
virtual ~DistLODClass(void);
|
||||
virtual RenderObjClass * Clone(void) const { return W3DNEW DistLODClass(*this); }
|
||||
virtual int Class_ID(void) const { return CLASSID_DISTLOD; }
|
||||
virtual int Get_Num_Polys(void) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Rendering
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - "Scene Graph"
|
||||
// Access each LOD individually through Get_Sub_Object.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
|
||||
virtual int Get_Num_Sub_Objects(void) const;
|
||||
virtual RenderObjClass * Get_Sub_Object(int index) const;
|
||||
|
||||
virtual int Add_Sub_Object_To_Bone(RenderObjClass * subobj,int bone_index);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Hierarchical Animation
|
||||
// Here again, these functions are passed on to all LODs. Each LOD is
|
||||
// assumed to use the same HTree (or have no HTree, this is so that LODs are
|
||||
// animation-compatible) so the bone query functions simply pass to the top
|
||||
// LOD.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Animation( void );
|
||||
virtual void Set_Animation( HAnimClass * motion, float frame, int anim_mode = ANIM_MODE_MANUAL);
|
||||
virtual void Set_Animation( HAnimClass * motion0,float frame0,HAnimClass * motion1,float frame1,float percentage);
|
||||
virtual void Set_Animation( HAnimComboClass * anim_combo);
|
||||
virtual HAnimClass * Peek_Animation( void );
|
||||
virtual int Get_Num_Bones(void);
|
||||
virtual const char * Get_Bone_Name(int bone_index);
|
||||
virtual int Get_Bone_Index(const char * bonename);
|
||||
virtual const Matrix3D & Get_Bone_Transform(const char * bonename);
|
||||
virtual const Matrix3D & Get_Bone_Transform(int boneindex);
|
||||
virtual void Capture_Bone(int bindex);
|
||||
virtual void Release_Bone(int bindex);
|
||||
virtual bool Is_Bone_Captured(int bindex) const;
|
||||
virtual void Control_Bone(int bindex,const Matrix3D & tm,bool world_space_translation = false);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Collision Detection, Ray Tracing
|
||||
// Collision tests are performed on the top-level LOD.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Attributes, Options, Properties, etc
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Get_Num_Snap_Points(void);
|
||||
virtual void Get_Snap_Point(int index,Vector3 * set);
|
||||
virtual void Scale(float scale);
|
||||
virtual void Scale(float scalex, float scaley, float scalez);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// DistLOD Interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual float Get_Switch_Up_Dist(int index) const { return Lods[index].ResUpDist; }
|
||||
virtual float Get_Switch_Down_Dist(int index) const { return Lods[index].ResDownDist; }
|
||||
virtual void Set_Switch_Up_Dist(int index, float dist) { Lods[index].ResUpDist = dist; }
|
||||
virtual void Set_Switch_Down_Dist(int index, float dist) { Lods[index].ResDownDist = dist; }
|
||||
|
||||
private:
|
||||
|
||||
enum { HIGHEST_LOD = 0 };
|
||||
|
||||
void Free(void);
|
||||
void Update_Lod(const CameraClass & camera);
|
||||
void Increment_Lod(void);
|
||||
void Decrement_Lod(void);
|
||||
|
||||
struct LODNodeClass
|
||||
{
|
||||
RenderObjClass * Model;
|
||||
float ResUpDist;
|
||||
float ResDownDist;
|
||||
};
|
||||
|
||||
int LodCount; // how many models are in this LOD object
|
||||
int CurLod; // which model is currently used for rendering
|
||||
int VpPushLod; // which model was used for the vp->push (in CurLod changes before the pop)
|
||||
LODNodeClass * Lods; // one LODNodeClass for each level
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Loaders for DistLODClass
|
||||
*/
|
||||
class DistLODLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Chunk_Type (void) { return W3D_CHUNK_LODMODEL; }
|
||||
virtual PrototypeClass * Load_W3D(ChunkLoadClass & cload);
|
||||
};
|
||||
|
||||
/*
|
||||
** DistLODModelDefStruct
|
||||
** Describes a single model in a Distance-Based LOD Object
|
||||
*/
|
||||
struct DistLODNodeDefStruct
|
||||
{
|
||||
DistLODNodeDefStruct(void) : Name(NULL),ResDownDist(0.0f),ResUpDist(0.0f) {}
|
||||
|
||||
char * Name;
|
||||
float ResDownDist;
|
||||
float ResUpDist;
|
||||
};
|
||||
|
||||
/*
|
||||
** DistLODDefClass
|
||||
** Description of a Distance-Based LOD Object. These are similar
|
||||
** to the HModelDef's that are used by the asset manager to construct
|
||||
** HModels.
|
||||
*/
|
||||
class DistLODDefClass
|
||||
{
|
||||
public:
|
||||
|
||||
DistLODDefClass(void);
|
||||
DistLODDefClass(const char * name,int lodcount,DistLODNodeDefStruct * lods);
|
||||
~DistLODDefClass(void);
|
||||
|
||||
WW3DErrorType Load_W3D(ChunkLoadClass & cload);
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
|
||||
private:
|
||||
|
||||
char * Name;
|
||||
|
||||
int LodCount;
|
||||
DistLODNodeDefStruct * Lods;
|
||||
|
||||
void Free(void);
|
||||
bool read_header(ChunkLoadClass & cload);
|
||||
bool read_node(ChunkLoadClass & cload,DistLODNodeDefStruct * node);
|
||||
|
||||
friend class DistLODClass;
|
||||
};
|
||||
|
||||
/*
|
||||
** Prototype for Dist-LOD objects
|
||||
*/
|
||||
class DistLODPrototypeClass : public W3DMPO, public PrototypeClass
|
||||
{
|
||||
W3DMPO_GLUE(DistLODPrototypeClass)
|
||||
public:
|
||||
DistLODPrototypeClass( DistLODDefClass *def ) { Definition = def; }
|
||||
|
||||
virtual const char * Get_Name(void) const { return Definition->Get_Name(); }
|
||||
virtual int Get_Class_ID(void) const { return RenderObjClass::CLASSID_DISTLOD; }
|
||||
virtual RenderObjClass * Create(void);
|
||||
virtual void DeleteSelf() { delete this; }
|
||||
|
||||
protected:
|
||||
virtual ~DistLODPrototypeClass(void) { delete Definition; }
|
||||
|
||||
private:
|
||||
DistLODDefClass * Definition;
|
||||
};
|
||||
|
||||
/*
|
||||
** Instance of the loaders which the asset manager install
|
||||
*/
|
||||
extern DistLODLoaderClass _DistLODLoader;
|
||||
|
||||
#endif
|
||||
209
Generals/Code/Libraries/Source/WWVegas/WW3D2/dllist.h
Normal file
209
Generals/Code/Libraries/Source/WWVegas/WW3D2/dllist.h
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dllist.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 3/21/01 6:18p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DLLIST_H
|
||||
#define DLLIST_H
|
||||
|
||||
|
||||
template <class T> class DLNodeClass;
|
||||
|
||||
template <class T>
|
||||
class DLListClass
|
||||
{
|
||||
friend DLNodeClass<T>;
|
||||
DLNodeClass<T>* head;
|
||||
DLNodeClass<T>* tail;
|
||||
|
||||
public:
|
||||
DLListClass() : head(0), tail(0) {}
|
||||
virtual ~DLListClass() { }
|
||||
|
||||
void Add_Head(DLNodeClass<T>* node);
|
||||
void Remove_Head();
|
||||
void Add_Tail(DLNodeClass<T>* node);
|
||||
void Remove_Tail();
|
||||
|
||||
T* Head() { return static_cast<T*>(head); }
|
||||
T* Tail() { return static_cast<T*>(tail); }
|
||||
const T* Const_Head() const { return static_cast<const T*>(head); }
|
||||
const T* Const_Tail() const { return static_cast<const T*>(tail); }
|
||||
};
|
||||
|
||||
// Destroy-list will call delete for all nodes when the list is destructed. Note that the class doesn't work
|
||||
// with undeclared pointer types (destructor has to be known).
|
||||
template <class T>
|
||||
class DLDestroyListClass : public DLListClass<T>
|
||||
{
|
||||
public:
|
||||
virtual ~DLDestroyListClass()
|
||||
{
|
||||
while (T* t=Head()) {
|
||||
delete t;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DLNodeClass : public W3DMPO
|
||||
{
|
||||
// nope, this is an ABC
|
||||
//W3DMPO_GLUE(DLNodeClass)
|
||||
|
||||
friend DLListClass<T>;
|
||||
DLNodeClass<T>* succ;
|
||||
DLNodeClass<T>* pred;
|
||||
DLListClass<T>* list;
|
||||
public:
|
||||
DLNodeClass() : succ(0), pred(0), list(0) {}
|
||||
~DLNodeClass() { Remove(); }
|
||||
|
||||
void Insert_Before(DLNodeClass<T>* n)
|
||||
{
|
||||
list=n->list;
|
||||
succ=n;
|
||||
pred=n->pred;
|
||||
if (n->pred) n->pred->succ=this;
|
||||
n->pred=this;
|
||||
|
||||
if (list->head==n) {
|
||||
list->head=this;
|
||||
}
|
||||
}
|
||||
|
||||
void Insert_After(DLNodeClass<T>* n)
|
||||
{
|
||||
list=n->list;
|
||||
pred=n;
|
||||
succ=n->succ;
|
||||
if (n->succ) n->succ->pred=this;
|
||||
n->succ=this;
|
||||
|
||||
if (list->tail==n) {
|
||||
list->tail=this;
|
||||
}
|
||||
}
|
||||
|
||||
void Remove()
|
||||
{
|
||||
if (!list) return;
|
||||
if (list->Head()==this) {
|
||||
DLListClass<T>* tmp_list=list;
|
||||
list=0;
|
||||
tmp_list->Remove_Head();
|
||||
return;
|
||||
}
|
||||
if (list->Tail()==this) {
|
||||
DLListClass<T>* tmp_list=list;
|
||||
list=0;
|
||||
tmp_list->Remove_Tail();
|
||||
return;
|
||||
}
|
||||
if (succ) succ->pred=pred;
|
||||
if (pred) pred->succ=succ;
|
||||
list=0;
|
||||
}
|
||||
|
||||
|
||||
T* Succ() { return static_cast<T*>(succ); }
|
||||
T* Pred() { return static_cast<T*>(pred); }
|
||||
const T* Const_Succ() const { return static_cast<const T*>(succ); }
|
||||
const T* Const_Pred() const { return static_cast<const T*>(pred); }
|
||||
|
||||
DLListClass<T>* List() { return list; }
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
inline void DLListClass<T>::Add_Head(DLNodeClass<T>* n)
|
||||
{
|
||||
n->list=this;
|
||||
if (head) {
|
||||
n->Insert_Before(head);
|
||||
head=n;
|
||||
}
|
||||
else {
|
||||
tail=n;
|
||||
head=n;
|
||||
n->succ=0;
|
||||
n->pred=0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void DLListClass<T>::Add_Tail(DLNodeClass<T>* n)
|
||||
{
|
||||
n->list=this;
|
||||
if (tail) {
|
||||
n->Insert_After(tail);
|
||||
tail=n;
|
||||
}
|
||||
else {
|
||||
tail=n;
|
||||
head=n;
|
||||
n->succ=0;
|
||||
n->pred=0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void DLListClass<T>::Remove_Head()
|
||||
{
|
||||
if (!head) return;
|
||||
DLNodeClass<T>* n=head;
|
||||
head=head->Succ();
|
||||
if (!head) tail=head;
|
||||
else head->pred=0;
|
||||
n->Remove();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void DLListClass<T>::Remove_Tail()
|
||||
{
|
||||
if (!tail) return;
|
||||
DLNodeClass<T>* n=tail;
|
||||
tail=tail->Pred();
|
||||
if (!tail) head=tail;
|
||||
else tail->succ=0;
|
||||
n->Remove();
|
||||
}
|
||||
|
||||
#endif //DLLIST_H
|
||||
199
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp
Normal file
199
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : dx8 caps *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/ww3d2/dx8caps.cpp $*
|
||||
* *
|
||||
* Original Author:: Hector Yee *
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 8/29/01 8:16p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "always.h"
|
||||
#include "dx8caps.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "formconv.h"
|
||||
|
||||
D3DCAPS8 DX8Caps::hwVPCaps;
|
||||
D3DCAPS8 DX8Caps::swVPCaps;
|
||||
bool DX8Caps::UseTnL;
|
||||
bool DX8Caps::SupportDOT3;
|
||||
bool DX8Caps::SupportDXTC;
|
||||
bool DX8Caps::supportGamma;
|
||||
bool DX8Caps::SupportNPatches;
|
||||
bool DX8Caps::SupportBumpEnvmap;
|
||||
bool DX8Caps::SupportBumpEnvmapLuminance;
|
||||
bool DX8Caps::SupportTextureFormat[WW3D_FORMAT_COUNT];
|
||||
int DX8Caps::VertexShaderVersion;
|
||||
int DX8Caps::PixelShaderVersion;
|
||||
int DX8Caps::MaxSimultaneousTextures;
|
||||
|
||||
enum {
|
||||
VENDOR_ID_NVIDIA=0x10de,
|
||||
VENROD_ID_ATI=0x1002
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Init the caps structure
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8Caps::Init_Caps(IDirect3DDevice8* D3DDevice)
|
||||
{
|
||||
D3DDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING,TRUE);
|
||||
DX8CALL(GetDeviceCaps(&swVPCaps));
|
||||
|
||||
if ((swVPCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)==D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
|
||||
UseTnL=true;
|
||||
|
||||
D3DDevice->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING,FALSE);
|
||||
DX8CALL(GetDeviceCaps(&hwVPCaps));
|
||||
} else {
|
||||
UseTnL=false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Compute the caps bits
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8Caps::Compute_Caps(D3DFORMAT display_format, D3DFORMAT depth_stencil_format, IDirect3DDevice8* D3DDevice)
|
||||
{
|
||||
const D3DADAPTER_IDENTIFIER8& adapter_id=DX8Wrapper::Get_Current_Adapter_Identifier();
|
||||
|
||||
Init_Caps(D3DDevice);
|
||||
|
||||
const D3DCAPS8& caps=Get_Default_Caps();
|
||||
|
||||
if ((caps.DevCaps&D3DDEVCAPS_NPATCHES)==D3DDEVCAPS_NPATCHES) {
|
||||
SupportNPatches=true;
|
||||
} else {
|
||||
SupportNPatches=false;
|
||||
}
|
||||
|
||||
if ((caps.TextureOpCaps&D3DTEXOPCAPS_DOTPRODUCT3)==D3DTEXOPCAPS_DOTPRODUCT3) {
|
||||
SupportDOT3=true;
|
||||
} else {
|
||||
SupportDOT3=false;
|
||||
}
|
||||
|
||||
supportGamma=((swVPCaps.Caps2&D3DCAPS2_FULLSCREENGAMMA)==D3DCAPS2_FULLSCREENGAMMA);
|
||||
|
||||
Check_Texture_Format_Support(display_format,caps);
|
||||
Check_Texture_Compression_Support(caps);
|
||||
Check_Bumpmap_Support(caps);
|
||||
Check_Shader_Support(caps);
|
||||
Check_Maximum_Texture_Support(caps);
|
||||
Vendor_Specific_Hacks(adapter_id);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Check bump map texture support
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8Caps::Check_Bumpmap_Support(const D3DCAPS8& caps)
|
||||
{
|
||||
SupportBumpEnvmap=!!(caps.TextureOpCaps & D3DTEXOPCAPS_BUMPENVMAP);
|
||||
SupportBumpEnvmapLuminance=!!(caps.TextureOpCaps & D3DTEXOPCAPS_BUMPENVMAPLUMINANCE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Check compressed texture support
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8Caps::Check_Texture_Compression_Support(const D3DCAPS8& caps)
|
||||
{
|
||||
SupportDXTC=SupportTextureFormat[WW3D_FORMAT_DXT1]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT2]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT3]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT4]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT5];
|
||||
}
|
||||
|
||||
void DX8Caps::Check_Texture_Format_Support(D3DFORMAT display_format,const D3DCAPS8& caps)
|
||||
{
|
||||
for (unsigned i=0;i<WW3D_FORMAT_COUNT;++i) {
|
||||
if (i==WW3D_FORMAT_UNKNOWN) {
|
||||
SupportTextureFormat[i]=false;
|
||||
}
|
||||
else {
|
||||
SupportTextureFormat[i]=SUCCEEDED(
|
||||
DX8Wrapper::_Get_D3D8()->CheckDeviceFormat(
|
||||
caps.AdapterOrdinal,
|
||||
caps.DeviceType,
|
||||
display_format,
|
||||
0,
|
||||
D3DRTYPE_TEXTURE,
|
||||
WW3DFormat_To_D3DFormat((WW3DFormat)i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DX8Caps::Check_Maximum_Texture_Support(const D3DCAPS8& caps)
|
||||
{
|
||||
MaxSimultaneousTextures=caps.MaxSimultaneousTextures;
|
||||
}
|
||||
|
||||
void DX8Caps::Check_Shader_Support(const D3DCAPS8& caps)
|
||||
{
|
||||
VertexShaderVersion=caps.VertexShaderVersion;
|
||||
PixelShaderVersion=caps.PixelShaderVersion;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Implement some vendor-specific hacks to fix certain driver bugs that can't be
|
||||
// avoided otherwise.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8Caps::Vendor_Specific_Hacks(const D3DADAPTER_IDENTIFIER8& adapter_id)
|
||||
{
|
||||
if (adapter_id.VendorId==VENDOR_ID_NVIDIA) {
|
||||
SupportNPatches = false; // Driver incorrectly report N-Patch support
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT1] = false; // DXT1 is broken on NVidia hardware
|
||||
SupportDXTC=
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT1]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT2]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT3]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT4]|
|
||||
SupportTextureFormat[WW3D_FORMAT_DXT5];
|
||||
}
|
||||
|
||||
// SupportDXTC=false;
|
||||
|
||||
}
|
||||
105
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h
Normal file
105
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : DX8 Caps *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/ww3d2/dx8caps.h $*
|
||||
* *
|
||||
* Original Author:: Hector Yee *
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 8/29/01 8:16p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if _MSC_VER >= 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER >= 1000
|
||||
|
||||
#ifndef DX8CAPS_H
|
||||
#define DX8CAPS_H
|
||||
|
||||
#include "always.h"
|
||||
#include "ww3dformat.h"
|
||||
#include <d3d8.h>
|
||||
|
||||
class DX8Caps
|
||||
{
|
||||
public:
|
||||
static void Compute_Caps(D3DFORMAT display_format, D3DFORMAT depth_stencil_format, IDirect3DDevice8* D3DDevice);
|
||||
static bool Use_TnL() { return UseTnL; };
|
||||
static bool Support_DXTC() { return SupportDXTC; }
|
||||
static bool Support_Gamma() { return supportGamma; }
|
||||
static bool Support_NPatches() { return SupportNPatches; }
|
||||
static bool Support_DOT3() { return SupportDOT3; }
|
||||
static bool Support_Bump_Envmap() { return SupportBumpEnvmap; }
|
||||
static bool Support_Bump_Envmap_Luminance() { return SupportBumpEnvmapLuminance; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
//
|
||||
// Vertex shader support. Version number is split in major and minor, such that 1.0 would
|
||||
// have 1 as major and 0 as minor version number.
|
||||
//
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static int Get_Vertex_Shader_Majon_Version() { return 0xff&(VertexShaderVersion>>8); }
|
||||
static int Get_Vertex_Shader_Minor_Version() { return 0xff&(VertexShaderVersion); }
|
||||
static int Get_Pixel_Shader_Majon_Version() { return 0xff&(PixelShaderVersion>>8); }
|
||||
static int Get_Pixel_Shader_Minor_Version() { return 0xff&(PixelShaderVersion); }
|
||||
static int Get_Max_Simultaneous_Textures() { return MaxSimultaneousTextures;}
|
||||
|
||||
static bool Support_Texture_Format(WW3DFormat format) { return SupportTextureFormat[format]; }
|
||||
|
||||
static D3DCAPS8 const & Get_HW_VP_Caps() { return hwVPCaps; };
|
||||
static D3DCAPS8 const & Get_SW_VP_Caps() { return swVPCaps; };
|
||||
static D3DCAPS8 const & Get_Default_Caps() { return (UseTnL?hwVPCaps:swVPCaps); };
|
||||
|
||||
private:
|
||||
static void Init_Caps(IDirect3DDevice8* D3DDevice);
|
||||
static void Check_Texture_Format_Support(D3DFORMAT display_format,const D3DCAPS8& caps);
|
||||
static void Check_Texture_Compression_Support(const D3DCAPS8& caps);
|
||||
static void Check_Bumpmap_Support(const D3DCAPS8& caps);
|
||||
static void Check_Shader_Support(const D3DCAPS8& caps);
|
||||
static void Check_Maximum_Texture_Support(const D3DCAPS8& caps);
|
||||
static void Vendor_Specific_Hacks(const D3DADAPTER_IDENTIFIER8& adapter_id);
|
||||
|
||||
static D3DCAPS8 hwVPCaps;
|
||||
static D3DCAPS8 swVPCaps;
|
||||
static bool UseTnL;
|
||||
static bool SupportDXTC;
|
||||
static bool supportGamma;
|
||||
static bool SupportNPatches;
|
||||
static bool SupportDOT3;
|
||||
static bool SupportBumpEnvmap;
|
||||
static bool SupportBumpEnvmapLuminance;
|
||||
static bool SupportTextureFormat[WW3D_FORMAT_COUNT];
|
||||
static int VertexShaderVersion;
|
||||
static int PixelShaderVersion;
|
||||
static int MaxSimultaneousTextures;
|
||||
};
|
||||
|
||||
#endif
|
||||
77
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8fvf.cpp
Normal file
77
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8fvf.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
#include "dx8fvf.h"
|
||||
#include "wwstring.h"
|
||||
#include <D3dx8core.h>
|
||||
|
||||
static unsigned Get_FVF_Vertex_Size(unsigned FVF)
|
||||
{
|
||||
return D3DXGetFVFVertexSize(FVF);
|
||||
}
|
||||
|
||||
FVFInfoClass::FVFInfoClass(unsigned FVF_)
|
||||
:
|
||||
FVF(FVF_),
|
||||
fvf_size(Get_FVF_Vertex_Size(FVF))
|
||||
{
|
||||
location_offset=0;
|
||||
blend_offset=location_offset;
|
||||
|
||||
if ((FVF&D3DFVF_XYZ)==D3DFVF_XYZ) blend_offset+=3*sizeof(float);
|
||||
normal_offset=blend_offset;
|
||||
|
||||
if ( ((FVF&D3DFVF_XYZB4)==D3DFVF_XYZB4) &&
|
||||
((FVF&D3DFVF_LASTBETA_UBYTE4)==D3DFVF_LASTBETA_UBYTE4) ) normal_offset+=3*sizeof(float)+sizeof(DWORD);
|
||||
diffuse_offset=normal_offset;
|
||||
|
||||
if ((FVF&D3DFVF_NORMAL)==D3DFVF_NORMAL) diffuse_offset+=3*sizeof(float);
|
||||
specular_offset=diffuse_offset;
|
||||
|
||||
if ((FVF&D3DFVF_DIFFUSE)==D3DFVF_DIFFUSE) specular_offset+=sizeof(DWORD);
|
||||
texcoord_offset[0]=specular_offset;
|
||||
|
||||
if ((FVF&D3DFVF_SPECULAR)==D3DFVF_SPECULAR) texcoord_offset[0]+=sizeof(DWORD);
|
||||
|
||||
for (unsigned int i=1; i<D3DDP_MAXTEXCOORD; i++)
|
||||
{
|
||||
texcoord_offset[i]=texcoord_offset[i-1];
|
||||
|
||||
if ((int(FVF)&D3DFVF_TEXCOORDSIZE1(i-1))==D3DFVF_TEXCOORDSIZE1(i-1)) texcoord_offset[i]+=sizeof(float);
|
||||
else if ((int(FVF)&D3DFVF_TEXCOORDSIZE2(i-1))==D3DFVF_TEXCOORDSIZE2(i-1)) texcoord_offset[i]+=2*sizeof(float);
|
||||
else if ((int(FVF)&D3DFVF_TEXCOORDSIZE3(i-1))==D3DFVF_TEXCOORDSIZE3(i-1)) texcoord_offset[i]+=3*sizeof(float);
|
||||
else if ((int(FVF)&D3DFVF_TEXCOORDSIZE4(i-1))==D3DFVF_TEXCOORDSIZE4(i-1)) texcoord_offset[i]+=4*sizeof(float);
|
||||
}
|
||||
}
|
||||
|
||||
void FVFInfoClass::Get_FVF_Name(StringClass& fvfname) const
|
||||
{
|
||||
switch (Get_FVF()) {
|
||||
case DX8_FVF_XYZ: fvfname="D3DFVF_XYZ"; break;
|
||||
case DX8_FVF_XYZN: fvfname="D3DFVF_XYZ|D3DFVF_NORMAL"; break;
|
||||
case DX8_FVF_XYZNUV1: fvfname="D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1"; break;
|
||||
case DX8_FVF_XYZNUV2: fvfname="D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2"; break;
|
||||
case DX8_FVF_XYZNDUV1: fvfname="D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1|D3DFVF_DIFFUSE"; break;
|
||||
case DX8_FVF_XYZNDUV2: fvfname="D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2|D3DFVF_DIFFUSE"; break;
|
||||
case DX8_FVF_XYZDUV1: fvfname="D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_DIFFUSE"; break;
|
||||
case DX8_FVF_XYZDUV2: fvfname="D3DFVF_XYZ|D3DFVF_TEX2|D3DFVF_DIFFUSE"; break;
|
||||
case DX8_FVF_XYZUV1: fvfname="D3DFVF_XYZ|D3DFVF_TEX1"; break;
|
||||
case DX8_FVF_XYZUV2: fvfname="D3DFVF_XYZ|D3DFVF_TEX2"; break;
|
||||
default: fvfname="Unknown!";
|
||||
}
|
||||
}
|
||||
224
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8fvf.h
Normal file
224
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8fvf.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8fvf.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 3/29/01 12:44a $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8_FVF_H
|
||||
#define DX8_FVF_H
|
||||
|
||||
#include "always.h"
|
||||
#include <d3d8.h>
|
||||
#ifdef WWDEBUG
|
||||
#include "wwdebug.h"
|
||||
#endif
|
||||
|
||||
class StringClass;
|
||||
|
||||
enum {
|
||||
DX8_FVF_XYZ = D3DFVF_XYZ,
|
||||
DX8_FVF_XYZN = D3DFVF_XYZ|D3DFVF_NORMAL,
|
||||
DX8_FVF_XYZNUV1 = D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,
|
||||
DX8_FVF_XYZNUV2 = D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2,
|
||||
DX8_FVF_XYZNDUV1 = D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1|D3DFVF_DIFFUSE,
|
||||
DX8_FVF_XYZNDUV2 = D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2|D3DFVF_DIFFUSE,
|
||||
DX8_FVF_XYZDUV1 = D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_DIFFUSE,
|
||||
DX8_FVF_XYZDUV2 = D3DFVF_XYZ|D3DFVF_TEX2|D3DFVF_DIFFUSE,
|
||||
DX8_FVF_XYZUV1 = D3DFVF_XYZ|D3DFVF_TEX1,
|
||||
DX8_FVF_XYZUV2 = D3DFVF_XYZ|D3DFVF_TEX2
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Util structures for vertex buffer handling. Cast the void pointer returned
|
||||
// by the vertex buffer to one of these structures.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct VertexFormatXYZ
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZNUV1
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
float u1;
|
||||
float v1;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZNUV2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
float u1;
|
||||
float v1;
|
||||
float u2;
|
||||
float v2;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZN
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZNDUV1
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
unsigned diffuse;
|
||||
float u1;
|
||||
float v1;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZNDUV2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
unsigned diffuse;
|
||||
float u1;
|
||||
float v1;
|
||||
float u2;
|
||||
float v2;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZDUV1
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
unsigned diffuse;
|
||||
float u1;
|
||||
float v1;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZDUV2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
unsigned diffuse;
|
||||
float u1;
|
||||
float v1;
|
||||
float u2;
|
||||
float v2;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZUV1
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float u1;
|
||||
float v1;
|
||||
};
|
||||
|
||||
struct VertexFormatXYZUV2
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float u1;
|
||||
float v1;
|
||||
float u2;
|
||||
float v2;
|
||||
};
|
||||
|
||||
// FVF info class can be created for any legal FVF. It constructs information
|
||||
// of offsets to various elements in the vertex buffer.
|
||||
|
||||
class FVFInfoClass : public W3DMPO
|
||||
{
|
||||
W3DMPO_GLUE(FVFInfoClass)
|
||||
|
||||
unsigned FVF;
|
||||
unsigned fvf_size;
|
||||
|
||||
unsigned location_offset;
|
||||
unsigned normal_offset;
|
||||
unsigned blend_offset;
|
||||
unsigned texcoord_offset[D3DDP_MAXTEXCOORD];
|
||||
unsigned diffuse_offset;
|
||||
unsigned specular_offset;
|
||||
public:
|
||||
FVFInfoClass(unsigned FVF);
|
||||
|
||||
inline unsigned Get_Location_Offset() const { return location_offset; }
|
||||
inline unsigned Get_Normal_Offset() const { return normal_offset; }
|
||||
#ifdef WWDEBUG
|
||||
inline unsigned Get_Tex_Offset(unsigned int n) const { WWASSERT(n<D3DDP_MAXTEXCOORD); return texcoord_offset[n]; }
|
||||
#else
|
||||
inline unsigned Get_Tex_Offset(unsigned int n) const { return texcoord_offset[n]; }
|
||||
#endif
|
||||
|
||||
inline unsigned Get_Diffuse_Offset() const { return diffuse_offset; }
|
||||
inline unsigned Get_Specular_Offset() const { return specular_offset; }
|
||||
inline unsigned Get_FVF() const { return FVF; }
|
||||
inline unsigned Get_FVF_Size() const { return fvf_size; }
|
||||
|
||||
void Get_FVF_Name(StringClass& fvfname) const; // For debug purposes
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
504
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.cpp
Normal file
504
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8indexbuffer.cpp $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/10/01 1:30p $*
|
||||
* *
|
||||
* $Revision:: 22 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
//#define INDEX_BUFFER_LOG
|
||||
|
||||
#include "dx8indexbuffer.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "dx8caps.h"
|
||||
#include "sphere.h"
|
||||
#include "thread.h"
|
||||
|
||||
#define DEFAULT_IB_SIZE 5000
|
||||
|
||||
static bool _DynamicSortingIndexArrayInUse=false;
|
||||
static SortingIndexBufferClass* _DynamicSortingIndexArray;
|
||||
static unsigned short _DynamicSortingIndexArraySize=0;
|
||||
static unsigned short _DynamicSortingIndexArrayOffset=0;
|
||||
|
||||
static bool _DynamicDX8IndexBufferInUse=false;
|
||||
static DX8IndexBufferClass* _DynamicDX8IndexBuffer=NULL;
|
||||
static unsigned short _DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
|
||||
static unsigned short _DynamicDX8IndexBufferOffset=0;
|
||||
|
||||
static int _IndexBufferCount;
|
||||
static int _IndexBufferTotalIndices;
|
||||
static int _IndexBufferTotalSize;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
IndexBufferClass::IndexBufferClass(unsigned type_, unsigned short index_count_)
|
||||
:
|
||||
index_count(index_count_),
|
||||
type(type_),
|
||||
engine_refs(0)
|
||||
{
|
||||
WWASSERT(type==BUFFER_TYPE_DX8 || type==BUFFER_TYPE_SORTING);
|
||||
WWASSERT(index_count);
|
||||
|
||||
_IndexBufferCount++;
|
||||
_IndexBufferTotalIndices+=index_count;
|
||||
_IndexBufferTotalSize+=index_count*sizeof(unsigned short);
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("New IB, %d indices, size %d bytes\n",index_count,index_count*sizeof(unsigned short)));
|
||||
WWDEBUG_SAY(("Total IB count: %d, total %d indices, total size %d bytes\n",
|
||||
_IndexBufferCount,
|
||||
_IndexBufferTotalIndices,
|
||||
_IndexBufferTotalSize));
|
||||
#endif
|
||||
}
|
||||
|
||||
IndexBufferClass::~IndexBufferClass()
|
||||
{
|
||||
_IndexBufferCount--;
|
||||
_IndexBufferTotalIndices-=index_count;
|
||||
_IndexBufferTotalSize-=index_count*sizeof(unsigned short);
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("Delete IB, %d indices, size %d bytes\n",index_count,index_count*sizeof(unsigned short)));
|
||||
WWDEBUG_SAY(("Total IB count: %d, total %d indices, total size %d bytes\n",
|
||||
_IndexBufferCount,
|
||||
_IndexBufferTotalIndices,
|
||||
_IndexBufferTotalSize));
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned IndexBufferClass::Get_Total_Buffer_Count()
|
||||
{
|
||||
return _IndexBufferCount;
|
||||
}
|
||||
|
||||
unsigned IndexBufferClass::Get_Total_Allocated_Indices()
|
||||
{
|
||||
return _IndexBufferTotalIndices;
|
||||
}
|
||||
|
||||
unsigned IndexBufferClass::Get_Total_Allocated_Memory()
|
||||
{
|
||||
return _IndexBufferTotalSize;
|
||||
}
|
||||
|
||||
void IndexBufferClass::Add_Engine_Ref() const
|
||||
{
|
||||
engine_refs++;
|
||||
}
|
||||
|
||||
void IndexBufferClass::Release_Engine_Ref() const
|
||||
{
|
||||
engine_refs--;
|
||||
WWASSERT(engine_refs>=0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void IndexBufferClass::Copy(unsigned int* indices,unsigned first_index,unsigned count)
|
||||
{
|
||||
WWASSERT(indices);
|
||||
|
||||
if (first_index) {
|
||||
DX8IndexBufferClass::AppendLockClass l(this,first_index,count);
|
||||
unsigned short* inds=l.Get_Index_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
*inds++=unsigned short(*indices++);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DX8IndexBufferClass::WriteLockClass l(this);
|
||||
unsigned short* inds=l.Get_Index_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
*inds++=unsigned short(*indices++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void IndexBufferClass::Copy(unsigned short* indices,unsigned first_index,unsigned count)
|
||||
{
|
||||
WWASSERT(indices);
|
||||
|
||||
if (first_index) {
|
||||
DX8IndexBufferClass::AppendLockClass l(this,first_index,count);
|
||||
unsigned short* inds=l.Get_Index_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
*inds++=*indices++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DX8IndexBufferClass::WriteLockClass l(this);
|
||||
unsigned short* inds=l.Get_Index_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
*inds++=*indices++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
IndexBufferClass::WriteLockClass::WriteLockClass(IndexBufferClass* index_buffer_) : index_buffer(index_buffer_)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(index_buffer);
|
||||
WWASSERT(!index_buffer->Engine_Refs());
|
||||
index_buffer->Add_Ref();
|
||||
switch (index_buffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->Get_DX8_Index_Buffer()->Lock(
|
||||
0,
|
||||
index_buffer->Get_Index_Count()*sizeof(WORD),
|
||||
(unsigned char**)&indices,
|
||||
0));
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
indices=static_cast<SortingIndexBufferClass*>(index_buffer)->index_buffer;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
IndexBufferClass::WriteLockClass::~WriteLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (index_buffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
index_buffer->Release_Ref();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
IndexBufferClass::AppendLockClass::AppendLockClass(IndexBufferClass* index_buffer_,unsigned start_index, unsigned index_range)
|
||||
:
|
||||
index_buffer(index_buffer_)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(start_index+index_range<=index_buffer->Get_Index_Count());
|
||||
WWASSERT(index_buffer);
|
||||
WWASSERT(!index_buffer->Engine_Refs());
|
||||
index_buffer->Add_Ref();
|
||||
switch (index_buffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Lock(
|
||||
start_index*sizeof(unsigned short),
|
||||
index_range*sizeof(unsigned short),
|
||||
(unsigned char**)&indices,
|
||||
NULL)); // Optional pointer to receive the buffer size
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
indices=static_cast<SortingIndexBufferClass*>(index_buffer)->index_buffer+start_index;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
IndexBufferClass::AppendLockClass::~AppendLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (index_buffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(index_buffer)->index_buffer->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
index_buffer->Release_Ref();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8IndexBufferClass::DX8IndexBufferClass(unsigned short index_count_,UsageType usage)
|
||||
:
|
||||
IndexBufferClass(BUFFER_TYPE_DX8,index_count_)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(index_count);
|
||||
unsigned usage_flags=
|
||||
D3DUSAGE_WRITEONLY|
|
||||
((usage&USAGE_DYNAMIC) ? D3DUSAGE_DYNAMIC : 0)|
|
||||
((usage&USAGE_NPATCHES) ? D3DUSAGE_NPATCHES : 0)|
|
||||
((usage&USAGE_SOFTWAREPROCESSING) ? D3DUSAGE_SOFTWAREPROCESSING : 0);
|
||||
|
||||
DX8CALL(CreateIndexBuffer(
|
||||
sizeof(WORD)*index_count,
|
||||
usage_flags,
|
||||
D3DFMT_INDEX16,
|
||||
(usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
|
||||
&index_buffer));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8IndexBufferClass::~DX8IndexBufferClass()
|
||||
{
|
||||
index_buffer->Release();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SortingIndexBufferClass::SortingIndexBufferClass(unsigned short index_count_)
|
||||
:
|
||||
IndexBufferClass(BUFFER_TYPE_SORTING,index_count_)
|
||||
{
|
||||
WWASSERT(index_count);
|
||||
|
||||
index_buffer=W3DNEWARRAY unsigned short[index_count];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SortingIndexBufferClass::~SortingIndexBufferClass()
|
||||
{
|
||||
delete[] index_buffer;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DynamicIBAccessClass::DynamicIBAccessClass(unsigned short type_, unsigned short index_count_)
|
||||
:
|
||||
IndexCount(index_count_),
|
||||
IndexBuffer(0),
|
||||
Type(type_)
|
||||
{
|
||||
WWASSERT(Type==BUFFER_TYPE_DYNAMIC_DX8 || Type==BUFFER_TYPE_DYNAMIC_SORTING);
|
||||
if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
|
||||
Allocate_DX8_Dynamic_Buffer();
|
||||
}
|
||||
else {
|
||||
Allocate_Sorting_Dynamic_Buffer();
|
||||
}
|
||||
}
|
||||
|
||||
DynamicIBAccessClass::~DynamicIBAccessClass()
|
||||
{
|
||||
REF_PTR_RELEASE(IndexBuffer);
|
||||
if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
|
||||
_DynamicDX8IndexBufferInUse=false;
|
||||
_DynamicDX8IndexBufferOffset+=IndexCount;
|
||||
}
|
||||
else {
|
||||
_DynamicSortingIndexArrayInUse=false;
|
||||
_DynamicSortingIndexArrayOffset+=IndexCount;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicIBAccessClass::_Deinit()
|
||||
{
|
||||
WWASSERT ((_DynamicDX8IndexBuffer == NULL) || (_DynamicDX8IndexBuffer->Num_Refs() == 1));
|
||||
REF_PTR_RELEASE(_DynamicDX8IndexBuffer);
|
||||
_DynamicDX8IndexBufferInUse=false;
|
||||
_DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
|
||||
_DynamicDX8IndexBufferOffset=0;
|
||||
|
||||
WWASSERT ((_DynamicSortingIndexArray == NULL) || (_DynamicSortingIndexArray->Num_Refs() == 1));
|
||||
REF_PTR_RELEASE(_DynamicSortingIndexArray);
|
||||
_DynamicSortingIndexArrayInUse=false;
|
||||
_DynamicSortingIndexArraySize=0;
|
||||
_DynamicSortingIndexArrayOffset=0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DynamicIBAccessClass::WriteLockClass::WriteLockClass(DynamicIBAccessClass* ib_access_)
|
||||
:
|
||||
DynamicIBAccess(ib_access_)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
DynamicIBAccess->IndexBuffer->Add_Ref();
|
||||
switch (DynamicIBAccess->Get_Type()) {
|
||||
case BUFFER_TYPE_DYNAMIC_DX8:
|
||||
WWASSERT(DynamicIBAccess);
|
||||
// WWASSERT(!dynamic_dx8_index_buffer->Engine_Refs());
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(
|
||||
static_cast<DX8IndexBufferClass*>(DynamicIBAccess->IndexBuffer)->Get_DX8_Index_Buffer()->Lock(
|
||||
DynamicIBAccess->IndexBufferOffset*sizeof(WORD),
|
||||
DynamicIBAccess->Get_Index_Count()*sizeof(WORD),
|
||||
(unsigned char**)&Indices,
|
||||
!DynamicIBAccess->IndexBufferOffset ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE));
|
||||
break;
|
||||
case BUFFER_TYPE_DYNAMIC_SORTING:
|
||||
Indices=static_cast<SortingIndexBufferClass*>(DynamicIBAccess->IndexBuffer)->index_buffer;
|
||||
Indices+=DynamicIBAccess->IndexBufferOffset;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicIBAccessClass::WriteLockClass::~WriteLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (DynamicIBAccess->Get_Type()) {
|
||||
case BUFFER_TYPE_DYNAMIC_DX8:
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8IndexBufferClass*>(DynamicIBAccess->IndexBuffer)->Get_DX8_Index_Buffer()->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_DYNAMIC_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
DynamicIBAccess->IndexBuffer->Release_Ref();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DynamicIBAccessClass::Allocate_DX8_Dynamic_Buffer()
|
||||
{
|
||||
WWASSERT(!_DynamicDX8IndexBufferInUse);
|
||||
_DynamicDX8IndexBufferInUse=true;
|
||||
|
||||
// If requesting more indices than dynamic index buffer can fit, delete the ib
|
||||
// and adjust the size to the new count.
|
||||
if (IndexCount>_DynamicDX8IndexBufferSize) {
|
||||
REF_PTR_RELEASE(_DynamicDX8IndexBuffer);
|
||||
_DynamicDX8IndexBufferSize=IndexCount;
|
||||
if (_DynamicDX8IndexBufferSize<DEFAULT_IB_SIZE) _DynamicDX8IndexBufferSize=DEFAULT_IB_SIZE;
|
||||
}
|
||||
|
||||
// Create a new vb if one doesn't exist currently
|
||||
if (!_DynamicDX8IndexBuffer) {
|
||||
unsigned usage=DX8IndexBufferClass::USAGE_DYNAMIC;
|
||||
if (DX8Caps::Support_NPatches()) {
|
||||
usage|=DX8IndexBufferClass::USAGE_NPATCHES;
|
||||
}
|
||||
|
||||
_DynamicDX8IndexBuffer=NEW_REF(DX8IndexBufferClass,(
|
||||
_DynamicDX8IndexBufferSize,
|
||||
(DX8IndexBufferClass::UsageType)usage));
|
||||
_DynamicDX8IndexBufferOffset=0;
|
||||
}
|
||||
|
||||
// Any room at the end of the buffer?
|
||||
if (((unsigned)IndexCount+_DynamicDX8IndexBufferOffset)>_DynamicDX8IndexBufferSize) {
|
||||
_DynamicDX8IndexBufferOffset=0;
|
||||
}
|
||||
|
||||
REF_PTR_SET(IndexBuffer,_DynamicDX8IndexBuffer);
|
||||
IndexBufferOffset=_DynamicDX8IndexBufferOffset;
|
||||
}
|
||||
|
||||
void DynamicIBAccessClass::Allocate_Sorting_Dynamic_Buffer()
|
||||
{
|
||||
WWASSERT(!_DynamicSortingIndexArrayInUse);
|
||||
_DynamicSortingIndexArrayInUse=true;
|
||||
|
||||
unsigned new_index_count=_DynamicSortingIndexArrayOffset+IndexCount;
|
||||
WWASSERT(new_index_count<65536);
|
||||
if (new_index_count>_DynamicSortingIndexArraySize) {
|
||||
REF_PTR_RELEASE(_DynamicSortingIndexArray);
|
||||
_DynamicSortingIndexArraySize=new_index_count;
|
||||
if (_DynamicSortingIndexArraySize<DEFAULT_IB_SIZE) _DynamicSortingIndexArraySize=DEFAULT_IB_SIZE;
|
||||
}
|
||||
|
||||
if (!_DynamicSortingIndexArray) {
|
||||
_DynamicSortingIndexArray=NEW_REF(SortingIndexBufferClass,(_DynamicSortingIndexArraySize));
|
||||
_DynamicSortingIndexArrayOffset=0;
|
||||
}
|
||||
|
||||
REF_PTR_SET(IndexBuffer,_DynamicSortingIndexArray);
|
||||
IndexBufferOffset=_DynamicSortingIndexArrayOffset;
|
||||
}
|
||||
|
||||
void DynamicIBAccessClass::_Reset(bool frame_changed)
|
||||
{
|
||||
_DynamicSortingIndexArrayOffset=0;
|
||||
if (frame_changed) _DynamicDX8IndexBufferOffset=0;
|
||||
}
|
||||
|
||||
unsigned short DynamicIBAccessClass::Get_Default_Index_Count(void)
|
||||
{
|
||||
return _DynamicDX8IndexBufferSize;
|
||||
}
|
||||
208
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.h
Normal file
208
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8indexbuffer.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8indexbuffer.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/10/01 12:27p $*
|
||||
* *
|
||||
* $Revision:: 12 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8INDEXBUFFER_H
|
||||
#define DX8INDEXBUFFER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwdebug.h"
|
||||
#include "refcount.h"
|
||||
#include "sphere.h"
|
||||
|
||||
class DX8Wrapper;
|
||||
class SortingRendererClass;
|
||||
struct IDirect3DIndexBuffer8;
|
||||
class DX8IndexBufferClass;
|
||||
class SortingIndexBufferClass;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IndexBufferClass : public W3DMPO, public RefCountClass
|
||||
{
|
||||
// nope, it's an ABC
|
||||
//W3DMPO_GLUE(IndexBufferClass)
|
||||
protected:
|
||||
virtual ~IndexBufferClass();
|
||||
public:
|
||||
IndexBufferClass(unsigned type, unsigned short index_count);
|
||||
|
||||
void Copy(unsigned int* indices,unsigned start_index,unsigned index_count);
|
||||
void Copy(unsigned short* indices,unsigned start_index,unsigned index_count);
|
||||
|
||||
inline unsigned short Get_Index_Count() const { return index_count; }
|
||||
|
||||
inline unsigned Type() const { return type; }
|
||||
|
||||
void Add_Engine_Ref() const;
|
||||
void Release_Engine_Ref() const;
|
||||
inline unsigned Engine_Refs() const { return engine_refs; }
|
||||
|
||||
class WriteLockClass
|
||||
{
|
||||
IndexBufferClass* index_buffer;
|
||||
unsigned short* indices;
|
||||
public:
|
||||
WriteLockClass(IndexBufferClass* index_buffer);
|
||||
~WriteLockClass();
|
||||
|
||||
unsigned short* Get_Index_Array() { return indices; }
|
||||
};
|
||||
|
||||
class AppendLockClass
|
||||
{
|
||||
IndexBufferClass* index_buffer;
|
||||
unsigned short* indices;
|
||||
public:
|
||||
AppendLockClass(IndexBufferClass* index_buffer,unsigned start_index, unsigned index_range);
|
||||
~AppendLockClass();
|
||||
|
||||
unsigned short* Get_Index_Array() { return indices; }
|
||||
};
|
||||
|
||||
static unsigned Get_Total_Buffer_Count();
|
||||
static unsigned Get_Total_Allocated_Indices();
|
||||
static unsigned Get_Total_Allocated_Memory();
|
||||
|
||||
protected:
|
||||
mutable int engine_refs;
|
||||
unsigned short index_count; // number of indices
|
||||
unsigned type;
|
||||
};
|
||||
|
||||
|
||||
// HY 2/14/01
|
||||
// Created
|
||||
class DynamicIBAccessClass : public W3DMPO
|
||||
{
|
||||
W3DMPO_GLUE(DynamicIBAccessClass)
|
||||
|
||||
friend DX8Wrapper;
|
||||
friend SortingRendererClass;
|
||||
|
||||
unsigned Type;
|
||||
unsigned short IndexCount;
|
||||
unsigned short IndexBufferOffset;
|
||||
IndexBufferClass* IndexBuffer;
|
||||
|
||||
void Allocate_Sorting_Dynamic_Buffer();
|
||||
void Allocate_DX8_Dynamic_Buffer();
|
||||
|
||||
public:
|
||||
DynamicIBAccessClass(unsigned short type, unsigned short index_count);
|
||||
~DynamicIBAccessClass();
|
||||
|
||||
unsigned Get_Type() const { return Type; }
|
||||
unsigned short Get_Index_Count() const { return IndexCount; }
|
||||
|
||||
// Call at the end of the execution, or at whatever time you wish to release
|
||||
// the recycled dynamic index buffer.
|
||||
static void _Deinit();
|
||||
static void _Reset(bool frame_changed);
|
||||
static unsigned short Get_Default_Index_Count(void); ///<current size of dynamic index buffer
|
||||
|
||||
// To lock the index buffer, create instance of this write class locally.
|
||||
// The buffer is automatically unlocked when you exit the scope.
|
||||
class WriteLockClass
|
||||
{
|
||||
DynamicIBAccessClass* DynamicIBAccess;
|
||||
unsigned short* Indices;
|
||||
public:
|
||||
WriteLockClass(DynamicIBAccessClass* ib_access);
|
||||
~WriteLockClass();
|
||||
unsigned short* Get_Index_Array() { return Indices; }
|
||||
};
|
||||
|
||||
friend WriteLockClass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DX8IndexBufferClass
|
||||
** This class wraps a DX8 index buffer.
|
||||
*/
|
||||
class DX8IndexBufferClass : public IndexBufferClass
|
||||
{
|
||||
W3DMPO_GLUE(DX8IndexBufferClass)
|
||||
|
||||
friend IndexBufferClass::WriteLockClass;
|
||||
friend IndexBufferClass::AppendLockClass;
|
||||
public:
|
||||
enum UsageType {
|
||||
USAGE_DEFAULT=0,
|
||||
USAGE_DYNAMIC=1,
|
||||
USAGE_SOFTWAREPROCESSING=2,
|
||||
USAGE_NPATCHES=4
|
||||
};
|
||||
|
||||
DX8IndexBufferClass(unsigned short index_count,UsageType usage=USAGE_DEFAULT);
|
||||
~DX8IndexBufferClass();
|
||||
|
||||
void Copy(unsigned int* indices,unsigned start_index,unsigned index_count);
|
||||
void Copy(unsigned short* indices,unsigned start_index,unsigned index_count);
|
||||
|
||||
inline IDirect3DIndexBuffer8* Get_DX8_Index_Buffer() { return index_buffer; }
|
||||
|
||||
private:
|
||||
IDirect3DIndexBuffer8* index_buffer; // actual dx8 index buffer
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SortingIndexBufferClass : public IndexBufferClass
|
||||
{
|
||||
W3DMPO_GLUE(SortingIndexBufferClass)
|
||||
|
||||
friend DX8Wrapper;
|
||||
friend SortingRendererClass;
|
||||
friend IndexBufferClass::WriteLockClass;
|
||||
friend IndexBufferClass::AppendLockClass;
|
||||
friend DynamicIBAccessClass::WriteLockClass;
|
||||
public:
|
||||
SortingIndexBufferClass(unsigned short index_count);
|
||||
~SortingIndexBufferClass();
|
||||
|
||||
protected:
|
||||
unsigned short* index_buffer;
|
||||
};
|
||||
|
||||
#endif //DX8INDEXBUFFER_H
|
||||
|
||||
73
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8list.h
Normal file
73
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8list.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8list.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Hector_y $*
|
||||
* *
|
||||
* $Modtime:: 4/25/01 1:37p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8LIST_H
|
||||
#define DX8LIST_H
|
||||
|
||||
#include "always.h"
|
||||
#include "multilist.h"
|
||||
|
||||
|
||||
/*
|
||||
** Here we're just typedefing some multi-lists so we don't have to write the
|
||||
** long template names.
|
||||
*/
|
||||
class DX8TextureCategoryClass;
|
||||
typedef MultiListClass<DX8TextureCategoryClass> TextureCategoryList;
|
||||
typedef MultiListIterator<DX8TextureCategoryClass> TextureCategoryListIterator;
|
||||
|
||||
class DX8FVFCategoryContainer;
|
||||
typedef MultiListClass<DX8FVFCategoryContainer> FVFCategoryList;
|
||||
typedef MultiListIterator<DX8FVFCategoryContainer> FVFCategoryListIterator;
|
||||
|
||||
class DX8PolygonRendererClass;
|
||||
typedef MultiListClass<DX8PolygonRendererClass> DX8PolygonRendererList;
|
||||
typedef MultiListIterator<DX8PolygonRendererClass> DX8PolygonRendererListIterator;
|
||||
|
||||
class DX8TextureTrackerClass;
|
||||
typedef MultiListClass<DX8TextureTrackerClass> DX8TextureTrackerList;
|
||||
typedef MultiListIterator<DX8TextureTrackerClass> DX8TextureTrackerListIterator;
|
||||
|
||||
|
||||
#endif //DX8LIST_H
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8polygonrenderer.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 8/22/01 6:54p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
|
||||
#include "dx8polygonrenderer.h"
|
||||
#include "dx8renderer.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8PolygonRendererClass::DX8PolygonRendererClass(
|
||||
unsigned index_count_,
|
||||
MeshModelClass* mmc_,
|
||||
DX8TextureCategoryClass* tex_cat,
|
||||
unsigned vertex_offset_,
|
||||
unsigned index_offset_,
|
||||
bool strip_,
|
||||
unsigned pass_)
|
||||
:
|
||||
mmc(mmc_),
|
||||
texture_category(tex_cat),
|
||||
index_offset(index_offset_),
|
||||
vertex_offset(vertex_offset_),
|
||||
min_vertex_index(0),
|
||||
vertex_index_range(0),
|
||||
index_count(index_count_),
|
||||
strip(strip_),
|
||||
pass(pass_)
|
||||
{
|
||||
WWASSERT(index_count);
|
||||
mmc->PolygonRendererList.Add_Tail(this);
|
||||
}
|
||||
|
||||
DX8PolygonRendererClass::DX8PolygonRendererClass(const DX8PolygonRendererClass& src,MeshModelClass* mmc_)
|
||||
:
|
||||
mmc(mmc_),
|
||||
texture_category(src.texture_category),
|
||||
index_offset(src.index_offset),
|
||||
vertex_offset(src.vertex_offset),
|
||||
min_vertex_index(src.min_vertex_index),
|
||||
vertex_index_range(src.vertex_index_range),
|
||||
index_count(src.index_count),
|
||||
strip(src.strip),
|
||||
pass(src.pass)
|
||||
{
|
||||
mmc->PolygonRendererList.Add_Tail(this);
|
||||
}
|
||||
|
||||
DX8PolygonRendererClass::~DX8PolygonRendererClass()
|
||||
{
|
||||
if (texture_category) texture_category->Remove_Polygon_Renderer(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8PolygonRendererClass::Log()
|
||||
{
|
||||
StringClass work(true);
|
||||
|
||||
work.Format(" %8d %8d %6d %6d %6d %s\n",
|
||||
index_count,
|
||||
index_count/3,
|
||||
index_offset,
|
||||
min_vertex_index,
|
||||
vertex_index_range,
|
||||
mmc->Get_Name());
|
||||
|
||||
/* work.Format(
|
||||
" Index count: %d (%d polys) i_offset: %d min_vi: %d vi_range: %d ident: %d (%s)\n",
|
||||
index_count,
|
||||
index_count/3,
|
||||
index_offset,
|
||||
min_vertex_index,
|
||||
vertex_index_range,
|
||||
mmc->ident,
|
||||
mmc->Get_Name());
|
||||
*/ WWDEBUG_SAY((work));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8polygonrenderer.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/12/01 6:38p $*
|
||||
* *
|
||||
* $Revision:: 22 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8_POLYGON_RENDERER_H
|
||||
#define DX8_POLYGON_RENDERER_H
|
||||
|
||||
|
||||
#include "always.h"
|
||||
#include "meshmdl.h"
|
||||
#include "dx8list.h"
|
||||
#include "sortingrenderer.h"
|
||||
#include "mesh.h"
|
||||
#include "dx8wrapper.h"
|
||||
|
||||
class DX8PolygonRendererClass;
|
||||
class DX8TextureCategoryClass;
|
||||
|
||||
|
||||
/**
|
||||
** DX8PolygonRendererClass
|
||||
** This is a record of a batch/range of polygons to be rendered. These hang off of the DX8TextureCategoryClass's
|
||||
** and are rendered after the system installs a vertex buffer and textures in the DX8 wrapper.
|
||||
*/
|
||||
class DX8PolygonRendererClass : public MultiListObjectClass
|
||||
{
|
||||
MeshModelClass * mmc;
|
||||
DX8TextureCategoryClass * texture_category;
|
||||
unsigned index_offset; // absolute index of index 0 for our parent mesh
|
||||
unsigned vertex_offset; // absolute index of vertex 0 for our parent mesh
|
||||
unsigned index_count; // number of indices
|
||||
unsigned min_vertex_index; // relative index of the first vertex our polys reference
|
||||
unsigned vertex_index_range; // range to the last vertex our polys reference
|
||||
bool strip; // is this a strip?
|
||||
unsigned pass; // rendering pass
|
||||
|
||||
public:
|
||||
DX8PolygonRendererClass(
|
||||
unsigned index_count,
|
||||
MeshModelClass* mmc_,
|
||||
DX8TextureCategoryClass* tex_cat,
|
||||
unsigned vertex_offset,
|
||||
unsigned index_offset,
|
||||
bool strip,
|
||||
unsigned pass);
|
||||
DX8PolygonRendererClass(const DX8PolygonRendererClass& src,MeshModelClass* mmc_);
|
||||
~DX8PolygonRendererClass();
|
||||
|
||||
void Render(/*const Matrix3D & tm,*/int base_vertex_offset);
|
||||
void Render_Sorted(/*const Matrix3D & tm,*/int base_vertex_offset,const SphereClass & bounding_sphere);
|
||||
void Set_Vertex_Index_Range(unsigned min_vertex_index_,unsigned vertex_index_range_);
|
||||
|
||||
unsigned Get_Vertex_Offset(void) { return vertex_offset; }
|
||||
unsigned Get_Index_Offset(void) { return index_offset; }
|
||||
inline unsigned Get_Pass(void) { return pass; }
|
||||
|
||||
MeshModelClass* Get_Mesh_Model_Class() { return mmc; }
|
||||
DX8TextureCategoryClass* Get_Texture_Category() { return texture_category; }
|
||||
void Set_Texture_Category(DX8TextureCategoryClass* tc) { texture_category=tc; }
|
||||
|
||||
void Log();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline void DX8PolygonRendererClass::Set_Vertex_Index_Range(unsigned min_vertex_index_,unsigned vertex_index_range_)
|
||||
{
|
||||
// WWDEBUG_SAY(("Set_Vertex_Index_Range - min: %d, range: %d\n",min_vertex_index_,vertex_index_range_));
|
||||
// if (vertex_index_range_>30000) {
|
||||
// int a=0;
|
||||
// a++;
|
||||
// }
|
||||
min_vertex_index=min_vertex_index_;
|
||||
vertex_index_range=vertex_index_range_;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline void DX8PolygonRendererClass::Render(/*const Matrix3D & tm,*/int base_vertex_offset)
|
||||
{
|
||||
// DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
// SNAPSHOT_SAY(("Set_Transform\n"));
|
||||
SNAPSHOT_SAY(("Set_Index_Buffer_Index_Offset(%d)\n",base_vertex_offset));
|
||||
|
||||
DX8Wrapper::Set_Index_Buffer_Index_Offset(base_vertex_offset);
|
||||
if (strip) {
|
||||
SNAPSHOT_SAY(("Draw_Strip(%d,%d,%d,%d)\n",index_offset,index_count-2,min_vertex_index,vertex_index_range));
|
||||
DX8Wrapper::Draw_Strip(
|
||||
index_offset,
|
||||
index_count-2,
|
||||
min_vertex_index,
|
||||
vertex_index_range);
|
||||
}
|
||||
else {
|
||||
SNAPSHOT_SAY(("Draw_Triangles(%d,%d,%d,%d)\n",index_offset,index_count-2,min_vertex_index,vertex_index_range));
|
||||
DX8Wrapper::Draw_Triangles(
|
||||
index_offset,
|
||||
index_count/3,
|
||||
min_vertex_index,
|
||||
vertex_index_range);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DX8PolygonRendererClass::Render_Sorted(/*const Matrix3D & tm,*/int base_vertex_offset,const SphereClass & bounding_sphere)
|
||||
{
|
||||
WWASSERT(!strip); // Strips can't be sorted for now
|
||||
// DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
|
||||
// SNAPSHOT_SAY(("Set_Transform\n"));
|
||||
SNAPSHOT_SAY(("Set_Index_Buffer_Index_Offset(%d)\n",base_vertex_offset));
|
||||
SNAPSHOT_SAY(("Insert_Sorting_Triangles(%d,%d,%d,%d)\n",index_offset,index_count-2,min_vertex_index,vertex_index_range));
|
||||
|
||||
DX8Wrapper::Set_Index_Buffer_Index_Offset(base_vertex_offset);
|
||||
SortingRendererClass::Insert_Triangles(
|
||||
bounding_sphere,
|
||||
index_offset,
|
||||
index_count/3,
|
||||
min_vertex_index,
|
||||
vertex_index_range);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
2188
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp
Normal file
2188
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
343
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.h
Normal file
343
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8renderer.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/10/01 5:49p $*
|
||||
* *
|
||||
* $Revision:: 28 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8_RENDERER_H
|
||||
#define DX8_RENDERER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwstring.h"
|
||||
#include "simplevec.h"
|
||||
#include "refcount.h"
|
||||
#include "vector.h"
|
||||
#include "dx8list.h"
|
||||
#include "shader.h"
|
||||
#include "dx8wrapper.h"
|
||||
|
||||
class IndexBufferClass;
|
||||
class VertexBufferClass;
|
||||
class DX8RenderTypeArrayClass;
|
||||
class MeshClass;
|
||||
class MeshModelClass;
|
||||
class DX8PolygonRendererClass;
|
||||
class Vertex_Split_Table;
|
||||
class DX8FVFCategoryContainer;
|
||||
class DecalMeshClass;
|
||||
class MaterialPassClass;
|
||||
class MatPassTaskClass;
|
||||
class PolyRenderTaskClass;
|
||||
class TextureClass;
|
||||
class VertexMaterialClass;
|
||||
class CameraClass;
|
||||
|
||||
#define RECORD_RENDER(I,P) render_stats[I].count++; render_stats[I].polys+=P;
|
||||
|
||||
/**
|
||||
** DX8TextureCategoryClass
|
||||
** This class is used for each Material-Texture-Shader combination that is encountered during rendering.
|
||||
** Each polygon_renderer that uses the same 'TextureCategory' will be linked to the 'TextureCategory' object.
|
||||
** Then, all polygons will be rendered in 'TextureCategory' batches to reduce the number of stage changes
|
||||
** (and most importantly, texture changes) that we cause in DX8.
|
||||
*/
|
||||
class DX8TextureCategoryClass : public MultiListObjectClass
|
||||
{
|
||||
int pass;
|
||||
TextureClass * textures[MAX_TEXTURE_STAGES];
|
||||
ShaderClass shader;
|
||||
VertexMaterialClass * material;
|
||||
DX8PolygonRendererList PolygonRendererList;
|
||||
DX8FVFCategoryContainer* container;
|
||||
|
||||
PolyRenderTaskClass * render_task_head; // polygon renderers queued for rendering
|
||||
static bool m_gForceMultiply; // Forces opaque materials to use the multiply blend - pseudo transparent effect. jba.
|
||||
|
||||
public:
|
||||
|
||||
DX8TextureCategoryClass(DX8FVFCategoryContainer* container,TextureClass** textures, ShaderClass shd, VertexMaterialClass* mat,int pass);
|
||||
~DX8TextureCategoryClass();
|
||||
|
||||
void Add_Render_Task(DX8PolygonRendererClass * p_renderer,MeshClass * p_mesh);
|
||||
|
||||
void Render(void);
|
||||
bool Anything_To_Render() { return (render_task_head != NULL); }
|
||||
void Clear_Render_List() { render_task_head = NULL; }
|
||||
|
||||
TextureClass * Peek_Texture(int stage) { return textures[stage]; }
|
||||
const VertexMaterialClass * Peek_Material() { return material; }
|
||||
ShaderClass Get_Shader() { return shader; }
|
||||
|
||||
DX8PolygonRendererList& Get_Polygon_Renderer_List() { return PolygonRendererList; }
|
||||
|
||||
unsigned Add_Mesh(
|
||||
Vertex_Split_Table& split_buffer,
|
||||
unsigned vertex_offset,
|
||||
unsigned index_offset,
|
||||
IndexBufferClass* index_buffer,
|
||||
unsigned pass);
|
||||
void Log(bool only_visible);
|
||||
|
||||
void Remove_Polygon_Renderer(DX8PolygonRendererClass* p_renderer);
|
||||
void Add_Polygon_Renderer(DX8PolygonRendererClass* p_renderer,DX8PolygonRendererClass* add_after_this=NULL);
|
||||
|
||||
|
||||
DX8FVFCategoryContainer * Get_Container(void) { return container; }
|
||||
|
||||
// Force multiply blend on all objects inserted from now on. (Doesn't affect the objects that are already in the lists)
|
||||
static void SetForceMultiply(bool multiply) { m_gForceMultiply=multiply; }
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** DX8FVFCategoryContainer
|
||||
*/
|
||||
|
||||
class DX8FVFCategoryContainer : public MultiListObjectClass
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MAX_PASSES=4
|
||||
};
|
||||
protected:
|
||||
|
||||
TextureCategoryList texture_category_list[MAX_PASSES];
|
||||
TextureCategoryList visible_texture_category_list[MAX_PASSES];
|
||||
|
||||
MatPassTaskClass * visible_matpass_head;
|
||||
MatPassTaskClass * visible_matpass_tail;
|
||||
|
||||
IndexBufferClass * index_buffer;
|
||||
int used_indices;
|
||||
unsigned FVF;
|
||||
unsigned passes;
|
||||
unsigned uv_coordinate_channels;
|
||||
bool sorting;
|
||||
bool AnythingToRender;
|
||||
|
||||
void Generate_Texture_Categories(Vertex_Split_Table& split_table,unsigned vertex_offset);
|
||||
void DX8FVFCategoryContainer::Insert_To_Texture_Category(
|
||||
Vertex_Split_Table& split_table,
|
||||
TextureClass** textures,
|
||||
VertexMaterialClass* mat,
|
||||
ShaderClass shader,
|
||||
int pass,
|
||||
unsigned vertex_offset);
|
||||
inline bool Anything_To_Render();
|
||||
void Render_Procedural_Material_Passes(void);
|
||||
|
||||
DX8TextureCategoryClass* Find_Matching_Texture_Category(
|
||||
TextureClass* texture,
|
||||
unsigned pass,
|
||||
unsigned stage,
|
||||
DX8TextureCategoryClass* ref_category);
|
||||
|
||||
DX8TextureCategoryClass* Find_Matching_Texture_Category(
|
||||
VertexMaterialClass* vmat,
|
||||
unsigned pass,
|
||||
DX8TextureCategoryClass* ref_category);
|
||||
|
||||
public:
|
||||
|
||||
DX8FVFCategoryContainer(unsigned FVF,bool sorting);
|
||||
virtual ~DX8FVFCategoryContainer();
|
||||
|
||||
static unsigned Define_FVF(MeshModelClass* mmc,bool enable_lighting);
|
||||
bool Is_Sorting() const { return sorting; }
|
||||
|
||||
void Change_Polygon_Renderer_Texture(
|
||||
DX8PolygonRendererList& polygon_renderer_list,
|
||||
TextureClass* texture,
|
||||
TextureClass* new_texture,
|
||||
unsigned pass,
|
||||
unsigned stage);
|
||||
|
||||
void Change_Polygon_Renderer_Material(
|
||||
DX8PolygonRendererList& polygon_renderer_list,
|
||||
VertexMaterialClass* vmat,
|
||||
VertexMaterialClass* new_vmat,
|
||||
unsigned pass);
|
||||
|
||||
void Remove_Texture_Category(DX8TextureCategoryClass* tex_category);
|
||||
|
||||
virtual void Render(void)=0;
|
||||
virtual void Add_Mesh(MeshModelClass* mmc)=0;
|
||||
virtual void Log(bool only_visible)=0;
|
||||
virtual bool Check_If_Mesh_Fits(MeshModelClass* mmc)=0;
|
||||
|
||||
inline unsigned Get_FVF() const { return FVF; }
|
||||
|
||||
inline void Add_Visible_Texture_Category(DX8TextureCategoryClass * tex_category,int pass)
|
||||
{
|
||||
WWASSERT(pass<MAX_PASSES);
|
||||
WWASSERT(tex_category != NULL);
|
||||
WWASSERT(texture_category_list[pass].Contains(tex_category));
|
||||
visible_texture_category_list[pass].Add(tex_category);
|
||||
AnythingToRender=true;
|
||||
}
|
||||
|
||||
void Add_Visible_Material_Pass(MaterialPassClass * pass,MeshClass * mesh);
|
||||
|
||||
|
||||
};
|
||||
|
||||
bool DX8FVFCategoryContainer::Anything_To_Render()
|
||||
{
|
||||
/* for (unsigned p=0;p<passes;++p) {
|
||||
TextureCategoryListIterator it(&texture_category_list[p]);
|
||||
while (!it.Is_Done()) {
|
||||
if (it.Peek_Obj()->Anything_To_Render()) return true;
|
||||
it.Next();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
return AnythingToRender;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** DX8RigidFVFCategoryContainer
|
||||
** This is an FVFCategoryContainer for rigid (non-skin) meshes
|
||||
*/
|
||||
class DX8RigidFVFCategoryContainer : public DX8FVFCategoryContainer
|
||||
{
|
||||
public:
|
||||
DX8RigidFVFCategoryContainer(unsigned FVF,bool sorting);
|
||||
~DX8RigidFVFCategoryContainer();
|
||||
|
||||
void Add_Mesh(MeshModelClass* mmc);
|
||||
void Log(bool only_visible);
|
||||
bool Check_If_Mesh_Fits(MeshModelClass* mmc);
|
||||
|
||||
void Render(void); // Generic render function
|
||||
|
||||
protected:
|
||||
|
||||
VertexBufferClass * vertex_buffer;
|
||||
int used_vertices;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** DX8SkinFVFCategoryContainer
|
||||
** This is an FVFCategoryContainer for skin meshes
|
||||
*/
|
||||
class DX8SkinFVFCategoryContainer: public DX8FVFCategoryContainer
|
||||
{
|
||||
public:
|
||||
DX8SkinFVFCategoryContainer(bool sorting);
|
||||
~DX8SkinFVFCategoryContainer();
|
||||
|
||||
void Render(void);
|
||||
void Add_Mesh(MeshModelClass* mmc);
|
||||
void Log(bool only_visible);
|
||||
bool Check_If_Mesh_Fits(MeshModelClass* mmc);
|
||||
|
||||
void Add_Visible_Skin(MeshClass * mesh);
|
||||
|
||||
private:
|
||||
|
||||
void Reset();
|
||||
void clearVisibleSkinList();
|
||||
|
||||
unsigned int VisibleVertexCount;
|
||||
MeshClass * VisibleSkinHead;
|
||||
MeshClass * VisibleSkinTail;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** DX8MeshRendererClass
|
||||
** This object is controller for the entire DX8 mesh rendering system. It organizes mesh
|
||||
** fragments into groups based on FVF, texture, and material. During rendering, a list of
|
||||
** the visible mesh fragments is composed and rendered. There is a global instance of this
|
||||
** class called TheDX8MeshRenderer that should be used for all mesh rendering.
|
||||
*/
|
||||
class DX8MeshRendererClass
|
||||
{
|
||||
public:
|
||||
DX8MeshRendererClass();
|
||||
~DX8MeshRendererClass();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Flush();
|
||||
void Clear_Pending_Delete_Lists();
|
||||
|
||||
void Log_Statistics_String(bool only_visible);
|
||||
static void Request_Log_Statistics();
|
||||
|
||||
void Register_Mesh_Type(MeshModelClass* mmc);
|
||||
void Unregister_Mesh_Type(MeshModelClass* mmc);
|
||||
void Set_Camera(CameraClass* cam) { camera=cam; }
|
||||
CameraClass * Peek_Camera(void) { return camera; }
|
||||
void Add_To_Render_List(DecalMeshClass * decalmesh);
|
||||
|
||||
// Enable or disable lighting on all objects inserted from now on. (Doesn't affect the objects that are already in the lists)
|
||||
void Enable_Lighting(bool enable) { enable_lighting=enable; }
|
||||
|
||||
// This should be called at the beginning of a game or menu or after a major modifications to the scene...
|
||||
void Invalidate(bool shutdown=false); // Added flag so it doesn't allocate more mem when shutting down. -MW
|
||||
|
||||
protected:
|
||||
|
||||
void Render_Decal_Meshes(void);
|
||||
|
||||
bool enable_lighting;
|
||||
CameraClass * camera;
|
||||
|
||||
SimpleDynVecClass<FVFCategoryList *> texture_category_container_lists_rigid;
|
||||
FVFCategoryList * texture_category_container_list_skin;
|
||||
|
||||
DecalMeshClass * visible_decal_meshes;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern DX8MeshRendererClass TheDX8MeshRenderer;
|
||||
|
||||
#endif
|
||||
196
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp
Normal file
196
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : DX8 Texture Manager *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/dx8texman.cpp $*
|
||||
* *
|
||||
* Original Author:: Hector Yee *
|
||||
* *
|
||||
* $Author:: Hector_y $*
|
||||
* *
|
||||
* $Modtime:: 4/26/01 1:41p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* DX8TextureManagerClass::Shutdown -- Shuts down the texture manager *
|
||||
* DX8TextureManagerClass::Add -- Adds a texture to be managed *
|
||||
* DX8TextureManagerClass::Remove -- Removes a texture from being managed *
|
||||
* DX8TextureManagerClass::Release_Textures -- Releases the internal d3d texture *
|
||||
* DX8TextureManagerClass::Recreate_Textures -- Reallocates lost textures *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
// This class manages textures that are in the default pool
|
||||
// ensuring that they are released on device loss
|
||||
// and created on device reset
|
||||
|
||||
// Note: It does NOT addref to textures because it is called in the texture
|
||||
// destructor
|
||||
|
||||
#include "dx8texman.h"
|
||||
|
||||
DX8TextureTrackerList DX8TextureManagerClass::Managed_Textures;
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DX8TextureManagerClass::Shutdown -- Shuts down the texture manager *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 hy : Created. *
|
||||
*=============================================================================================*/
|
||||
void DX8TextureManagerClass::Shutdown()
|
||||
{
|
||||
while (!Managed_Textures.Is_Empty())
|
||||
{
|
||||
DX8TextureTrackerClass *track=Managed_Textures.Remove_Head();
|
||||
delete track;
|
||||
track=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* DX8TextureManagerClass::Add -- Adds a texture to be managed *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 hy : Created. *
|
||||
*=============================================================================================*/
|
||||
void DX8TextureManagerClass::Add(DX8TextureTrackerClass *track)
|
||||
{
|
||||
// this function should only be called by the texture constructor
|
||||
Managed_Textures.Add(track);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DX8TextureManagerClass::Remove -- Removes a texture from being managed *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 hy : Created. *
|
||||
*=============================================================================================*/
|
||||
void DX8TextureManagerClass::Remove(TextureClass *tex)
|
||||
{
|
||||
// this function should only be called by the texture destructor
|
||||
DX8TextureTrackerListIterator it(&Managed_Textures);
|
||||
|
||||
while (!it.Is_Done())
|
||||
{
|
||||
DX8TextureTrackerClass *track=it.Peek_Obj();
|
||||
if (track->Texture==tex)
|
||||
{
|
||||
it.Remove_Current_Object();
|
||||
delete track;
|
||||
break;
|
||||
}
|
||||
it.Next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DX8TextureManagerClass::Release_Textures -- Releases the internal d3d texture *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 hy : Created. *
|
||||
*=============================================================================================*/
|
||||
void DX8TextureManagerClass::Release_Textures()
|
||||
{
|
||||
DX8TextureTrackerListIterator it(&Managed_Textures);
|
||||
|
||||
while (!it.Is_Done())
|
||||
{
|
||||
DX8TextureTrackerClass *track=it.Peek_Obj();
|
||||
WWASSERT(track->Texture->D3DTexture);
|
||||
track->Texture->D3DTexture->Release();
|
||||
track->Texture->D3DTexture=NULL;
|
||||
it.Next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* DX8TextureManagerClass::Recreate_Textures -- Reallocates lost textures *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 hy : Created. *
|
||||
*=============================================================================================*/
|
||||
void DX8TextureManagerClass::Recreate_Textures()
|
||||
{
|
||||
DX8TextureTrackerListIterator it(&Managed_Textures);
|
||||
|
||||
while (!it.Is_Done())
|
||||
{
|
||||
DX8TextureTrackerClass *track=it.Peek_Obj();
|
||||
WWASSERT(track->Texture->D3DTexture==NULL);
|
||||
track->Texture->D3DTexture=DX8Wrapper::_Create_DX8_Texture(track->Width,track->Height,
|
||||
track->Format,track->Mip_level_count,D3DPOOL_DEFAULT,track->RenderTarget);
|
||||
track->Texture->Dirty=true;
|
||||
it.Next();
|
||||
}
|
||||
}
|
||||
92
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h
Normal file
92
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : DX8 Texture Manager *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/dx8texman.h $*
|
||||
* *
|
||||
* Original Author:: Hector Yee *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/26/01 5:12p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8TEXTUREMANAGER_H
|
||||
#define DX8TEXTUREMANAGER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "texture.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "ww3dformat.h"
|
||||
#include "dx8list.h"
|
||||
#include "ww3dformat.h"
|
||||
#include "multilist.h"
|
||||
|
||||
class DX8TextureManagerClass;
|
||||
|
||||
class DX8TextureTrackerClass : public MultiListObjectClass
|
||||
{
|
||||
friend DX8TextureManagerClass;
|
||||
public:
|
||||
DX8TextureTrackerClass(unsigned int w, unsigned int h, WW3DFormat format,
|
||||
TextureClass::MipCountType count,bool rt,
|
||||
TextureClass *tex):
|
||||
Width(w),
|
||||
Height(h),
|
||||
Format(format),
|
||||
Mip_level_count(count),
|
||||
RenderTarget(rt),
|
||||
Texture(tex)
|
||||
{
|
||||
}
|
||||
private:
|
||||
unsigned int Width;
|
||||
unsigned int Height;
|
||||
WW3DFormat Format;
|
||||
TextureClass::MipCountType Mip_level_count;
|
||||
bool RenderTarget;
|
||||
TextureClass *Texture;
|
||||
};
|
||||
|
||||
class DX8TextureManagerClass
|
||||
{
|
||||
public:
|
||||
static void Shutdown();
|
||||
static void Add(DX8TextureTrackerClass *track);
|
||||
static void Remove(TextureClass *tex);
|
||||
static void Release_Textures();
|
||||
static void Recreate_Textures();
|
||||
private:
|
||||
static DX8TextureTrackerList Managed_Textures;
|
||||
};
|
||||
|
||||
#endif // ifdef TEXTUREMANAGER
|
||||
896
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.cpp
Normal file
896
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.cpp
Normal file
@@ -0,0 +1,896 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8vertexbuffer.cpp $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/10/01 1:33p $*
|
||||
* *
|
||||
* $Revision:: 34 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
//#define VERTEX_BUFFER_LOG
|
||||
|
||||
#include "dx8vertexbuffer.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "dx8fvf.h"
|
||||
#include "dx8caps.h"
|
||||
#include "thread.h"
|
||||
#include <D3dx8core.h>
|
||||
|
||||
#define DEFAULT_VB_SIZE 5000
|
||||
|
||||
static bool _DynamicSortingVertexArrayInUse=false;
|
||||
//static VertexFormatXYZNDUV2* _DynamicSortingVertexArray=NULL;
|
||||
static SortingVertexBufferClass* _DynamicSortingVertexArray=NULL;
|
||||
static unsigned short _DynamicSortingVertexArraySize=0;
|
||||
static unsigned short _DynamicSortingVertexArrayOffset=0;
|
||||
|
||||
static bool _DynamicDX8VertexBufferInUse=false;
|
||||
static DX8VertexBufferClass* _DynamicDX8VertexBuffer=NULL;
|
||||
static unsigned short _DynamicDX8VertexBufferSize=DEFAULT_VB_SIZE;
|
||||
static unsigned short _DynamicDX8VertexBufferOffset=0;
|
||||
|
||||
static const FVFInfoClass _DynamicFVFInfo(dynamic_fvf_type);
|
||||
|
||||
static int _DX8VertexBufferCount=0;
|
||||
|
||||
static int _VertexBufferCount;
|
||||
static int _VertexBufferTotalVertices;
|
||||
static int _VertexBufferTotalSize;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::VertexBufferClass(unsigned type_, unsigned FVF, unsigned short vertex_count_)
|
||||
:
|
||||
VertexCount(vertex_count_),
|
||||
type(type_),
|
||||
engine_refs(0)
|
||||
{
|
||||
WWASSERT(VertexCount);
|
||||
WWASSERT(type==BUFFER_TYPE_DX8 || type==BUFFER_TYPE_SORTING);
|
||||
fvf_info=W3DNEW FVFInfoClass(FVF);
|
||||
|
||||
_VertexBufferCount++;
|
||||
_VertexBufferTotalVertices+=VertexCount;
|
||||
_VertexBufferTotalSize+=VertexCount*fvf_info->Get_FVF_Size();
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("New VB, %d vertices, size %d bytes\n",VertexCount,VertexCount*fvf_info->Get_FVF_Size()));
|
||||
WWDEBUG_SAY(("Total VB count: %d, total %d vertices, total size %d bytes\n",
|
||||
_VertexBufferCount,
|
||||
_VertexBufferTotalVertices,
|
||||
_VertexBufferTotalSize));
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::~VertexBufferClass()
|
||||
{
|
||||
_VertexBufferCount--;
|
||||
_VertexBufferTotalVertices-=VertexCount;
|
||||
_VertexBufferTotalSize-=VertexCount*fvf_info->Get_FVF_Size();
|
||||
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("Delete VB, %d vertices, size %d bytes\n",VertexCount,VertexCount*fvf_info->Get_FVF_Size()));
|
||||
WWDEBUG_SAY(("Total VB count: %d, total %d vertices, total size %d bytes\n",
|
||||
_VertexBufferCount,
|
||||
_VertexBufferTotalVertices,
|
||||
_VertexBufferTotalSize));
|
||||
#endif
|
||||
delete fvf_info;
|
||||
}
|
||||
|
||||
unsigned VertexBufferClass::Get_Total_Buffer_Count()
|
||||
{
|
||||
return _VertexBufferCount;
|
||||
}
|
||||
|
||||
unsigned VertexBufferClass::Get_Total_Allocated_Vertices()
|
||||
{
|
||||
return _VertexBufferTotalVertices;
|
||||
}
|
||||
|
||||
unsigned VertexBufferClass::Get_Total_Allocated_Memory()
|
||||
{
|
||||
return _VertexBufferTotalSize;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void VertexBufferClass::Add_Engine_Ref() const
|
||||
{
|
||||
engine_refs++;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void VertexBufferClass::Release_Engine_Ref() const
|
||||
{
|
||||
engine_refs--;
|
||||
WWASSERT(engine_refs>=0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::WriteLockClass::WriteLockClass(VertexBufferClass* VertexBuffer)
|
||||
:
|
||||
VertexBufferLockClass(VertexBuffer)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(VertexBuffer);
|
||||
WWASSERT(!VertexBuffer->Engine_Refs());
|
||||
VertexBuffer->Add_Ref();
|
||||
switch (VertexBuffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
{
|
||||
StringClass fvf_name;
|
||||
VertexBuffer->FVF_Info().Get_FVF_Name(fvf_name);
|
||||
WWDEBUG_SAY(("VertexBuffer->Lock(start_index: 0, index_range: 0(%d), fvf_size: %d, fvf: %s)\n",
|
||||
VertexBuffer->Get_Vertex_Count(),
|
||||
VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
fvf_name));
|
||||
}
|
||||
#endif
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(VertexBuffer)->Get_DX8_Vertex_Buffer()->Lock(
|
||||
0,
|
||||
0,
|
||||
(unsigned char**)&Vertices,
|
||||
0)); // Default (no) flags
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
Vertices=static_cast<SortingVertexBufferClass*>(VertexBuffer)->VertexBuffer;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::WriteLockClass::~WriteLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (VertexBuffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("VertexBuffer->Unlock()\n"));
|
||||
#endif
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(VertexBuffer)->Get_DX8_Vertex_Buffer()->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
VertexBuffer->Release_Ref();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::AppendLockClass::AppendLockClass(VertexBufferClass* VertexBuffer,unsigned start_index, unsigned index_range)
|
||||
:
|
||||
VertexBufferLockClass(VertexBuffer)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(VertexBuffer);
|
||||
WWASSERT(!VertexBuffer->Engine_Refs());
|
||||
WWASSERT(start_index+index_range<=VertexBuffer->Get_Vertex_Count());
|
||||
VertexBuffer->Add_Ref();
|
||||
switch (VertexBuffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
{
|
||||
StringClass fvf_name;
|
||||
VertexBuffer->FVF_Info().Get_FVF_Name(fvf_name);
|
||||
WWDEBUG_SAY(("VertexBuffer->Lock(start_index: %d, index_range: %d, fvf_size: %d, fvf: %s)\n",
|
||||
start_index,
|
||||
index_range,
|
||||
VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
fvf_name));
|
||||
}
|
||||
#endif
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(VertexBuffer)->Get_DX8_Vertex_Buffer()->Lock(
|
||||
start_index*VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
index_range*VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
(unsigned char**)&Vertices,
|
||||
0)); // Default (no) flags
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
Vertices=static_cast<SortingVertexBufferClass*>(VertexBuffer)->VertexBuffer+start_index;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
VertexBufferClass::AppendLockClass::~AppendLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (VertexBuffer->Type()) {
|
||||
case BUFFER_TYPE_DX8:
|
||||
DX8_Assert();
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("VertexBuffer->Unlock()\n"));
|
||||
#endif
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(VertexBuffer)->Get_DX8_Vertex_Buffer()->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
VertexBuffer->Release_Ref();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SortingVertexBufferClass::SortingVertexBufferClass(unsigned short VertexCount)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_SORTING, dynamic_fvf_type, VertexCount)
|
||||
{
|
||||
VertexBuffer=W3DNEWARRAY VertexFormatXYZNDUV2[VertexCount];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SortingVertexBufferClass::~SortingVertexBufferClass()
|
||||
{
|
||||
delete[] VertexBuffer;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// bool dynamic=false,bool softwarevp=false);
|
||||
|
||||
DX8VertexBufferClass::DX8VertexBufferClass(unsigned FVF, unsigned short vertex_count_, UsageType usage)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_DX8, FVF, vertex_count_),
|
||||
VertexBuffer(NULL)
|
||||
{
|
||||
Create_Vertex_Buffer(usage);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8VertexBufferClass::DX8VertexBufferClass(
|
||||
const Vector3* vertices,
|
||||
const Vector3* normals,
|
||||
const Vector2* tex_coords,
|
||||
unsigned short VertexCount,
|
||||
UsageType usage)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_DX8, D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_NORMAL, VertexCount),
|
||||
VertexBuffer(NULL)
|
||||
{
|
||||
WWASSERT(vertices);
|
||||
WWASSERT(normals);
|
||||
WWASSERT(tex_coords);
|
||||
|
||||
Create_Vertex_Buffer(usage);
|
||||
Copy(vertices,normals,tex_coords,0,VertexCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8VertexBufferClass::DX8VertexBufferClass(
|
||||
const Vector3* vertices,
|
||||
const Vector3* normals,
|
||||
const Vector4* diffuse,
|
||||
const Vector2* tex_coords,
|
||||
unsigned short VertexCount,
|
||||
UsageType usage)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_DX8, D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_NORMAL|D3DFVF_DIFFUSE, VertexCount),
|
||||
VertexBuffer(NULL)
|
||||
{
|
||||
WWASSERT(vertices);
|
||||
WWASSERT(normals);
|
||||
WWASSERT(tex_coords);
|
||||
WWASSERT(diffuse);
|
||||
|
||||
Create_Vertex_Buffer(usage);
|
||||
Copy(vertices,normals,tex_coords,diffuse,0,VertexCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8VertexBufferClass::DX8VertexBufferClass(
|
||||
const Vector3* vertices,
|
||||
const Vector4* diffuse,
|
||||
const Vector2* tex_coords,
|
||||
unsigned short VertexCount,
|
||||
UsageType usage)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_DX8, D3DFVF_XYZ|D3DFVF_TEX1|D3DFVF_DIFFUSE, VertexCount),
|
||||
VertexBuffer(NULL)
|
||||
{
|
||||
WWASSERT(vertices);
|
||||
WWASSERT(tex_coords);
|
||||
WWASSERT(diffuse);
|
||||
|
||||
Create_Vertex_Buffer(usage);
|
||||
Copy(vertices,tex_coords,diffuse,0,VertexCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8VertexBufferClass::DX8VertexBufferClass(
|
||||
const Vector3* vertices,
|
||||
const Vector2* tex_coords,
|
||||
unsigned short VertexCount,
|
||||
UsageType usage)
|
||||
:
|
||||
VertexBufferClass(BUFFER_TYPE_DX8, D3DFVF_XYZ|D3DFVF_TEX1, VertexCount),
|
||||
VertexBuffer(NULL)
|
||||
{
|
||||
WWASSERT(vertices);
|
||||
WWASSERT(tex_coords);
|
||||
|
||||
Create_Vertex_Buffer(usage);
|
||||
Copy(vertices,tex_coords,0,VertexCount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DX8VertexBufferClass::~DX8VertexBufferClass()
|
||||
{
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
WWDEBUG_SAY(("VertexBuffer->Release()\n"));
|
||||
_DX8VertexBufferCount--;
|
||||
WWDEBUG_SAY(("Current vertex buffer count: %d\n",_DX8VertexBufferCount));
|
||||
#endif
|
||||
VertexBuffer->Release();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Create_Vertex_Buffer(UsageType usage)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
WWASSERT(!VertexBuffer);
|
||||
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
StringClass fvf_name;
|
||||
FVF_Info().Get_FVF_Name(fvf_name);
|
||||
WWDEBUG_SAY(("CreateVertexBuffer(fvfsize=%d, vertex_count=%d, D3DUSAGE_WRITEONLY|%s|%s, fvf: %s, %s)\n",
|
||||
FVF_Info().Get_FVF_Size(),
|
||||
VertexCount,
|
||||
usage&USAGE_DYNAMIC ? "D3DUSAGE_DYNAMIC" : "-",
|
||||
usage&USAGE_SOFTWAREPROCESSING ? "D3DUSAGE_SOFTWAREPROCESSING" : "-",
|
||||
fvf_name,
|
||||
dynamic ? "D3DPOOL_DEFAULT" : "D3DPOOL_MANAGED"));
|
||||
_DX8VertexBufferCount++;
|
||||
WWDEBUG_SAY(("Current vertex buffer count: %d\n",_DX8VertexBufferCount));
|
||||
#endif
|
||||
|
||||
unsigned usage_flags=
|
||||
D3DUSAGE_WRITEONLY|
|
||||
((usage&USAGE_DYNAMIC) ? D3DUSAGE_DYNAMIC : 0)|
|
||||
((usage&USAGE_NPATCHES) ? D3DUSAGE_NPATCHES : 0)|
|
||||
((usage&USAGE_SOFTWAREPROCESSING) ? D3DUSAGE_SOFTWAREPROCESSING : 0);
|
||||
|
||||
// New Code
|
||||
if (!DX8Caps::Use_TnL()) {
|
||||
usage_flags|=D3DUSAGE_SOFTWAREPROCESSING;
|
||||
}
|
||||
|
||||
HRESULT ret=DX8Wrapper::_Get_D3D_Device8()->CreateVertexBuffer(
|
||||
FVF_Info().Get_FVF_Size()*VertexCount,
|
||||
usage_flags,
|
||||
FVF_Info().Get_FVF(),
|
||||
(usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
|
||||
&VertexBuffer);
|
||||
if (SUCCEEDED(ret)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WWDEBUG_SAY(("Vertex buffer creation failed, trying to release assets...\n"));
|
||||
|
||||
// Vertex buffer creation failed. Must be out of memory. Try releasing all our D3D assets and re-creating
|
||||
// them.
|
||||
|
||||
// Invalidate the mesh cache
|
||||
WW3D::_Invalidate_Mesh_Cache();
|
||||
|
||||
//@todo: Find some way to invalidate the textures too
|
||||
ret = DX8Wrapper::_Get_D3D_Device8()->ResourceManagerDiscardBytes(0);
|
||||
|
||||
// Try again...
|
||||
ret=DX8Wrapper::_Get_D3D_Device8()->CreateVertexBuffer(
|
||||
FVF_Info().Get_FVF_Size()*VertexCount,
|
||||
usage_flags,
|
||||
FVF_Info().Get_FVF(),
|
||||
(usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
|
||||
&VertexBuffer);
|
||||
|
||||
if (SUCCEEDED(ret)) {
|
||||
WWDEBUG_SAY(("...Vertex buffer creation succesful\n"));
|
||||
}
|
||||
|
||||
// If it still fails it is fatal
|
||||
DX8_ErrorCode(ret);
|
||||
|
||||
/* Old Code
|
||||
DX8CALL(CreateVertexBuffer(
|
||||
FVF_Info().Get_FVF_Size()*VertexCount,
|
||||
usage_flags,
|
||||
FVF_Info().Get_FVF(),
|
||||
(usage&USAGE_DYNAMIC) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED,
|
||||
&VertexBuffer));
|
||||
*/
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, const Vector3* norm, const Vector2* uv, unsigned first_vertex,unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(norm);
|
||||
WWASSERT(uv);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZNUV1);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZNUV1* verts=(VertexFormatXYZNUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZNUV1* verts=(VertexFormatXYZNUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, unsigned first_vertex, unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZ);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZ* verts=(VertexFormatXYZ*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZ* verts=(VertexFormatXYZ*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, const Vector2* uv, unsigned first_vertex, unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(uv);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZUV1);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZUV1* verts=(VertexFormatXYZUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZUV1* verts=(VertexFormatXYZUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, const Vector3* norm, unsigned first_vertex, unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(norm);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZN);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZN* verts=(VertexFormatXYZN*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZN* verts=(VertexFormatXYZN*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, const Vector3* norm, const Vector2* uv, const Vector4* diffuse, unsigned first_vertex, unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(norm);
|
||||
WWASSERT(uv);
|
||||
WWASSERT(diffuse);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZNDUV1);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZNDUV1* verts=(VertexFormatXYZNDUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
verts[v].diffuse=DX8Wrapper::Convert_Color(diffuse[v]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZNDUV1* verts=(VertexFormatXYZNDUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].nx=(*norm)[0];
|
||||
verts[v].ny=(*norm)[1];
|
||||
verts[v].nz=(*norm++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
verts[v].diffuse=DX8Wrapper::Convert_Color(diffuse[v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DX8VertexBufferClass::Copy(const Vector3* loc, const Vector2* uv, const Vector4* diffuse, unsigned first_vertex, unsigned count)
|
||||
{
|
||||
WWASSERT(loc);
|
||||
WWASSERT(uv);
|
||||
WWASSERT(diffuse);
|
||||
WWASSERT(count<=VertexCount);
|
||||
WWASSERT(FVF_Info().Get_FVF()==DX8_FVF_XYZDUV1);
|
||||
|
||||
if (first_vertex) {
|
||||
VertexBufferClass::AppendLockClass l(this,first_vertex,count);
|
||||
VertexFormatXYZDUV1* verts=(VertexFormatXYZDUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
verts[v].diffuse=DX8Wrapper::Convert_Color(diffuse[v]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexBufferClass::WriteLockClass l(this);
|
||||
VertexFormatXYZDUV1* verts=(VertexFormatXYZDUV1*)l.Get_Vertex_Array();
|
||||
for (unsigned v=0;v<count;++v) {
|
||||
verts[v].x=(*loc)[0];
|
||||
verts[v].y=(*loc)[1];
|
||||
verts[v].z=(*loc++)[2];
|
||||
verts[v].u1=(*uv)[0];
|
||||
verts[v].v1=(*uv++)[1];
|
||||
verts[v].diffuse=DX8Wrapper::Convert_Color(diffuse[v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DynamicVBAccessClass::DynamicVBAccessClass(unsigned t,unsigned fvf,unsigned short vertex_count_)
|
||||
:
|
||||
Type(t),
|
||||
FVFInfo(_DynamicFVFInfo),
|
||||
VertexCount(vertex_count_),
|
||||
VertexBuffer(0)
|
||||
{
|
||||
WWASSERT(fvf==dynamic_fvf_type);
|
||||
WWASSERT(Type==BUFFER_TYPE_DYNAMIC_DX8 || Type==BUFFER_TYPE_DYNAMIC_SORTING);
|
||||
|
||||
if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
|
||||
Allocate_DX8_Dynamic_Buffer();
|
||||
}
|
||||
else {
|
||||
Allocate_Sorting_Dynamic_Buffer();
|
||||
}
|
||||
}
|
||||
|
||||
DynamicVBAccessClass::~DynamicVBAccessClass()
|
||||
{
|
||||
if (Type==BUFFER_TYPE_DYNAMIC_DX8) {
|
||||
_DynamicDX8VertexBufferInUse=false;
|
||||
_DynamicDX8VertexBufferOffset+=(unsigned) VertexCount;
|
||||
}
|
||||
else {
|
||||
_DynamicSortingVertexArrayInUse=false;
|
||||
_DynamicSortingVertexArrayOffset+=VertexCount;
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE (VertexBuffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DynamicVBAccessClass::_Deinit()
|
||||
{
|
||||
WWASSERT ((_DynamicDX8VertexBuffer == NULL) || (_DynamicDX8VertexBuffer->Num_Refs() == 1));
|
||||
REF_PTR_RELEASE(_DynamicDX8VertexBuffer);
|
||||
_DynamicDX8VertexBufferInUse=false;
|
||||
_DynamicDX8VertexBufferSize=DEFAULT_VB_SIZE;
|
||||
_DynamicDX8VertexBufferOffset=0;
|
||||
|
||||
WWASSERT ((_DynamicSortingVertexArray == NULL) || (_DynamicSortingVertexArray->Num_Refs() == 1));
|
||||
REF_PTR_RELEASE(_DynamicSortingVertexArray);
|
||||
WWASSERT(!_DynamicSortingVertexArrayInUse);
|
||||
_DynamicSortingVertexArrayInUse=false;
|
||||
_DynamicSortingVertexArraySize=0;
|
||||
_DynamicSortingVertexArrayOffset=0;
|
||||
}
|
||||
|
||||
void DynamicVBAccessClass::Allocate_DX8_Dynamic_Buffer()
|
||||
{
|
||||
WWASSERT(!_DynamicDX8VertexBufferInUse);
|
||||
_DynamicDX8VertexBufferInUse=true;
|
||||
|
||||
// If requesting more vertices than dynamic vertex buffer can fit, delete the vb
|
||||
// and adjust the size to the new count.
|
||||
if (VertexCount>_DynamicDX8VertexBufferSize) {
|
||||
REF_PTR_RELEASE(_DynamicDX8VertexBuffer);
|
||||
_DynamicDX8VertexBufferSize=VertexCount;
|
||||
if (_DynamicDX8VertexBufferSize<DEFAULT_VB_SIZE) _DynamicDX8VertexBufferSize=DEFAULT_VB_SIZE;
|
||||
}
|
||||
|
||||
// Create a new vb if one doesn't exist currently
|
||||
if (!_DynamicDX8VertexBuffer) {
|
||||
unsigned usage=DX8VertexBufferClass::USAGE_DYNAMIC;
|
||||
if (DX8Caps::Support_NPatches()) {
|
||||
usage|=DX8VertexBufferClass::USAGE_NPATCHES;
|
||||
}
|
||||
|
||||
_DynamicDX8VertexBuffer=NEW_REF(DX8VertexBufferClass,(
|
||||
dynamic_fvf_type,
|
||||
_DynamicDX8VertexBufferSize,
|
||||
(DX8VertexBufferClass::UsageType)usage));
|
||||
_DynamicDX8VertexBufferOffset=0;
|
||||
}
|
||||
|
||||
// Any room at the end of the buffer?
|
||||
if (((unsigned)VertexCount+_DynamicDX8VertexBufferOffset)>_DynamicDX8VertexBufferSize) {
|
||||
_DynamicDX8VertexBufferOffset=0;
|
||||
}
|
||||
|
||||
REF_PTR_SET(VertexBuffer,_DynamicDX8VertexBuffer);
|
||||
VertexBufferOffset=_DynamicDX8VertexBufferOffset;
|
||||
}
|
||||
|
||||
void DynamicVBAccessClass::Allocate_Sorting_Dynamic_Buffer()
|
||||
{
|
||||
WWASSERT(!_DynamicSortingVertexArrayInUse);
|
||||
_DynamicSortingVertexArrayInUse=true;
|
||||
|
||||
unsigned new_vertex_count=_DynamicSortingVertexArrayOffset+VertexCount;
|
||||
WWASSERT(new_vertex_count<65536);
|
||||
if (new_vertex_count>_DynamicSortingVertexArraySize) {
|
||||
REF_PTR_RELEASE(_DynamicSortingVertexArray);
|
||||
_DynamicSortingVertexArraySize=new_vertex_count;
|
||||
if (_DynamicSortingVertexArraySize<DEFAULT_VB_SIZE) _DynamicSortingVertexArraySize=DEFAULT_VB_SIZE;
|
||||
}
|
||||
|
||||
if (!_DynamicSortingVertexArray) {
|
||||
_DynamicSortingVertexArray=NEW_REF(SortingVertexBufferClass,(_DynamicSortingVertexArraySize));
|
||||
_DynamicSortingVertexArrayOffset=0;
|
||||
}
|
||||
|
||||
REF_PTR_SET(VertexBuffer,_DynamicSortingVertexArray);
|
||||
VertexBufferOffset=_DynamicSortingVertexArrayOffset;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static int dx8_lock;
|
||||
DynamicVBAccessClass::WriteLockClass::WriteLockClass(DynamicVBAccessClass* dynamic_vb_access_)
|
||||
:
|
||||
DynamicVBAccess(dynamic_vb_access_)
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (DynamicVBAccess->Get_Type()) {
|
||||
case BUFFER_TYPE_DYNAMIC_DX8:
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
{
|
||||
WWASSERT(!dx8_lock);
|
||||
dx8_lock++;
|
||||
StringClass fvf_name;
|
||||
DynamicVBAccess->VertexBuffer->FVF_Info().Get_FVF_Name(fvf_name);
|
||||
WWDEBUG_SAY(("DynamicVertexBuffer->Lock(start_index: %d, index_range: %d, fvf_size: %d, fvf: %s)\n",
|
||||
DynamicVBAccess->VertexBufferOffset,
|
||||
DynamicVBAccess->Get_Vertex_Count(),
|
||||
DynamicVBAccess->VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
fvf_name));
|
||||
}
|
||||
#endif
|
||||
WWASSERT(_DynamicDX8VertexBuffer);
|
||||
// WWASSERT(!_DynamicDX8VertexBuffer->Engine_Refs());
|
||||
|
||||
DX8_Assert();
|
||||
// Lock with discard contents if the buffer offset is zero
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(DynamicVBAccess->VertexBuffer)->Get_DX8_Vertex_Buffer()->Lock(
|
||||
DynamicVBAccess->VertexBufferOffset*_DynamicDX8VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
DynamicVBAccess->Get_Vertex_Count()*DynamicVBAccess->VertexBuffer->FVF_Info().Get_FVF_Size(),
|
||||
(unsigned char**)&Vertices,
|
||||
D3DLOCK_NOSYSLOCK | (!DynamicVBAccess->VertexBufferOffset ? D3DLOCK_DISCARD : D3DLOCK_NOOVERWRITE)));
|
||||
break;
|
||||
case BUFFER_TYPE_DYNAMIC_SORTING:
|
||||
Vertices=static_cast<SortingVertexBufferClass*>(DynamicVBAccess->VertexBuffer)->VertexBuffer;
|
||||
Vertices+=DynamicVBAccess->VertexBufferOffset;
|
||||
// vertices=_DynamicSortingVertexArray+_DynamicSortingVertexArrayOffset;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
DynamicVBAccessClass::WriteLockClass::~WriteLockClass()
|
||||
{
|
||||
DX8_THREAD_ASSERT();
|
||||
switch (DynamicVBAccess->Get_Type()) {
|
||||
case BUFFER_TYPE_DYNAMIC_DX8:
|
||||
#ifdef VERTEX_BUFFER_LOG
|
||||
dx8_lock--;
|
||||
WWASSERT(!dx8_lock);
|
||||
WWDEBUG_SAY(("DynamicVertexBuffer->Unlock()\n"));
|
||||
#endif
|
||||
DX8_Assert();
|
||||
DX8_ErrorCode(static_cast<DX8VertexBufferClass*>(DynamicVBAccess->VertexBuffer)->Get_DX8_Vertex_Buffer()->Unlock());
|
||||
break;
|
||||
case BUFFER_TYPE_DYNAMIC_SORTING:
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void DynamicVBAccessClass::_Reset(bool frame_changed)
|
||||
{
|
||||
_DynamicSortingVertexArrayOffset=0;
|
||||
if (frame_changed) _DynamicDX8VertexBufferOffset=0;
|
||||
}
|
||||
|
||||
unsigned short DynamicVBAccessClass::Get_Default_Vertex_Count(void)
|
||||
{
|
||||
return _DynamicDX8VertexBufferSize;
|
||||
}
|
||||
|
||||
264
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.h
Normal file
264
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8vertexbuffer.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/dx8vertexbuffer.h $*
|
||||
* *
|
||||
* Original Author:: Jani Penttinen *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/09/01 8:15p $*
|
||||
* *
|
||||
* $Revision:: 25 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DX8VERTEXBUFFER_H
|
||||
#define DX8VERTEXBUFFER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwdebug.h"
|
||||
#include "refcount.h"
|
||||
#include "dx8fvf.h"
|
||||
|
||||
const unsigned dynamic_fvf_type=D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2|D3DFVF_DIFFUSE;
|
||||
|
||||
class DX8Wrapper;
|
||||
class SortingRendererClass;
|
||||
class Vector2;
|
||||
class Vector3;
|
||||
class Vector4;
|
||||
class StringClass;
|
||||
class DX8VertexBufferClass;
|
||||
class FVFInfoClass;
|
||||
struct IDirect3DVertexBuffer8;
|
||||
class VertexBufferClass;
|
||||
struct VertexFormatXYZNDUV2;
|
||||
|
||||
class VertexBufferLockClass
|
||||
{
|
||||
protected:
|
||||
VertexBufferClass* VertexBuffer;
|
||||
void* Vertices;
|
||||
|
||||
// This class can't be used directly, so constructor as to be protected
|
||||
VertexBufferLockClass(VertexBufferClass* vertex_buffer_) : VertexBuffer(vertex_buffer_) {}
|
||||
public:
|
||||
void* Get_Vertex_Array() { return Vertices; }
|
||||
};
|
||||
|
||||
/**
|
||||
** DX8VertexBufferClass
|
||||
** This class wraps a DX8 vertex buffer. Use the lock objects to modify or append to the vertex buffer.
|
||||
*/
|
||||
class VertexBufferClass : public W3DMPO, public RefCountClass
|
||||
{
|
||||
// nope, an ABC
|
||||
//W3DMPO_GLUE(VertexBufferClass)
|
||||
|
||||
protected:
|
||||
VertexBufferClass(unsigned type, unsigned FVF, unsigned short VertexCount);
|
||||
virtual ~VertexBufferClass();
|
||||
public:
|
||||
|
||||
inline const FVFInfoClass& FVF_Info() const { return *fvf_info; }
|
||||
inline unsigned short Get_Vertex_Count() const { return VertexCount; }
|
||||
inline unsigned Type() const { return type; }
|
||||
|
||||
void Add_Engine_Ref() const;
|
||||
void Release_Engine_Ref() const;
|
||||
inline unsigned Engine_Refs() const { return engine_refs; }
|
||||
|
||||
class WriteLockClass : public VertexBufferLockClass
|
||||
{
|
||||
public:
|
||||
WriteLockClass(VertexBufferClass* vertex_buffer);
|
||||
~WriteLockClass();
|
||||
};
|
||||
|
||||
class AppendLockClass : public VertexBufferLockClass
|
||||
{
|
||||
public:
|
||||
AppendLockClass(VertexBufferClass* vertex_buffer,unsigned start_index, unsigned index_range);
|
||||
~AppendLockClass();
|
||||
};
|
||||
|
||||
static unsigned Get_Total_Buffer_Count();
|
||||
static unsigned Get_Total_Allocated_Vertices();
|
||||
static unsigned Get_Total_Allocated_Memory();
|
||||
|
||||
protected:
|
||||
unsigned type;
|
||||
unsigned short VertexCount;
|
||||
mutable int engine_refs;
|
||||
FVFInfoClass* fvf_info;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** Dynamic vertex buffer access is a wrapper to a single cycled dynamic vertex
|
||||
** buffer.
|
||||
** DynamicVBAccess gains an access to the dynamic vertex buffer and only
|
||||
** only of these are allowed at any one time.
|
||||
**
|
||||
** The dynamic fvf buffers are always of the same type.
|
||||
**
|
||||
** NOTE: Dynamic vertex buffers accessors should only be used locally!
|
||||
**
|
||||
*/
|
||||
|
||||
class DynamicVBAccessClass
|
||||
{
|
||||
friend DX8Wrapper;
|
||||
friend SortingRendererClass;
|
||||
|
||||
const FVFInfoClass& FVFInfo;
|
||||
unsigned Type;
|
||||
unsigned short VertexCount;
|
||||
unsigned short VertexBufferOffset;
|
||||
VertexBufferClass* VertexBuffer;
|
||||
// static VertexFormatXYZNDUV2* _Get_Sorting_Vertex_Array();
|
||||
|
||||
void Allocate_Sorting_Dynamic_Buffer();
|
||||
void Allocate_DX8_Dynamic_Buffer();
|
||||
public:
|
||||
// Type parameter can be either BUFFER_TYPE_DYNAMIC_DX8 or BUFFER_TYPE_DYNAMIC_SORTING.
|
||||
|
||||
// Note: Even though the constructor takes fvf as a parameter, currently the
|
||||
// only acceptable parameter is "dynamic_fvf_type". Any other type will
|
||||
// result to an assert.
|
||||
DynamicVBAccessClass(unsigned type,unsigned fvf,unsigned short vertex_count);
|
||||
~DynamicVBAccessClass();
|
||||
|
||||
// Access fvf
|
||||
const FVFInfoClass& FVF_Info() const { return FVFInfo; }
|
||||
unsigned Get_Type() const { return Type; }
|
||||
unsigned short Get_Vertex_Count() const { return VertexCount; }
|
||||
|
||||
// Call at the end of the execution, or at whatever time you wish to release
|
||||
// the recycled dynamic vertex buffer.
|
||||
static void _Deinit();
|
||||
static void _Reset(bool frame_changed);
|
||||
static unsigned short Get_Default_Vertex_Count(void); ///<current size of dynamic vertex buffer
|
||||
|
||||
// To lock the vertex buffer, create instance of this write class locally.
|
||||
// The buffer is automatically unlocked when you exit the scope.
|
||||
class WriteLockClass// : public VertexBufferLockClass
|
||||
{
|
||||
DynamicVBAccessClass* DynamicVBAccess;
|
||||
VertexFormatXYZNDUV2 * Vertices;
|
||||
public:
|
||||
WriteLockClass(DynamicVBAccessClass* vb_access);
|
||||
~WriteLockClass();
|
||||
|
||||
// Use this function to get a pointer to the first vertex you can write into.
|
||||
// If we ever change the format used by DynamicVBAccessClass, then the
|
||||
// return type of this function will change and we'll easily find all code
|
||||
// using it.
|
||||
VertexFormatXYZNDUV2 * Get_Formatted_Vertex_Array();
|
||||
};
|
||||
friend WriteLockClass;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
inline VertexFormatXYZNDUV2 * DynamicVBAccessClass::WriteLockClass::Get_Formatted_Vertex_Array()
|
||||
{
|
||||
// assert that the format of the dynamic vertex buffer is still what we think it is.
|
||||
WWASSERT(DynamicVBAccess->VertexBuffer->FVF_Info().Get_FVF() == (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2|D3DFVF_DIFFUSE));
|
||||
return Vertices;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** DX8VertexBufferClass
|
||||
** This class wraps a DX8 vertex buffer. Use the lock objects to modify or append to the vertex buffer.
|
||||
*/
|
||||
class DX8VertexBufferClass : public VertexBufferClass
|
||||
{
|
||||
W3DMPO_GLUE(DX8VertexBufferClass)
|
||||
protected:
|
||||
~DX8VertexBufferClass();
|
||||
public:
|
||||
enum UsageType {
|
||||
USAGE_DEFAULT=0,
|
||||
USAGE_DYNAMIC=1,
|
||||
USAGE_SOFTWAREPROCESSING=2,
|
||||
USAGE_NPATCHES=4
|
||||
};
|
||||
|
||||
DX8VertexBufferClass(unsigned FVF, unsigned short VertexCount, UsageType usage=USAGE_DEFAULT);
|
||||
DX8VertexBufferClass(const Vector3* vertices, const Vector3* normals, const Vector2* tex_coords, unsigned short VertexCount,UsageType usage=USAGE_DEFAULT);
|
||||
DX8VertexBufferClass(const Vector3* vertices, const Vector3* normals, const Vector4* diffuse, const Vector2* tex_coords, unsigned short VertexCount,UsageType usage=USAGE_DEFAULT);
|
||||
DX8VertexBufferClass(const Vector3* vertices, const Vector4* diffuse, const Vector2* tex_coords, unsigned short VertexCount,UsageType usage=USAGE_DEFAULT);
|
||||
DX8VertexBufferClass(const Vector3* vertices, const Vector2* tex_coords, unsigned short VertexCount,UsageType usage=USAGE_DEFAULT);
|
||||
|
||||
IDirect3DVertexBuffer8* Get_DX8_Vertex_Buffer() { return VertexBuffer; }
|
||||
|
||||
void Copy(const Vector3* loc, unsigned first_vertex, unsigned count);
|
||||
void Copy(const Vector3* loc, const Vector2* uv, unsigned first_vertex, unsigned count);
|
||||
void Copy(const Vector3* loc, const Vector3* norm, unsigned first_vertex, unsigned count);
|
||||
void Copy(const Vector3* loc, const Vector3* norm, const Vector2* uv, unsigned first_vertex, unsigned count);
|
||||
void Copy(const Vector3* loc, const Vector3* norm, const Vector2* uv, const Vector4* diffuse, unsigned first_vertex, unsigned count);
|
||||
void Copy(const Vector3* loc, const Vector2* uv, const Vector4* diffuse, unsigned first_vertex, unsigned count);
|
||||
|
||||
protected:
|
||||
IDirect3DVertexBuffer8* VertexBuffer;
|
||||
|
||||
void Create_Vertex_Buffer(UsageType usage);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** SortingVertexBufferClass
|
||||
** This class acts as a vertex buffer for the vertices that need to be passed to alpha renderer.
|
||||
*/
|
||||
class SortingVertexBufferClass : public VertexBufferClass
|
||||
{
|
||||
W3DMPO_GLUE(SortingVertexBufferClass)
|
||||
|
||||
friend DX8Wrapper;
|
||||
friend SortingRendererClass;
|
||||
friend VertexBufferClass::WriteLockClass;
|
||||
friend VertexBufferClass::AppendLockClass;
|
||||
friend DynamicVBAccessClass::WriteLockClass;
|
||||
|
||||
VertexFormatXYZNDUV2* VertexBuffer;
|
||||
|
||||
protected:
|
||||
~SortingVertexBufferClass();
|
||||
public:
|
||||
SortingVertexBufferClass(unsigned short VertexCount);
|
||||
};
|
||||
|
||||
|
||||
#endif //DX8VERTEXBUFFER_H
|
||||
242
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8webbrowser.cpp
Normal file
242
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8webbrowser.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
//******************************************************************************************
|
||||
//
|
||||
// Earth And Beyond
|
||||
// Copyright (c) 2002 Electronic Arts , Inc. - Westwood Studios
|
||||
//
|
||||
// File Name : dx8webbrowser.cpp
|
||||
// Description : Implementation of D3D Embedded Browser wrapper.
|
||||
// Author : Darren Schueller
|
||||
// Date of Creation : 6/4/2002
|
||||
//
|
||||
//******************************************************************************************
|
||||
// $Header: $
|
||||
//******************************************************************************************
|
||||
|
||||
#include "dx8webbrowser.h"
|
||||
#include "ww3d.h"
|
||||
#include "dx8wrapper.h"
|
||||
|
||||
#if ENABLE_EMBEDDED_BROWSER
|
||||
|
||||
// Import the Browser Type Library
|
||||
// BGC, the path for the dll file is pretty odd, no?
|
||||
// I'll leave it like this till I can figure out a
|
||||
// better way.
|
||||
#import "..\..\..\..\..\run\BrowserEngine.DLL" no_namespace
|
||||
|
||||
static IFEBrowserEngine2Ptr pBrowser = 0;
|
||||
|
||||
HWND DX8WebBrowser::hWnd = 0;
|
||||
|
||||
bool DX8WebBrowser::Initialize( const char* badpageurl,
|
||||
const char* loadingpageurl,
|
||||
const char* mousefilename,
|
||||
const char* mousebusyfilename)
|
||||
{
|
||||
if(pBrowser == 0)
|
||||
{
|
||||
// Initialize COM
|
||||
CoInitialize(0);
|
||||
|
||||
// Create an instance of the browser control
|
||||
HRESULT hr = pBrowser.CreateInstance(__uuidof(FEBrowserEngine2));
|
||||
|
||||
if(hr == REGDB_E_CLASSNOTREG)
|
||||
{
|
||||
HMODULE lib = ::LoadLibrary("BrowserEngine.DLL");
|
||||
if(lib)
|
||||
{
|
||||
FARPROC proc = ::GetProcAddress(lib,"DllRegisterServer");
|
||||
if(proc)
|
||||
{
|
||||
proc();
|
||||
// Create an instance of the browser control
|
||||
hr = pBrowser.CreateInstance(__uuidof(FEBrowserEngine2));
|
||||
}
|
||||
FreeLibrary(lib);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the browser.
|
||||
if(hr == S_OK)
|
||||
{
|
||||
hWnd = (HWND)WW3D::Get_Window();
|
||||
pBrowser->Initialize(reinterpret_cast<long*>(DX8Wrapper::_Get_D3D_Device8()));
|
||||
|
||||
if(badpageurl)
|
||||
pBrowser->put_BadPageURL(_bstr_t(badpageurl));
|
||||
|
||||
if(loadingpageurl)
|
||||
pBrowser->put_LoadingPageURL(_bstr_t(loadingpageurl));
|
||||
|
||||
if(mousefilename)
|
||||
pBrowser->put_MouseFileName(_bstr_t(mousefilename));
|
||||
|
||||
if(mousebusyfilename)
|
||||
pBrowser->put_MouseBusyFileName(_bstr_t(mousebusyfilename));
|
||||
}
|
||||
else
|
||||
{
|
||||
pBrowser = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DX8WebBrowser::Shutdown()
|
||||
{
|
||||
if(pBrowser)
|
||||
{
|
||||
// Shutdown the browser
|
||||
pBrowser->Shutdown();
|
||||
|
||||
// Release the smart pointer.
|
||||
pBrowser = 0;
|
||||
|
||||
hWnd = 0;
|
||||
|
||||
// Shut down COM
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::Update
|
||||
// ******************************************************************************************
|
||||
// * Description: Updates the browser image surfaces by copying the bits from the browser
|
||||
// * DCs to the D3D Image surfaces.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: void
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
void DX8WebBrowser::Update(void)
|
||||
{
|
||||
if(pBrowser) pBrowser->D3DUpdate();
|
||||
};
|
||||
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::Render
|
||||
// ******************************************************************************************
|
||||
// * Description: Draws all browsers to the back buffer.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: int backbufferindex
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
void DX8WebBrowser::Render(int backbufferindex)
|
||||
{
|
||||
if(pBrowser) pBrowser->D3DRender(backbufferindex);
|
||||
};
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::CreateBrowser
|
||||
// ******************************************************************************************
|
||||
// * Description: Creates a browser window.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: const char* browsername - This is a "name" used to identify the
|
||||
// * browser instance. Multiple browsers can
|
||||
// * be created, and are referenced using this name.
|
||||
// * Argument: const char* url - The url to display.
|
||||
// * Argument: int x - The position and size of the browser (in pixels)
|
||||
// * Argument: int y
|
||||
// * Argument: int w
|
||||
// * Argument: int h
|
||||
// * Argument: int updateticks - When non-zero, this forces the browser image to get updated
|
||||
// * at the specified rate (number of milliseconds) regardless
|
||||
// * of paint messages. When this is zero (the default) the browser
|
||||
// * image is only updated whenever a paint message is received.
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
void DX8WebBrowser::CreateBrowser(const char* browsername, const char* url, int x, int y, int w, int h, int updateticks, LONG options, LPDISPATCH gamedispatch)
|
||||
{
|
||||
DEBUG_LOG(("DX8WebBrowser::CreateBrowser - Creating browser with the name %s, url = %s, (x, y, w, h) = (%d, %d, %d, %d), update ticks = %d\n", browsername, url, x, y, h, w, updateticks));
|
||||
if(pBrowser)
|
||||
{
|
||||
_bstr_t brsname(browsername);
|
||||
pBrowser->CreateBrowser(brsname, _bstr_t(url), reinterpret_cast<long>(hWnd), x, y, w, h, options, gamedispatch);
|
||||
pBrowser->SetUpdateRate(brsname, updateticks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::DestroyBrowser
|
||||
// ******************************************************************************************
|
||||
// * Description: Destroys the specified browser. This closes the window and releases
|
||||
// * the browser instance.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: const char* browsername - The name of the browser to destroy.
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
void DX8WebBrowser::DestroyBrowser(const char* browsername)
|
||||
{
|
||||
DEBUG_LOG(("DX8WebBrowser::DestroyBrowser - destroying browser %s\n", browsername));
|
||||
if(pBrowser)
|
||||
pBrowser->DestroyBrowser(_bstr_t(browsername));
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::Is_Browser_Open
|
||||
// ******************************************************************************************
|
||||
// * Description: This function checks to see if a browser of the specified name exists and
|
||||
// * is currently open.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: const char* browsername - The name of the browser to test.
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
bool DX8WebBrowser::Is_Browser_Open(const char* browsername)
|
||||
{
|
||||
if(pBrowser == 0) return false;
|
||||
return (pBrowser->IsOpen(_bstr_t(browsername)) != 0);
|
||||
}
|
||||
|
||||
// ******************************************************************************************
|
||||
// * Function Name: DX8WebBrowser::Navigate
|
||||
// ******************************************************************************************
|
||||
// * Description: This function causes the browser to navigate to the specified page.
|
||||
// *
|
||||
// * Return Type:
|
||||
// *
|
||||
// * Argument: const char* browsername - The name of the browser to test.
|
||||
// * const char* url - The url to navigate to.
|
||||
// *
|
||||
// ******************************************************************************************
|
||||
void DX8WebBrowser::Navigate(const char* browsername, const char* url)
|
||||
{
|
||||
if(pBrowser == 0) return;
|
||||
pBrowser->Navigate(_bstr_t(browsername),_bstr_t(url));
|
||||
}
|
||||
|
||||
#endif
|
||||
93
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8webbrowser.h
Normal file
93
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8webbrowser.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
//******************************************************************************************
|
||||
//
|
||||
// Earth And Beyond
|
||||
// Copyright (c) 2002 Electronic Arts , Inc. - Westwood Studios
|
||||
//
|
||||
// File Name : dx8webbrowser.h
|
||||
// Description : Implementation of D3D Embedded Browser Wrapper
|
||||
// Author : Darren Schueller
|
||||
// Date of Creation : 6/4/2002
|
||||
//
|
||||
//******************************************************************************************
|
||||
// $Header: $
|
||||
//******************************************************************************************
|
||||
|
||||
#ifndef DX8_WEBBROWSER_H
|
||||
#define DX8_WEBBROWSER_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "d3d8.h"
|
||||
|
||||
// ***********************************
|
||||
// Set this to 0 to remove all embedded browser code.
|
||||
//
|
||||
#define ENABLE_EMBEDDED_BROWSER 1
|
||||
//
|
||||
// ***********************************
|
||||
|
||||
#if ENABLE_EMBEDDED_BROWSER
|
||||
|
||||
// These options must match the browser option bits defined in the BrowserEngine code.
|
||||
// Look in febrowserengine.h
|
||||
#define BROWSEROPTION_SCROLLBARS 0x0001
|
||||
#define BROWSEROPTION_3DBORDER 0x0002
|
||||
|
||||
struct IDirect3DDevice8;
|
||||
|
||||
/**
|
||||
** DX8WebBrowser
|
||||
**
|
||||
** DX8 interface wrapper class. This encapsulates the BrowserEngine interface.
|
||||
*/
|
||||
class DX8WebBrowser
|
||||
{
|
||||
public:
|
||||
|
||||
static bool Initialize( const char* badpageurl = 0,
|
||||
const char* loadingpageurl = 0,
|
||||
const char* mousefilename = 0,
|
||||
const char* mousebusyfilename = 0); //Initialize the Embedded Browser
|
||||
|
||||
static void Shutdown(void); // Shutdown the embedded browser. Will close any open browsers.
|
||||
|
||||
static void Update(void); // Copies all browser contexts to D3D Image surfaces.
|
||||
static void Render(int backbufferindex); //Draws all browsers to the backbuffer.
|
||||
|
||||
// Creates a browser with the specified name
|
||||
static void CreateBrowser(const char* browsername, const char* url, int x, int y, int w, int h, int updateticks = 0, LONG options = BROWSEROPTION_SCROLLBARS | BROWSEROPTION_3DBORDER, LPDISPATCH gamedispatch = 0);
|
||||
|
||||
// Destroys the browser with the specified name
|
||||
static void DestroyBrowser(const char* browsername);
|
||||
|
||||
// Returns true if a browser with the specified name is open.
|
||||
static bool Is_Browser_Open(const char* browsername);
|
||||
|
||||
// Navigates the specified browser to the specified page.
|
||||
static void Navigate(const char* browsername, const char* url);
|
||||
|
||||
private:
|
||||
// The window handle of the application. This is initialized by Initialize().
|
||||
static HWND hWnd;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2655
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
Normal file
2655
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1147
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h
Normal file
1147
Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h
Normal file
File diff suppressed because it is too large
Load Diff
803
Generals/Code/Libraries/Source/WWVegas/WW3D2/dynamesh.cpp
Normal file
803
Generals/Code/Libraries/Source/WWVegas/WW3D2/dynamesh.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Commando *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/ww3d2/dynamesh.cpp $*
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 8/29/01 7:29p $*
|
||||
* *
|
||||
* $Revision:: 23 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "dynamesh.h"
|
||||
#include "dx8vertexbuffer.h"
|
||||
#include "dx8indexbuffer.h"
|
||||
#include "dx8wrapper.h"
|
||||
#include "sortingrenderer.h"
|
||||
#include "rinfo.h"
|
||||
#include "camera.h"
|
||||
#include "dx8fvf.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** DynamicMeshModel implementation
|
||||
*/
|
||||
|
||||
DynamicMeshModel::DynamicMeshModel(unsigned int max_polys, unsigned int max_verts) :
|
||||
MeshGeometryClass(),
|
||||
DynamicMeshPNum(0),
|
||||
DynamicMeshVNum(0),
|
||||
MatDesc(NULL),
|
||||
MatInfo(NULL)
|
||||
{
|
||||
MatInfo = NEW_REF(MaterialInfoClass, ());
|
||||
|
||||
MatDesc = W3DNEW MeshMatDescClass;
|
||||
MatDesc->Set_Polygon_Count(max_polys);
|
||||
MatDesc->Set_Vertex_Count(max_verts);
|
||||
|
||||
Reset_Geometry(max_polys, max_verts);
|
||||
}
|
||||
|
||||
DynamicMeshModel::DynamicMeshModel(unsigned int max_polys, unsigned int max_verts, MaterialInfoClass *mat_info) :
|
||||
MeshGeometryClass(),
|
||||
DynamicMeshPNum(0),
|
||||
DynamicMeshVNum(0),
|
||||
MatDesc(NULL),
|
||||
MatInfo(NULL)
|
||||
{
|
||||
MatInfo = mat_info;
|
||||
MatInfo->Add_Ref();
|
||||
|
||||
MatDesc = W3DNEW MeshMatDescClass;
|
||||
MatDesc->Set_Polygon_Count(max_polys);
|
||||
MatDesc->Set_Vertex_Count(max_verts);
|
||||
|
||||
Reset_Geometry(max_polys, max_verts);
|
||||
}
|
||||
|
||||
DynamicMeshModel::DynamicMeshModel(const DynamicMeshModel &src) :
|
||||
MeshGeometryClass(src),
|
||||
DynamicMeshPNum(src.DynamicMeshPNum),
|
||||
DynamicMeshVNum(src.DynamicMeshVNum),
|
||||
MatDesc(NULL),
|
||||
MatInfo(NULL)
|
||||
{
|
||||
// Copy the material info structure.
|
||||
MatInfo = NEW_REF(MaterialInfoClass, (*(src.MatInfo)));
|
||||
|
||||
// remap!
|
||||
MaterialRemapperClass remapper(src.MatInfo, MatInfo);
|
||||
remapper.Remap_Mesh(src.MatDesc, MatDesc);
|
||||
|
||||
MatDesc = W3DNEW MeshMatDescClass;
|
||||
}
|
||||
|
||||
DynamicMeshModel::~DynamicMeshModel(void)
|
||||
{
|
||||
if (MatDesc) {
|
||||
delete MatDesc;
|
||||
MatDesc = NULL;
|
||||
}
|
||||
REF_PTR_RELEASE(MatInfo);
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Compute_Plane_Equations(void)
|
||||
{
|
||||
// Make sure the arrays are allocated before we do this
|
||||
get_vert_normals();
|
||||
Vector4 * planes = get_planes(true);
|
||||
|
||||
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
||||
// set them back.
|
||||
int old_poly_count = PolyCount;
|
||||
int old_vert_count = VertexCount;
|
||||
PolyCount = DynamicMeshPNum;
|
||||
VertexCount = DynamicMeshVNum;
|
||||
|
||||
MeshGeometryClass::Compute_Plane_Equations(planes);
|
||||
|
||||
PolyCount = old_poly_count;
|
||||
VertexCount = old_vert_count;
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Compute_Vertex_Normals(void)
|
||||
{
|
||||
// Make sure the arrays are allocated before we do this
|
||||
Vector3 * vnorms = get_vert_normals();
|
||||
get_planes(true);
|
||||
|
||||
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
||||
// set them back.
|
||||
int old_poly_count = PolyCount;
|
||||
int old_vert_count = VertexCount;
|
||||
PolyCount = DynamicMeshPNum;
|
||||
VertexCount = DynamicMeshVNum;
|
||||
|
||||
MeshGeometryClass::Compute_Vertex_Normals(vnorms);
|
||||
|
||||
PolyCount = old_poly_count;
|
||||
VertexCount = old_vert_count;
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Compute_Bounds(Vector3 * verts)
|
||||
{
|
||||
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
||||
// set them back.
|
||||
int old_poly_count = PolyCount;
|
||||
int old_vert_count = VertexCount;
|
||||
PolyCount = DynamicMeshPNum;
|
||||
VertexCount = DynamicMeshVNum;
|
||||
|
||||
MeshGeometryClass::Compute_Bounds(verts);
|
||||
|
||||
PolyCount = old_poly_count;
|
||||
VertexCount = old_vert_count;
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Reset(void)
|
||||
{
|
||||
Set_Counts(0, 0);
|
||||
int polycount = Get_Polygon_Count();
|
||||
int vertcount = Get_Vertex_Count();
|
||||
Reset_Geometry(polycount, vertcount);
|
||||
MatDesc->Reset(polycount, vertcount, 1);
|
||||
REF_PTR_RELEASE(MatInfo);
|
||||
MatInfo = NEW_REF(MaterialInfoClass, ());
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
// Process texture reductions:
|
||||
// MatInfo->Process_Texture_Reduction();
|
||||
|
||||
unsigned buffer_type=(Get_Flag(MeshGeometryClass::SORT)&& WW3D::Is_Sorting_Enabled()) ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8;
|
||||
|
||||
/*
|
||||
** Write the vertex data to the vertex buffer. We assume the FVF contains positions, normals,
|
||||
** one texture channel, and the diffuse color channel (color0). If it does not contain all
|
||||
** these components, the code will fail.
|
||||
*/
|
||||
DynamicVBAccessClass dynamic_vb(buffer_type,dynamic_fvf_type,DynamicMeshVNum);
|
||||
const FVFInfoClass &fvf_info = dynamic_vb.FVF_Info();
|
||||
|
||||
{ // scope for lock
|
||||
|
||||
DynamicVBAccessClass::WriteLockClass lock(&dynamic_vb);
|
||||
unsigned char *vertices = (unsigned char*)lock.Get_Formatted_Vertex_Array();
|
||||
const Vector3 *locs = Get_Vertex_Array();
|
||||
const Vector3 *normals = Get_Vertex_Normal_Array();
|
||||
const Vector2 *uvs = MatDesc->Get_UV_Array_By_Index(0, false);
|
||||
const unsigned *colors = MatDesc->Get_Color_Array(0, false);
|
||||
const static Vector3 default_normal(0.0f, 0.0f, 0.0f);
|
||||
const static Vector2 default_uv(0.0f, 0.0f);
|
||||
const unsigned int default_color = 0xFFFFFFFF;
|
||||
for (int i=0; i < DynamicMeshVNum; i++)
|
||||
{
|
||||
*(Vector3 *)(vertices + fvf_info.Get_Location_Offset()) = locs[i];
|
||||
*(Vector3 *)(vertices + fvf_info.Get_Normal_Offset()) = normals[i];
|
||||
if (uvs) {
|
||||
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(0)) = uvs[i];
|
||||
} else {
|
||||
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(0)) = default_uv;
|
||||
}
|
||||
if (colors) {
|
||||
*(unsigned int *)(vertices + fvf_info.Get_Diffuse_Offset()) = colors[i];
|
||||
} else {
|
||||
*(unsigned int *)(vertices + fvf_info.Get_Diffuse_Offset()) = default_color;
|
||||
}
|
||||
vertices += fvf_info.Get_FVF_Size();
|
||||
}
|
||||
|
||||
} // end scope for lock
|
||||
|
||||
/*
|
||||
** Write index data to index buffers
|
||||
*/
|
||||
DynamicIBAccessClass dynamic_ib(buffer_type,DynamicMeshPNum * 3);
|
||||
const Vector3i *tris = Get_Polygon_Array();
|
||||
|
||||
{ // scope for lock
|
||||
|
||||
DynamicIBAccessClass::WriteLockClass lock(&dynamic_ib);
|
||||
unsigned short * indices = lock.Get_Index_Array();
|
||||
for (int i=0; i < DynamicMeshPNum; i++)
|
||||
{
|
||||
indices[i*3 + 0] = (unsigned short)tris[i][0];
|
||||
indices[i*3 + 1] = (unsigned short)tris[i][1];
|
||||
indices[i*3 + 2] = (unsigned short)tris[i][2];
|
||||
}
|
||||
|
||||
} // end scope for lock
|
||||
|
||||
/*
|
||||
** Set vertex and index buffers
|
||||
*/
|
||||
DX8Wrapper::Set_Vertex_Buffer(dynamic_vb);
|
||||
DX8Wrapper::Set_Index_Buffer(dynamic_ib,0);
|
||||
|
||||
/*
|
||||
** Draw dynamesh, one pass at a time
|
||||
*/
|
||||
unsigned int pass_count = Get_Pass_Count();
|
||||
for (unsigned int pass = 0; pass < pass_count; pass++) {
|
||||
|
||||
/*
|
||||
** Set current render states (texture, vertex material, shader). Scan triangles until one
|
||||
** of these changes, and then draw.
|
||||
*/
|
||||
|
||||
// The vertex index range used
|
||||
unsigned short min_vert_idx = DynamicMeshVNum - 1;
|
||||
unsigned short max_vert_idx = 0;
|
||||
unsigned short start_tri_idx = 0;
|
||||
unsigned short cur_tri_idx = 0;
|
||||
|
||||
bool done = false;
|
||||
bool texture_changed = false;
|
||||
bool material_changed = false;
|
||||
bool shader_changed = false;
|
||||
|
||||
TextureClass **texture_array = NULL;
|
||||
TexBufferClass * tex_buf = MatDesc->Get_Texture_Array(pass, 0, false);
|
||||
if (tex_buf) {
|
||||
texture_array = tex_buf->Get_Array();
|
||||
} else {
|
||||
texture_array = NULL;
|
||||
}
|
||||
VertexMaterialClass **material_array = NULL;
|
||||
MatBufferClass * mat_buf = MatDesc->Get_Material_Array(pass, false);
|
||||
if (mat_buf) {
|
||||
material_array = mat_buf->Get_Array();
|
||||
} else {
|
||||
material_array = NULL;
|
||||
}
|
||||
ShaderClass *shader_array = MatDesc->Get_Shader_Array(pass, false);
|
||||
|
||||
// Set the DX8 state to the first triangle's state
|
||||
if (texture_array) {
|
||||
DX8Wrapper::Set_Texture(0,texture_array[0]);
|
||||
} else {
|
||||
DX8Wrapper::Set_Texture(0,MatDesc->Peek_Single_Texture(pass, 0));
|
||||
}
|
||||
if (material_array) {
|
||||
DX8Wrapper::Set_Material(material_array[tris[0].I]);
|
||||
} else {
|
||||
DX8Wrapper::Set_Material(MatDesc->Peek_Single_Material(pass));
|
||||
}
|
||||
if (shader_array) {
|
||||
DX8Wrapper::Set_Shader(shader_array[0]);
|
||||
} else {
|
||||
DX8Wrapper::Set_Shader(MatDesc->Get_Single_Shader(pass));
|
||||
}
|
||||
|
||||
SphereClass sphere(Vector3(0.0f,0.0f,0.0f),0.0f);
|
||||
Get_Bounding_Sphere(&sphere);
|
||||
|
||||
// If no texture, shader or material arrays for this pass just draw and go to next pass
|
||||
if (!texture_array && !material_array && !shader_array) {
|
||||
if (buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) {
|
||||
SortingRendererClass::Insert_Triangles(sphere,0, DynamicMeshPNum, 0, DynamicMeshVNum);
|
||||
}
|
||||
else {
|
||||
DX8Wrapper::Draw_Triangles(0, DynamicMeshPNum, 0, DynamicMeshVNum);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
|
||||
// Add vertex indices of tri[cur_tri_idx] to min_vert_idx, max_vert_idx
|
||||
const Vector3i &tri = tris[cur_tri_idx];
|
||||
unsigned short min_idx = (short)MIN(MIN(tri.I, tri.J), tri.K);
|
||||
unsigned short max_idx = (short)MAX(MAX(tri.I, tri.J), tri.K);
|
||||
min_vert_idx = MIN(min_vert_idx, min_idx);
|
||||
max_vert_idx = MAX(max_vert_idx, max_idx);
|
||||
|
||||
// Check the next triangle to see if the current run has ended.
|
||||
unsigned short next_tri_idx = cur_tri_idx + 1;
|
||||
done = next_tri_idx >= DynamicMeshPNum;
|
||||
if (done) {
|
||||
texture_changed = false;
|
||||
material_changed = false;
|
||||
shader_changed = false;
|
||||
} else {
|
||||
texture_changed = texture_array && texture_array[cur_tri_idx] != texture_array[next_tri_idx];
|
||||
material_changed = material_array && material_array[tris[cur_tri_idx].I] != material_array[tris[next_tri_idx].I];
|
||||
shader_changed = shader_array && shader_array[cur_tri_idx] != shader_array[next_tri_idx];
|
||||
}
|
||||
|
||||
// If run ends (mesh ends or state changes) draw, reset indices, set state for next run.
|
||||
if (done || texture_changed || material_changed || shader_changed) {
|
||||
if (buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) {
|
||||
SortingRendererClass::Insert_Triangles(
|
||||
sphere,
|
||||
(start_tri_idx * 3),
|
||||
(1 + cur_tri_idx - start_tri_idx),
|
||||
min_vert_idx,
|
||||
1 + max_vert_idx - min_vert_idx);
|
||||
}
|
||||
else {
|
||||
DX8Wrapper::Draw_Triangles(
|
||||
(start_tri_idx * 3),
|
||||
(1 + cur_tri_idx - start_tri_idx),
|
||||
min_vert_idx,
|
||||
1 + max_vert_idx - min_vert_idx);
|
||||
}
|
||||
start_tri_idx = next_tri_idx;
|
||||
min_vert_idx = DynamicMeshVNum - 1;
|
||||
max_vert_idx = 0;
|
||||
if (texture_changed) DX8Wrapper::Set_Texture(0,texture_array[next_tri_idx]);
|
||||
if (material_changed) DX8Wrapper::Set_Material(material_array[tris[next_tri_idx].I]);
|
||||
if (shader_changed) DX8Wrapper::Set_Shader(shader_array[next_tri_idx]);
|
||||
}
|
||||
|
||||
cur_tri_idx = next_tri_idx;
|
||||
|
||||
} // while (!done)
|
||||
|
||||
} // for (pass)
|
||||
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Initialize_Texture_Array(int pass, int stage, TextureClass *texture)
|
||||
{
|
||||
TexBufferClass * texlist = MatDesc->Get_Texture_Array(pass, 0, true);
|
||||
for (int lp = 0; lp < PolyCount; lp++) {
|
||||
texlist->Set_Element(lp, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMeshModel::Initialize_Material_Array(int pass, VertexMaterialClass *vmat)
|
||||
{
|
||||
MatBufferClass * vertmatlist = MatDesc->Get_Material_Array(pass, true);
|
||||
for (int lp = 0; lp < VertexCount; lp++) {
|
||||
vertmatlist->Set_Element(lp, vmat);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMeshClass::Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
if (Is_Not_Hidden_At_All() == false) return;
|
||||
|
||||
// test for an empty mesh..
|
||||
if (PolyCount == 0 ) return;
|
||||
|
||||
// If static sort lists are enabled and this mesh has a sort level, put it on the list instead
|
||||
// of rendering it.
|
||||
|
||||
if (WW3D::Are_Static_Sort_Lists_Enabled() && SortLevel != SORT_LEVEL_NONE) {
|
||||
|
||||
WW3D::Add_To_Static_Sort_List(this, SortLevel);
|
||||
|
||||
} else {
|
||||
|
||||
const FrustumClass & frustum = rinfo.Camera.Get_Frustum();
|
||||
|
||||
if (CollisionMath::Overlap_Test(frustum, Get_Bounding_Box()) != CollisionMath::OUTSIDE) {
|
||||
DX8Wrapper::Set_Transform(D3DTS_WORLD, Transform);
|
||||
Model->Render(rinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DynamicMeshClass::End_Vertex()
|
||||
{
|
||||
// check that we have room for a new vertex
|
||||
WWASSERT(VertCount < Model->Get_Vertex_Count());
|
||||
|
||||
// if we are a multi-material object record the material
|
||||
int pass = Get_Pass_Count();
|
||||
while (pass--) {
|
||||
if (MultiVertexMaterial[pass]) {
|
||||
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
||||
Model->Set_Material(VertCount, mat, pass);
|
||||
REF_PTR_RELEASE(mat);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we are multi colored, record the color
|
||||
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
||||
if (MultiVertexColor[color_array_index]) {
|
||||
// Vector4 * color = &((Model->Get_Color_Array(color_array_index))[VertCount]);
|
||||
// color->X = CurVertexColor[color_array_index].X;
|
||||
// color->Y = CurVertexColor[color_array_index].Y;
|
||||
// color->Z = CurVertexColor[color_array_index].Z;
|
||||
// color->W = CurVertexColor[color_array_index].W;
|
||||
unsigned * color = &((Model->Get_Color_Array(color_array_index))[VertCount]);
|
||||
*color=DX8Wrapper::Convert_Color_Clamp(CurVertexColor[color_array_index]);
|
||||
}
|
||||
}
|
||||
|
||||
// mark this vertex as being complete
|
||||
VertCount++;
|
||||
TriVertexCount++;
|
||||
|
||||
// if we have 3 or more vertices, add a new poly
|
||||
if (TriVertexCount >= 3) {
|
||||
|
||||
// check that we have room for a new poly
|
||||
WWASSERT(PolyCount < Model->Get_Polygon_Count());
|
||||
|
||||
// set vertex indices
|
||||
Vector3i *poly = &(Model->Get_Non_Const_Polygon_Array())[PolyCount];
|
||||
if (TriMode == TRI_MODE_STRIPS) {
|
||||
(*poly)[0] = VertCount-3;
|
||||
(*poly)[1] = VertCount-2;
|
||||
(*poly)[2] = VertCount-1;
|
||||
|
||||
// for every other tri, reverse vertex order
|
||||
if (Flip_Face()) {
|
||||
(*poly)[1] = VertCount-1;
|
||||
(*poly)[2] = VertCount-2;
|
||||
}
|
||||
} else {
|
||||
(*poly)[0] = FanVertex;
|
||||
(*poly)[1] = VertCount-2;
|
||||
(*poly)[2] = VertCount-1;
|
||||
}
|
||||
|
||||
// check each pass
|
||||
int pass = Get_Pass_Count();
|
||||
while (pass--) {
|
||||
|
||||
// If we are multi texture
|
||||
if (MultiTexture[pass]) {
|
||||
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
||||
Model->Set_Texture(PolyCount, tex, pass);
|
||||
REF_PTR_RELEASE(tex);
|
||||
}
|
||||
}
|
||||
|
||||
// increase the count and record that we have a new material
|
||||
PolyCount++;
|
||||
Model->Set_Counts(PolyCount, VertCount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
**
|
||||
** DynamicMeshClass
|
||||
**
|
||||
*******************************************************************/
|
||||
DynamicMeshClass::DynamicMeshClass(int max_poly, int max_vert) :
|
||||
Model(NULL),
|
||||
PolyCount(0),
|
||||
VertCount(0),
|
||||
TriVertexCount(0),
|
||||
FanVertex(0),
|
||||
TriMode(TRI_MODE_STRIPS),
|
||||
SortLevel(SORT_LEVEL_NONE)
|
||||
{
|
||||
int pass = MAX_PASSES;
|
||||
while (pass--) {
|
||||
MultiTexture[pass] = false;
|
||||
TextureIdx[pass] = -1;
|
||||
|
||||
MultiVertexMaterial[pass] = false;
|
||||
VertexMaterialIdx[pass] = -1;
|
||||
}
|
||||
|
||||
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
||||
MultiVertexColor[color_array_index] = false;
|
||||
CurVertexColor[color_array_index].Set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
Model = NEW_REF(DynamicMeshModel, (max_poly, max_vert));
|
||||
}
|
||||
|
||||
DynamicMeshClass::DynamicMeshClass(int max_poly, int max_vert, MaterialInfoClass *mat_info) :
|
||||
Model(NULL),
|
||||
PolyCount(0),
|
||||
VertCount(0),
|
||||
TriVertexCount(0),
|
||||
FanVertex(0),
|
||||
TriMode(TRI_MODE_STRIPS),
|
||||
SortLevel(SORT_LEVEL_NONE)
|
||||
{
|
||||
int pass = MAX_PASSES;
|
||||
while (pass--) {
|
||||
MultiTexture[pass] = false;
|
||||
TextureIdx[pass] = -1;
|
||||
|
||||
MultiVertexMaterial[pass] = false;
|
||||
VertexMaterialIdx[pass] = -1;
|
||||
}
|
||||
|
||||
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
||||
MultiVertexColor[color_array_index] = false;
|
||||
CurVertexColor[color_array_index].Set(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
Model = NEW_REF(DynamicMeshModel, (max_poly, max_vert, mat_info));
|
||||
}
|
||||
|
||||
DynamicMeshClass::DynamicMeshClass(const DynamicMeshClass & src) :
|
||||
RenderObjClass(src),
|
||||
Model(NULL),
|
||||
PolyCount(src.PolyCount),
|
||||
VertCount(src.VertCount),
|
||||
TriVertexCount(src.TriVertexCount),
|
||||
FanVertex(src.FanVertex),
|
||||
TriMode(src.TriMode),
|
||||
SortLevel(src.SortLevel)
|
||||
{
|
||||
int pass = MAX_PASSES;
|
||||
while (pass--) {
|
||||
MultiTexture[pass] = src.MultiTexture[pass];
|
||||
TextureIdx[pass] = src.TextureIdx[pass];
|
||||
|
||||
MultiVertexMaterial[pass] = src.MultiVertexMaterial[pass];
|
||||
VertexMaterialIdx[pass] = src.VertexMaterialIdx[pass];
|
||||
|
||||
MultiVertexColor[pass] = src.MultiVertexColor[pass];
|
||||
CurVertexColor[pass] = src.CurVertexColor[pass];
|
||||
}
|
||||
|
||||
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
||||
MultiVertexColor[color_array_index] = src.MultiVertexColor[color_array_index];
|
||||
CurVertexColor[color_array_index] = src.CurVertexColor[color_array_index];
|
||||
}
|
||||
|
||||
Model = NEW_REF(DynamicMeshModel, (*(src.Model)));
|
||||
}
|
||||
|
||||
void DynamicMeshClass::Resize(int max_polys, int max_verts)
|
||||
{
|
||||
Reset();
|
||||
|
||||
REF_PTR_RELEASE(Model);
|
||||
Model = NEW_REF(DynamicMeshModel, (max_polys, max_verts));
|
||||
|
||||
// reset all the texture & vertex material indices
|
||||
int pass = MAX_PASSES;
|
||||
while (pass--) {
|
||||
TextureIdx[pass] = -1;
|
||||
VertexMaterialIdx[pass] = -1;
|
||||
MultiVertexMaterial[pass] = false;
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMeshClass::~DynamicMeshClass()
|
||||
{
|
||||
REF_PTR_RELEASE(Model);
|
||||
}
|
||||
|
||||
RenderObjClass * DynamicMeshClass::Clone(void) const
|
||||
{
|
||||
return NEW_REF(DynamicMeshClass, (*this));
|
||||
}
|
||||
|
||||
void DynamicMeshClass::Location(float x, float y, float z)
|
||||
{
|
||||
Vector3 * loc = Model->Get_Vertex_Array();
|
||||
assert(loc);
|
||||
|
||||
loc[VertCount].X = x;
|
||||
loc[VertCount].Y = y;
|
||||
loc[VertCount].Z = z;
|
||||
}
|
||||
|
||||
/*
|
||||
** For moving a vertex after the DynaMesh has already been created.
|
||||
*/
|
||||
void DynamicMeshClass::Move_Vertex(int index, float x, float y, float z)
|
||||
{
|
||||
Vector3 * loc = Model->Get_Vertex_Array();
|
||||
assert(loc);
|
||||
loc[index][0] = x;
|
||||
loc[index][1] = y;
|
||||
loc[index][2] = z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Get a vertex value.
|
||||
*/
|
||||
void DynamicMeshClass::Get_Vertex(int index, float &x, float &y, float &z)
|
||||
{
|
||||
Vector3 * loc = Model->Get_Vertex_Array();
|
||||
assert(loc);
|
||||
x = loc[index][0];
|
||||
y = loc[index][1];
|
||||
z = loc[index][2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Offset the entire mesh
|
||||
*/
|
||||
void DynamicMeshClass::Translate_Vertices(const Vector3 & offset)
|
||||
{
|
||||
Vector3 * loc = Model->Get_Vertex_Array();
|
||||
assert(loc);
|
||||
for (int i=0; i < Get_Num_Vertices(); i++) {
|
||||
loc[i].X += offset.X;
|
||||
loc[i].Y += offset.Y;
|
||||
loc[i].Z += offset.Z;
|
||||
}
|
||||
|
||||
Set_Dirty_Bounds();
|
||||
Set_Dirty_Planes();
|
||||
}
|
||||
|
||||
int DynamicMeshClass::Set_Vertex_Material(int idx, int pass)
|
||||
{
|
||||
assert(idx < Peek_Material_Info()->Vertex_Material_Count());
|
||||
VertexMaterialIdx[pass] = idx;
|
||||
if (!MultiVertexMaterial[pass]) {
|
||||
// WWASSERT( VertexMaterialIdx[pass] == 0);
|
||||
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
||||
Model->Set_Single_Material(mat, pass);
|
||||
mat->Release_Ref();
|
||||
}
|
||||
return VertexMaterialIdx[pass];
|
||||
}
|
||||
|
||||
int DynamicMeshClass::Set_Vertex_Material(VertexMaterialClass *material, bool dont_search, int pass)
|
||||
{
|
||||
// Check if same as the last vertex material
|
||||
if (Peek_Material_Info()->Vertex_Material_Count() && (VertexMaterialIdx[pass] != -1) && Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]) == material) {
|
||||
return VertexMaterialIdx[pass];
|
||||
}
|
||||
|
||||
// if there are vertex materials in the list then we may have just jumped
|
||||
// to becoming a multi-vertex-material object. Take care of that here.
|
||||
if ((!MultiVertexMaterial[pass]) && Peek_Material_Info()->Vertex_Material_Count() && (VertexMaterialIdx[pass] != -1) && Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]) != material) {
|
||||
|
||||
// allocate the array of per-vertex vertex material overrides
|
||||
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
||||
Model->Initialize_Material_Array(pass, mat);
|
||||
mat->Release_Ref();
|
||||
|
||||
// flag that we need to write the per -vertex vertex material override array
|
||||
MultiVertexMaterial[pass] = true;
|
||||
}
|
||||
|
||||
// add the material to the material info class if we cant find it in the
|
||||
// list. if we are not supposed to search the list for it then just add
|
||||
// it.
|
||||
if (!dont_search) {
|
||||
for (int lp = 0, found = 0; lp < Peek_Material_Info()->Vertex_Material_Count(); lp ++) {
|
||||
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(lp);
|
||||
if (material == mat) {
|
||||
VertexMaterialIdx[pass] = lp;
|
||||
found = true;
|
||||
mat->Release_Ref();
|
||||
break;
|
||||
}
|
||||
mat->Release_Ref();
|
||||
}
|
||||
if (!found) {
|
||||
Peek_Material_Info()->Add_Vertex_Material(material);
|
||||
VertexMaterialIdx[pass] = Peek_Material_Info()->Vertex_Material_Count() - 1;
|
||||
}
|
||||
} else {
|
||||
Peek_Material_Info()->Add_Vertex_Material(material);
|
||||
VertexMaterialIdx[pass] = Peek_Material_Info()->Vertex_Material_Count() - 1;
|
||||
}
|
||||
|
||||
if (!MultiVertexMaterial[pass]) {
|
||||
Model->Set_Single_Material(Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]), pass);
|
||||
}
|
||||
return(VertexMaterialIdx[pass]);
|
||||
}
|
||||
|
||||
int DynamicMeshClass::Set_Texture(int idx, int pass)
|
||||
{
|
||||
WWASSERT(idx < Peek_Material_Info()->Texture_Count());
|
||||
TextureIdx[pass] = idx;
|
||||
if (!MultiTexture[pass]) {
|
||||
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
||||
Model->Set_Single_Texture(tex, pass);
|
||||
tex->Release_Ref();
|
||||
}
|
||||
return TextureIdx[pass];
|
||||
}
|
||||
|
||||
int DynamicMeshClass::Set_Texture(TextureClass *texture, bool dont_search, int pass)
|
||||
{
|
||||
// Check if same as the last texture
|
||||
if (Peek_Material_Info()->Texture_Count() && (TextureIdx[pass] != -1) && Peek_Material_Info()->Peek_Texture(TextureIdx[pass]) == texture) {
|
||||
return TextureIdx[pass];
|
||||
}
|
||||
|
||||
// if there are textures in the list then we may have just jumped
|
||||
// to becoming a multi-texture object. Take care of that here.
|
||||
if ((!MultiTexture[pass]) && Peek_Material_Info()->Texture_Count() && (TextureIdx[pass] != -1) && Peek_Material_Info()->Peek_Texture(TextureIdx[pass]) != texture) {
|
||||
|
||||
// allocate the array of per polygon material over-rides
|
||||
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
||||
Model->Initialize_Texture_Array(pass, 0, tex);
|
||||
tex->Release_Ref();
|
||||
|
||||
// flag that we need to write the per polygon material overide array
|
||||
MultiTexture[pass] = true;
|
||||
}
|
||||
|
||||
// add the material to the material info class if we cant find it in the
|
||||
// list. if we are not supposed to search the list for it then just add
|
||||
// it.
|
||||
if (!dont_search) {
|
||||
for (int lp = 0, found = 0; lp < Peek_Material_Info()->Texture_Count(); lp ++) {
|
||||
TextureClass *tex = Peek_Material_Info()->Get_Texture(lp);
|
||||
if (texture == tex) {
|
||||
TextureIdx[pass] = lp;
|
||||
found = true;
|
||||
tex->Release_Ref();
|
||||
break;
|
||||
}
|
||||
tex->Release_Ref();
|
||||
}
|
||||
if (!found) {
|
||||
Peek_Material_Info()->Add_Texture(texture);
|
||||
TextureIdx[pass] = Peek_Material_Info()->Texture_Count() - 1;
|
||||
}
|
||||
} else {
|
||||
Peek_Material_Info()->Add_Texture(texture);
|
||||
TextureIdx[pass] = Peek_Material_Info()->Texture_Count() - 1;
|
||||
}
|
||||
|
||||
if (!MultiTexture[pass]) {
|
||||
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
||||
Model->Set_Single_Texture(tex, pass);
|
||||
tex->Release_Ref();
|
||||
}
|
||||
return(TextureIdx[pass]);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
// Remap locations to match a screen
|
||||
void DynamicScreenMeshClass::Location( float x, float y, float z)
|
||||
{
|
||||
DynamicMeshClass::Location( (x * 2) - 1, Aspect - (y * 2 * Aspect), 0);
|
||||
}
|
||||
|
||||
// For moving a vertex after the DynaMesh has already been created.
|
||||
void DynamicScreenMeshClass::Move_Vertex(int index, float x, float y, float z)
|
||||
{
|
||||
DynamicMeshClass::Move_Vertex( index, (x * 2) - 1, Aspect - (y * 2 * Aspect), 0);
|
||||
}
|
||||
|
||||
// Set position
|
||||
void DynamicScreenMeshClass::Set_Position(const Vector3 &v)
|
||||
{
|
||||
DynamicMeshClass::Set_Position(Vector3(v.X * 2, -(v.Y * 2 * Aspect), 0));
|
||||
}
|
||||
|
||||
void DynamicScreenMeshClass::Reset( void )
|
||||
{
|
||||
Reset_Flags();
|
||||
Reset_Mesh_Counters();
|
||||
}
|
||||
|
||||
|
||||
577
Generals/Code/Libraries/Source/WWVegas/WW3D2/dynamesh.h
Normal file
577
Generals/Code/Libraries/Source/WWVegas/WW3D2/dynamesh.h
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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 : Commando *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/dynamesh.h $*
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 4/11/01 4:52p $*
|
||||
* *
|
||||
* $Revision:: 13 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef DYNAMESH_H
|
||||
#define DYNAMESH_H
|
||||
|
||||
#include "meshgeometry.h"
|
||||
#include "meshmatdesc.h"
|
||||
#include "matinfo.h"
|
||||
#include "rendobj.h"
|
||||
#include "polyinfo.h"
|
||||
#include "dx8wrapper.h"
|
||||
|
||||
class ShaderClass;
|
||||
class IntersectionClass;
|
||||
class IntersectionResultClass;
|
||||
|
||||
/*
|
||||
** DynamicMeshModel: used for low-level rendering of DynamicMeshClass.
|
||||
** It is composed of the same two classes (one base, one embedded as
|
||||
** MeshModelClass, so many of its features are similar (see meshmdl.h)
|
||||
*/
|
||||
class DynamicMeshModel : public MeshGeometryClass
|
||||
{
|
||||
W3DMPO_GLUE(DynamicMeshModel)
|
||||
|
||||
public:
|
||||
|
||||
DynamicMeshModel(unsigned int max_polys, unsigned int max_verts);
|
||||
DynamicMeshModel(unsigned int max_polys, unsigned int max_verts, MaterialInfoClass *mat_info);
|
||||
DynamicMeshModel(const DynamicMeshModel &src);
|
||||
~DynamicMeshModel(void);
|
||||
|
||||
// Inherited from MeshGeometryClass
|
||||
virtual void Compute_Plane_Equations(void);
|
||||
virtual void Compute_Vertex_Normals(void);
|
||||
virtual void Compute_Bounds(Vector3 * verts);
|
||||
|
||||
// Reset mesh (with existing max polygon and max vertex counts)
|
||||
void Reset(void);
|
||||
|
||||
// Render mesh
|
||||
void Render(RenderInfoClass & rinfo);
|
||||
|
||||
// Set current polygon and vertex counts
|
||||
void Set_Counts(int pnum, int vnum) { DynamicMeshPNum = pnum; DynamicMeshVNum = vnum; }
|
||||
|
||||
// Access to material stuff:
|
||||
unsigned * Get_Color_Array(int color_array_index) { return MatDesc->Get_Color_Array(color_array_index); }
|
||||
Vector2 * Get_UV_Array(int uv_array_index) { return MatDesc->Get_UV_Array_By_Index(uv_array_index); }
|
||||
|
||||
void Set_Single_Material(VertexMaterialClass * vmat, int pass=0) { MatDesc->Set_Single_Material(vmat, pass); }
|
||||
void Set_Single_Texture(TextureClass * tex, int pass=0, int stage=0) { MatDesc->Set_Single_Texture(tex, pass, stage); }
|
||||
void Set_Single_Shader(ShaderClass shader, int pass=0) { MatDesc->Set_Single_Shader(shader, pass); }
|
||||
|
||||
void Set_Material(int vidx, VertexMaterialClass * vmat, int pass=0) { MatDesc->Set_Material(vidx, vmat, pass); }
|
||||
void Set_Shader(int pidx, ShaderClass shader, int pass=0) { MatDesc->Set_Shader(pidx, shader, pass); }
|
||||
void Set_Texture(int pidx, TextureClass * tex, int pass=0, int stage=0) { MatDesc->Set_Texture(pidx, tex, pass, stage); }
|
||||
void Set_Pass_Count(int passes) { MatDesc->Set_Pass_Count(passes); }
|
||||
int Get_Pass_Count(void) const { return MatDesc->Get_Pass_Count(); }
|
||||
|
||||
// Create the array (if it doesn't exist), fill it with the supplied value.
|
||||
void Initialize_Texture_Array(int pass, int stage, TextureClass *texture = NULL);
|
||||
void Initialize_Material_Array(int pass, VertexMaterialClass *vmat = NULL);
|
||||
|
||||
// Accessors to material info:
|
||||
MaterialInfoClass *Peek_Material_Info(void) { return MatInfo; }
|
||||
MaterialInfoClass *Get_Material_Info(void) { if (MatInfo) MatInfo->Add_Ref(); return MatInfo;}
|
||||
void Set_Material_Info(MaterialInfoClass *mat_info)
|
||||
{
|
||||
if (MatInfo)
|
||||
MatInfo->Release_Ref();
|
||||
WWASSERT(MatInfo != 0);
|
||||
MatInfo = mat_info;
|
||||
MatInfo->Add_Ref();
|
||||
}
|
||||
|
||||
// New geometry accessors (non-const)
|
||||
Vector3i * Get_Non_Const_Polygon_Array(void);
|
||||
Vector3 * Get_Non_Const_Vertex_Normal_Array(void);
|
||||
|
||||
private:
|
||||
|
||||
// These are current counts, as opposed to those in the mesh geometry and
|
||||
// material description which are actually maximum counts.
|
||||
int DynamicMeshPNum;
|
||||
int DynamicMeshVNum;
|
||||
|
||||
// All non-geometry properties (uvs, colors, textures, shaders, etc)
|
||||
MeshMatDescClass * MatDesc;
|
||||
|
||||
// Lists of textures and vertex materials for ease of processing
|
||||
MaterialInfoClass * MatInfo;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
** Dynamic Meshes
|
||||
*/
|
||||
class DynamicMeshClass : public RenderObjClass {
|
||||
|
||||
public:
|
||||
|
||||
// constructor and destructor
|
||||
DynamicMeshClass( int max_poly, int max_vert);
|
||||
DynamicMeshClass( int max_poly, int max_vert, MaterialInfoClass *mat_info);
|
||||
DynamicMeshClass( const DynamicMeshClass & src);
|
||||
virtual ~DynamicMeshClass( void);
|
||||
|
||||
// Inherited from RenderObjClass:
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const { return CLASSID_DYNAMESH; }
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
|
||||
virtual MaterialInfoClass *Peek_Material_Info(void) { return Model->Peek_Material_Info(); }
|
||||
virtual MaterialInfoClass *Get_Material_Info(void) { return Model->Get_Material_Info(); }
|
||||
virtual void Set_Material_Info(MaterialInfoClass *mat_info) { Model->Set_Material_Info(mat_info); }
|
||||
|
||||
// all render objects should be able to tell you how many polygons were
|
||||
// used in the making of the render object.
|
||||
virtual int Get_Num_Polys(void) const { return PolyCount; }
|
||||
|
||||
// return the number of vertices used by this renderobject
|
||||
virtual int Get_Num_Vertices(void) const { return VertCount; }
|
||||
|
||||
// Get and set static sort level
|
||||
virtual int Get_Sort_Level(void) const { return SortLevel; }
|
||||
virtual void Set_Sort_Level(int level) { SortLevel = level; if(level != SORT_LEVEL_NONE) Disable_Sort();}
|
||||
|
||||
// object space bounding volumes
|
||||
virtual inline void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual inline void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
// Set the vertex material for the current triangle
|
||||
int Set_Vertex_Material( int idx, int pass = 0);
|
||||
int Set_Vertex_Material( VertexMaterialClass *material, bool dont_search = false, int pass = 0);
|
||||
|
||||
// Set the number of passes for the mesh
|
||||
void Set_Pass_Count(int passes) { assert(PolyCount == 0); Model->Set_Pass_Count(passes); }
|
||||
int Get_Pass_Count() { return Model->Get_Pass_Count(); }
|
||||
|
||||
// Set the texture for the current triangle
|
||||
int Set_Texture( int idx, int pass = 0);
|
||||
int Set_Texture( TextureClass *texture, bool dont_search = false, int pass = 0);
|
||||
|
||||
// Set the shader for the current triangle
|
||||
int Set_Shader( const ShaderClass & shader, int pass = 0) { Model->Set_Single_Shader(shader, pass); return 0; }
|
||||
|
||||
// set the shader, texture, and vertex material as found in the polygon info object
|
||||
void Set_Polygon_Info(const PolygonInfoClass &polyInfo, bool dont_search_texture = false, bool dont_search_vertex_material = false, int pass = 0)
|
||||
{
|
||||
// there must be a shader..
|
||||
assert(polyInfo.Peek_Shader() != 0);
|
||||
Set_Shader(* (polyInfo.Peek_Shader()), pass);
|
||||
|
||||
assert(polyInfo.Peek_Vertex_Material() != 0);
|
||||
Set_Vertex_Material(polyInfo.Peek_Vertex_Material(), dont_search_vertex_material, pass);
|
||||
|
||||
if (polyInfo.Peek_Texture())
|
||||
Set_Texture(polyInfo.Peek_Texture(), dont_search_texture, pass);
|
||||
}
|
||||
|
||||
// Set vertex Color
|
||||
inline int Set_Vertex_Color(const Vector4 & color, int color_array_index = 0);
|
||||
inline int Set_Vertex_Color(const Vector3 & color, int color_array_index = 0);
|
||||
|
||||
// reset the mesh flags
|
||||
void Reset_Flags() { Set_Dirty(); }
|
||||
|
||||
// Flush the mesh
|
||||
void Reset_Native_Mesh() { Model->Reset(); }
|
||||
|
||||
// reset our poly and vertex counts
|
||||
void Reset_Mesh_Counters()
|
||||
{
|
||||
Model->Set_Counts(0, 0);
|
||||
Disable_Sort();
|
||||
PolyCount = 0;
|
||||
VertCount = 0;
|
||||
}
|
||||
|
||||
// Reset all polys and verts. Call the other reset functions directly if you do not want all
|
||||
// characteristics to be reset.
|
||||
virtual void Reset( void )
|
||||
{
|
||||
// Note that the active poly count has changed since the last render call by setting the dirty flag
|
||||
Reset_Flags();
|
||||
Reset_Native_Mesh();
|
||||
Reset_Mesh_Counters();
|
||||
|
||||
// reset all the texture & vertex material indices
|
||||
int pass = MAX_PASSES;
|
||||
while (pass--) {
|
||||
TextureIdx[pass] = -1;
|
||||
VertexMaterialIdx[pass] = -1;
|
||||
MultiVertexMaterial[pass] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes mesh and recreates it with new max_polys and verts.
|
||||
void Resize(int max_polys, int max_verts);
|
||||
|
||||
// Triangle creation routines
|
||||
void Begin_Tri_Strip( void ) { TriVertexCount = 0; TriMode = TRI_MODE_STRIPS; }
|
||||
void Begin_Tri_Fan( void ) { TriVertexCount = 0; TriMode = TRI_MODE_FANS; FanVertex = VertCount; }
|
||||
|
||||
// vertex creation routines
|
||||
void Begin_Vertex( void) {}
|
||||
|
||||
virtual void Location( float x, float y, float z);
|
||||
|
||||
// version for speedier use in certain cases
|
||||
void Location_Inline( float x, float y, float z )
|
||||
{
|
||||
Vector3 * loc = Model->Get_Vertex_Array();
|
||||
assert(loc);
|
||||
|
||||
loc[VertCount].X = x;
|
||||
loc[VertCount].Y = y;
|
||||
loc[VertCount].Z = z;
|
||||
}
|
||||
void Location_Inline(Vector3 &v) { Location_Inline(v.X,v.Y,v.Z); }
|
||||
|
||||
// retrieve a reference to the vertex in the object
|
||||
// WARNING: does not validate index
|
||||
Vector3 & Get_Location(int index) {
|
||||
return Model->Get_Vertex_Array()[index];
|
||||
}
|
||||
|
||||
void Normal( float x, float y, float z)
|
||||
{
|
||||
Vector3 * norms = Model->Get_Non_Const_Vertex_Normal_Array();
|
||||
assert(norms);
|
||||
|
||||
norms[VertCount].X = x;
|
||||
norms[VertCount].Y = y;
|
||||
norms[VertCount].Z = z;
|
||||
}
|
||||
void Normal(Vector3 &v) { Normal(v.X,v.Y,v.Z); }
|
||||
|
||||
// retrieve a reference to the normal vector3 in the object
|
||||
// WARNING: does not validate index
|
||||
Vector3 & Get_Normal(int index) { return Model->Get_Non_Const_Vertex_Normal_Array()[index]; }
|
||||
|
||||
void Color(float r, float g, float b, float a, int color_array_index = 0)
|
||||
{
|
||||
// Vector4 * color = Model->Get_Color_Array(color_array_index);
|
||||
unsigned * color = Model->Get_Color_Array(color_array_index);
|
||||
assert(color);
|
||||
|
||||
color[VertCount]=DX8Wrapper::Convert_Color_Clamp(Vector4(r,g,b,a));
|
||||
// color[VertCount].X = r;
|
||||
// color[VertCount].Y = g;
|
||||
// color[VertCount].Z = b;
|
||||
// color[VertCount].W = a;
|
||||
}
|
||||
void Color(const Vector4 &v, int color_array_index = 0) { Color(v.X, v.Y, v.Z, v.W, color_array_index); }
|
||||
void Color(unsigned v, int color_array_index=0)
|
||||
{
|
||||
unsigned * color = Model->Get_Color_Array(color_array_index);
|
||||
assert(color);
|
||||
color[VertCount]=v;
|
||||
}
|
||||
|
||||
// retrieve a reference to a color entry in the object
|
||||
// WARNING: does not validate index
|
||||
// Vector4 & Get_Color(int index, int color_array_index = 0) { return Model->Get_Color_Array(color_array_index)[index]; }
|
||||
unsigned Get_Color(int index, int color_array_index = 0) { return Model->Get_Color_Array(color_array_index)[index]; }
|
||||
|
||||
void UV(float u, float v, int uv_array_index = 0)
|
||||
{
|
||||
Vector2 * uv = Model->Get_UV_Array(uv_array_index);
|
||||
assert(uv);
|
||||
|
||||
uv[VertCount].U = u;
|
||||
uv[VertCount].V = v;
|
||||
}
|
||||
void UV( Vector2 &v, int uv_array_index = 0) { UV(v.U, v.V, uv_array_index); }
|
||||
// retrieve a reference to a UV entry in the object
|
||||
// WARNING: does not validate index
|
||||
Vector2 & Get_UV(int index, int uv_array_index = 0 )
|
||||
{
|
||||
return Model->Get_UV_Array(uv_array_index)[index];
|
||||
}
|
||||
|
||||
bool End_Vertex( void);
|
||||
|
||||
// vertex creation shortcut, performs a begin, projected, rotated, and end
|
||||
bool Vertex(float x, float y, float z, float u, float v)
|
||||
{
|
||||
Begin_Vertex();
|
||||
Location(x, y, z);
|
||||
UV(u, v);
|
||||
return End_Vertex();
|
||||
}
|
||||
|
||||
bool Vertex(Vector2 v)
|
||||
{
|
||||
Begin_Vertex();
|
||||
Location(v.X, v.Y, 0);
|
||||
return End_Vertex();
|
||||
}
|
||||
|
||||
void End_Tri_Strip( void )
|
||||
{
|
||||
TriVertexCount = 0;
|
||||
}
|
||||
|
||||
void End_Tri_Fan( void )
|
||||
{
|
||||
TriVertexCount = 0;
|
||||
}
|
||||
|
||||
// For moving a vertex after the DynaMesh has already been created.
|
||||
virtual void Move_Vertex(int index, float x, float y, float z);
|
||||
virtual void Get_Vertex(int index, float &x, float &y, float &z);
|
||||
|
||||
// For moving all vertices in the mesh by a fixed amount
|
||||
void Translate_Vertices(const Vector3 & offset);
|
||||
|
||||
// For changing the color of a vertex after DynaMesh has been created.
|
||||
virtual void Change_Vertex_Color(int index, const Vector4 &color, int color_array_index)
|
||||
{
|
||||
// check if switching to multivertexcolor
|
||||
if (!MultiVertexColor[color_array_index]) {
|
||||
Switch_To_Multi_Vertex_Color(color_array_index);
|
||||
}
|
||||
CurVertexColor[color_array_index].X = color.X;
|
||||
CurVertexColor[color_array_index].Y = color.Y;
|
||||
CurVertexColor[color_array_index].Z = color.Z;
|
||||
CurVertexColor[color_array_index].W = color.W;
|
||||
// Vector4 * color_list = Model->Get_Color_Array(color_array_index);
|
||||
unsigned * color_list = Model->Get_Color_Array(color_array_index);
|
||||
color_list[index] = DX8Wrapper::Convert_Color_Clamp(color);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The following are a bunch of inlined functions for setting & clearing the mesh model's various flags
|
||||
*/
|
||||
// dirty flags
|
||||
void Set_Dirty_Bounds(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_BOUNDS, true); }
|
||||
void Clear_Dirty_Bounds(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_BOUNDS, false); }
|
||||
void Set_Dirty_Planes(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_PLANES, true); }
|
||||
void Clear_Dirty_Planes(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_PLANES, false); }
|
||||
void Set_Dirty_Vertex_Normals(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_VNORMALS, true); }
|
||||
void Clear_Dirty_Vertex_Normals(void) { Model->Set_Flag(MeshGeometryClass::DIRTY_VNORMALS, false); }
|
||||
|
||||
// control flags
|
||||
void Disable_Sort(void) { Model->Set_Flag(MeshGeometryClass::SORT, false); }
|
||||
void Enable_Sort(void) { Model->Set_Flag(MeshGeometryClass::SORT, true); }
|
||||
bool Sort_Enabled(void) { return (Model->Get_Flag(MeshGeometryClass::SORT) != 0); }
|
||||
|
||||
void Disable_Bounding_Box(void) { Model->Set_Flag(MeshGeometryClass::DISABLE_BOUNDING_BOX, true); }
|
||||
void Enable_Bounding_Box(void) { Model->Set_Flag(MeshGeometryClass::DISABLE_BOUNDING_BOX, false); }
|
||||
bool Test_Bounding_Box(void) { return (Model->Get_Flag(MeshGeometryClass::DISABLE_BOUNDING_BOX) == 0); }
|
||||
|
||||
void Disable_Bounding_Sphere(void) { Model->Set_Flag(MeshGeometryClass::DISABLE_BOUNDING_SPHERE, true); }
|
||||
void Enable_Bounding_Sphere(void) { Model->Set_Flag(MeshGeometryClass::DISABLE_BOUNDING_SPHERE, false); }
|
||||
bool Test_Bounding_Sphere(void) { return (Model->Get_Flag(MeshGeometryClass::DISABLE_BOUNDING_SPHERE) == 0); }
|
||||
|
||||
// this is called by the Reset function
|
||||
void Set_Dirty( void) { Set_Dirty_Bounds(); Set_Dirty_Planes(); Set_Dirty_Vertex_Normals(); }
|
||||
|
||||
enum {
|
||||
MAX_COLOR_ARRAYS = MeshMatDescClass::MAX_COLOR_ARRAYS,
|
||||
MAX_PASSES = MeshMatDescClass::MAX_PASSES
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
inline void Switch_To_Multi_Vertex_Color(int color_array_index = 0);
|
||||
|
||||
// tells when the triangle needs to be back flipped
|
||||
virtual bool Flip_Face( void) { return (!(TriVertexCount & 1)); }
|
||||
|
||||
// Low-level mesh object
|
||||
DynamicMeshModel * Model;
|
||||
|
||||
int VertexMaterialIdx[MAX_PASSES];
|
||||
bool MultiVertexMaterial[MAX_PASSES];
|
||||
int TextureIdx[MAX_PASSES];
|
||||
bool MultiTexture[MAX_PASSES];
|
||||
|
||||
Vector4 CurVertexColor[MAX_COLOR_ARRAYS];
|
||||
bool MultiVertexColor[MAX_COLOR_ARRAYS];
|
||||
|
||||
// number of polygons in the mesh
|
||||
int PolyCount;
|
||||
|
||||
// number of vertices in the mesh
|
||||
int VertCount;
|
||||
|
||||
// triangle vertex number
|
||||
int TriVertexCount;
|
||||
|
||||
// base vertex when submitting fans
|
||||
int FanVertex;
|
||||
|
||||
// is user currently submitting strips or fans
|
||||
enum { TRI_MODE_STRIPS = 0, TRI_MODE_FANS = 1 };
|
||||
int TriMode;
|
||||
|
||||
// The static sort level
|
||||
char SortLevel;
|
||||
};
|
||||
|
||||
inline Vector3 * DynamicMeshModel::Get_Non_Const_Vertex_Normal_Array(void)
|
||||
{
|
||||
if (Get_Flag(DIRTY_VNORMALS)) {
|
||||
Compute_Vertex_Normals();
|
||||
}
|
||||
return get_vert_normals();
|
||||
}
|
||||
|
||||
inline Vector3i * DynamicMeshModel::Get_Non_Const_Polygon_Array(void)
|
||||
{
|
||||
return get_polys();
|
||||
}
|
||||
|
||||
inline void DynamicMeshClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
||||
{
|
||||
if (!Bounding_Volumes_Valid()) {
|
||||
Model->Compute_Bounds(NULL);
|
||||
}
|
||||
Model->Get_Bounding_Sphere(&sphere);
|
||||
}
|
||||
|
||||
inline void DynamicMeshClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
||||
{
|
||||
if (!Bounding_Volumes_Valid()) {
|
||||
Model->Compute_Bounds(NULL);
|
||||
}
|
||||
Model->Get_Bounding_Box(&box);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void DynamicMeshClass::Switch_To_Multi_Vertex_Color(int color_array_index)
|
||||
{
|
||||
/* Vector4 * color_list = Model->Get_Color_Array(color_array_index);
|
||||
// set the proper color for all the existing vertices
|
||||
for (int lp = 0; lp < VertCount; lp++) {
|
||||
color_list[lp].X = CurVertexColor[color_array_index].X;
|
||||
color_list[lp].Y = CurVertexColor[color_array_index].Y;
|
||||
color_list[lp].Z = CurVertexColor[color_array_index].Z;
|
||||
color_list[lp].W = CurVertexColor[color_array_index].W;
|
||||
}
|
||||
*/
|
||||
unsigned * color_list = Model->Get_Color_Array(color_array_index);
|
||||
// set the proper color for all the existing vertices
|
||||
unsigned vertex_color=DX8Wrapper::Convert_Color_Clamp(CurVertexColor[color_array_index]);
|
||||
for (int lp = 0; lp < VertCount; lp++) {
|
||||
color_list[lp]=vertex_color;
|
||||
}
|
||||
|
||||
MultiVertexColor[color_array_index] = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the color of all vertices in the mesh for one color_array_index
|
||||
*/
|
||||
int DynamicMeshClass::Set_Vertex_Color(const Vector4 & color, int color_array_index)
|
||||
{
|
||||
// check if switching to multivertexcolor
|
||||
if (!MultiVertexColor[color_array_index]) {
|
||||
Switch_To_Multi_Vertex_Color(color_array_index);
|
||||
}
|
||||
|
||||
CurVertexColor[color_array_index] = color;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DynamicMeshClass::Set_Vertex_Color(const Vector3 & color, int color_array_index)
|
||||
{
|
||||
Set_Vertex_Color(Vector4(color.X,color.Y,color.Z,1),color_array_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Dynamic Screen Meshes
|
||||
**
|
||||
** Same as DynamicMesh, but mapped in Screen Coordinates
|
||||
**
|
||||
** Screen -> 0,0 1,0
|
||||
** +---+
|
||||
** | |
|
||||
** +---+
|
||||
** 0,1 1,1
|
||||
**
|
||||
**
|
||||
** View -> -1,1 1,1
|
||||
** +---+
|
||||
** | |
|
||||
** +---+
|
||||
** -1,-1 1,-1
|
||||
**
|
||||
** Note: since y is inverted, it switches from right handed to left handed
|
||||
** (from counter-clockwise to clockwise), so Flip Face accounts for this
|
||||
*/
|
||||
class DynamicScreenMeshClass : public DynamicMeshClass {
|
||||
|
||||
public:
|
||||
// constructor and destructor
|
||||
DynamicScreenMeshClass( int max_poly, int max_vert, float aspect = 1.0f ) : DynamicMeshClass( max_poly, max_vert), Aspect( aspect ) {}
|
||||
DynamicScreenMeshClass( const DynamicScreenMeshClass & src) : DynamicMeshClass(src), Aspect(src.Aspect) {}
|
||||
virtual ~DynamicScreenMeshClass( void) {}
|
||||
|
||||
// function to clone a dynamic screen mesh class
|
||||
virtual RenderObjClass * Clone(void) const { return NEW_REF( DynamicScreenMeshClass, (*this)); }
|
||||
|
||||
// class id of this render object
|
||||
virtual int Class_ID(void) const { return CLASSID_DYNASCREENMESH; }
|
||||
|
||||
// Remap locations to match a screen
|
||||
virtual void Location( float x, float y, float z = 0.0f);
|
||||
|
||||
// For moving a vertex after the DynaMesh has already been created.
|
||||
virtual void Move_Vertex(int index, float x, float y, float z = 0.0f);
|
||||
|
||||
// Set position
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
|
||||
virtual void Reset( void);
|
||||
|
||||
virtual void Set_Aspect(float aspect) { Aspect=aspect; };
|
||||
|
||||
protected:
|
||||
|
||||
// Aspect Ratio of the virtual screen.
|
||||
// 1.0 gives a -1,-1 to 1,1 display
|
||||
// 3/4 givs a -1,-3/4 to 1,3/4 display
|
||||
float Aspect;
|
||||
|
||||
// tells when the triangle needs to be back flipped
|
||||
virtual bool Flip_Face( void) { return !DynamicMeshClass::Flip_Face(); }
|
||||
};
|
||||
|
||||
#endif // DYNAMESH
|
||||
426
Generals/Code/Libraries/Source/WWVegas/WW3D2/font3d.cpp
Normal file
426
Generals/Code/Libraries/Source/WWVegas/WW3D2/font3d.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/font3d.cpp $*
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 4/11/01 10:17p $*
|
||||
* *
|
||||
* $Revision:: 16 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "font3d.h"
|
||||
#include "assetmgr.h"
|
||||
#include "texture.h"
|
||||
#include <assert.h>
|
||||
#include <wwdebug.h>
|
||||
#include "surfaceclass.h"
|
||||
#include "texture.h"
|
||||
#include "vector2i.h"
|
||||
|
||||
static SurfaceClass *_surface;
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DDataClass::Font3DDataClass -- constructor *
|
||||
* *
|
||||
* Constructs and load a Targa font image to create a texture matetial *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
Font3DDataClass::Font3DDataClass( const char *filename )
|
||||
{
|
||||
Texture = NULL;
|
||||
Load_Font_Image( filename);
|
||||
Name = strdup( filename);
|
||||
Name = strupr( Name);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DDataClass::~Font3DDataClass -- destructor *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
Font3DDataClass::~Font3DDataClass(void)
|
||||
{
|
||||
if (Name != NULL) {
|
||||
free(Name);
|
||||
Name = NULL;
|
||||
}
|
||||
|
||||
REF_PTR_RELEASE(Texture);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* FontClass::Minimize_Font_Image *
|
||||
* *
|
||||
* Rebuilds the give image to better pack characters and to insure a square power of two size *
|
||||
* Must be called AFTER Make_Proportional() so each chars minimal bounding box is known *
|
||||
* Will only create a new texture of size 128x128 or 256x256, dependent on original width *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
SurfaceClass *Font3DDataClass::Minimize_Font_Image( SurfaceClass *surface )
|
||||
{
|
||||
SurfaceClass::SurfaceDescription sd;
|
||||
|
||||
surface->Get_Description(sd);
|
||||
|
||||
float current_width = sd.Width;
|
||||
float current_height = sd.Height;
|
||||
|
||||
// determine new width make the size of the new image either 128x128 or 256x256,
|
||||
// dependent on the width of the original image
|
||||
int new_width;
|
||||
if (current_width < 256) {
|
||||
new_width = 128;
|
||||
} else {
|
||||
new_width = 256;
|
||||
}
|
||||
|
||||
int new_height = new_width;
|
||||
// create a new 4 bit alpha image to build into
|
||||
// We dont support non-homogeneous copies just yet
|
||||
SurfaceClass *new_surface = NEW_REF(SurfaceClass,(new_width, new_height,WW3D_FORMAT_A4R4G4B4));
|
||||
//SurfaceClass *new_surface0 = NEW_REF(SurfaceClass,(new_width, new_height,sd.Format));
|
||||
|
||||
// fill with transparent black
|
||||
new_surface->Clear();
|
||||
|
||||
// indices for the location of each added char
|
||||
int new_x = 0;
|
||||
int new_y = 0;
|
||||
|
||||
// for each character, copy minimum bounding area to (new_x, new_y) in the new image
|
||||
for (int char_index = 0; char_index < 256; char_index++) {
|
||||
|
||||
// find the lop left coordinate and the height and width of the char's bounding box
|
||||
// (must convert the normalized uv tables to pixels and round off)
|
||||
int src_x = (int)(UOffsetTable[ char_index ] * current_width + 0.5);
|
||||
int src_y = (int)(VOffsetTable[ char_index ] * current_height + 0.5);
|
||||
int width = (int)(UWidthTable[ char_index ] * current_width + 0.5);
|
||||
int height = (int)(VHeight * current_height + 0.5);
|
||||
|
||||
// if the character has any visible pixels at all...
|
||||
if (width != 0) {
|
||||
|
||||
// if this charactger will not fit on the current line, goto the next line
|
||||
if (new_x + width > new_width) {
|
||||
new_x = 0;
|
||||
new_y += height;
|
||||
|
||||
// if we have run out of lines, we have a problem
|
||||
// we assert because we have already modified tables for some of the chars
|
||||
if (new_y + height > new_height) {
|
||||
new_y -= height;
|
||||
WWDEBUG_SAY(( "Font doesn't fit texture 2 on char %c\n", char_index ));
|
||||
}
|
||||
}
|
||||
|
||||
// blit from original image to new image
|
||||
|
||||
new_surface->Copy(new_x, new_y,src_x,src_y,width,height,surface);
|
||||
|
||||
}
|
||||
|
||||
// update the U and V tables to show new character location
|
||||
UOffsetTable[ char_index ] = (float)(new_x) / (float)new_width;
|
||||
VOffsetTable[ char_index ] = (float)(new_y) / (float)new_width;
|
||||
|
||||
// update width in terms of new normal image width
|
||||
UWidthTable[ char_index ] *= (float)current_width / (float)new_width;
|
||||
|
||||
new_x += width;
|
||||
}
|
||||
|
||||
// update height in terms of new normal image height
|
||||
VHeight *= (float)current_height / (float)new_height;
|
||||
|
||||
// be sure the new image is SMALLER than the old image
|
||||
// assert ( (new_width * new_height) <= (current_width * current_height));
|
||||
|
||||
// release the old surface and return the new one
|
||||
REF_PTR_RELEASE(surface);
|
||||
|
||||
_surface = new_surface;
|
||||
|
||||
return _surface;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* FontClass::Make_Proportional *
|
||||
* *
|
||||
* Modifys U and Width tables to convert a monospace font into a proportional font. Hieght *
|
||||
* remains the same. Performed by getting the current mono-space bounding box and bringing *
|
||||
* in the left and right edges to the first non-transparent ( != 0 ) pixel. Then the U and *
|
||||
* width tables are updated with the new values. The image itself is not modified unless... *
|
||||
* *
|
||||
* we complete by calling Minimize_Font_Image to shink the image & insure a power of 2 square *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
SurfaceClass *Font3DDataClass::Make_Proportional( SurfaceClass *surface )
|
||||
{
|
||||
SurfaceClass::SurfaceDescription sd;
|
||||
surface->Get_Description(sd);
|
||||
float width = sd.Width;
|
||||
float height = sd.Height;
|
||||
|
||||
// for each character in the font...
|
||||
for (int char_index = 0; char_index < 256; char_index++) {
|
||||
|
||||
// find the current bounding box
|
||||
// (must convert the normalized uv tables to pixels and round off)
|
||||
int x0 = (int)(UOffsetTable[ char_index ] * width + 0.5);
|
||||
int y0 = (int)(VOffsetTable[ char_index ] * height + 0.5);
|
||||
int x1 = x0 + (int)(UWidthTable[ char_index ] * width + 0.5);
|
||||
int y1 = y0 + (int)(VHeight * height + 0.5);
|
||||
|
||||
// find minimum bounding box by finding the minimum and maximum non-0 x pixel location
|
||||
Vector2i minb(x0,y0);
|
||||
Vector2i maxb(x1,y1);
|
||||
|
||||
surface->FindBB(&minb,&maxb);
|
||||
|
||||
// set the new edges
|
||||
x0 = minb.I;
|
||||
x1 = maxb.I+1;
|
||||
|
||||
// if we didn't find ANY non-transparent pixels, the char has no width.
|
||||
if (x1 < x0) {
|
||||
x1 = x0;
|
||||
}
|
||||
|
||||
// turn off all character after del
|
||||
if (char_index > 0x80) {
|
||||
x1 = x0;
|
||||
}
|
||||
|
||||
// update the U and width tables
|
||||
UOffsetTable[ char_index ] = (float)x0 / width;
|
||||
UWidthTable[ char_index ] = (float)( x1 - x0 ) / width;
|
||||
CharWidthTable[ char_index ] = x1 - x0;
|
||||
}
|
||||
|
||||
// now shink the image given the minimum char sizes
|
||||
// surface = Minimize_Font_Image( surface );
|
||||
Minimize_Font_Image( _surface );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DDataClass::Load_Font_Image( SR_SCENE *scene, char *filename ) *
|
||||
* *
|
||||
* Loads a targa font image file, arranged as 16x16 characters, and builds u v tables to *
|
||||
* find each character. Converts the mono-space font into a proportional font, then uploads *
|
||||
* the image to the scene as a textur material. *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
bool Font3DDataClass::Load_Font_Image( const char *filename )
|
||||
{
|
||||
// get the font surface
|
||||
SurfaceClass *surface = NEW_REF(SurfaceClass,(filename));
|
||||
WWASSERT(surface);
|
||||
|
||||
SurfaceClass::SurfaceDescription sd;
|
||||
surface->Get_Description(sd);
|
||||
|
||||
// If input is a font strike (strip) process it as such
|
||||
if ( sd.Width > 8 * sd.Height ) {
|
||||
|
||||
// the height of the strike is the height of the characters
|
||||
VHeight = 1;
|
||||
CharHeight = sd.Height;
|
||||
|
||||
int column = 0;
|
||||
int width = sd.Width;
|
||||
|
||||
|
||||
// for each char, find the uv start location and set the
|
||||
// mono-spaced width and height in normalized screen units
|
||||
for (int char_index = 0; char_index < 256; char_index++) {
|
||||
|
||||
if ( char_index >= 0x7F ) {
|
||||
|
||||
UOffsetTable[ char_index ] = 0;
|
||||
VOffsetTable[ char_index ] = 0;
|
||||
UWidthTable[ char_index ] = 0;
|
||||
CharWidthTable[ char_index ] = 0;
|
||||
|
||||
} else {
|
||||
|
||||
// find the first non-transparent column...
|
||||
while (( column < width ) && ( surface->Is_Transparent_Column(column) )) column++;
|
||||
int start = column;
|
||||
|
||||
// find the first transparent column...
|
||||
while (( column < width ) && ( !surface->Is_Transparent_Column(column) )) column++;
|
||||
int end = column;
|
||||
|
||||
if ( end <= start ) {
|
||||
WWDEBUG_SAY(( "Error Char %d start %d end %d width %d\n", char_index, start, end, width ));
|
||||
}
|
||||
|
||||
// WWASSERT( end > start );
|
||||
|
||||
UOffsetTable[ char_index ] = (float)start / width;
|
||||
VOffsetTable[ char_index ] = 0;
|
||||
UWidthTable[ char_index ] = (float)(end - start) / width;
|
||||
CharWidthTable[ char_index ] = end - start;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// convert the just created mon-spaced font to proportional (optional)
|
||||
// surface = Make_Proportional( surface );
|
||||
_surface = surface;
|
||||
surface = NULL;
|
||||
Minimize_Font_Image( _surface );
|
||||
|
||||
} else {
|
||||
|
||||
// Determine the width and height of each mono spaced character in pixels
|
||||
// (assumes 16x16 array of chars)
|
||||
float font_width = sd.Width;
|
||||
float font_height = sd.Height;
|
||||
float mono_pixel_width = (font_width / 16);
|
||||
float mono_pixel_height = (font_height / 16);
|
||||
|
||||
// for each char, find the uv start location and set the
|
||||
// mono-spaced width and height in normalized screen units
|
||||
for (int char_index = 0; char_index < 256; char_index++) {
|
||||
UOffsetTable[ char_index ] = (float)((char_index % 16) * mono_pixel_width) / font_width;
|
||||
VOffsetTable[ char_index ] = (float)((char_index / 16) * mono_pixel_height) / font_height;
|
||||
UWidthTable[ char_index ] = mono_pixel_width / font_width;
|
||||
CharWidthTable[ char_index ] = mono_pixel_width;
|
||||
}
|
||||
VHeight = mono_pixel_height / font_height;
|
||||
CharHeight = mono_pixel_height;
|
||||
|
||||
// convert the just created mon-spaced font to proportional (optional)
|
||||
|
||||
_surface = surface;
|
||||
surface = NULL;
|
||||
Make_Proportional( _surface );
|
||||
}
|
||||
|
||||
// create the texture
|
||||
if ( _surface ) {
|
||||
Texture = NEW_REF(TextureClass,(_surface,TextureClass::MIP_LEVELS_1));
|
||||
REF_PTR_RELEASE(_surface);
|
||||
}
|
||||
|
||||
// return SUCCESS!
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DInstanceClass::Font3DInstanceClass -- constructor *
|
||||
* *
|
||||
* Constructs and load a Targa font image to create a texture matetial *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
Font3DInstanceClass::Font3DInstanceClass( const char *filename )
|
||||
{
|
||||
FontData = WW3DAssetManager::Get_Instance()->Get_Font3DData( filename);
|
||||
MonoSpacing = 0.0f;
|
||||
Scale = 1.0f;
|
||||
SpaceSpacing = (int)(FontData->Char_Width('H') / 2.0f);
|
||||
InterCharSpacing = 1;
|
||||
Build_Cached_Tables();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DInstanceClass::~Font3DInstanceClass -- destructor *
|
||||
* *
|
||||
***********************************************************************************************/
|
||||
Font3DInstanceClass::~Font3DInstanceClass(void)
|
||||
{
|
||||
REF_PTR_RELEASE(FontData);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void Font3DInstanceClass::Set_Mono_Spaced( void )
|
||||
{
|
||||
MonoSpacing = FontData->Char_Width('W') + 1;
|
||||
Build_Cached_Tables();
|
||||
}
|
||||
|
||||
void Font3DInstanceClass::Build_Cached_Tables()
|
||||
{
|
||||
// Rebuild the cached tables
|
||||
for (int a=0;a<256;++a) {
|
||||
float width = (float)FontData->Char_Width(a);
|
||||
if ( a == ' ' ) {
|
||||
width = SpaceSpacing;
|
||||
}
|
||||
|
||||
ScaledWidthTable[a] = Scale * width;
|
||||
if (MonoSpacing != 0.0f) {
|
||||
ScaledSpacingTable[a] = Scale * MonoSpacing;
|
||||
} else {
|
||||
ScaledSpacingTable[a] = Scale * (width + InterCharSpacing);
|
||||
}
|
||||
}
|
||||
ScaledHeight = floorf(Scale * (float)FontData->Char_Height('A'));
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* *
|
||||
* Font3DInstanceClass::String_Screen_Width( char *test_str ) *
|
||||
* *
|
||||
* Finds the normalized screenspace width of a character string - useful for checking before *
|
||||
* printing to avoid overflowing the screen. * *
|
||||
***********************************************************************************************/
|
||||
float Font3DInstanceClass::String_Width( const WCHAR *test_str )
|
||||
{
|
||||
float width = 0.0;
|
||||
for (; *test_str; test_str++) {
|
||||
width += Char_Spacing(*test_str);
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
float Font3DInstanceClass::String_Width( const char *test_str )
|
||||
{
|
||||
float width = 0.0;
|
||||
for (; *test_str; test_str++) {
|
||||
width += Char_Spacing(*test_str);
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
223
Generals/Code/Libraries/Source/WWVegas/WW3D2/font3d.h
Normal file
223
Generals/Code/Libraries/Source/WWVegas/WW3D2/font3d.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/font3d.h $*
|
||||
* *
|
||||
* $Author:: Byon_g $*
|
||||
* *
|
||||
* $Modtime:: 4/05/01 2:19p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef FONT3D_H
|
||||
#define FONT3D_H
|
||||
|
||||
#include "always.h"
|
||||
#include "refcount.h"
|
||||
#include "vector4.h"
|
||||
#include "widestring.h"
|
||||
#include "rect.h"
|
||||
|
||||
class TextureClass;
|
||||
class SurfaceClass;
|
||||
|
||||
/******************************************************************
|
||||
**
|
||||
** Font3DDataClass
|
||||
**
|
||||
** This class provides an interface to a font texture. Once
|
||||
** created and loaded with a font, the object can return texture
|
||||
** u v coordinate for any character in the font, as well as the
|
||||
** character width for proportional fonts. Fonts are loaded as
|
||||
** 16-bit Targa files, then converted to proportional fonts by
|
||||
** finding the minimum bounding box for each chacter. The font
|
||||
** texture is then minimized to a 256x256 or 128x128 texture
|
||||
** material by re-stacking chars by thier minimum bounding box.
|
||||
**
|
||||
** During use, this class is really no more than a data table accessor
|
||||
** Only during creation is any real code run.
|
||||
**
|
||||
** Since the space char nevers needs to be drawn, do not use
|
||||
** the conventional method of acessing and drawing chars (which will
|
||||
** still work). Instead, call Get_Space_Width to determine the user-
|
||||
** settable width, and skip the drawing.
|
||||
**
|
||||
*******************************************************************/
|
||||
class Font3DDataClass : public RefCountClass {
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
** Constructor, Constructor which loads a targa file,
|
||||
** and Destructor
|
||||
*/
|
||||
Font3DDataClass( const char *filename );
|
||||
~Font3DDataClass();
|
||||
|
||||
// the name of the font data (used for name matching and the like.)
|
||||
char *Name;
|
||||
|
||||
/*
|
||||
** access character width and height in pixels (clamp char to 0.255)
|
||||
*/
|
||||
|
||||
unsigned char Char_Width( WCHAR ch = (WCHAR)'H' ) { return CharWidthTable[ch&0xFF]; }// & 0xFF]; } // No need to "& 0xff" with chars!!!
|
||||
unsigned char Char_Height( WCHAR /*ch = 'H'*/ ) { return CharHeight; }
|
||||
|
||||
// u and v are in normalized texture space
|
||||
inline float Char_U_Offset( WCHAR ch = (WCHAR)'H') { return UOffsetTable[ch&0xFF]; }// & 0xFF]; }
|
||||
inline float Char_V_Offset( WCHAR ch = (WCHAR)'H') { return VOffsetTable[ch&0xFF]; }// & 0xFF]; }
|
||||
inline float Char_U_Width( WCHAR ch = (WCHAR)'H' ) { return UWidthTable[ch&0xFF]; }// & 0xFF]; }
|
||||
inline float Char_V_Height( WCHAR /*ch = 'H'*/) { return VHeight; }
|
||||
|
||||
// get all four UV values as one vector4
|
||||
Vector4 Char_UV_Corners( WCHAR ch = (WCHAR)'H' )
|
||||
{
|
||||
// ch &= 0xFF;
|
||||
return Vector4( UOffsetTable[ch], VOffsetTable[ch],
|
||||
UOffsetTable[ch] + UWidthTable[ch],
|
||||
VOffsetTable[ch] + VHeight );
|
||||
}
|
||||
|
||||
/*
|
||||
** access texture material
|
||||
*/
|
||||
TextureClass * Peek_Texture( void ) { return Texture; }
|
||||
|
||||
private:
|
||||
/*
|
||||
** The material (texture) which holds the font
|
||||
*/
|
||||
TextureClass * Texture;
|
||||
|
||||
/*
|
||||
** Normalized texture page offsets for each character
|
||||
*/
|
||||
float UOffsetTable[ 256 ];
|
||||
float VOffsetTable[ 256 ];
|
||||
float UWidthTable[ 256 ];
|
||||
float VHeight;
|
||||
|
||||
unsigned char CharWidthTable[ 256 ];
|
||||
unsigned char CharHeight;
|
||||
|
||||
/*
|
||||
** load a targa font image (.TGA)
|
||||
*/
|
||||
bool Load_Font_Image( const char *filename );
|
||||
|
||||
/*
|
||||
** routines to convert a mono-spaced font to a proportional
|
||||
** font and minimize texture image size as a result
|
||||
*/
|
||||
SurfaceClass *Make_Proportional( SurfaceClass *font_image );
|
||||
SurfaceClass *Minimize_Font_Image( SurfaceClass *font_image );
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
**
|
||||
** Font3DInstanceClass
|
||||
**
|
||||
*******************************************************************/
|
||||
class Font3DInstanceClass : public RefCountClass {
|
||||
|
||||
public:
|
||||
/*
|
||||
** Constructor which creates/gets a Font3DDataClass object,
|
||||
** and Destructor
|
||||
*/
|
||||
Font3DInstanceClass( const char *filename );
|
||||
~Font3DInstanceClass();
|
||||
|
||||
/*
|
||||
** access texture material
|
||||
*/
|
||||
TextureClass *Peek_Texture( void ) { return FontData->Peek_Texture(); }
|
||||
|
||||
/*
|
||||
** The non-scaled monospace char width in pixels ( set to 0 for proportional spaced font )
|
||||
*/
|
||||
void Set_Mono_Spaced( void );
|
||||
void Set_Proportional( void ) { MonoSpacing = 0; Build_Cached_Tables(); }
|
||||
|
||||
|
||||
/*
|
||||
** Set the font scale (default to 1)
|
||||
** This amount will be automatically applied to all Char_Screen_Width calls
|
||||
*/
|
||||
void Set_Scale( float scale ) { Scale = scale; Build_Cached_Tables(); }
|
||||
// float Get_Scale() const { return Scale; }
|
||||
|
||||
/*
|
||||
** The scaled character pixel width, height, and spacing data (clamp char to 0.255)
|
||||
*/
|
||||
float Char_Width( WCHAR ch ) const { return ScaledWidthTable[ch&0xFF]; }
|
||||
float Char_Spacing( WCHAR ch ) const { return ScaledSpacingTable[ch&0xFF]; }
|
||||
float Char_Height( void ) const { return ScaledHeight; }
|
||||
|
||||
|
||||
/*
|
||||
** The scaled pixel width of a string; useful before printing to avoid screen overflows.
|
||||
*/
|
||||
float String_Width( const WCHAR *test_str );
|
||||
float String_Width( const char *test_str );
|
||||
|
||||
/*
|
||||
** Char UVs
|
||||
*/
|
||||
// u and v are in normalized texture space
|
||||
// inline float Char_U_Offset( WCHAR ch = (WCHAR)'H') { return FontData->Char_U_Offset( ch & 0xFF ); }
|
||||
// inline float Char_V_Offset( WCHAR ch = (WCHAR)'H') { return FontData->Char_V_Offset( ch & 0xFF ); }
|
||||
// inline float Char_U_Width( WCHAR ch = (WCHAR)'H' ) { return FontData->Char_U_Width( ch & 0xFF ); }
|
||||
// inline float Char_V_Height( WCHAR ch = (WCHAR)'H') { return FontData->Char_V_Height( ch & 0xFF ); }
|
||||
// Vector4 Char_UV_Corners( WCHAR ch = (WCHAR)'H' ) { return FontData->Char_UV_Corners( ch & 0xFF ); }
|
||||
RectClass Char_UV( WCHAR ch ) { return RectClass( FontData->Char_U_Offset(ch),
|
||||
FontData->Char_V_Offset(ch),
|
||||
FontData->Char_U_Offset(ch) + FontData->Char_U_Width(ch),
|
||||
FontData->Char_V_Offset(ch) + FontData->Char_V_Height(ch) ); }
|
||||
private:
|
||||
|
||||
Font3DDataClass * FontData; // The font data
|
||||
float Scale; // The current scale factor
|
||||
float SpaceSpacing; // non-scaled width of space in pixels ( defaults to 1/2 'H' width )
|
||||
float InterCharSpacing; // non-scaled width between chars in pixels
|
||||
float MonoSpacing; // non-scaled monospace char width in pixels (0 for proportional)
|
||||
|
||||
float ScaledWidthTable[256]; // scaled cache of the chars pixel widths
|
||||
float ScaledSpacingTable[256]; // scaled cache of the chars pixel spacing
|
||||
float ScaledHeight; // scaled cache of the chars pixel height
|
||||
|
||||
void Build_Cached_Tables();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
157
Generals/Code/Libraries/Source/WWVegas/WW3D2/formconv.cpp
Normal file
157
Generals/Code/Libraries/Source/WWVegas/WW3D2/formconv.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/formconv.cpp $*
|
||||
* *
|
||||
* Original Author:: Nathaniel Hoffman *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/16/01 1:33p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include "formconv.h"
|
||||
|
||||
D3DFORMAT WW3DFormatToD3DFormatConversionArray[WW3D_FORMAT_COUNT] = {
|
||||
D3DFMT_UNKNOWN,
|
||||
D3DFMT_R8G8B8,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DFMT_X8R8G8B8,
|
||||
D3DFMT_R5G6B5,
|
||||
D3DFMT_X1R5G5B5,
|
||||
D3DFMT_A1R5G5B5,
|
||||
D3DFMT_A4R4G4B4,
|
||||
D3DFMT_R3G3B2,
|
||||
D3DFMT_A8,
|
||||
D3DFMT_A8R3G3B2,
|
||||
D3DFMT_X4R4G4B4,
|
||||
D3DFMT_A8P8,
|
||||
D3DFMT_P8,
|
||||
D3DFMT_L8,
|
||||
D3DFMT_A8L8,
|
||||
D3DFMT_A4L4,
|
||||
D3DFMT_V8U8, // Bumpmap
|
||||
D3DFMT_L6V5U5, // Bumpmap
|
||||
D3DFMT_X8L8V8U8, // Bumpmap
|
||||
D3DFMT_DXT1,
|
||||
D3DFMT_DXT2,
|
||||
D3DFMT_DXT3,
|
||||
D3DFMT_DXT4,
|
||||
D3DFMT_DXT5
|
||||
};
|
||||
|
||||
/*
|
||||
#define HIGHEST_SUPPORTED_D3DFORMAT D3DFMT_X8L8V8U8 //A4L4
|
||||
WW3DFormat D3DFormatToWW3DFormatConversionArray[HIGHEST_SUPPORTED_D3DFORMAT + 1] = {
|
||||
WW3D_FORMAT_UNKNOWN, // 0
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_R8G8B8, // 20
|
||||
WW3D_FORMAT_A8R8G8B8,
|
||||
WW3D_FORMAT_X8R8G8B8,
|
||||
WW3D_FORMAT_R5G6B5,
|
||||
WW3D_FORMAT_X1R5G5B5,
|
||||
WW3D_FORMAT_A1R5G5B5,
|
||||
WW3D_FORMAT_A4R4G4B4,
|
||||
WW3D_FORMAT_R3G3B2,
|
||||
WW3D_FORMAT_A8,
|
||||
WW3D_FORMAT_A8R3G3B2,
|
||||
WW3D_FORMAT_X4R4G4B4, // 30
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_A8P8, // 40
|
||||
WW3D_FORMAT_P8,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN, WW3D_FORMAT_UNKNOWN,
|
||||
WW3D_FORMAT_L8, // 50
|
||||
WW3D_FORMAT_A8L8,
|
||||
WW3D_FORMAT_A4L4
|
||||
};
|
||||
*/
|
||||
|
||||
#define HIGHEST_SUPPORTED_D3DFORMAT D3DFMT_X8L8V8U8
|
||||
WW3DFormat D3DFormatToWW3DFormatConversionArray[HIGHEST_SUPPORTED_D3DFORMAT + 1];
|
||||
|
||||
D3DFORMAT WW3DFormat_To_D3DFormat(WW3DFormat ww3d_format) {
|
||||
if (ww3d_format >= WW3D_FORMAT_COUNT) {
|
||||
return D3DFMT_UNKNOWN;
|
||||
} else {
|
||||
return WW3DFormatToD3DFormatConversionArray[(unsigned int)ww3d_format];
|
||||
}
|
||||
}
|
||||
|
||||
WW3DFormat D3DFormat_To_WW3DFormat(D3DFORMAT d3d_format)
|
||||
{
|
||||
switch (d3d_format) {
|
||||
// The DXT-codes are created with FOURCC macro and thus can't be placed in the conversion table
|
||||
case D3DFMT_DXT1: return WW3D_FORMAT_DXT1;
|
||||
case D3DFMT_DXT2: return WW3D_FORMAT_DXT2;
|
||||
case D3DFMT_DXT3: return WW3D_FORMAT_DXT3;
|
||||
case D3DFMT_DXT4: return WW3D_FORMAT_DXT4;
|
||||
case D3DFMT_DXT5: return WW3D_FORMAT_DXT5;
|
||||
default:
|
||||
if (d3d_format > HIGHEST_SUPPORTED_D3DFORMAT) {
|
||||
return WW3D_FORMAT_UNKNOWN;
|
||||
} else {
|
||||
return D3DFormatToWW3DFormatConversionArray[(unsigned int)d3d_format];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Init_D3D_To_WW3_Conversion()
|
||||
{
|
||||
for (int i=0;i<HIGHEST_SUPPORTED_D3DFORMAT;++i) {
|
||||
D3DFormatToWW3DFormatConversionArray[i]=WW3D_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_R8G8B8]=WW3D_FORMAT_R8G8B8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A8R8G8B8]=WW3D_FORMAT_A8R8G8B8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_X8R8G8B8]=WW3D_FORMAT_X8R8G8B8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_R5G6B5]=WW3D_FORMAT_R5G6B5;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_X1R5G5B5]=WW3D_FORMAT_X1R5G5B5;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A1R5G5B5]=WW3D_FORMAT_A1R5G5B5;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A4R4G4B4]=WW3D_FORMAT_A4R4G4B4;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_R3G3B2]=WW3D_FORMAT_R3G3B2;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A8]=WW3D_FORMAT_A8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A8R3G3B2]=WW3D_FORMAT_A8R3G3B2;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_X4R4G4B4]=WW3D_FORMAT_X4R4G4B4;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A8P8]=WW3D_FORMAT_A8P8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_P8]=WW3D_FORMAT_P8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_L8]=WW3D_FORMAT_L8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A8L8]=WW3D_FORMAT_A8L8;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_A4L4]=WW3D_FORMAT_A4L4;
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_V8U8]=WW3D_FORMAT_U8V8; // Bumpmap
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_L6V5U5]=WW3D_FORMAT_L6V5U5; // Bumpmap
|
||||
D3DFormatToWW3DFormatConversionArray[D3DFMT_X8L8V8U8]=WW3D_FORMAT_X8L8V8U8; // Bumpmap
|
||||
|
||||
};
|
||||
58
Generals/Code/Libraries/Source/WWVegas/WW3D2/formconv.h
Normal file
58
Generals/Code/Libraries/Source/WWVegas/WW3D2/formconv.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/formconv.h $*
|
||||
* *
|
||||
* Original Author:: Nathaniel Hoffman *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 7/16/01 1:33p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef FORMCONV_H
|
||||
#define FORMCONV_H
|
||||
|
||||
#include "ww3dformat.h"
|
||||
#include <d3d8.h>
|
||||
|
||||
/*
|
||||
** This file is used for conversions between D3DFORMAT and WW3DFormat.
|
||||
*/
|
||||
|
||||
D3DFORMAT WW3DFormat_To_D3DFormat(WW3DFormat ww3d_format);
|
||||
WW3DFormat D3DFormat_To_WW3DFormat(D3DFORMAT d3d_format);
|
||||
|
||||
void Init_D3D_To_WW3_Conversion();
|
||||
|
||||
#endif
|
||||
117
Generals/Code/Libraries/Source/WWVegas/WW3D2/framgrab.h
Normal file
117
Generals/Code/Libraries/Source/WWVegas/WW3D2/framgrab.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/framgrab.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef FRAMEGRAB_H
|
||||
#define FRAMEGRAB_H
|
||||
|
||||
#ifndef ALWAYS_H
|
||||
#include "always.h"
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning (push, 3) // (gth) system headers complain at warning level 4...
|
||||
#endif
|
||||
|
||||
#ifndef _WINDOWS_
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
#ifndef _INC_WINDOWSX
|
||||
#include "windowsx.h"
|
||||
#endif
|
||||
|
||||
#ifndef _INC_VFW
|
||||
#include "vfw.h"
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
// FramGrab.h: interface for the FrameGrabClass class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FrameGrabClass
|
||||
{
|
||||
public:
|
||||
enum MODE {
|
||||
RAW,
|
||||
AVI
|
||||
};
|
||||
|
||||
// depending on which mode you select, it will produce either frames or an AVI.
|
||||
FrameGrabClass(const char *filename, MODE mode, int width, int height, int bitdepth, float framerate );
|
||||
|
||||
virtual ~FrameGrabClass();
|
||||
|
||||
void ConvertGrab(void *BitmapPointer);
|
||||
void Grab(void *BitmapPointer);
|
||||
|
||||
long * GetBuffer() { return Bitmap; }
|
||||
float GetFrameRate() { return FrameRate; }
|
||||
|
||||
protected:
|
||||
const char *Filename;
|
||||
float FrameRate;
|
||||
|
||||
MODE Mode;
|
||||
long Counter; // used for incrementing filename cunter, etc.
|
||||
|
||||
void GrabAVI(void *BitmapPointer);
|
||||
void GrabRawFrame(void *BitmapPointer);
|
||||
|
||||
// avi settings
|
||||
PAVIFILE AVIFile;
|
||||
long *Bitmap;
|
||||
PAVISTREAM Stream;
|
||||
AVISTREAMINFO AVIStreamInfo;
|
||||
BITMAPINFOHEADER BitmapInfoHeader;
|
||||
|
||||
// general purpose cleanup routine
|
||||
void CleanupAVI();
|
||||
|
||||
// convert the SR image into AVI byte ordering
|
||||
void ConvertFrame(void *BitmapPointer);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
448
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanim.cpp
Normal file
448
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanim.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hanim.cpp 2 1/23/01 2:12p Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hanim.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 1/22/01 6:23p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "hanim.h"
|
||||
#include "assetmgr.h"
|
||||
#include "htree.h"
|
||||
#include "motchan.h"
|
||||
#include "chunkio.h"
|
||||
#include "w3d_file.h"
|
||||
#include "wwdebug.h"
|
||||
#include <string.h>
|
||||
#include <nstrdup.h>
|
||||
|
||||
|
||||
|
||||
/*
|
||||
**
|
||||
** HAnimComboClass
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
NamedPivotMapClass::~NamedPivotMapClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
NamedPivotMapClass::WeightInfoStruct & NamedPivotMapClass::WeightInfoStruct::operator = (WeightInfoStruct const &that)
|
||||
{
|
||||
if(Name) delete [] Name;
|
||||
assert(that.Name != 0);
|
||||
Name = nstrdup(that.Name);
|
||||
Weight = that.Weight;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// add a name & weight to the arrays
|
||||
void NamedPivotMapClass::Add(const char *Name, float Weight)
|
||||
{
|
||||
WeightInfoStruct info;
|
||||
info.Name = (char *) Name;
|
||||
info.Weight = Weight;
|
||||
WeightInfo.Add(info);
|
||||
info.Name = 0;
|
||||
}
|
||||
|
||||
// configure the base pivot map using the specified tree
|
||||
void NamedPivotMapClass::Update_Pivot_Map(const HTreeClass *Tree)
|
||||
{
|
||||
// first, resize the base pivot map to fit the tree
|
||||
int numPivots = Tree->Num_Pivots();
|
||||
|
||||
Resize(numPivots);
|
||||
ActiveCount = numPivots;
|
||||
|
||||
// first, reset all weights to 1 (the default)
|
||||
while(numPivots--) {
|
||||
(*this)[numPivots] = 1.0f;
|
||||
}
|
||||
|
||||
// for each named pivot, find the correct index and set the weight if the indicated bone is present
|
||||
// note: there is no check for redundant names
|
||||
int count = WeightInfo.Count();
|
||||
while(count--) {
|
||||
int actualPivot = Tree->Get_Bone_Index(WeightInfo[count].Name);
|
||||
if(actualPivot != -1) {
|
||||
(*this)[actualPivot] = WeightInfo[count].Weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
DEFINE_AUTO_POOL(HAnimComboDataClass,256);
|
||||
|
||||
HAnimComboDataClass::HAnimComboDataClass(bool shared)
|
||||
: Shared(shared), HAnim(0), PivotMap(0), Frame(0), Weight(1)
|
||||
{}
|
||||
|
||||
|
||||
HAnimComboDataClass::HAnimComboDataClass(const HAnimComboDataClass &src)
|
||||
: PivotMap(src.Get_Pivot_Map()),
|
||||
HAnim(src.Get_HAnim())
|
||||
{
|
||||
Shared = src.Is_Shared();
|
||||
Frame = src.Get_Frame();
|
||||
Weight = src.Get_Weight();
|
||||
}
|
||||
|
||||
void HAnimComboDataClass::Copy(const HAnimComboDataClass *src)
|
||||
{
|
||||
if(src) {
|
||||
HAnim = src->Get_HAnim();
|
||||
PivotMap = src->Get_Pivot_Map();
|
||||
Frame = src->Get_Frame();
|
||||
Weight = src->Get_Weight();
|
||||
} else {
|
||||
HAnim = 0;
|
||||
PivotMap = 0;
|
||||
Frame = 0;
|
||||
Weight = 1;
|
||||
}
|
||||
}
|
||||
|
||||
HAnimComboDataClass::~HAnimComboDataClass(void)
|
||||
{
|
||||
if(HAnim)
|
||||
HAnim->Release_Ref();
|
||||
if(PivotMap)
|
||||
PivotMap->Release_Ref();
|
||||
}
|
||||
|
||||
void HAnimComboDataClass::Clear(void)
|
||||
{
|
||||
if ( HAnim != NULL ) {
|
||||
HAnim->Release_Ref();
|
||||
HAnim = NULL;
|
||||
}
|
||||
|
||||
// not sure if the pivot map should be deleted or just have everything set to one.
|
||||
// removing it effectively sets it to one, so that's what I'm doing for now.
|
||||
if(PivotMap) {
|
||||
PivotMap->Release_Ref();
|
||||
PivotMap = NULL;
|
||||
}
|
||||
|
||||
Frame = 0.0f;
|
||||
Weight = 1.0;
|
||||
PivotMap = NULL;
|
||||
}
|
||||
|
||||
void HAnimComboDataClass::Set_HAnim(HAnimClass *motion)
|
||||
{
|
||||
if ( motion != NULL ) {
|
||||
motion->Add_Ref();
|
||||
}
|
||||
if ( HAnim != NULL ) {
|
||||
HAnim->Release_Ref();
|
||||
}
|
||||
HAnim = motion;
|
||||
}
|
||||
|
||||
|
||||
void HAnimComboDataClass::Set_Pivot_Map(PivotMapClass *map)
|
||||
{
|
||||
if ( map != NULL ) {
|
||||
map->Add_Ref();
|
||||
}
|
||||
if ( PivotMap != NULL ) {
|
||||
PivotMap->Release_Ref();
|
||||
}
|
||||
PivotMap = map;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function will replace the current pivot map (if any) with another pivot map that is
|
||||
** set to 1 for only those pivot indices that actually have data.
|
||||
*/
|
||||
void HAnimComboDataClass::Build_Active_Pivot_Map(void)
|
||||
{
|
||||
if ( PivotMap != NULL ) {
|
||||
PivotMap->Release_Ref();
|
||||
}
|
||||
if(HAnim == NULL) {
|
||||
PivotMap = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int numpivots = HAnim->Get_Num_Pivots();
|
||||
PivotMap = NEW_REF( PivotMapClass, ());
|
||||
PivotMap->Resize(numpivots);
|
||||
|
||||
int count = 0;
|
||||
while(count < numpivots) {
|
||||
if(HAnim->Is_Node_Motion_Present(count)) {
|
||||
PivotMap->Add(1);
|
||||
|
||||
} else {
|
||||
PivotMap->Add(0);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** HAnimComboClass
|
||||
**
|
||||
**
|
||||
*/
|
||||
|
||||
HAnimComboClass::HAnimComboClass(void)
|
||||
{}
|
||||
|
||||
HAnimComboClass::HAnimComboClass( int num_animations )
|
||||
{
|
||||
HAnimComboData.Resize(num_animations);
|
||||
|
||||
while(num_animations--) {
|
||||
HAnimComboData.Add(new HAnimComboDataClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HAnimComboClass::~HAnimComboClass(void)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
void HAnimComboClass::Clear( void )
|
||||
{
|
||||
int numAnimations = HAnimComboData.Count();
|
||||
while ( numAnimations-- ) {
|
||||
HAnimComboDataClass *data = HAnimComboData[numAnimations];
|
||||
if(data && (! data->Is_Shared()))
|
||||
data->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void HAnimComboClass::Reset( void )
|
||||
{
|
||||
int numAnimations = HAnimComboData.Count();
|
||||
while ( numAnimations-- ) {
|
||||
HAnimComboDataClass *data = HAnimComboData[numAnimations];
|
||||
if(data && (! data->Is_Shared())) {
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
HAnimComboData.Reset_Active();
|
||||
}
|
||||
|
||||
bool HAnimComboClass::Normalize_Weights(void)
|
||||
{
|
||||
// NOTE: This can only work if either no anims have pivot weight maps (in which case we will
|
||||
// adjust the anim weights to ensure normalization), or else if all do (in which case we will
|
||||
// adjust the pivot maps). Otherwise we do nothing and return false.
|
||||
int anim_count = Get_Num_Anims();
|
||||
if (!anim_count) return true; // Trivially succeeded
|
||||
|
||||
// Loop over all anims. Check if all or none have pivot maps, and also calculate the minimum
|
||||
// number of pivots.
|
||||
int anim_idx = 0;
|
||||
bool all_pivot_maps = true;
|
||||
bool none_pivot_maps = true;
|
||||
int num_anim_pivots = 100000;
|
||||
for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
|
||||
num_anim_pivots = MIN(num_anim_pivots, Peek_Motion(anim_idx)->Get_Num_Pivots());
|
||||
bool has_pivot_map = Peek_Pivot_Weight_Map(anim_idx) != NULL;
|
||||
all_pivot_maps &= has_pivot_map;
|
||||
none_pivot_maps &= !has_pivot_map;
|
||||
}
|
||||
if ( num_anim_pivots == 100000 ) {
|
||||
num_anim_pivots = 0;
|
||||
}
|
||||
|
||||
if (none_pivot_maps) {
|
||||
|
||||
// Calculate total weight of all active anims, ensure it is very close to 1.
|
||||
float weight_total = 0.0f;
|
||||
for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
|
||||
if (Peek_Motion(anim_idx) != NULL ) {
|
||||
float weight = Get_Weight(anim_idx);
|
||||
weight_total += weight;
|
||||
}
|
||||
}
|
||||
|
||||
// weight_total should be very close to 1. If not, normalize this pivot's weights
|
||||
if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
|
||||
float oo_total = 1.0f / weight_total;
|
||||
for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
|
||||
if (Peek_Motion(anim_idx) != NULL ) {
|
||||
Set_Weight(anim_idx, Get_Weight(anim_idx) * oo_total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (all_pivot_maps) {
|
||||
|
||||
// For each pivot, calculate total weight of all active anims, ensure close to 1.
|
||||
for (int piv_idx = 1; piv_idx < num_anim_pivots; piv_idx++) {
|
||||
|
||||
float weight_total = 0.0f;
|
||||
for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
|
||||
if (Peek_Motion(anim_idx) != NULL ) {
|
||||
float weight = Get_Weight(anim_idx) * (*Peek_Pivot_Weight_Map(anim_idx))[piv_idx];
|
||||
weight_total += weight;
|
||||
}
|
||||
}
|
||||
|
||||
// weight_total should be very close to 1. If not, normalize this pivot's weights
|
||||
if (weight_total != 0.0 && WWMath::Fabs( weight_total - 1.0 ) > WWMATH_EPSILON) {
|
||||
float oo_total = 1.0f / weight_total;
|
||||
for (anim_idx = 0; anim_idx < anim_count; anim_idx++ ) {
|
||||
if (Peek_Motion(anim_idx) != NULL ) {
|
||||
PivotMapClass *pivot_map = Get_Pivot_Weight_Map(anim_idx);
|
||||
float new_weight = (*pivot_map)[piv_idx] * oo_total;
|
||||
(*pivot_map)[piv_idx] = new_weight;
|
||||
pivot_map->Release_Ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void HAnimComboClass::Set_Motion( int index, HAnimClass *motion )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
data->Set_HAnim(motion);
|
||||
}
|
||||
|
||||
HAnimClass *HAnimComboClass::Get_Motion( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
HAnimClass *anim = data->Peek_HAnim();
|
||||
|
||||
if ( anim != NULL ) {
|
||||
anim->Add_Ref();
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
HAnimClass *HAnimComboClass::Peek_Motion( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
HAnimClass *anim = data->Peek_HAnim();
|
||||
return anim;
|
||||
}
|
||||
|
||||
void HAnimComboClass::Set_Frame( int index, float frame )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
data->Set_Frame(frame);
|
||||
}
|
||||
|
||||
float HAnimComboClass::Get_Frame( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
return data->Get_Frame();
|
||||
}
|
||||
|
||||
void HAnimComboClass::Set_Weight( int index, float weight )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
data->Set_Weight(weight);
|
||||
}
|
||||
|
||||
float HAnimComboClass::Get_Weight( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
return data->Get_Weight();
|
||||
}
|
||||
|
||||
void HAnimComboClass::Set_Pivot_Weight_Map( int index, PivotMapClass *map )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
data->Set_Pivot_Map(map);
|
||||
}
|
||||
|
||||
PivotMapClass *HAnimComboClass::Get_Pivot_Weight_Map( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
return data->Get_Pivot_Map();
|
||||
}
|
||||
|
||||
PivotMapClass *HAnimComboClass::Peek_Pivot_Weight_Map( int index )
|
||||
{
|
||||
HAnimComboDataClass *data = HAnimComboData[index];
|
||||
WWASSERT(data);
|
||||
|
||||
return data->Peek_Pivot_Map();
|
||||
}
|
||||
|
||||
void HAnimComboClass::Append_Anim_Combo_Data(HAnimComboDataClass * Data)
|
||||
{
|
||||
HAnimComboData.Add(Data);
|
||||
}
|
||||
|
||||
void HAnimComboClass::Remove_Anim_Combo_Data(HAnimComboDataClass * Data)
|
||||
{
|
||||
HAnimComboData.Delete(Data);
|
||||
}
|
||||
|
||||
|
||||
260
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanim.h
Normal file
260
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanim.h
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hanim.h 2 6/29/01 6:41p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hanim.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:35p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HANIM_H
|
||||
#define HANIM_H
|
||||
|
||||
#include "always.h"
|
||||
#include "quat.h"
|
||||
#include "refcount.h"
|
||||
#include "w3d_file.h"
|
||||
#include "hash.h"
|
||||
#include "mempool.h"
|
||||
#include <refcount.h>
|
||||
#include <slist.h>
|
||||
#include <vector.h>
|
||||
|
||||
struct NodeMotionStruct;
|
||||
class MotionChannelClass;
|
||||
class BitChannelClass;
|
||||
class HTreeClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class HTreeClass;
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
|
||||
HAnimClass
|
||||
|
||||
This is the base class for all animation formats used in W3D. It
|
||||
contains the virtual interface that all animations must support.
|
||||
|
||||
**********************************************************************************/
|
||||
class HAnimClass : public RefCountClass, public HashableClass
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
CLASSID_UNKNOWNANIM = 0xFFFFFFFF,
|
||||
CLASSID_HRAWANIM = 0,
|
||||
CLASSID_LASTANIM = 0x0000FFFF
|
||||
};
|
||||
|
||||
HAnimClass(void) { }
|
||||
virtual ~HAnimClass(void) { }
|
||||
|
||||
virtual const char * Get_Name(void) const = 0;
|
||||
virtual const char * Get_HName(void) const = 0;
|
||||
|
||||
virtual const char * Get_Key( void ) { return Get_Name(); }
|
||||
|
||||
virtual int Get_Num_Frames(void) = 0;
|
||||
virtual float Get_Frame_Rate() = 0;
|
||||
virtual float Get_Total_Time() = 0;
|
||||
|
||||
// virtual Vector3 Get_Translation(int pividx,float frame) = 0;
|
||||
// virtual Quaternion Get_Orientation(int pividx,float frame) = 0;
|
||||
// Jani: Changed to pass in reference of destination to avoid copying
|
||||
virtual void Get_Translation(int pividx,float frame) {} // todo: remove
|
||||
virtual void Get_Orientation(int pividx,float frame) {} // todo: remove
|
||||
virtual void Get_Translation(Vector3& translation, int pividx,float frame) const = 0;
|
||||
virtual void Get_Orientation(Quaternion& orientation, int pividx,float frame) const = 0;
|
||||
virtual void Get_Transform(Matrix3D&, int pividx, float frame) const = 0;
|
||||
virtual bool Get_Visibility(int pividx,float frame) = 0;
|
||||
|
||||
virtual int Get_Num_Pivots(void) const = 0;
|
||||
virtual bool Is_Node_Motion_Present(int pividx) = 0;
|
||||
|
||||
// Methods that test the presence of a certain motion channel.
|
||||
virtual bool Has_X_Translation (int pividx) { return true; }
|
||||
virtual bool Has_Y_Translation (int pividx) { return true; }
|
||||
virtual bool Has_Z_Translation (int pividx) { return true; }
|
||||
virtual bool Has_Rotation (int pividx) { return true; }
|
||||
virtual bool Has_Visibility (int pividx) { return true; }
|
||||
virtual int Class_ID(void) const { return CLASSID_UNKNOWNANIM; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** The PivotMapClass is used by the HAnimComboDataClass (sometimes) to keep track of animation
|
||||
** weights per-pivot point.
|
||||
*/
|
||||
class NamedPivotMapClass;
|
||||
|
||||
class PivotMapClass : public DynamicVectorClass<float>, public RefCountClass
|
||||
{
|
||||
public:
|
||||
virtual NamedPivotMapClass * As_Named_Pivot_Map() { return 0; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** The NamedPivotMapClass allows us to create HAnimComboDataClass objects with pivot maps without
|
||||
** having to have the HAnim available. Later, when an HAnim is retrieved from the asset manager,
|
||||
** the pivot map can be updated to produce the correct map.
|
||||
*/
|
||||
class NamedPivotMapClass : public PivotMapClass
|
||||
{
|
||||
public:
|
||||
~NamedPivotMapClass(void);
|
||||
|
||||
virtual NamedPivotMapClass * As_Named_Pivot_Map() { return this; }
|
||||
|
||||
// add a name & weight to the arrays
|
||||
void Add(const char *Name, float Weight);
|
||||
|
||||
// configure the base pivot map using the specified tree
|
||||
void Update_Pivot_Map(const HTreeClass *Tree);
|
||||
|
||||
private:
|
||||
|
||||
// This info is packaged into a struct to minimize DynamicVectorClass overhead
|
||||
struct WeightInfoStruct {
|
||||
WeightInfoStruct() : Name(0) {}
|
||||
~WeightInfoStruct() { if(Name) delete [] Name; }
|
||||
|
||||
char *Name;
|
||||
float Weight;
|
||||
|
||||
// operators required for the DynamicVectorClass
|
||||
WeightInfoStruct & operator = (WeightInfoStruct const &that);
|
||||
bool operator == (WeightInfoStruct const &that) const { return &that == this; }
|
||||
bool operator != (WeightInfoStruct const &that) const { return &that != this; }
|
||||
};
|
||||
|
||||
DynamicVectorClass<WeightInfoStruct> WeightInfo;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** The HAnimComboDataClass is used by the new HAnimComboClass to allow for a mix of shared/unshared data
|
||||
** which will allow us to have the anim combo refer to data whereever we wish to put it.
|
||||
*/
|
||||
class HAnimComboDataClass : public AutoPoolClass<HAnimComboDataClass,256> {
|
||||
public:
|
||||
HAnimComboDataClass(bool shared = false);
|
||||
HAnimComboDataClass(const HAnimComboDataClass &);
|
||||
~HAnimComboDataClass(void);
|
||||
|
||||
void Copy(const HAnimComboDataClass *);
|
||||
|
||||
void Clear(void);
|
||||
void Set_HAnim(HAnimClass *motion);
|
||||
void Give_HAnim(HAnimClass *motion) { if(HAnim) HAnim->Release_Ref(); HAnim = motion; } // used for giving this object the reference
|
||||
|
||||
void Set_Frame(float frame) { Frame = frame; }
|
||||
void Set_Weight(float weight) { Weight = weight; }
|
||||
void Set_Pivot_Map(PivotMapClass *map);
|
||||
|
||||
|
||||
HAnimClass * Peek_HAnim(void) const { return HAnim; } // note: does not add reference
|
||||
HAnimClass * Get_HAnim(void) const { if(HAnim) HAnim->Add_Ref(); return HAnim; } // note: does not add reference
|
||||
float Get_Frame(void) const { return Frame; }
|
||||
float Get_Weight(void) const { return Weight; }
|
||||
PivotMapClass * Peek_Pivot_Map(void) const { return PivotMap; }
|
||||
PivotMapClass * Get_Pivot_Map(void) const { if(PivotMap) PivotMap->Add_Ref(); return PivotMap; }
|
||||
bool Is_Shared(void) const { return Shared; }
|
||||
|
||||
void Build_Active_Pivot_Map(void);
|
||||
|
||||
private:
|
||||
|
||||
HAnimClass *HAnim;
|
||||
float Frame;
|
||||
float Weight;
|
||||
PivotMapClass * PivotMap;
|
||||
bool Shared; // this is set to false when the HAnimCombo allocates it
|
||||
};
|
||||
|
||||
/*
|
||||
** defines a combination of animations for blending/mixing
|
||||
*/
|
||||
class HAnimComboClass {
|
||||
|
||||
public:
|
||||
|
||||
HAnimComboClass(void);
|
||||
HAnimComboClass( int num_animations ); // allocates specified number of channels and sets then all to not-shared
|
||||
~HAnimComboClass(void);
|
||||
|
||||
void Clear( void ); // zeros all data
|
||||
|
||||
void Reset( void ); // empties the dynamic vector
|
||||
|
||||
bool Normalize_Weights(void); // Normalizes all weights (returns true if succeeded)
|
||||
int Get_Num_Anims( void ) { return HAnimComboData.Count(); }
|
||||
|
||||
void Set_Motion( int indx, HAnimClass *motion );
|
||||
HAnimClass *Get_Motion( int indx );
|
||||
HAnimClass *Peek_Motion( int indx );
|
||||
|
||||
void Set_Frame( int indx, float frame );
|
||||
float Get_Frame( int indx );
|
||||
|
||||
void Set_Weight( int indx, float weight );
|
||||
float Get_Weight( int indx );
|
||||
|
||||
void Set_Pivot_Weight_Map( int indx, PivotMapClass * map );
|
||||
PivotMapClass * Get_Pivot_Weight_Map( int indx );
|
||||
PivotMapClass * Peek_Pivot_Weight_Map( int indx );
|
||||
|
||||
|
||||
// add an entry to the dynamic vector
|
||||
void Append_Anim_Combo_Data(HAnimComboDataClass * AnimComboData);
|
||||
|
||||
// remove an entry from the vector
|
||||
void Remove_Anim_Combo_Data(HAnimComboDataClass * AnimComboData);
|
||||
|
||||
// retrieve a specific combo data
|
||||
HAnimComboDataClass * Peek_Anim_Combo_Data(int index) { return HAnimComboData[index]; }
|
||||
|
||||
protected:
|
||||
|
||||
DynamicVectorClass<HAnimComboDataClass *> HAnimComboData;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
456
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanimmgr.cpp
Normal file
456
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanimmgr.cpp
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hanimmgr.cpp 1 1/22/01 3:36p Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hanimmgr.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* HAnimManagerClass::HAnimManagerClass -- constructor *
|
||||
* HAnimManagerClass::~HAnimManagerClass -- destructor *
|
||||
* HAnimManagerClass::Load_Anim -- loads a set of motion data from a file *
|
||||
* HAnimManagerClass::Get_Anim_ID -- looks up the ID of a named Hierarchy Animation *
|
||||
* HAnimManagerClass::Get_Anim -- returns a pointer to the specified animation data *
|
||||
* HAnimManagerClass::Get_Anim -- returns a pointer to the specified Hierarchy Animation *
|
||||
* HAnimManagerClass::Free -- de-allocate all memory in use *
|
||||
* HAnimManagerClass::Free_All_Anims -- de-allocate all currently loaded animations *
|
||||
* HAnimManagerClass::Load_Raw_Anim -- Load a raw anim *
|
||||
* HAnimManagerClass::Load_Compressed_Anim -- load a compressed animation *
|
||||
* HAnimManagerClass::Add_Anim -- Adds an externally created animation to the manager *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "hanimmgr.h"
|
||||
#include <string.h>
|
||||
#include "hanim.h"
|
||||
#include "hrawanim.h"
|
||||
#include "hcanim.h"
|
||||
#include "hmorphanim.h"
|
||||
#include "chunkio.h"
|
||||
#include "wwmemlog.h"
|
||||
#include "w3dexclusionlist.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::HAnimManagerClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HAnimManagerClass::HAnimManagerClass(void)
|
||||
{
|
||||
// Create the hash tables
|
||||
AnimPtrTable = W3DNEW HashTableClass( 2048 );
|
||||
MissingAnimTable = W3DNEW HashTableClass( 2048 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::~HAnimManagerClass -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HAnimManagerClass::~HAnimManagerClass(void)
|
||||
{
|
||||
Free_All_Anims();
|
||||
|
||||
delete AnimPtrTable;
|
||||
AnimPtrTable = NULL;
|
||||
|
||||
Reset_Missing();
|
||||
delete MissingAnimTable;
|
||||
MissingAnimTable = NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Load_Anim -- loads a set of motion data from a file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HAnimManagerClass::Load_Anim(ChunkLoadClass & cload)
|
||||
{
|
||||
WWMEMLOG(MEM_ANIMATION);
|
||||
|
||||
switch (cload.Cur_Chunk_ID())
|
||||
{
|
||||
case W3D_CHUNK_ANIMATION:
|
||||
return Load_Raw_Anim(cload);
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_COMPRESSED_ANIMATION:
|
||||
return Load_Compressed_Anim(cload);
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_MORPH_ANIMATION:
|
||||
return Load_Morph_Anim(cload);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Load_Morph_Anim -- Load a HMorphAnimClass *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/23/2000 pds : Created. *
|
||||
*=============================================================================================*/
|
||||
int HAnimManagerClass::Load_Morph_Anim(ChunkLoadClass & cload)
|
||||
{
|
||||
HMorphAnimClass * newanim = W3DNEW HMorphAnimClass;
|
||||
|
||||
if (newanim == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
SET_REF_OWNER( newanim );
|
||||
|
||||
if (newanim->Load_W3D(cload) != HMorphAnimClass::OK) {
|
||||
// load failed!
|
||||
newanim->Release_Ref();
|
||||
goto Error;
|
||||
} else if (Peek_Anim(newanim->Get_Name()) != NULL) {
|
||||
// duplicate exists!
|
||||
newanim->Release_Ref(); // Release the one we just loaded
|
||||
goto Error;
|
||||
} else {
|
||||
Add_Anim( newanim );
|
||||
newanim->Release_Ref();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Load_Raw_Anim -- Load a raw anim *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/23/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
int HAnimManagerClass::Load_Raw_Anim(ChunkLoadClass & cload)
|
||||
{
|
||||
HRawAnimClass * newanim = W3DNEW HRawAnimClass;
|
||||
|
||||
if (newanim == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
SET_REF_OWNER( newanim );
|
||||
|
||||
if (newanim->Load_W3D(cload) != HRawAnimClass::OK) {
|
||||
// load failed!
|
||||
newanim->Release_Ref();
|
||||
goto Error;
|
||||
} else if (Peek_Anim(newanim->Get_Name()) != NULL) {
|
||||
// duplicate exists!
|
||||
newanim->Release_Ref(); // Release the one we just loaded
|
||||
goto Error;
|
||||
} else {
|
||||
Add_Anim( newanim );
|
||||
newanim->Release_Ref();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Load_Compressed_Anim -- load a compressed animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 5/23/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
int HAnimManagerClass::Load_Compressed_Anim(ChunkLoadClass & cload)
|
||||
{
|
||||
HCompressedAnimClass * newanim = W3DNEW HCompressedAnimClass;
|
||||
|
||||
if (newanim == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
SET_REF_OWNER( newanim );
|
||||
|
||||
if (newanim->Load_W3D(cload) != HCompressedAnimClass::OK) {
|
||||
// load failed!
|
||||
newanim->Release_Ref();
|
||||
goto Error;
|
||||
} else if (Peek_Anim(newanim->Get_Name()) != NULL) {
|
||||
// duplicate exists!
|
||||
newanim->Release_Ref(); // Release the one we just loaded
|
||||
goto Error;
|
||||
} else {
|
||||
Add_Anim( newanim );
|
||||
newanim->Release_Ref();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Peek_Anim -- returns a pointer to the specified animation data *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HAnimClass * HAnimManagerClass::Peek_Anim(const char * name)
|
||||
{
|
||||
return (HAnimClass*)AnimPtrTable->Find( name );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Get_Anim -- returns a pointer to the specified animation data *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HAnimClass * HAnimManagerClass::Get_Anim(const char * name)
|
||||
{
|
||||
HAnimClass * anim = Peek_Anim( name );
|
||||
if ( anim != NULL ) {
|
||||
anim->Add_Ref();
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Free_All_Anims -- de-allocate all currently loaded animations *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HAnimManagerClass::Free_All_Anims(void)
|
||||
{
|
||||
// Make an iterator, and release all ptrs
|
||||
HAnimManagerIterator it( *this );
|
||||
for( it.First(); !it.Is_Done(); it.Next() ) {
|
||||
HAnimClass *anim = it.Get_Current_Anim();
|
||||
anim->Release_Ref();
|
||||
}
|
||||
|
||||
// Then clear the table
|
||||
AnimPtrTable->Reset();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Free_All_Anims_With_Exclusion_List -- release animations not in the list *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/12/2002 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HAnimManagerClass::Free_All_Anims_With_Exclusion_List(const W3DExclusionListClass & exclusion_list)
|
||||
{
|
||||
// Remove and Release_Ref any animation not in the exclusion list.
|
||||
HAnimManagerIterator it( *this );
|
||||
for( it.First(); !it.Is_Done(); it.Next() ) {
|
||||
HAnimClass *anim = it.Get_Current_Anim();
|
||||
|
||||
if ((anim->Num_Refs() == 1) && (exclusion_list.Is_Excluded(anim) == false)) {
|
||||
//WWDEBUG_SAY(("deleting HAnim %s\n",anim->Get_Name()));
|
||||
AnimPtrTable->Remove(anim);
|
||||
anim->Release_Ref();
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// WWDEBUG_SAY(("keeping HAnim %s (ref %d)\n",anim->Get_Name(),anim->Num_Refs()));
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Create_Asset_List -- Create a list of the W3D files that are loaded *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/12/2002 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HAnimManagerClass::Create_Asset_List(DynamicVectorClass<StringClass> & exclusion_list)
|
||||
{
|
||||
HAnimManagerIterator it( *this );
|
||||
for( it.First(); !it.Is_Done(); it.Next() ) {
|
||||
HAnimClass *anim = it.Get_Current_Anim();
|
||||
|
||||
// File that this anim came from should be the name after the '.'
|
||||
// Anims are named in the format: <skeleton>.<animname>
|
||||
const char * anim_name = anim->Get_Name();
|
||||
char * filename = strchr(anim_name,'.');
|
||||
if (filename != NULL) {
|
||||
exclusion_list.Add(StringClass(filename+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimManagerClass::Add_Anim -- Adds an externally created animation to the manager *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/31/2000 PDS : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HAnimManagerClass::Add_Anim(HAnimClass *new_anim)
|
||||
{
|
||||
WWASSERT (new_anim != NULL);
|
||||
|
||||
// Increment the refcount on the W3DNEW animation and add it to our table.
|
||||
new_anim->Add_Ref ();
|
||||
AnimPtrTable->Add( new_anim );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Missing Anims
|
||||
**
|
||||
** The idea here, allow the system to register which anims are determined to be missing
|
||||
** so that if they are asked for again, we can quickly return NULL, without searching the
|
||||
** disk again.
|
||||
*/
|
||||
void HAnimManagerClass::Register_Missing( const char * name )
|
||||
{
|
||||
MissingAnimTable->Add( W3DNEW MissingAnimClass( name ) );
|
||||
}
|
||||
|
||||
bool HAnimManagerClass::Is_Missing( const char * name )
|
||||
{
|
||||
return ( MissingAnimTable->Find( name ) != NULL );
|
||||
}
|
||||
|
||||
void HAnimManagerClass::Reset_Missing( void )
|
||||
{
|
||||
// Make an iterator, and release all ptrs
|
||||
HashTableIteratorClass it( *MissingAnimTable );
|
||||
for( it.First(); !it.Is_Done(); it.Next() ) {
|
||||
MissingAnimClass *missing = (MissingAnimClass *)it.Get_Current();
|
||||
delete missing;
|
||||
}
|
||||
|
||||
// Then clear the table
|
||||
MissingAnimTable->Reset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Iterator converter from HashableClass to HAnimClass
|
||||
*/
|
||||
HAnimClass * HAnimManagerIterator::Get_Current_Anim( void )
|
||||
{
|
||||
return (HAnimClass *)Get_Current();
|
||||
}
|
||||
|
||||
117
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanimmgr.h
Normal file
117
Generals/Code/Libraries/Source/WWVegas/WW3D2/hanimmgr.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hanimmgr.h 1 1/22/01 3:36p Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hanimmgr.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HANIMMGR_H
|
||||
#define HANIMMGR_H
|
||||
|
||||
#include "always.h"
|
||||
#include "hash.h"
|
||||
#include "wwstring.h"
|
||||
#include "vector.h"
|
||||
|
||||
class HAnimClass;
|
||||
class ChunkLoadClass;
|
||||
class W3DExclusionListClass;
|
||||
|
||||
/*
|
||||
** An entry for a table of anims not found, so we can quickly determine their loss
|
||||
*/
|
||||
class MissingAnimClass : public HashableClass {
|
||||
|
||||
public:
|
||||
MissingAnimClass( const char * name ) : Name( name ) {}
|
||||
virtual ~MissingAnimClass( void ) {}
|
||||
|
||||
virtual const char * Get_Key( void ) { return Name; }
|
||||
|
||||
private:
|
||||
StringClass Name;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
HAnimManagerClass
|
||||
|
||||
This class is used to keep track of all of the motion data.
|
||||
*/
|
||||
|
||||
class HAnimManagerClass
|
||||
{
|
||||
|
||||
public:
|
||||
HAnimManagerClass(void);
|
||||
~HAnimManagerClass(void);
|
||||
|
||||
int Load_Anim(ChunkLoadClass & cload);
|
||||
HAnimClass * Get_Anim(const char * name);
|
||||
HAnimClass * Peek_Anim(const char * name);
|
||||
bool Add_Anim(HAnimClass *new_anim);
|
||||
void Free_All_Anims(void);
|
||||
void Free_All_Anims_With_Exclusion_List(const W3DExclusionListClass & exclusion_list);
|
||||
void Create_Asset_List(DynamicVectorClass<StringClass> & exclusion_list);
|
||||
|
||||
void Register_Missing( const char * name );
|
||||
bool Is_Missing( const char * name );
|
||||
void Reset_Missing( void );
|
||||
|
||||
private:
|
||||
int Load_Compressed_Anim(ChunkLoadClass & cload);
|
||||
int Load_Raw_Anim(ChunkLoadClass & cload);
|
||||
int Load_Morph_Anim(ChunkLoadClass & cload);
|
||||
|
||||
HashTableClass * AnimPtrTable;
|
||||
HashTableClass * MissingAnimTable;
|
||||
|
||||
friend class HAnimManagerIterator;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** An Iterator to get to all loaded HAnims in a HAnimManager
|
||||
*/
|
||||
class HAnimManagerIterator : public HashTableIteratorClass {
|
||||
public:
|
||||
HAnimManagerIterator( HAnimManagerClass & manager ) : HashTableIteratorClass( *manager.AnimPtrTable ) {}
|
||||
HAnimClass * Get_Current_Anim( void );
|
||||
};
|
||||
|
||||
#endif
|
||||
710
Generals/Code/Libraries/Source/WWVegas/WW3D2/hcanim.cpp
Normal file
710
Generals/Code/Libraries/Source/WWVegas/WW3D2/hcanim.cpp
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hcanim.cpp 3 6/29/01 6:41p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hcanim.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:50p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* NodeMotionStruct::NodeMotionStruct -- constructor *
|
||||
* NodeMotionStruct::~NodeMotionStruct -- destructor *
|
||||
* HCompressedAnimClass::HCompressedAnimClass -- constructor *
|
||||
* HCompressedAnimClass::~HCompressedAnimClass -- Destructor *
|
||||
* HCompressedAnimClass::Free -- De-allocates all memory in use *
|
||||
* HCompressedAnimClass::Load -- Loads hierarchy animation from a file *
|
||||
* HCompressedAnimClass::read_channel -- Reads in a single channel of motion *
|
||||
* HCompressedAnimClass::add_channel -- Adds a motion channel to the animation *
|
||||
* HCompressedAnimClass::Get_Translation -- returns the translation vector for the given fram*
|
||||
* HCompressedAnimClass::Get_Orientation -- returns a quaternion for the orientation of the p*
|
||||
* HCompressedAnimClass::read_bit_channel -- read a bit channel from the file *
|
||||
* HCompressedAnimClass::add_bit_channel -- install a bit channel into the animation *
|
||||
* HCompressedAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "hcanim.h"
|
||||
#include "assetmgr.h"
|
||||
#include "htree.h"
|
||||
#include "motchan.h"
|
||||
#include "chunkio.h"
|
||||
#include "w3d_file.h"
|
||||
#include "wwdebug.h"
|
||||
#include <string.h>
|
||||
#include <nstrdup.h>
|
||||
|
||||
|
||||
struct NodeCompressedMotionStruct
|
||||
{
|
||||
NodeCompressedMotionStruct();
|
||||
~NodeCompressedMotionStruct();
|
||||
|
||||
void SetFlavor(int flavor) {Flavor = flavor;}
|
||||
|
||||
int Flavor;
|
||||
|
||||
union {
|
||||
struct {
|
||||
TimeCodedMotionChannelClass * X;
|
||||
TimeCodedMotionChannelClass * Y;
|
||||
TimeCodedMotionChannelClass * Z;
|
||||
TimeCodedMotionChannelClass * Q;
|
||||
} tc;
|
||||
|
||||
struct {
|
||||
AdaptiveDeltaMotionChannelClass * X;
|
||||
AdaptiveDeltaMotionChannelClass * Y;
|
||||
AdaptiveDeltaMotionChannelClass * Z;
|
||||
AdaptiveDeltaMotionChannelClass * Q;
|
||||
|
||||
} ad;
|
||||
|
||||
struct {
|
||||
void * X;
|
||||
void * Y;
|
||||
void * Z;
|
||||
void * Q;
|
||||
} vd;
|
||||
};
|
||||
|
||||
|
||||
TimeCodedBitChannelClass * Vis;
|
||||
};
|
||||
|
||||
/***********************************************************************************************
|
||||
* NodeCompressedMotionStruct::NodeCompressedMotionStruct -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
NodeCompressedMotionStruct::NodeCompressedMotionStruct() :
|
||||
Vis(NULL)
|
||||
{
|
||||
vd.X = NULL;
|
||||
vd.Y = NULL;
|
||||
vd.Z = NULL;
|
||||
vd.Q = NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* NodeCompressedMotionStruct::~NodeCompressedMotionStruct -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/23/98 GTH : Created. *
|
||||
* 02/02/00 JGA : Compressed *
|
||||
*=============================================================================================*/
|
||||
NodeCompressedMotionStruct::~NodeCompressedMotionStruct()
|
||||
{
|
||||
// Needs to be changed to call the correct destructors
|
||||
|
||||
switch (Flavor) {
|
||||
case ANIM_FLAVOR_TIMECODED:
|
||||
if (tc.X) delete tc.X;
|
||||
if (tc.Y) delete tc.Y;
|
||||
if (tc.Z) delete tc.Z;
|
||||
if (tc.Q) delete tc.Q;
|
||||
break;
|
||||
case ANIM_FLAVOR_ADAPTIVE_DELTA:
|
||||
if (ad.X) delete ad.X;
|
||||
if (ad.Y) delete ad.Y;
|
||||
if (ad.Z) delete ad.Z;
|
||||
if (ad.Q) delete ad.Q;
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0); // unknown flavor
|
||||
break;
|
||||
}
|
||||
|
||||
if (Vis) delete Vis;
|
||||
|
||||
} // ~NodeCompressedMotionStruct
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::HCompressedAnimClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HCompressedAnimClass::HCompressedAnimClass(void) :
|
||||
NumFrames(0),
|
||||
NumNodes(0),
|
||||
Flavor(0),
|
||||
FrameRate(0),
|
||||
NodeMotion(NULL)
|
||||
{
|
||||
memset(Name,0,W3D_NAME_LEN);
|
||||
memset(HierarchyName,0,W3D_NAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::~HCompressedAnimClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HCompressedAnimClass::~HCompressedAnimClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Free -- De-allocates all memory in use *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::Free(void)
|
||||
{
|
||||
if (NodeMotion != NULL) {
|
||||
delete[] NodeMotion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Load -- Loads hierarchy animation from a file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload)
|
||||
{
|
||||
int i = 0;
|
||||
/*
|
||||
** First make sure we release any memory in use
|
||||
*/
|
||||
Free();
|
||||
|
||||
/*
|
||||
** Open the first chunk, it should be the animation header
|
||||
*/
|
||||
if (!cload.Open_Chunk()) return LOAD_ERROR;
|
||||
|
||||
if (cload.Cur_Chunk_ID() != W3D_CHUNK_COMPRESSED_ANIMATION_HEADER) {
|
||||
// ERROR: Expected Animation Header!
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
|
||||
W3dCompressedAnimHeaderStruct aheader;
|
||||
if (cload.Read(&aheader,sizeof(W3dAnimHeaderStruct)) != sizeof(W3dAnimHeaderStruct)) {
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
|
||||
cload.Close_Chunk();
|
||||
|
||||
strcpy(Name,aheader.HierarchyName);
|
||||
strcat(Name,".");
|
||||
strcat(Name,aheader.Name);
|
||||
|
||||
// TSS chasing crash bug 05/26/99
|
||||
WWASSERT(HierarchyName != NULL);
|
||||
WWASSERT(aheader.HierarchyName != NULL);
|
||||
WWASSERT(sizeof(HierarchyName) >= W3D_NAME_LEN);
|
||||
strncpy(HierarchyName,aheader.HierarchyName,W3D_NAME_LEN);
|
||||
|
||||
HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
|
||||
if (base_pose == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
NumNodes = base_pose->Num_Pivots();
|
||||
|
||||
NumFrames = aheader.NumFrames;
|
||||
FrameRate = aheader.FrameRate;
|
||||
Flavor = aheader.Flavor;
|
||||
|
||||
// Just for now
|
||||
WWASSERT((Flavor == ANIM_FLAVOR_TIMECODED)||(Flavor == ANIM_FLAVOR_ADAPTIVE_DELTA));
|
||||
|
||||
NodeMotion = W3DNEWARRAY NodeCompressedMotionStruct[ NumNodes ];
|
||||
if (NodeMotion == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// Initialize Flavor
|
||||
for (i=0; i<NumNodes; i++) {
|
||||
NodeMotion[i].SetFlavor(Flavor);
|
||||
}
|
||||
|
||||
/*
|
||||
** Now, read in all of the other chunks (motion channels).
|
||||
*/
|
||||
TimeCodedMotionChannelClass * tc_chan;
|
||||
AdaptiveDeltaMotionChannelClass * ad_chan;
|
||||
TimeCodedBitChannelClass * newbitchan;
|
||||
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch (cload.Cur_Chunk_ID()) {
|
||||
|
||||
case W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL:
|
||||
|
||||
switch ( Flavor ) {
|
||||
|
||||
case ANIM_FLAVOR_TIMECODED:
|
||||
|
||||
if (!read_channel(cload,&tc_chan)) {
|
||||
goto Error;
|
||||
}
|
||||
if (tc_chan->Get_Pivot() < NumNodes) {
|
||||
add_channel(tc_chan);
|
||||
} else {
|
||||
// PWG 12-14-98: we have only allocated space for NumNode pivots.
|
||||
// If we have an index thats equal or higher than NumNode we are
|
||||
// gonna trash memory. Boy will we trash memory.
|
||||
// GTH 09-25-2000: print a warning and survive this error
|
||||
delete tc_chan;
|
||||
WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ANIM_FLAVOR_ADAPTIVE_DELTA:
|
||||
if (!read_channel(cload,&ad_chan)) {
|
||||
goto Error;
|
||||
}
|
||||
if (ad_chan->Get_Pivot() < NumNodes) {
|
||||
add_channel(ad_chan);
|
||||
} else {
|
||||
// PWG 12-14-98: we have only allocated space for NumNode pivots.
|
||||
// If we have an index thats equal or higher than NumNode we are
|
||||
// gonna trash memory. Boy will we trash memory.
|
||||
// GTH 09-25-2000: print a warning and survive this error
|
||||
delete ad_chan;
|
||||
WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_COMPRESSED_BIT_CHANNEL:
|
||||
if (!read_bit_channel(cload,&newbitchan)) {
|
||||
goto Error;
|
||||
}
|
||||
if (newbitchan->Get_Pivot() < NumNodes) {
|
||||
add_bit_channel(newbitchan);
|
||||
} else {
|
||||
// PWG 12-14-98: we have only allocated space for NumNode pivots.
|
||||
// If we have an index thats equal or higher than NumNode we are
|
||||
// gonna trash memory. Boy will we trash memory.
|
||||
// GTH 09-25-2000: print a warning and survive this error
|
||||
delete newbitchan;
|
||||
WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!\r\n",Name));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
Error:
|
||||
|
||||
Free();
|
||||
return LOAD_ERROR;
|
||||
|
||||
} // Load_W3D
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::read_channel -- Reads in a single channel of motion *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,TimeCodedMotionChannelClass * * newchan)
|
||||
{
|
||||
*newchan = W3DNEW TimeCodedMotionChannelClass;
|
||||
bool result = (*newchan)->Load_W3D(cload);
|
||||
|
||||
return result;
|
||||
|
||||
} // read_channel
|
||||
|
||||
bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,AdaptiveDeltaMotionChannelClass * * newchan)
|
||||
{
|
||||
*newchan = W3DNEW AdaptiveDeltaMotionChannelClass;
|
||||
bool result = (*newchan)->Load_W3D(cload);
|
||||
|
||||
return result;
|
||||
|
||||
} // read_channel
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::add_channel -- Adds a motion channel to the animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::add_channel(TimeCodedMotionChannelClass * newchan)
|
||||
{
|
||||
int idx = newchan->Get_Pivot();
|
||||
|
||||
switch (newchan->Get_Type())
|
||||
{
|
||||
case ANIM_CHANNEL_X:
|
||||
NodeMotion[idx].tc.X = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Y:
|
||||
NodeMotion[idx].tc.Y = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Z:
|
||||
NodeMotion[idx].tc.Z = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Q:
|
||||
NodeMotion[idx].tc.Q = newchan;
|
||||
break;
|
||||
}
|
||||
|
||||
} // add_channel
|
||||
|
||||
void HCompressedAnimClass::add_channel(AdaptiveDeltaMotionChannelClass * newchan)
|
||||
{
|
||||
int idx = newchan->Get_Pivot();
|
||||
|
||||
switch (newchan->Get_Type())
|
||||
{
|
||||
case ANIM_CHANNEL_X:
|
||||
NodeMotion[idx].ad.X = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Y:
|
||||
NodeMotion[idx].ad.Y = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Z:
|
||||
NodeMotion[idx].ad.Z = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Q:
|
||||
NodeMotion[idx].ad.Q = newchan;
|
||||
break;
|
||||
}
|
||||
|
||||
} // add_channel
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::read_bit_channel -- read a bit channel from the file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HCompressedAnimClass::read_bit_channel(ChunkLoadClass & cload,TimeCodedBitChannelClass * * newchan)
|
||||
{
|
||||
*newchan = W3DNEW TimeCodedBitChannelClass;
|
||||
bool result = (*newchan)->Load_W3D(cload);
|
||||
|
||||
return result;
|
||||
|
||||
} // read_bit_channel
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::add_bit_channel -- install a bit channel into the animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::add_bit_channel(TimeCodedBitChannelClass * newchan)
|
||||
{
|
||||
int idx = newchan->Get_Pivot();
|
||||
|
||||
switch (newchan->Get_Type())
|
||||
{
|
||||
case BIT_CHANNEL_VIS:
|
||||
NodeMotion[idx].Vis = newchan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Get_Translation -- returns the translation vector for the given frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::Get_Translation( Vector3& trans, int pividx, float frame ) const
|
||||
{
|
||||
struct NodeCompressedMotionStruct * motion = &NodeMotion[pividx];
|
||||
|
||||
trans=Vector3(0,0,0);
|
||||
|
||||
switch(Flavor) {
|
||||
case ANIM_FLAVOR_TIMECODED:
|
||||
if (motion->tc.X) motion->tc.X->Get_Vector(frame, &(trans[0]));
|
||||
if (motion->tc.Y) motion->tc.Y->Get_Vector(frame, &(trans[1]));
|
||||
if (motion->tc.Z) motion->tc.Z->Get_Vector(frame, &(trans[2]));
|
||||
break;
|
||||
case ANIM_FLAVOR_ADAPTIVE_DELTA:
|
||||
if (motion->ad.X) motion->ad.X->Get_Vector(frame, &(trans[0]));
|
||||
if (motion->ad.Y) motion->ad.Y->Get_Vector(frame, &(trans[1]));
|
||||
if (motion->ad.Z) motion->ad.Z->Get_Vector(frame, &(trans[2]));
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0); // unknown flavor
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Get_Orientation -- returns a quaternion for the orientation of the *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::Get_Orientation(Quaternion& q, int pividx,float frame) const
|
||||
{
|
||||
switch(Flavor) {
|
||||
case ANIM_FLAVOR_TIMECODED:
|
||||
if (NodeMotion[pividx].tc.Q) q = NodeMotion[pividx].tc.Q->Get_QuatVector(frame);
|
||||
else q.Make_Identity();
|
||||
break;
|
||||
case ANIM_FLAVOR_ADAPTIVE_DELTA:
|
||||
if (NodeMotion[pividx].ad.Q) q = NodeMotion[pividx].ad.Q->Get_QuatVector(frame);
|
||||
else q.Make_Identity();
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0); // unknown flavor
|
||||
break;
|
||||
}
|
||||
} // Get_Orientation
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Get_Transform -- returns the transform matrix for the given frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HCompressedAnimClass::Get_Transform( Matrix3D& mtx, int pividx, float frame ) const
|
||||
{
|
||||
struct NodeCompressedMotionStruct * motion = &NodeMotion[pividx];
|
||||
|
||||
switch(Flavor) {
|
||||
case ANIM_FLAVOR_TIMECODED:
|
||||
if (NodeMotion[pividx].tc.Q) {
|
||||
Quaternion q;
|
||||
q = NodeMotion[pividx].tc.Q->Get_QuatVector(frame);
|
||||
::Build_Matrix3D(q,mtx);
|
||||
}
|
||||
else mtx.Make_Identity();
|
||||
if (motion->tc.X) motion->tc.X->Get_Vector(frame, &(mtx[0][3]));
|
||||
if (motion->tc.Y) motion->tc.Y->Get_Vector(frame, &(mtx[1][3]));
|
||||
if (motion->tc.Z) motion->tc.Z->Get_Vector(frame, &(mtx[2][3]));
|
||||
break;
|
||||
case ANIM_FLAVOR_ADAPTIVE_DELTA:
|
||||
if (NodeMotion[pividx].ad.Q) {
|
||||
Quaternion q;
|
||||
q = NodeMotion[pividx].ad.Q->Get_QuatVector(frame);
|
||||
::Build_Matrix3D(q,mtx);
|
||||
}
|
||||
else mtx.Make_Identity();
|
||||
|
||||
if (motion->ad.X) motion->ad.X->Get_Vector(frame, &(mtx[0][3]));
|
||||
if (motion->ad.Y) motion->ad.Y->Get_Vector(frame, &(mtx[1][3]));
|
||||
if (motion->ad.Z) motion->ad.Z->Get_Vector(frame, &(mtx[2][3]));
|
||||
break;
|
||||
default:
|
||||
WWASSERT(0); // unknown flavor
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HCompressedAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HCompressedAnimClass::Get_Visibility(int pividx,float frame)
|
||||
{
|
||||
|
||||
if (NodeMotion[pividx].Vis != NULL) {
|
||||
return (NodeMotion[pividx].Vis->Get_Bit((int)frame) == 1);
|
||||
}
|
||||
|
||||
|
||||
// default to always visible...
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HAnimClass::Is_Node_Motion_Present -- return true if there is motion defined for this frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/23/99 EHC : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HCompressedAnimClass::Is_Node_Motion_Present(int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
|
||||
if (NodeMotion[pividx].vd.X != NULL) return true;
|
||||
if (NodeMotion[pividx].vd.Y != NULL) return true;
|
||||
if (NodeMotion[pividx].vd.Z != NULL) return true;
|
||||
if (NodeMotion[pividx].vd.Q != NULL) return true;
|
||||
if (NodeMotion[pividx].Vis != NULL) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HCompressedAnimClass::Has_X_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].vd.X != NULL;
|
||||
}
|
||||
|
||||
bool HCompressedAnimClass::Has_Y_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].vd.Y != NULL;
|
||||
}
|
||||
|
||||
bool HCompressedAnimClass::Has_Z_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].vd.Z != NULL;
|
||||
}
|
||||
|
||||
bool HCompressedAnimClass::Has_Rotation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].vd.Q != NULL;
|
||||
}
|
||||
|
||||
bool HCompressedAnimClass::Has_Visibility (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].Vis != NULL;
|
||||
}
|
||||
|
||||
|
||||
// eof - hcanim.cpp
|
||||
139
Generals/Code/Libraries/Source/WWVegas/WW3D2/hcanim.h
Normal file
139
Generals/Code/Libraries/Source/WWVegas/WW3D2/hcanim.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/hcanim.h 2 6/29/01 6:41p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/hcanim.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:35p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HCANIM_H
|
||||
#define HCANIM_H
|
||||
|
||||
#include "always.h"
|
||||
#include "quat.h"
|
||||
#include "refcount.h"
|
||||
#include "w3d_file.h"
|
||||
#include "slist.h"
|
||||
#include "vector.h"
|
||||
#include "hanim.h"
|
||||
|
||||
struct NodeCompressedMotionStruct;
|
||||
class TimeCodedMotionChannelClass;
|
||||
class TimeCodedBitChannelClass;
|
||||
class AdaptiveDeltaMotionChannelClass;
|
||||
class HTreeClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
|
||||
Hierarchy Compressed Animation Class
|
||||
|
||||
Stores motion data to be applied to a HierarchyTree. Each frame
|
||||
of the motion contains deltas from the HierarchyTree's base position
|
||||
to the desired position.
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
class HCompressedAnimClass : public HAnimClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
OK,
|
||||
LOAD_ERROR
|
||||
};
|
||||
|
||||
HCompressedAnimClass(void);
|
||||
~HCompressedAnimClass(void);
|
||||
|
||||
int Load_W3D(ChunkLoadClass & cload);
|
||||
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
const char * Get_HName(void) const { return HierarchyName; }
|
||||
int Get_Num_Frames(void) { return NumFrames; }
|
||||
float Get_Frame_Rate() { return FrameRate; }
|
||||
float Get_Total_Time() { return (float)NumFrames / FrameRate; }
|
||||
int Get_Flavor() { return Flavor; }
|
||||
|
||||
// Vector3 Get_Translation(int pividx,float frame);
|
||||
// Quaternion Get_Orientation(int pividx,float frame);
|
||||
void Get_Translation(Vector3& translation, int pividx,float frame) const;
|
||||
void Get_Orientation(Quaternion& orientation, int pividx,float frame) const;
|
||||
void Get_Transform(Matrix3D& transform, int pividx,float frame) const;
|
||||
bool Get_Visibility(int pividx,float frame);
|
||||
|
||||
bool Is_Node_Motion_Present(int pividx);
|
||||
int Get_Num_Pivots(void) const { return NumNodes; }
|
||||
|
||||
// Methods that test the presence of a certain motion channel.
|
||||
bool Has_X_Translation (int pividx);
|
||||
bool Has_Y_Translation (int pividx);
|
||||
bool Has_Z_Translation (int pividx);
|
||||
bool Has_Rotation (int pividx);
|
||||
bool Has_Visibility (int pividx);
|
||||
|
||||
private:
|
||||
|
||||
char Name[2*W3D_NAME_LEN];
|
||||
char HierarchyName[W3D_NAME_LEN];
|
||||
|
||||
int NumFrames;
|
||||
int NumNodes;
|
||||
int Flavor;
|
||||
float FrameRate;
|
||||
|
||||
NodeCompressedMotionStruct * NodeMotion;
|
||||
|
||||
void Free(void);
|
||||
bool read_channel(ChunkLoadClass & cload,TimeCodedMotionChannelClass * * newchan);
|
||||
bool read_channel(ChunkLoadClass & cload,AdaptiveDeltaMotionChannelClass * * newchan);
|
||||
void add_channel(TimeCodedMotionChannelClass * newchan);
|
||||
void add_channel(AdaptiveDeltaMotionChannelClass * newchan);
|
||||
|
||||
|
||||
bool read_bit_channel(ChunkLoadClass & cload,TimeCodedBitChannelClass * * newchan);
|
||||
void add_bit_channel(TimeCodedBitChannelClass * newchan);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // hcanim.h
|
||||
|
||||
3645
Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp
Normal file
3645
Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
395
Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.h
Normal file
395
Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.h
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hlod.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/25/01 1:37p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HLOD_H
|
||||
#define HLOD_H
|
||||
|
||||
#ifndef ANIMOBJ_H
|
||||
#include "animobj.h"
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR_H
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
#ifndef SNAPPTS_H
|
||||
#include "snappts.h"
|
||||
#endif
|
||||
|
||||
#ifndef PROTO_H
|
||||
#include "proto.h"
|
||||
#endif
|
||||
|
||||
#ifndef W3DERR_H
|
||||
#include "w3derr.h"
|
||||
#endif
|
||||
|
||||
#ifndef __PROXY_H
|
||||
#include "proxy.h"
|
||||
#endif
|
||||
|
||||
|
||||
class DistLODClass;
|
||||
class HModelClass;
|
||||
class HLodDefClass;
|
||||
class HModelDefClass;
|
||||
class ProxyArrayClass;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
HLodClass
|
||||
|
||||
This is an hierarchical, animatable level-of-detail model.
|
||||
|
||||
*/
|
||||
class HLodClass : public W3DMPO, public Animatable3DObjClass
|
||||
{
|
||||
W3DMPO_GLUE(HLodClass)
|
||||
public:
|
||||
|
||||
HLodClass(const HLodClass & src);
|
||||
HLodClass(const char * name,RenderObjClass ** lods,int count);
|
||||
HLodClass(const HLodDefClass & def);
|
||||
HLodClass(const HModelDefClass & def);
|
||||
|
||||
HLodClass & operator = (const HLodClass &);
|
||||
virtual ~HLodClass(void);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Cloning and Identification
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual RenderObjClass * Clone(void) const;
|
||||
virtual int Class_ID(void) const { return CLASSID_HLOD; }
|
||||
virtual int Get_Num_Polys(void) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// HLod Interface - Editing and information
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Max_Screen_Size(int lod_index, float size);
|
||||
virtual float Get_Max_Screen_Size(int lod_index) const;
|
||||
|
||||
virtual int Get_Lod_Count(void) const;
|
||||
virtual int Get_Lod_Model_Count (int lod_index) const;
|
||||
virtual RenderObjClass * Peek_Lod_Model (int lod_index, int model_index) const;
|
||||
virtual RenderObjClass * Get_Lod_Model (int lod_index, int model_index) const;
|
||||
virtual int Get_Lod_Model_Bone (int lod_index, int model_index) const;
|
||||
virtual int Get_Additional_Model_Count(void) const;
|
||||
virtual RenderObjClass * Peek_Additional_Model (int model_index) const;
|
||||
virtual RenderObjClass * Get_Additional_Model (int model_index) const;
|
||||
virtual int Get_Additional_Model_Bone (int model_index) const;
|
||||
|
||||
virtual bool Is_NULL_Lod_Included (void) const;
|
||||
virtual void Include_NULL_Lod (bool include = true);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Proxy interface
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Get_Proxy_Count (void) const;
|
||||
virtual bool Get_Proxy (int index, ProxyClass &proxy) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Rendering
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Render(RenderInfoClass & rinfo);
|
||||
virtual void Special_Render(SpecialRenderInfoClass & rinfo);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - "Scene Graph"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Transform(const Matrix3D &m);
|
||||
virtual void Set_Position(const Vector3 &v);
|
||||
|
||||
virtual void Notify_Added(SceneClass * scene);
|
||||
virtual void Notify_Removed(SceneClass * scene);
|
||||
|
||||
virtual int Get_Num_Sub_Objects(void) const;
|
||||
virtual RenderObjClass * Get_Sub_Object(int index) const;
|
||||
virtual int Add_Sub_Object(RenderObjClass * subobj);
|
||||
virtual int Remove_Sub_Object(RenderObjClass * robj);
|
||||
|
||||
virtual int Get_Num_Sub_Objects_On_Bone(int boneindex) const;
|
||||
virtual RenderObjClass * Get_Sub_Object_On_Bone(int index,int boneindex) const;
|
||||
virtual int Get_Sub_Object_Bone_Index(RenderObjClass * subobj) const;
|
||||
virtual int Get_Sub_Object_Bone_Index(int LodIndex, int ModelIndex) const;
|
||||
virtual int Add_Sub_Object_To_Bone(RenderObjClass * subobj,int bone_index);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Hierarchical Animation
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Set_Animation(void);
|
||||
virtual void Set_Animation( HAnimClass * motion,
|
||||
float frame, int anim_mode = ANIM_MODE_MANUAL);
|
||||
virtual void Set_Animation( HAnimClass * motion0,
|
||||
float frame0,
|
||||
HAnimClass * motion1,
|
||||
float frame1,
|
||||
float percentage);
|
||||
virtual void Set_Animation( HAnimComboClass * anim_combo);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Collision Detection, Ray Tracing
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual bool Cast_Ray(RayCollisionTestClass & raytest);
|
||||
virtual bool Cast_AABox(AABoxCollisionTestClass & boxtest);
|
||||
virtual bool Cast_OBBox(OBBoxCollisionTestClass & boxtest);
|
||||
virtual bool Intersect_AABox(AABoxIntersectionTestClass & boxtest);
|
||||
virtual bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Predictive LOD
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Prepare_LOD(CameraClass &camera);
|
||||
virtual void Recalculate_Static_LOD_Factors(void);
|
||||
virtual void Increment_LOD(void);
|
||||
virtual void Decrement_LOD(void);
|
||||
virtual float Get_Cost(void) const;
|
||||
virtual float Get_Value(void) const;
|
||||
virtual float Get_Post_Increment_Value(void) const;
|
||||
virtual void Set_LOD_Level(int lod);
|
||||
virtual int Get_LOD_Level(void) const;
|
||||
virtual int Get_LOD_Count(void) const;
|
||||
virtual void Set_LOD_Bias(float bias);
|
||||
virtual int Calculate_Cost_Value_Arrays(float screen_area, float *values, float *costs) const;
|
||||
virtual RenderObjClass * Get_Current_LOD(void);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Bounding Volumes
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual const SphereClass & Get_Bounding_Sphere(void) const;
|
||||
virtual const AABoxClass & Get_Bounding_Box(void) const;
|
||||
virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const;
|
||||
virtual void Get_Obj_Space_Bounding_Box(AABoxClass & box) const;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Decals
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual void Create_Decal(DecalGeneratorClass * generator);
|
||||
virtual void Delete_Decal(uint32 decal_id);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Render Object Interface - Attributes, Options, Properties, etc
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// virtual void Set_Texture_Reduction_Factor(float trf);
|
||||
virtual void Scale(float scale);
|
||||
virtual void Scale(float scalex, float scaley, float scalez) { }
|
||||
virtual int Get_Num_Snap_Points(void);
|
||||
virtual void Get_Snap_Point(int index,Vector3 * set);
|
||||
virtual void Set_Hidden(int onoff);
|
||||
|
||||
// (gth) TESTING DYNAMICALLY SWAPPING SKELETONS!
|
||||
virtual void Set_HTree(HTreeClass * htree);
|
||||
|
||||
protected:
|
||||
|
||||
HLodClass(void);
|
||||
|
||||
void Free(void);
|
||||
virtual void Update_Sub_Object_Transforms(void);
|
||||
virtual void Update_Obj_Space_Bounding_Volumes(void);
|
||||
void add_lod_model(int lod,RenderObjClass * robj,int boneindex);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
class ModelNodeClass
|
||||
{
|
||||
public:
|
||||
RenderObjClass * Model;
|
||||
int BoneIndex;
|
||||
bool operator == (const ModelNodeClass & that) { return (Model == that.Model) && (BoneIndex == that.BoneIndex); }
|
||||
bool operator != (const ModelNodeClass & that) { return !operator == (that); }
|
||||
};
|
||||
|
||||
class ModelArrayClass : public DynamicVectorClass<ModelNodeClass>
|
||||
{
|
||||
public:
|
||||
ModelArrayClass(void) : MaxScreenSize(NO_MAX_SCREEN_SIZE), NonPixelCost(0.0f),
|
||||
PixelCostPerArea(0.0f), BenefitFactor(0.0f) {}
|
||||
float MaxScreenSize; // Maximum screen size for this LOD
|
||||
float NonPixelCost; // Cost heuristics of LODS (w/o per-pixel cost)
|
||||
float PixelCostPerArea; // PixelCostPerArea * area(normalized) + NonPixelCost = total Cost
|
||||
float BenefitFactor; // BenefitFactor * area(normalized) = Benefit
|
||||
};
|
||||
|
||||
// Lod Render Objects, basically one of the LOD Models will be rendered. Typically
|
||||
// each model in an HLodModel will be a mesh or a "simple" HLod (one with a single LOD)
|
||||
int LodCount;
|
||||
int CurLod;
|
||||
ModelArrayClass * Lod;
|
||||
|
||||
//
|
||||
// An animating heirarchy can use a hidden CLASSID_OBBOX mesh to represent its bounding
|
||||
// box as it animates. This is the sub object index of that mesh (if it exists).
|
||||
//
|
||||
int BoundingBoxIndex;
|
||||
|
||||
float * Cost; // Cost array (recalculated every frame)
|
||||
float * Value; // Value array (recalculated every frame)
|
||||
|
||||
// Additional Models, these models have been linked to one of the bones in this
|
||||
// model. They are all always rendered. They can be HLODs themselves in order
|
||||
// to implement switching on sub models.
|
||||
// NOTE: This uses ModelArrayClass for convenience, but MaxScreenSize,
|
||||
// NonPixelCost, PixelCostPerArea, BenefitFactor are not used here.
|
||||
ModelArrayClass AdditionalModels;
|
||||
|
||||
// possible array of snap points.
|
||||
SnapPointsClass * SnapPoints;
|
||||
|
||||
// possible array of proxy objects (names and bone indexes for application defined usage)
|
||||
ProxyArrayClass * ProxyArray;
|
||||
|
||||
// Current LOD Bias (affects recalculation of the Value array)
|
||||
float LODBias;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Loaders for HLodClass
|
||||
*/
|
||||
class HLodLoaderClass : public PrototypeLoaderClass
|
||||
{
|
||||
public:
|
||||
virtual int Chunk_Type (void) { return W3D_CHUNK_HLOD; }
|
||||
virtual PrototypeClass * Load_W3D(ChunkLoadClass & cload);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** HLodDefClass
|
||||
** This description object is generated when reading a W3D_CHUNK_HLOD. It
|
||||
** directly describes the contents of an HLod model.
|
||||
*/
|
||||
class HLodDefClass : public W3DMPO
|
||||
{
|
||||
W3DMPO_GLUE(HLodDefClass)
|
||||
public:
|
||||
|
||||
HLodDefClass(void);
|
||||
HLodDefClass(HLodClass &src_lod);
|
||||
~HLodDefClass(void);
|
||||
|
||||
WW3DErrorType Load_W3D(ChunkLoadClass & cload);
|
||||
WW3DErrorType Save(ChunkSaveClass & csave);
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
void Initialize(HLodClass &src_lod);
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** Serializtion methods
|
||||
*/
|
||||
WW3DErrorType Save_Header (ChunkSaveClass &csave);
|
||||
WW3DErrorType Save_Lod_Array (ChunkSaveClass &csave);
|
||||
WW3DErrorType Save_Aggregate_Array(ChunkSaveClass & csave);
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
** SubObjectArrayClass
|
||||
** Describes a level-of-detail in an HLod object. Note that this is
|
||||
** a render object which will be exploded when the HLod is constructed (its
|
||||
** sub-objects, if any, will be placed into the HLod).
|
||||
*/
|
||||
class SubObjectArrayClass
|
||||
{
|
||||
public:
|
||||
SubObjectArrayClass(void);
|
||||
~SubObjectArrayClass(void);
|
||||
void Reset(void);
|
||||
void operator = (const SubObjectArrayClass & that);
|
||||
|
||||
bool Load_W3D(ChunkLoadClass & cload);
|
||||
bool Save_W3D(ChunkSaveClass & csave);
|
||||
|
||||
float MaxScreenSize;
|
||||
int ModelCount;
|
||||
char ** ModelName; // array of model names
|
||||
int * BoneIndex; // array of bone indices
|
||||
};
|
||||
|
||||
char * Name;
|
||||
char * HierarchyTreeName;
|
||||
int LodCount;
|
||||
SubObjectArrayClass * Lod;
|
||||
SubObjectArrayClass Aggregates;
|
||||
ProxyArrayClass * ProxyArray;
|
||||
|
||||
void Free(void);
|
||||
bool read_header(ChunkLoadClass & cload);
|
||||
bool read_proxy_array(ChunkLoadClass & cload);
|
||||
|
||||
friend class HLodClass;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Prototype for HLod objects
|
||||
*/
|
||||
class HLodPrototypeClass : public W3DMPO, public PrototypeClass
|
||||
{
|
||||
W3DMPO_GLUE(HLodPrototypeClass)
|
||||
public:
|
||||
HLodPrototypeClass( HLodDefClass *def ) { Definition = def; }
|
||||
|
||||
virtual const char * Get_Name(void) const { return Definition->Get_Name(); }
|
||||
virtual int Get_Class_ID(void) const { return RenderObjClass::CLASSID_HLOD; }
|
||||
virtual RenderObjClass * Create(void);
|
||||
virtual void DeleteSelf() { delete this; }
|
||||
|
||||
HLodDefClass * Get_Definition(void) const { return Definition; }
|
||||
|
||||
protected:
|
||||
virtual ~HLodPrototypeClass(void) { delete Definition; }
|
||||
|
||||
private:
|
||||
HLodDefClass * Definition;
|
||||
};
|
||||
|
||||
/*
|
||||
** Instance of the loaders which the asset manager install
|
||||
*/
|
||||
extern HLodLoaderClass _HLodLoader;
|
||||
|
||||
|
||||
#endif
|
||||
112
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmdldef.H
Normal file
112
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmdldef.H
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hmdldef.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HMDLDEF_H
|
||||
#define HMDLDEF_H
|
||||
|
||||
#include "always.h"
|
||||
#include "w3d_file.h"
|
||||
|
||||
class FileClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class SnapPointsClass;
|
||||
|
||||
/*
|
||||
** Each render object to be attached into the hierarchy model
|
||||
** will be defined by an instance of the following structure.
|
||||
** The HmdlNodeDefStruct associates a named render object with
|
||||
** an indexed pivot/bone in the hierarchy tree.
|
||||
*/
|
||||
struct HmdlNodeDefStruct
|
||||
{
|
||||
char RenderObjName[2*W3D_NAME_LEN];
|
||||
int PivotID;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** HModelDefClass
|
||||
**
|
||||
** "Hierarchy Model Definition Class"
|
||||
** This class serves as a blueprint for creating HierarchyModelClasses.
|
||||
** The asset manager stores these objects internally and uses them to
|
||||
** create instances of HierarchyModels for the user.
|
||||
*/
|
||||
class HModelDefClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
OK,
|
||||
LOAD_ERROR
|
||||
};
|
||||
|
||||
HModelDefClass(void);
|
||||
~HModelDefClass(void);
|
||||
|
||||
int Load_W3D(ChunkLoadClass & cload);
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
|
||||
private:
|
||||
|
||||
char Name[2*W3D_NAME_LEN]; // <basepose>.<modelname>
|
||||
char ModelName[W3D_NAME_LEN]; // name of the model
|
||||
char BasePoseName[W3D_NAME_LEN]; // name of the base pose (hierarchy tree)
|
||||
|
||||
int SubObjectCount;
|
||||
HmdlNodeDefStruct * SubObjects;
|
||||
SnapPointsClass * SnapPoints;
|
||||
|
||||
void Free(void);
|
||||
bool read_header(ChunkLoadClass & cload);
|
||||
bool read_connection(ChunkLoadClass & cload,HmdlNodeDefStruct * con,bool pre30);
|
||||
bool read_mesh_connection(ChunkLoadClass & cload,int idx,bool pre30);
|
||||
bool read_collision_connection(ChunkLoadClass & cload,int idx,bool pre30);
|
||||
bool read_skin_connection(ChunkLoadClass & cload,int idx,bool pre30);
|
||||
|
||||
// HModelClass requires intimate knowlege of us
|
||||
friend class HModelClass;
|
||||
friend class HLodClass;
|
||||
};
|
||||
|
||||
#endif
|
||||
257
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmdldef.cpp
Normal file
257
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmdldef.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hmdldef.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* HModelDefClass::HModelDefClass -- Constructor *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "hmdldef.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "w3d_file.h"
|
||||
#include "chunkio.h"
|
||||
#include "snappts.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HModelDefClass::HModelDefClass -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/15/97 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
HModelDefClass::HModelDefClass(void) :
|
||||
SubObjectCount(0),
|
||||
SubObjects(NULL),
|
||||
SnapPoints(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HModelDefClass::~HModelDefClass -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HModelDefClass::~HModelDefClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HModelDefClass::Free -- de-allocate all memory in use *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HModelDefClass::Free(void)
|
||||
{
|
||||
if (SubObjects != NULL) {
|
||||
delete[] SubObjects;
|
||||
SubObjects = NULL;
|
||||
}
|
||||
SubObjectCount = 0;
|
||||
|
||||
if (SnapPoints != NULL) {
|
||||
SnapPoints->Release_Ref();
|
||||
SnapPoints = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HModelDefClass::Load -- load a set of mesh connections from a file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HModelDefClass::Load_W3D(ChunkLoadClass & cload)
|
||||
{
|
||||
bool pre30 = false;
|
||||
int subobjcounter = 0;
|
||||
|
||||
Free();
|
||||
|
||||
/*
|
||||
** Read the first chunk, it should be the header
|
||||
*/
|
||||
if (!cload.Open_Chunk()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HMODEL_HEADER) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
/*
|
||||
** read in the header
|
||||
*/
|
||||
W3dHModelHeaderStruct header;
|
||||
if (cload.Read(&header,sizeof(W3dHModelHeaderStruct)) != sizeof(W3dHModelHeaderStruct)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
cload.Close_Chunk();
|
||||
|
||||
/*
|
||||
** process the header info
|
||||
*/
|
||||
strncpy(ModelName,header.Name,W3D_NAME_LEN);
|
||||
ModelName[W3D_NAME_LEN - 1] = 0;
|
||||
strncpy(BasePoseName,header.HierarchyName,W3D_NAME_LEN);
|
||||
BasePoseName[W3D_NAME_LEN-1] = 0;
|
||||
strcpy(Name,ModelName);
|
||||
|
||||
/*
|
||||
** Just allocate a node for the number of sub objects we're expecting
|
||||
*/
|
||||
SubObjectCount = header.NumConnections;
|
||||
SubObjects = W3DNEWARRAY HmdlNodeDefStruct[SubObjectCount];
|
||||
if (SubObjects == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
/*
|
||||
** If this is pre-3.0 set a flag so that each render object's
|
||||
** bone id will be incremented by one to account for the new
|
||||
** root node added with version3.0 of the file format. Basically,
|
||||
** I'm making all of the code assume that node 0 is the root and
|
||||
** therefore, pre-3.0 files have to have it added and all of
|
||||
** the indices adjusted
|
||||
*/
|
||||
if (header.Version < W3D_MAKE_VERSION(3,0)) {
|
||||
pre30 = true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process the rest of the chunks
|
||||
*/
|
||||
subobjcounter = 0;
|
||||
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch (cload.Cur_Chunk_ID()) {
|
||||
|
||||
case W3D_CHUNK_NODE:
|
||||
case W3D_CHUNK_COLLISION_NODE:
|
||||
case W3D_CHUNK_SKIN_NODE:
|
||||
if (!read_connection(cload,&(SubObjects[subobjcounter]),pre30)) {
|
||||
goto Error;
|
||||
}
|
||||
subobjcounter++;
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_POINTS:
|
||||
SnapPoints = W3DNEW SnapPointsClass;
|
||||
SnapPoints->Load_W3D(cload);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
Error:
|
||||
|
||||
return LOAD_ERROR;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HModelDefClass::read_connection -- read a single connection from the file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
* 10/22/97 GH : Check for mesh connections with PivotID=-1 *
|
||||
*=============================================================================================*/
|
||||
bool HModelDefClass::read_connection(ChunkLoadClass & cload,HmdlNodeDefStruct * node,bool pre30)
|
||||
{
|
||||
|
||||
W3dHModelNodeStruct con;
|
||||
if (cload.Read(&con,sizeof(W3dHModelNodeStruct)) != sizeof(W3dHModelNodeStruct)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(node->RenderObjName,ModelName);
|
||||
strcat(node->RenderObjName,".");
|
||||
strcat(node->RenderObjName,con.RenderObjName);
|
||||
|
||||
if (pre30) {
|
||||
if (con.PivotIdx == 65535) {
|
||||
node->PivotID = 0;
|
||||
} else {
|
||||
node->PivotID = con.PivotIdx + 1;
|
||||
}
|
||||
} else {
|
||||
assert(con.PivotIdx != 65535);
|
||||
node->PivotID = con.PivotIdx;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
742
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.cpp
Normal file
742
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.cpp
Normal file
@@ -0,0 +1,742 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hmorphanim.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:50p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "hmorphanim.h"
|
||||
#include "w3d_file.h"
|
||||
#include "chunkio.h"
|
||||
#include "assetmgr.h"
|
||||
#include "htree.h"
|
||||
#include "wwstring.h"
|
||||
#include "textfile.h"
|
||||
#include "simplevec.h"
|
||||
|
||||
|
||||
|
||||
TimeCodedMorphKeysClass::TimeCodedMorphKeysClass(void)
|
||||
: CachedIdx (0)
|
||||
{
|
||||
}
|
||||
|
||||
TimeCodedMorphKeysClass::~TimeCodedMorphKeysClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
void TimeCodedMorphKeysClass::Free(void)
|
||||
{
|
||||
Keys.Delete_All ();
|
||||
CachedIdx = 0;
|
||||
}
|
||||
|
||||
bool TimeCodedMorphKeysClass::Load_W3D(ChunkLoadClass & cload)
|
||||
{
|
||||
Free();
|
||||
uint32 key_count = cload.Cur_Chunk_Length() / sizeof(W3dMorphAnimKeyStruct);
|
||||
|
||||
W3dMorphAnimKeyStruct w3dkey;
|
||||
for (uint32 i=0; i<key_count; i++) {
|
||||
cload.Read(&w3dkey,sizeof(w3dkey));
|
||||
Keys.Add (MorphKeyStruct (w3dkey.MorphFrame, w3dkey.PoseFrame));
|
||||
}
|
||||
CachedIdx = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimeCodedMorphKeysClass::Save_W3D(ChunkSaveClass & csave)
|
||||
{
|
||||
W3dMorphAnimKeyStruct w3dkey;
|
||||
for (int i=0; i<Keys.Count (); i++) {
|
||||
w3dkey.MorphFrame = Keys[i].MorphFrame;
|
||||
w3dkey.PoseFrame = Keys[i].PoseFrame;
|
||||
csave.Write(&w3dkey,sizeof(w3dkey));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimeCodedMorphKeysClass::Add_Key (uint32 morph_frame, uint32 pose_frame)
|
||||
{
|
||||
Keys.Add (MorphKeyStruct (morph_frame, pose_frame));
|
||||
return ;
|
||||
}
|
||||
|
||||
void TimeCodedMorphKeysClass::Get_Morph_Info(float morph_frame,int * pose_frame0,int * pose_frame1,float * fraction)
|
||||
{
|
||||
if (morph_frame < 0.0f) {
|
||||
*pose_frame0 = *pose_frame1 = Keys[0].PoseFrame;
|
||||
*fraction = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (morph_frame >= Keys[Keys.Count ()-1].MorphFrame) {
|
||||
*pose_frame0 = *pose_frame1 = Keys[Keys.Count ()-1].PoseFrame;
|
||||
*fraction = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
int key_index = get_index(morph_frame);
|
||||
|
||||
*pose_frame0 = Keys[key_index].PoseFrame;
|
||||
*pose_frame1 = Keys[key_index+1].PoseFrame;
|
||||
*fraction = (morph_frame - Keys[key_index].MorphFrame) / (Keys[key_index+1].MorphFrame - Keys[key_index].MorphFrame);
|
||||
}
|
||||
|
||||
|
||||
uint32 TimeCodedMorphKeysClass::get_index(float frame)
|
||||
{
|
||||
assert(CachedIdx <= (uint32)Keys.Count ()-1);
|
||||
|
||||
float cached_frame = Keys[CachedIdx].MorphFrame;
|
||||
|
||||
// check if the requested time is in the cached interval or the following one
|
||||
if (frame >= cached_frame) {
|
||||
|
||||
// special case for end packets
|
||||
if (CachedIdx == (uint32)Keys.Count ()-1) return(CachedIdx);
|
||||
|
||||
// check if the requested time is still in the cached interval
|
||||
if (frame < Keys[CachedIdx + 1].MorphFrame) return(CachedIdx);
|
||||
|
||||
// do one time look-ahead before reverting to a search
|
||||
CachedIdx++;
|
||||
|
||||
// again, special case the end interval
|
||||
if (CachedIdx == (uint32)Keys.Count ()-1) return(CachedIdx);
|
||||
|
||||
// check if requested time is in this interval
|
||||
if (frame < Keys[CachedIdx + 1].MorphFrame) return(CachedIdx);
|
||||
}
|
||||
|
||||
// nope, fall back to a binary search for the requested interval
|
||||
CachedIdx = binary_search_index(frame);
|
||||
|
||||
return(CachedIdx);
|
||||
}
|
||||
|
||||
uint32 TimeCodedMorphKeysClass::binary_search_index(float req_frame)
|
||||
{
|
||||
// special case first and last packet
|
||||
if (req_frame < Keys[0].MorphFrame) return 0;
|
||||
if (req_frame >= Keys[Keys.Count ()-1].MorphFrame) return Keys.Count ()-1;
|
||||
|
||||
int leftIdx = 0;
|
||||
int rightIdx = Keys.Count ();
|
||||
int idx,dx;
|
||||
|
||||
// binary search for the desired interval
|
||||
for (;;) {
|
||||
|
||||
// if we've zeroed in on the interval, return the left index
|
||||
dx = rightIdx - leftIdx;
|
||||
if (dx == 1) {
|
||||
WWASSERT(req_frame >= Keys[leftIdx].MorphFrame);
|
||||
WWASSERT(req_frame < Keys[rightIdx].MorphFrame);
|
||||
return leftIdx;
|
||||
}
|
||||
|
||||
// otherwise, split our interval in half and descend into one of them
|
||||
dx>>=1;
|
||||
idx = leftIdx + dx;
|
||||
|
||||
if (req_frame < Keys[idx].MorphFrame) {
|
||||
rightIdx = idx;
|
||||
} else {
|
||||
leftIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************
|
||||
**
|
||||
** HMorphAnimClass Implementation
|
||||
**
|
||||
*********************************************************************************************/
|
||||
|
||||
HMorphAnimClass::HMorphAnimClass(void) :
|
||||
FrameCount(0),
|
||||
FrameRate(0.0f),
|
||||
ChannelCount(0),
|
||||
NumNodes(0),
|
||||
PoseData(NULL),
|
||||
MorphKeyData(NULL),
|
||||
PivotChannel(NULL)
|
||||
{
|
||||
memset(Name,0,sizeof(Name));
|
||||
memset(HierarchyName,0,sizeof(HierarchyName));
|
||||
}
|
||||
|
||||
HMorphAnimClass::~HMorphAnimClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Free(void)
|
||||
{
|
||||
if (PoseData != NULL) {
|
||||
for (int i=0; i<ChannelCount; i++) {
|
||||
REF_PTR_RELEASE(PoseData[i]);
|
||||
}
|
||||
delete[] PoseData;
|
||||
PoseData = NULL;
|
||||
}
|
||||
|
||||
if (MorphKeyData != NULL) {
|
||||
delete[] MorphKeyData;
|
||||
MorphKeyData = NULL;
|
||||
}
|
||||
|
||||
if (PivotChannel != NULL) {
|
||||
delete[] PivotChannel;
|
||||
PivotChannel = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Build_List_From_String
|
||||
(
|
||||
const char * buffer,
|
||||
const char * delimiter,
|
||||
StringClass ** string_list
|
||||
)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
WWASSERT (buffer != NULL);
|
||||
WWASSERT (delimiter != NULL);
|
||||
WWASSERT (string_list != NULL);
|
||||
if ((buffer != NULL) &&
|
||||
(delimiter != NULL) &&
|
||||
(string_list != NULL))
|
||||
{
|
||||
int delim_len = ::strlen (delimiter);
|
||||
|
||||
//
|
||||
// Determine how many entries there will be in the list
|
||||
//
|
||||
for (const char *entry = buffer;
|
||||
(entry != NULL) && (entry[1] != 0);
|
||||
entry = ::strstr (entry, delimiter))
|
||||
{
|
||||
|
||||
//
|
||||
// Move past the current delimiter (if necessary)
|
||||
//
|
||||
if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
|
||||
entry += delim_len;
|
||||
}
|
||||
|
||||
// Increment the count of entries
|
||||
count ++;
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
|
||||
//
|
||||
// Allocate enough StringClass objects to hold all the strings in the list
|
||||
//
|
||||
(*string_list) = W3DNEWARRAY StringClass[count];
|
||||
|
||||
//
|
||||
// Parse the string and pull out its entries.
|
||||
//
|
||||
count = 0;
|
||||
for (entry = buffer;
|
||||
(entry != NULL) && (entry[1] != 0);
|
||||
entry = ::strstr (entry, delimiter))
|
||||
{
|
||||
|
||||
//
|
||||
// Move past the current delimiter (if necessary)
|
||||
//
|
||||
if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
|
||||
entry += delim_len;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy this entry into its own string
|
||||
//
|
||||
StringClass entry_string = entry;
|
||||
char *delim_start = ::strstr (entry_string, delimiter);
|
||||
if (delim_start != NULL) {
|
||||
delim_start[0] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Add this entry to our list
|
||||
//
|
||||
if ((entry_string.Get_Length () > 0) || (count == 0)) {
|
||||
(*string_list)[count++] = entry_string;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (delim_len > 0) {
|
||||
count = 1;
|
||||
(*string_list) = W3DNEWARRAY StringClass[count];
|
||||
(*string_list)[0] = buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Return the number of entries in our list
|
||||
//
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
bool Is_Number (const char *str)
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
while (retval && str[0] != NULL){
|
||||
retval = ((str[0] >= '0' && str[0] <= '9') || str[0] == '-' || str[0] == '.');
|
||||
str ++;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool HMorphAnimClass::Import(const char *hierarchy_name, TextFileClass &text_desc)
|
||||
{
|
||||
bool retval = false;
|
||||
Free ();
|
||||
FrameCount = 0;
|
||||
FrameRate = 30.0F;
|
||||
|
||||
//
|
||||
// Copy the hierarchy name into a class variable
|
||||
//
|
||||
::strncpy (HierarchyName, hierarchy_name, W3D_NAME_LEN);
|
||||
HierarchyName[W3D_NAME_LEN - 1] = 0;
|
||||
|
||||
//
|
||||
// Attempt to load the new base pose
|
||||
//
|
||||
HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
|
||||
WWASSERT (base_pose != NULL);
|
||||
NumNodes = base_pose->Num_Pivots();
|
||||
|
||||
//
|
||||
// Read the header from the file
|
||||
//
|
||||
StringClass header;
|
||||
bool success = text_desc.Read_Line (header);
|
||||
if (success) {
|
||||
|
||||
//
|
||||
// Get the list of comma-delimited strings from the header
|
||||
//
|
||||
StringClass *column_list = NULL;
|
||||
int column_count = Build_List_From_String (header, ",", &column_list);
|
||||
|
||||
//
|
||||
// The first column header should be 'Frame#', all other headers
|
||||
// should be channel animation names.
|
||||
//
|
||||
ChannelCount = column_count - 1;
|
||||
|
||||
WWASSERT (ChannelCount > 0);
|
||||
if (ChannelCount > 0) {
|
||||
|
||||
//
|
||||
// Allocate and initialize each animation channel
|
||||
//
|
||||
PoseData = W3DNEWARRAY HAnimClass *[ChannelCount];
|
||||
MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
|
||||
for (int index = 0; index < ChannelCount; index ++) {
|
||||
StringClass channel_anim_name;
|
||||
channel_anim_name.Format ("%s.%s", HierarchyName, (const char *)column_list[index + 1]);
|
||||
PoseData[index] = WW3DAssetManager::Get_Instance()->Get_HAnim (channel_anim_name);
|
||||
}
|
||||
|
||||
//
|
||||
// Now read the animation data for each frame
|
||||
//
|
||||
StringClass frame_desc;
|
||||
while (text_desc.Read_Line (frame_desc)) {
|
||||
|
||||
//
|
||||
// Get the frame descriptions from this line
|
||||
//
|
||||
StringClass *channel_list = NULL;
|
||||
int list_count = Build_List_From_String (frame_desc, ",", &channel_list);
|
||||
|
||||
WWASSERT (list_count > 0);
|
||||
if (list_count > 0) {
|
||||
|
||||
//
|
||||
// The first column contains the morph frame number
|
||||
//
|
||||
int frame = ::atoi (channel_list[0]);
|
||||
|
||||
//
|
||||
// Now read the animation frame number for each channel
|
||||
//
|
||||
for (int index = 1; index < list_count; index ++) {
|
||||
StringClass &channel_frame = channel_list[index];
|
||||
|
||||
//
|
||||
// If this channel contains a valid number, then record
|
||||
// its animation frame
|
||||
//
|
||||
if (::Is_Number (channel_frame)) {
|
||||
MorphKeyData[index - 1].Add_Key (frame, ::atoi (channel_frame));
|
||||
}
|
||||
}
|
||||
|
||||
FrameCount = frame + 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup
|
||||
//
|
||||
if (channel_list != NULL) {
|
||||
delete [] channel_list;
|
||||
channel_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate the pivot channel list
|
||||
//
|
||||
PivotChannel = W3DNEWARRAY uint32[NumNodes];
|
||||
Resolve_Pivot_Channels ();
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup
|
||||
//
|
||||
if (column_list != NULL) {
|
||||
delete [] column_list;
|
||||
column_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Resolve_Pivot_Channels(void)
|
||||
{
|
||||
WWASSERT (PivotChannel != NULL);
|
||||
|
||||
//
|
||||
// Loop over all the pivots in the HTree
|
||||
//
|
||||
for (int pivot = 0; pivot < NumNodes; pivot ++) {
|
||||
PivotChannel[pivot] = 0;
|
||||
|
||||
//
|
||||
// Find out which animation channel affects this pivot
|
||||
//
|
||||
for (int channel = 0; channel < ChannelCount; channel ++) {
|
||||
if (PoseData[channel]->Is_Node_Motion_Present (pivot)) {
|
||||
PivotChannel[pivot] = channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Set_Name(const char * name)
|
||||
{
|
||||
//
|
||||
// Copy the full name
|
||||
//
|
||||
::strcpy (Name, name);
|
||||
|
||||
//
|
||||
// Try to find the separator (a period)
|
||||
//
|
||||
StringClass full_name = name;
|
||||
char *separator = ::strchr (full_name, '.');
|
||||
if (separator != NULL) {
|
||||
|
||||
//
|
||||
// Null out the separator and copy the two names
|
||||
// into our two buffers
|
||||
//
|
||||
separator[0] = 0;
|
||||
::strcpy (AnimName, separator + 1);
|
||||
::strcpy (HierarchyName, full_name);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Free_Morph(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
int HMorphAnimClass::Create_New_Morph(const int channels, HAnimClass *anim[])
|
||||
{
|
||||
// clean out the previous instance of this class
|
||||
Free();
|
||||
|
||||
// set the number of channels
|
||||
ChannelCount = channels;
|
||||
|
||||
// read in the animation header
|
||||
if (anim == NULL) {
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
|
||||
// set up info
|
||||
// FrameCount = anim[0]->Get_Num_Frames();
|
||||
// FrameRate = anim[0]->Get_Frame_Rate();
|
||||
FrameCount = 0;
|
||||
FrameRate = 30.0f;
|
||||
NumNodes = anim[0]->Get_Num_Pivots();
|
||||
|
||||
// Set up the anim data for all the channels
|
||||
PoseData = W3DNEWARRAY HAnimClass * [ChannelCount];
|
||||
for(int i=0;i<ChannelCount;i++)
|
||||
PoseData[i] = anim[i];
|
||||
|
||||
// Create a timecodekey array for each channel and initialize the pivot channels
|
||||
MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
|
||||
PivotChannel = W3DNEWARRAY uint32[NumNodes];
|
||||
|
||||
// Resolve the pivots so that they correspond to the proper morphing channels
|
||||
memset(PivotChannel,0,NumNodes * sizeof(uint32));
|
||||
Resolve_Pivot_Channels();
|
||||
|
||||
// Signal successful process
|
||||
return OK;
|
||||
}
|
||||
|
||||
int HMorphAnimClass::Load_W3D(ChunkLoadClass & cload)
|
||||
{
|
||||
Free();
|
||||
|
||||
// read in the animation header
|
||||
W3dMorphAnimHeaderStruct header;
|
||||
cload.Open_Chunk();
|
||||
WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_HEADER);
|
||||
cload.Read(&header,sizeof(header));
|
||||
cload.Close_Chunk();
|
||||
|
||||
strncpy(AnimName,header.Name,sizeof(AnimName));
|
||||
strncpy(HierarchyName,header.HierarchyName,sizeof(HierarchyName));
|
||||
strcpy(Name,HierarchyName);
|
||||
strcat(Name,".");
|
||||
strcat(Name,AnimName);
|
||||
|
||||
HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
|
||||
if (base_pose == NULL) {
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
NumNodes = base_pose->Num_Pivots();
|
||||
|
||||
FrameCount = header.FrameCount;
|
||||
FrameRate = header.FrameRate;
|
||||
ChannelCount = header.ChannelCount;
|
||||
|
||||
PoseData = W3DNEWARRAY HAnimClass * [ChannelCount];
|
||||
MorphKeyData = W3DNEWARRAY TimeCodedMorphKeysClass[ChannelCount];
|
||||
PivotChannel = W3DNEWARRAY uint32[NumNodes];
|
||||
memset(PivotChannel,0,NumNodes * sizeof(uint32));
|
||||
|
||||
// read in the rest of the chunks
|
||||
int cur_channel = 0;
|
||||
while (cload.Open_Chunk()) {
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case W3D_CHUNK_MORPHANIM_CHANNEL:
|
||||
read_channel(cload,cur_channel++);
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA:
|
||||
cload.Read(PivotChannel,cload.Cur_Chunk_Length());
|
||||
break;
|
||||
};
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
void HMorphAnimClass::read_channel(ChunkLoadClass & cload,int channel)
|
||||
{
|
||||
WWASSERT(channel >= 0);
|
||||
WWASSERT(channel < ChannelCount);
|
||||
|
||||
StringClass anim_name;
|
||||
|
||||
cload.Open_Chunk();
|
||||
WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_POSENAME);
|
||||
cload.Read(anim_name.Get_Buffer(cload.Cur_Chunk_Length()),cload.Cur_Chunk_Length());
|
||||
cload.Close_Chunk();
|
||||
|
||||
//StringClass channel_anim_name;
|
||||
//channel_anim_name.Format ("%s.%s", HierarchyName, anim_name);
|
||||
PoseData[channel] = WW3DAssetManager::Get_Instance()->Get_HAnim(anim_name);
|
||||
WWASSERT(PoseData[channel] != NULL);
|
||||
|
||||
cload.Open_Chunk();
|
||||
WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_MORPHANIM_KEYDATA);
|
||||
MorphKeyData[channel].Load_W3D(cload);
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
|
||||
int HMorphAnimClass::Save_W3D(ChunkSaveClass & csave)
|
||||
{
|
||||
// W3D objects write their own wrapper chunks
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPH_ANIMATION);
|
||||
|
||||
// init the header data
|
||||
W3dMorphAnimHeaderStruct header;
|
||||
memset(&header,0,sizeof(header));
|
||||
strncpy(header.Name,AnimName,sizeof(header.Name));
|
||||
strncpy(header.HierarchyName,HierarchyName,sizeof(header.HierarchyName));
|
||||
|
||||
header.FrameCount = FrameCount;
|
||||
header.FrameRate = FrameRate;
|
||||
header.ChannelCount = ChannelCount;
|
||||
|
||||
// write out the animation header
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_HEADER);
|
||||
csave.Write(&header,sizeof(header));
|
||||
csave.End_Chunk();
|
||||
|
||||
// write out the morph channels
|
||||
for (int ci=0; ci<ChannelCount; ci++) {
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_CHANNEL);
|
||||
write_channel(csave,ci);
|
||||
csave.End_Chunk();
|
||||
}
|
||||
|
||||
// write out the pivot attachments
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA);
|
||||
csave.Write(PivotChannel,NumNodes * sizeof(uint32));
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.End_Chunk();
|
||||
return OK;
|
||||
}
|
||||
|
||||
void HMorphAnimClass::write_channel(ChunkSaveClass & csave,int channel)
|
||||
{
|
||||
WWASSERT(PoseData[channel] != NULL);
|
||||
|
||||
const char * pose_name = PoseData[channel]->Get_Name();
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_POSENAME);
|
||||
csave.Write(pose_name,strlen(pose_name) + 1);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(W3D_CHUNK_MORPHANIM_KEYDATA);
|
||||
MorphKeyData[channel].Save_W3D(csave);
|
||||
csave.End_Chunk();
|
||||
}
|
||||
|
||||
|
||||
void HMorphAnimClass::Get_Translation(Vector3& trans,int pividx,float frame) const
|
||||
{
|
||||
int channel = PivotChannel[pividx];
|
||||
int pose_frame0,pose_frame1;
|
||||
float fraction;
|
||||
MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
|
||||
|
||||
Vector3 t0;
|
||||
PoseData[channel]->Get_Translation(t0,pividx,pose_frame0);
|
||||
Vector3 t1;
|
||||
PoseData[channel]->Get_Translation(t1,pividx,pose_frame1);
|
||||
Vector3::Lerp(t0,t1,fraction,&trans);
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Get_Orientation(Quaternion& q, int pividx,float frame) const
|
||||
{
|
||||
int channel = PivotChannel[pividx];
|
||||
int pose_frame0,pose_frame1;
|
||||
float fraction;
|
||||
MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
|
||||
|
||||
Quaternion q0;
|
||||
PoseData[channel]->Get_Orientation(q0,pividx,pose_frame0);
|
||||
Quaternion q1;
|
||||
PoseData[channel]->Get_Orientation(q1,pividx,pose_frame1);
|
||||
::Fast_Slerp(q,q0,q1,fraction);
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Get_Transform(Matrix3D& mtx,int pividx,float frame) const
|
||||
{
|
||||
int channel = PivotChannel[pividx];
|
||||
int pose_frame0,pose_frame1;
|
||||
float fraction;
|
||||
MorphKeyData[channel].Get_Morph_Info(frame,&pose_frame0,&pose_frame1,&fraction);
|
||||
|
||||
Quaternion q0;
|
||||
PoseData[channel]->Get_Orientation(q0,pividx,pose_frame0);
|
||||
Quaternion q1;
|
||||
PoseData[channel]->Get_Orientation(q1,pividx,pose_frame1);
|
||||
Quaternion q;
|
||||
::Fast_Slerp(q,q0,q1,fraction);
|
||||
::Build_Matrix3D(q,mtx);
|
||||
Vector3 t0;
|
||||
PoseData[channel]->Get_Translation(t0,pividx,pose_frame0);
|
||||
Vector3 t1;
|
||||
PoseData[channel]->Get_Translation(t1,pividx,pose_frame1);
|
||||
Vector3 trans;
|
||||
Vector3::Lerp(t0,t1,fraction,&trans);
|
||||
mtx.Set_Translation(trans);
|
||||
}
|
||||
|
||||
|
||||
void HMorphAnimClass::Insert_Morph_Key(const int channel, uint32 morph_frame, uint32 pose_frame)
|
||||
{
|
||||
assert(channel<ChannelCount);
|
||||
MorphKeyData[channel].Add_Key(morph_frame,pose_frame);
|
||||
|
||||
// update the framecount to reflect the newly added key
|
||||
FrameCount = WWMath::Max(morph_frame,FrameCount);
|
||||
}
|
||||
|
||||
void HMorphAnimClass::Release_Keys(void)
|
||||
{
|
||||
for(int i=0;i<ChannelCount;i++)
|
||||
MorphKeyData[i].Free();
|
||||
|
||||
// update the framecount as 0
|
||||
FrameCount = 0;
|
||||
}
|
||||
192
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h
Normal file
192
Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hmorphanim.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:41p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HMORPHANIM_H
|
||||
#define HMORPHANIM_H
|
||||
|
||||
#include "always.h"
|
||||
#include "hanim.h"
|
||||
#include "simplevec.h"
|
||||
|
||||
class TimeCodedMorphKeysClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class TextFileClass;
|
||||
|
||||
/**********************************************************************************
|
||||
|
||||
HMorphAnimClass
|
||||
|
||||
This is an animation format designed for facial animation. It basically morphs the
|
||||
htree between a set of poses. These animations are created by exporting an
|
||||
HRawAnimClass which contains the poses, using Magpie to create a text file
|
||||
describing which pose to use on each frame, and finally using W3dView to combine
|
||||
the data into an HMorphAnimClass.
|
||||
|
||||
There can be multiple channels for the morphing. For example, some of the
|
||||
bones can be controlled by the "phoneme" poses (e.g. mouth) while other bones are
|
||||
controlled by the "expression" poses (e.g. eyebrows)
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
class HMorphAnimClass : public HAnimClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
OK,
|
||||
LOAD_ERROR
|
||||
};
|
||||
|
||||
HMorphAnimClass(void);
|
||||
~HMorphAnimClass(void);
|
||||
|
||||
void Free_Morph(void);
|
||||
int Create_New_Morph(const int channels, HAnimClass *anim[]);
|
||||
int Load_W3D(ChunkLoadClass & cload);
|
||||
int Save_W3D(ChunkSaveClass & csave);
|
||||
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
const char * Get_HName(void) const { return HierarchyName; }
|
||||
|
||||
int Get_Num_Frames(void) { return FrameCount; }
|
||||
float Get_Frame_Rate() { return FrameRate; }
|
||||
float Get_Total_Time() { return (float)FrameCount / FrameRate; }
|
||||
|
||||
// Vector3 Get_Translation(int pividx,float frame);
|
||||
// Quaternion Get_Orientation(int pividx,float frame);
|
||||
void Get_Translation(Vector3& translation, int pividx,float frame) const;
|
||||
void Get_Orientation(Quaternion& orientation, int pividx,float frame) const;
|
||||
void Get_Transform(Matrix3D& transform, int pividx,float frame) const;
|
||||
bool Get_Visibility(int pividx,float frame) { return true; }
|
||||
|
||||
void Insert_Morph_Key (const int channel, uint32 morph_frame, uint32 pose_frame);
|
||||
void Release_Keys (void);
|
||||
|
||||
bool Is_Node_Motion_Present(int pividx) { return true; }
|
||||
int Get_Num_Pivots(void) const { return NumNodes; }
|
||||
|
||||
void Set_Name(const char * name);
|
||||
void Set_HName(const char * hname);
|
||||
|
||||
bool Import(const char *hierarchy_name, TextFileClass &text_desc);
|
||||
|
||||
protected:
|
||||
|
||||
void Free(void);
|
||||
void read_channel(ChunkLoadClass & cload,int channel);
|
||||
void write_channel(ChunkSaveClass & csave,int channel);
|
||||
void Resolve_Pivot_Channels(void);
|
||||
|
||||
char Name[2*W3D_NAME_LEN];
|
||||
char AnimName[W3D_NAME_LEN];
|
||||
char HierarchyName[W3D_NAME_LEN];
|
||||
|
||||
int FrameCount; // number of frames in the animation
|
||||
float FrameRate; // framerate for playback
|
||||
int ChannelCount; // number of independent morphing channels
|
||||
int NumNodes;
|
||||
|
||||
HAnimClass ** PoseData; // pointer to pose for each morph channel
|
||||
TimeCodedMorphKeysClass * MorphKeyData; // morph keys for each channel
|
||||
uint32 * PivotChannel; // controlling channel for each pivot/bone
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************************************
|
||||
**
|
||||
** TimeCodedMorphKeysClass
|
||||
** This class basically stores a vector of morph keys. An HMorphAnimClass contains
|
||||
** one of these for each independent morphing channel. For example, the facial animation
|
||||
** stuff generates HMorphAnims which contain 2 channels, one which specifies what the
|
||||
** "phoneme" bones are doing and one which specifies what the "expression" bones are doing.
|
||||
**
|
||||
*********************************************************************************************/
|
||||
|
||||
class TimeCodedMorphKeysClass
|
||||
{
|
||||
public:
|
||||
|
||||
TimeCodedMorphKeysClass(void);
|
||||
~TimeCodedMorphKeysClass(void);
|
||||
|
||||
bool Load_W3D(ChunkLoadClass & cload);
|
||||
bool Save_W3D(ChunkSaveClass & csave);
|
||||
void Get_Morph_Info(float morph_frame,int * pose_frame0,int * pose_frame1,float * fraction);
|
||||
|
||||
void Add_Key (uint32 morph_frame, uint32 pose_frame);
|
||||
|
||||
private:
|
||||
|
||||
struct MorphKeyStruct
|
||||
{
|
||||
MorphKeyStruct (void)
|
||||
: MorphFrame (0),
|
||||
PoseFrame (0) {}
|
||||
|
||||
MorphKeyStruct (uint32 _morph, uint32 _pose)
|
||||
: MorphFrame (_morph),
|
||||
PoseFrame (_pose) {}
|
||||
|
||||
uint32 MorphFrame; // morph animation frame index
|
||||
uint32 PoseFrame; // which pose frame to use at this time
|
||||
};
|
||||
|
||||
SimpleDynVecClass<MorphKeyStruct> Keys; // morph key data
|
||||
uint32 CachedIdx; // last accessed index
|
||||
|
||||
void Free(void);
|
||||
|
||||
uint32 get_index(float time);
|
||||
uint32 binary_search_index(float time);
|
||||
|
||||
friend class HMorphAnimClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
733
Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp
Normal file
733
Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp
Normal file
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hrawanim.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:52p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* HRawAnimClass::HRawAnimClass -- constructor *
|
||||
* HRawAnimClass::~HRawAnimClass -- Destructor *
|
||||
* HRawAnimClass::Free -- De-allocates all memory in use *
|
||||
* HRawAnimClass::Load -- Loads hierarchy animation from a file *
|
||||
* HRawAnimClass::read_channel -- Reads in a single channel of motion *
|
||||
* HRawAnimClass::add_channel -- Adds a motion channel to the animation *
|
||||
* HRawAnimClass::Get_Translation -- returns the translation vector for the given frame *
|
||||
* HRawAnimClass::Get_Orientation -- returns a quaternion for the orientation of the pivot *
|
||||
* HRawAnimClass::Get_XRotation -- Returns the X euler angle for the given pivot, frame *
|
||||
* HRawAnimClass::Get_YRotation -- returns the Y Euler angle for the given pivot, frame *
|
||||
* HRawAnimClass::Get_ZRotation -- returns the Z Euler angle for the given pivot, frame *
|
||||
* HRawAnimClass::read_bit_channel -- read a bit channel from the file *
|
||||
* HRawAnimClass::add_bit_channel -- install a bit channel into the animation *
|
||||
* HRawAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "hrawanim.h"
|
||||
#include "motchan.h"
|
||||
#include "chunkio.h"
|
||||
#include "assetmgr.h"
|
||||
#include "htree.h"
|
||||
|
||||
/***********************************************************************************************
|
||||
* NodeMotionStruct::NodeMotionStruct -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
NodeMotionStruct::NodeMotionStruct() :
|
||||
X(NULL),
|
||||
Y(NULL),
|
||||
Z(NULL),
|
||||
XR(NULL),
|
||||
YR(NULL),
|
||||
ZR(NULL),
|
||||
Q(NULL),
|
||||
Vis(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* NodeMotionStruct::~NodeMotionStruct -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/23/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
NodeMotionStruct::~NodeMotionStruct()
|
||||
{
|
||||
if (X != NULL) {
|
||||
delete X;
|
||||
}
|
||||
if (Y != NULL) {
|
||||
delete Y;
|
||||
}
|
||||
if (Z != NULL) {
|
||||
delete Z;
|
||||
}
|
||||
if (XR != NULL) {
|
||||
delete XR;
|
||||
}
|
||||
if (YR != NULL) {
|
||||
delete YR;
|
||||
}
|
||||
if (ZR != NULL) {
|
||||
delete ZR;
|
||||
}
|
||||
if (Q != NULL) {
|
||||
delete Q;
|
||||
}
|
||||
if (Vis != NULL) {
|
||||
delete Vis;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::HRawAnimClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HRawAnimClass::HRawAnimClass(void) :
|
||||
NumFrames(0),
|
||||
NumNodes(0),
|
||||
FrameRate(0),
|
||||
NodeMotion(NULL)
|
||||
{
|
||||
memset(Name,0,W3D_NAME_LEN);
|
||||
memset(HierarchyName,0,W3D_NAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::~HRawAnimClass -- Destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HRawAnimClass::~HRawAnimClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Free -- De-allocates all memory in use *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::Free(void)
|
||||
{
|
||||
if (NodeMotion != NULL) {
|
||||
delete[] NodeMotion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Load -- Loads hierarchy animation from a file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HRawAnimClass::Load_W3D(ChunkLoadClass & cload)
|
||||
{
|
||||
bool pre30 = false;
|
||||
|
||||
/*
|
||||
** First make sure we release any memory in use
|
||||
*/
|
||||
Free();
|
||||
|
||||
/*
|
||||
** Open the first chunk, it should be the animation header
|
||||
*/
|
||||
if (!cload.Open_Chunk()) return LOAD_ERROR;
|
||||
|
||||
if (cload.Cur_Chunk_ID() != W3D_CHUNK_ANIMATION_HEADER) {
|
||||
// ERROR: Expected Animation Header!
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
|
||||
W3dAnimHeaderStruct aheader;
|
||||
if (cload.Read(&aheader,sizeof(W3dAnimHeaderStruct)) != sizeof(W3dAnimHeaderStruct)) {
|
||||
return LOAD_ERROR;
|
||||
}
|
||||
|
||||
cload.Close_Chunk();
|
||||
|
||||
/*
|
||||
** Check if the animation version is pre-3.0. If so, we need to add 1 to all of the
|
||||
** bone indexes. In version 3.0 onward, all htree's use bone 0 as the root node.
|
||||
*/
|
||||
if (aheader.Version < W3D_MAKE_VERSION(3,0)) {
|
||||
pre30 = true;
|
||||
}
|
||||
|
||||
strcpy(Name,aheader.HierarchyName);
|
||||
strcat(Name,".");
|
||||
strcat(Name,aheader.Name);
|
||||
|
||||
// TSS chasing crash bug 05/26/99
|
||||
WWASSERT(HierarchyName != NULL);
|
||||
WWASSERT(aheader.HierarchyName != NULL);
|
||||
WWASSERT(sizeof(HierarchyName) >= W3D_NAME_LEN);
|
||||
strncpy(HierarchyName,aheader.HierarchyName,W3D_NAME_LEN);
|
||||
|
||||
HTreeClass * base_pose = WW3DAssetManager::Get_Instance()->Get_HTree(HierarchyName);
|
||||
if (base_pose == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
NumNodes = base_pose->Num_Pivots();
|
||||
|
||||
NumFrames = aheader.NumFrames;
|
||||
FrameRate = aheader.FrameRate;
|
||||
|
||||
NodeMotion = W3DNEWARRAY NodeMotionStruct[ NumNodes ];
|
||||
if (NodeMotion == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
/*
|
||||
** Now, read in all of the other chunks (motion channels).
|
||||
*/
|
||||
MotionChannelClass * newchan;
|
||||
BitChannelClass * newbitchan;
|
||||
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch (cload.Cur_Chunk_ID()) {
|
||||
|
||||
case W3D_CHUNK_ANIMATION_CHANNEL:
|
||||
if (!read_channel(cload,&newchan,pre30)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// (gth) if the channel is referring to a node which is outside the range,
|
||||
// just throw away the channel. This probably means the animation must
|
||||
// be re-exported
|
||||
if (newchan->Get_Pivot() < NumNodes) {
|
||||
add_channel(newchan);
|
||||
} else {
|
||||
WWDEBUG_SAY(("Animation %s referring to missing Bone! Please re-export.\n",Name));
|
||||
delete newchan;
|
||||
}
|
||||
break;
|
||||
|
||||
case W3D_CHUNK_BIT_CHANNEL:
|
||||
if (!read_bit_channel(cload,&newbitchan,pre30)) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// (gth) if the channel is referring to a node which is outside the range,
|
||||
// just throw away the channel. This probably means the animation must
|
||||
// be re-exported
|
||||
if (newbitchan->Get_Pivot() < NumNodes) {
|
||||
add_bit_channel(newbitchan);
|
||||
} else {
|
||||
WWDEBUG_SAY(("Animation %s referring to missing Bone! Please re-export.\n",Name));
|
||||
delete newbitchan;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
Error:
|
||||
|
||||
Free();
|
||||
return LOAD_ERROR;
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::read_channel -- Reads in a single channel of motion *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HRawAnimClass::read_channel(ChunkLoadClass & cload,MotionChannelClass * * newchan,bool pre30)
|
||||
{
|
||||
*newchan = W3DNEW MotionChannelClass;
|
||||
bool result = (*newchan)->Load_W3D(cload);
|
||||
|
||||
if (result && pre30) {
|
||||
(*newchan)->PivotIdx += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::add_channel -- Adds a motion channel to the animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::add_channel(MotionChannelClass * newchan)
|
||||
{
|
||||
int idx = newchan->Get_Pivot();
|
||||
|
||||
switch (newchan->Get_Type())
|
||||
{
|
||||
case ANIM_CHANNEL_X:
|
||||
NodeMotion[idx].X = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Y:
|
||||
NodeMotion[idx].Y = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Z:
|
||||
NodeMotion[idx].Z = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_XR:
|
||||
NodeMotion[idx].XR = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_YR:
|
||||
NodeMotion[idx].YR = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_ZR:
|
||||
NodeMotion[idx].ZR = newchan;
|
||||
break;
|
||||
|
||||
case ANIM_CHANNEL_Q:
|
||||
NodeMotion[idx].Q = newchan;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::read_bit_channel -- read a bit channel from the file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HRawAnimClass::read_bit_channel(ChunkLoadClass & cload,BitChannelClass * * newchan,bool pre30)
|
||||
{
|
||||
*newchan = W3DNEW BitChannelClass;
|
||||
bool result = (*newchan)->Load_W3D(cload);
|
||||
|
||||
if (result && pre30) {
|
||||
(*newchan)->PivotIdx += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::add_bit_channel -- install a bit channel into the animation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::add_bit_channel(BitChannelClass * newchan)
|
||||
{
|
||||
int idx = newchan->Get_Pivot();
|
||||
|
||||
switch (newchan->Get_Type())
|
||||
{
|
||||
case BIT_CHANNEL_VIS:
|
||||
NodeMotion[idx].Vis = newchan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Get_Translation -- returns the translation vector for the given fr *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::Get_Translation(Vector3& trans, int pividx, float frame ) const
|
||||
{
|
||||
struct NodeMotionStruct * motion = &NodeMotion[pividx];
|
||||
|
||||
if ( (motion->X == NULL) && (motion->Y == NULL) && (motion->Z == NULL) ) {
|
||||
trans.Set(0.0f,0.0f,0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// int frame0 = (int)frame;
|
||||
int frame0=WWMath::Float_To_Long(frame-0.499999f);
|
||||
|
||||
int frame1 = frame0 + 1;
|
||||
|
||||
float ratio = frame - (float)frame0;
|
||||
WWASSERT( (ratio >= -WWMATH_EPSILON) && (ratio < 1.0f + WWMATH_EPSILON) );
|
||||
|
||||
if ( frame1 >= NumFrames ) {
|
||||
frame1 = 0;
|
||||
}
|
||||
|
||||
Vector3 trans0(0.0f,0.0f,0.0f);
|
||||
|
||||
if (motion->X != NULL) {
|
||||
motion->X->Get_Vector((int)frame0,&(trans0[0]));
|
||||
}
|
||||
if (motion->Y != NULL) {
|
||||
motion->Y->Get_Vector((int)frame0,&(trans0[1]));
|
||||
}
|
||||
if (motion->Z != NULL) {
|
||||
motion->Z->Get_Vector((int)frame0,&(trans0[2]));
|
||||
}
|
||||
|
||||
if ( ratio == 0.0f ) {
|
||||
trans=trans0;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 trans1(0.0f,0.0f,0.0f);
|
||||
|
||||
if (motion->X != NULL) {
|
||||
motion->X->Get_Vector((int)frame1,&(trans1[0]));
|
||||
}
|
||||
if (motion->Y != NULL) {
|
||||
motion->Y->Get_Vector((int)frame1,&(trans1[1]));
|
||||
}
|
||||
if (motion->Z != NULL) {
|
||||
motion->Z->Get_Vector((int)frame1,&(trans1[2]));
|
||||
}
|
||||
|
||||
Vector3::Lerp( trans0, trans1, ratio, &trans );
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Get_Orientation -- returns a quaternion for the orientation of the *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::Get_Orientation(Quaternion& q, int pividx,float frame) const
|
||||
{
|
||||
// int frame0 = (int)frame;
|
||||
int frame0 = WWMath::Float_To_Long(frame-0.499999f);
|
||||
int frame1 = frame0 + 1;
|
||||
|
||||
float ratio = frame - (float)frame0;
|
||||
WWASSERT( (ratio >= -WWMATH_EPSILON) && (ratio < 1.0f + WWMATH_EPSILON) );
|
||||
|
||||
if ( frame1 >= NumFrames )
|
||||
{
|
||||
frame1 = 0;
|
||||
}
|
||||
|
||||
#ifdef SPECIAL_GETVEC_AS_QUAT
|
||||
|
||||
Quaternion q0, q1;
|
||||
|
||||
MotionChannelClass* mc = NodeMotion[pividx].Q;
|
||||
if (mc != NULL)
|
||||
{
|
||||
mc->Get_Vector_As_Quat((int)frame0, q0);
|
||||
mc->Get_Vector_As_Quat((int)frame1, q1);
|
||||
}
|
||||
else
|
||||
{
|
||||
q0.Set();
|
||||
q1.Set();
|
||||
}
|
||||
|
||||
if ( ratio == 0.0f )
|
||||
{
|
||||
q = q0;
|
||||
}
|
||||
else if ( ratio == 1.0f )
|
||||
{
|
||||
q = q1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Fast_Slerp(q, q0, q1, ratio);
|
||||
}
|
||||
|
||||
#else
|
||||
float vals[4];
|
||||
|
||||
Quaternion q0(1);
|
||||
if (NodeMotion[pividx].Q != NULL) {
|
||||
NodeMotion[pividx].Q->Get_Vector((int)frame0,vals);
|
||||
q0.Set(vals[0],vals[1],vals[2],vals[3]);
|
||||
}
|
||||
|
||||
if ( ratio == 0.0f ) {
|
||||
q=q0;
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion q1(1);
|
||||
if (NodeMotion[pividx].Q != NULL) {
|
||||
NodeMotion[pividx].Q->Get_Vector((int)frame1,vals);
|
||||
q1.Set(vals[0],vals[1],vals[2],vals[3]);
|
||||
}
|
||||
|
||||
Fast_Slerp(q, q0, q1, ratio );
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Get_Transform -- returns the transform matrix for the given frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HRawAnimClass::Get_Transform(Matrix3D& mtx, int pividx, float frame ) const
|
||||
{
|
||||
struct NodeMotionStruct * motion = &NodeMotion[pividx];
|
||||
|
||||
// if ( (motion->X == NULL) && (motion->Y == NULL) && (motion->Z == NULL) ) {
|
||||
// trans.Set(0.0f,0.0f,0.0f);
|
||||
// return;
|
||||
// }
|
||||
|
||||
int frame0=WWMath::Float_To_Long(frame-0.499999f);
|
||||
|
||||
int frame1 = frame0 + 1;
|
||||
|
||||
float ratio = frame - (float)frame0;
|
||||
WWASSERT( (ratio >= -WWMATH_EPSILON) && (ratio < 1.0f + WWMATH_EPSILON) );
|
||||
|
||||
if ( frame1 >= NumFrames ) {
|
||||
frame1 = 0;
|
||||
}
|
||||
|
||||
float vals[4];
|
||||
Quaternion q0(1);
|
||||
if (NodeMotion[pividx].Q != NULL) {
|
||||
NodeMotion[pividx].Q->Get_Vector((int)frame0,vals);
|
||||
q0.Set(vals[0],vals[1],vals[2],vals[3]);
|
||||
}
|
||||
|
||||
if ( ratio == 0.0f ) {
|
||||
::Build_Matrix3D(q0,mtx);
|
||||
if (motion->X != NULL) motion->X->Get_Vector((int)frame0,&(mtx[0][3]));
|
||||
if (motion->Y != NULL) motion->Y->Get_Vector((int)frame0,&(mtx[1][3]));
|
||||
if (motion->Z != NULL) motion->Z->Get_Vector((int)frame0,&(mtx[2][3]));
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion q1(1);
|
||||
if (NodeMotion[pividx].Q != NULL) {
|
||||
NodeMotion[pividx].Q->Get_Vector((int)frame1,vals);
|
||||
q1.Set(vals[0],vals[1],vals[2],vals[3]);
|
||||
}
|
||||
|
||||
Quaternion q;
|
||||
Fast_Slerp(q, q0, q1, ratio );
|
||||
::Build_Matrix3D(q,mtx);
|
||||
|
||||
Vector3 trans0(0.0f,0.0f,0.0f);
|
||||
if (motion->X != NULL) motion->X->Get_Vector((int)frame0,&(trans0[0]));
|
||||
if (motion->Y != NULL) motion->Y->Get_Vector((int)frame0,&(trans0[1]));
|
||||
if (motion->Z != NULL) motion->Z->Get_Vector((int)frame0,&(trans0[2]));
|
||||
|
||||
Vector3 trans1(0.0f,0.0f,0.0f);
|
||||
if (motion->X != NULL) motion->X->Get_Vector((int)frame1,&(trans1[0]));
|
||||
if (motion->Y != NULL) motion->Y->Get_Vector((int)frame1,&(trans1[1]));
|
||||
if (motion->Z != NULL) motion->Z->Get_Vector((int)frame1,&(trans1[2]));
|
||||
|
||||
Vector3 trans;
|
||||
Vector3::Lerp( trans0, trans1, ratio, &trans );
|
||||
|
||||
mtx.Set_Translation(trans);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Get_Visibility -- return visibility state for given pivot/frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/19/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HRawAnimClass::Get_Visibility(int pividx,float frame)
|
||||
{
|
||||
if (NodeMotion[pividx].Vis != NULL) {
|
||||
return (NodeMotion[pividx].Vis->Get_Bit((int)frame) == 1);
|
||||
}
|
||||
|
||||
// default to always visible...
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HRawAnimClass::Is_Node_Motion_Present -- return true if there is motion defined for this frame *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/23/99 EHC : Created. *
|
||||
*=============================================================================================*/
|
||||
bool HRawAnimClass::Is_Node_Motion_Present(int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
|
||||
if (NodeMotion[pividx].X != NULL) return true;
|
||||
if (NodeMotion[pividx].Y != NULL) return true;
|
||||
if (NodeMotion[pividx].Z != NULL) return true;
|
||||
if (NodeMotion[pividx].XR != NULL) return true;
|
||||
if (NodeMotion[pividx].YR != NULL) return true;
|
||||
if (NodeMotion[pividx].ZR != NULL) return true;
|
||||
if (NodeMotion[pividx].Q != NULL) return true;
|
||||
if (NodeMotion[pividx].Vis != NULL) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HRawAnimClass::Has_X_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].X != NULL;
|
||||
}
|
||||
|
||||
bool HRawAnimClass::Has_Y_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].Y != NULL;
|
||||
}
|
||||
|
||||
bool HRawAnimClass::Has_Z_Translation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].Z != NULL;
|
||||
}
|
||||
|
||||
bool HRawAnimClass::Has_Rotation (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].Q != NULL;
|
||||
}
|
||||
|
||||
bool HRawAnimClass::Has_Visibility (int pividx)
|
||||
{
|
||||
WWASSERT((pividx >= 0) && (pividx < NumNodes));
|
||||
return NodeMotion[pividx].Vis != NULL;
|
||||
}
|
||||
|
||||
|
||||
143
Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h
Normal file
143
Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/hrawanim.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 6/27/01 7:50p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HRAWANIM_H
|
||||
#define HRAWANIM_H
|
||||
|
||||
#include "always.h"
|
||||
#include "hanim.h"
|
||||
|
||||
class MotionChannelClass;
|
||||
class BitChannelClass;
|
||||
|
||||
struct NodeMotionStruct
|
||||
{
|
||||
NodeMotionStruct();
|
||||
~NodeMotionStruct();
|
||||
|
||||
MotionChannelClass * X;
|
||||
MotionChannelClass * Y;
|
||||
MotionChannelClass * Z;
|
||||
MotionChannelClass * XR;
|
||||
MotionChannelClass * YR;
|
||||
MotionChannelClass * ZR;
|
||||
MotionChannelClass * Q;
|
||||
|
||||
BitChannelClass * Vis;
|
||||
};
|
||||
|
||||
/**********************************************************************************
|
||||
|
||||
HRawAnimClass
|
||||
|
||||
Stores motion data to be applied to a HierarchyTree. Each frame
|
||||
of the motion contains deltas from the HierarchyTree's base position
|
||||
to the desired position.
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
class HRawAnimClass : public HAnimClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
OK,
|
||||
LOAD_ERROR
|
||||
};
|
||||
|
||||
HRawAnimClass(void);
|
||||
~HRawAnimClass(void);
|
||||
|
||||
int Load_W3D(ChunkLoadClass & cload);
|
||||
|
||||
const char * Get_Name(void) const { return Name; }
|
||||
const char * Get_HName(void) const { return HierarchyName; }
|
||||
int Get_Num_Frames(void) { return NumFrames; }
|
||||
float Get_Frame_Rate() { return FrameRate; }
|
||||
float Get_Total_Time() { return (float)NumFrames / FrameRate; }
|
||||
|
||||
// Vector3 Get_Translation(int pividx,float frame);
|
||||
// Quaternion Get_Orientation(int pividx,float frame);
|
||||
void Get_Translation(Vector3& translation, int pividx,float frame) const;
|
||||
void Get_Orientation(Quaternion& orientation, int pividx,float frame) const;
|
||||
void Get_Transform(Matrix3D& transform, int pividx,float frame) const;
|
||||
bool Get_Visibility(int pividx,float frame);
|
||||
|
||||
bool Is_Node_Motion_Present(int pividx);
|
||||
int Get_Num_Pivots(void) const { return NumNodes; }
|
||||
|
||||
// Methods that test the presence of a certain motion channel.
|
||||
bool Has_X_Translation (int pividx);
|
||||
bool Has_Y_Translation (int pividx);
|
||||
bool Has_Z_Translation (int pividx);
|
||||
bool Has_Rotation (int pividx);
|
||||
bool Has_Visibility (int pividx);
|
||||
NodeMotionStruct *Get_Node_Motion_Array(void) {return NodeMotion;}
|
||||
virtual int Class_ID(void) const { return CLASSID_HRAWANIM; }
|
||||
|
||||
private:
|
||||
|
||||
char Name[2*W3D_NAME_LEN];
|
||||
char HierarchyName[W3D_NAME_LEN];
|
||||
|
||||
int NumFrames;
|
||||
int NumNodes;
|
||||
float FrameRate;
|
||||
|
||||
NodeMotionStruct * NodeMotion;
|
||||
|
||||
void Free(void);
|
||||
bool read_channel(ChunkLoadClass & cload,MotionChannelClass * * newchan,bool pre30);
|
||||
void add_channel(MotionChannelClass * newchan);
|
||||
|
||||
bool read_bit_channel(ChunkLoadClass & cload,BitChannelClass * * newchan,bool pre30);
|
||||
void add_bit_channel(BitChannelClass * newchan);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1097
Generals/Code/Libraries/Source/WWVegas/WW3D2/htree.cpp
Normal file
1097
Generals/Code/Libraries/Source/WWVegas/WW3D2/htree.cpp
Normal file
File diff suppressed because it is too large
Load Diff
207
Generals/Code/Libraries/Source/WWVegas/WW3D2/htree.h
Normal file
207
Generals/Code/Libraries/Source/WWVegas/WW3D2/htree.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /VSS_Sync/ww3d2/htree.h 4 8/29/01 9:49p Vss_sync $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/ww3d2/htree.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 8/29/01 7:29p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HTREE_H
|
||||
#define HTREE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "pivot.h"
|
||||
#include "quat.h"
|
||||
#include "matrix3d.h"
|
||||
#include "vector3.h"
|
||||
#include "w3d_file.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
class HAnimClass;
|
||||
class HAnimComboClass;
|
||||
class MeshClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class HRawAnimClass;
|
||||
|
||||
/*
|
||||
|
||||
HTreeClass
|
||||
|
||||
A hierarchy of coordinate systems in an initial
|
||||
configuration. All motion data is applied to one
|
||||
of these objects. Motion is stored as deltas from
|
||||
the hierarchy tree's initial configuration.
|
||||
|
||||
Normally, the user will probably not deal with
|
||||
HTreeClasses; they are used internally
|
||||
by the HierarchyModelClass.
|
||||
|
||||
*/
|
||||
class HTreeClass : public W3DMPO
|
||||
{
|
||||
W3DMPO_GLUE(HTreeClass)
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
OK,
|
||||
LOAD_ERROR
|
||||
};
|
||||
|
||||
HTreeClass(void);
|
||||
HTreeClass(const HTreeClass & src);
|
||||
~HTreeClass(void);
|
||||
|
||||
int Load_W3D(ChunkLoadClass & cload);
|
||||
void Init_Default(void);
|
||||
|
||||
WWINLINE const char * Get_Name(void) const { return Name; }
|
||||
WWINLINE int Num_Pivots(void) const { return NumPivots; }
|
||||
int Get_Bone_Index(const char * name) const;
|
||||
const char * Get_Bone_Name(int boneid) const;
|
||||
int Get_Parent_Index(int bone_indx) const;
|
||||
|
||||
void Base_Update(const Matrix3D & root);
|
||||
|
||||
void Anim_Update( const Matrix3D & root,
|
||||
HAnimClass * motion,
|
||||
float frame);
|
||||
void Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame);
|
||||
|
||||
void Blend_Update( const Matrix3D & root,
|
||||
HAnimClass * motion0,
|
||||
float frame0,
|
||||
HAnimClass * motion1,
|
||||
float frame1,
|
||||
float percentage);
|
||||
|
||||
void Combo_Update( const Matrix3D & root,
|
||||
HAnimComboClass * anim);
|
||||
|
||||
WWINLINE const Matrix3D & Get_Transform(int pivot) const;
|
||||
WWINLINE bool Get_Visibility(int pivot) const;
|
||||
|
||||
WWINLINE const Matrix3D & Get_Root_Transform(void) const;
|
||||
|
||||
// User control over a bone. While a bone is captured, you can over-ride the
|
||||
// animation transform used by the bone.
|
||||
void Capture_Bone(int boneindex);
|
||||
void Release_Bone(int boneindex);
|
||||
bool Is_Bone_Captured(int boneindex) const;
|
||||
void Control_Bone(int boneindex,const Matrix3D & relative_tm,bool world_space_translation = false);
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Simple pivot evaluation methods for when the caller doesn't want
|
||||
// to update the whole animation, but needs to know the transform of
|
||||
// a pivot at a given frame.
|
||||
//
|
||||
bool Simple_Evaluate_Pivot (HAnimClass *motion, int pivot_index, float frame, const Matrix3D &obj_tm, Matrix3D *end_tm) const;
|
||||
|
||||
// Scale this HTree by a constant factor:
|
||||
void Scale(float factor);
|
||||
|
||||
// Morph the bones on the HTree using weights from a number of other HTrees
|
||||
static HTreeClass * Create_Morphed( int num_morph_sources,
|
||||
const float morph_weights[],
|
||||
const HTreeClass *tree_array[] );
|
||||
|
||||
// Create an HTree by Interpolating between others
|
||||
static HTreeClass * Create_Interpolated( const HTreeClass * tree_a0_b0,
|
||||
const HTreeClass * tree_a0_b1,
|
||||
const HTreeClass * tree_a1_b0,
|
||||
const HTreeClass * tree_a1_b1,
|
||||
float lerp_a, float lerp_b );
|
||||
|
||||
// Create an HTree by Interpolating between others
|
||||
static HTreeClass * Create_Interpolated( const HTreeClass * tree_base,
|
||||
const HTreeClass * tree_a,
|
||||
const HTreeClass * tree_b,
|
||||
float a_scale, float b_scale );
|
||||
|
||||
private:
|
||||
|
||||
char Name[W3D_NAME_LEN];
|
||||
int NumPivots;
|
||||
PivotClass * Pivot;
|
||||
float ScaleFactor;
|
||||
|
||||
void Free(void);
|
||||
bool read_pivots(ChunkLoadClass & cload,bool pre30);
|
||||
|
||||
friend class MeshClass;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
WWINLINE const Matrix3D & HTreeClass::Get_Root_Transform(void) const
|
||||
{
|
||||
return Pivot[0].Transform;
|
||||
}
|
||||
|
||||
WWINLINE bool HTreeClass::Get_Visibility(int pivot) const
|
||||
{
|
||||
WWASSERT(pivot >= 0);
|
||||
WWASSERT(pivot < NumPivots);
|
||||
return Pivot[pivot].IsVisible;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeClass::Get_Transform -- returns the transformation for the desired pivot *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE const Matrix3D & HTreeClass::Get_Transform(int pivot) const
|
||||
{
|
||||
assert(pivot >= 0);
|
||||
assert(pivot < NumPivots);
|
||||
|
||||
return Pivot[pivot].Transform;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
308
Generals/Code/Libraries/Source/WWVegas/WW3D2/htreemgr.cpp
Normal file
308
Generals/Code/Libraries/Source/WWVegas/WW3D2/htreemgr.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
** Command & Conquer Generals(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/ww3d2/htreemgr.cpp 1 1/22/01 3:36p Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G 3D Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/ww3d2/htreemgr.cpp $*
|
||||
* *
|
||||
* Author:: Byon_g *
|
||||
* *
|
||||
* $Modtime:: 1/08/01 10:04a $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* HTreeManagerClass::HTreeManagerClass -- constructor *
|
||||
* HTreeManagerClass::~HTreeManagerClass -- destructor *
|
||||
* HTreeManagerClass::Free -- de-allocate all memory in use *
|
||||
* HTreeManagerClass::Free_All_Trees -- de-allocates all hierarchy trees currently loaded *
|
||||
* HTreeManagerClass::Load_Tree -- load a hierarchy tree from a file *
|
||||
* HTreeManagerClass::Get_Tree_ID -- look up the ID of a named hierarchy tree *
|
||||
* HTreeManagerClass::Get_Tree -- get a pointer to the specified hierarchy tree *
|
||||
* HTreeManagerClass::Get_Tree -- get a pointer to the specified hierarchy tree *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "htreemgr.h"
|
||||
#include <string.h>
|
||||
#include "htree.h"
|
||||
#include "chunkio.h"
|
||||
#include "wwmemlog.h"
|
||||
#include "w3dexclusionlist.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::HTreeManagerClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HTreeManagerClass::HTreeManagerClass(void) :
|
||||
NumTrees(0)
|
||||
{
|
||||
for (int treeidx=0; treeidx < MAX_TREES; treeidx++) {
|
||||
TreePtr[treeidx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::~HTreeManagerClass -- destructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HTreeManagerClass::~HTreeManagerClass(void)
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Free -- de-allocate all memory in use *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HTreeManagerClass::Free(void)
|
||||
{
|
||||
Free_All_Trees();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Free_All_Trees -- de-allocates all hierarchy trees currently loaded *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HTreeManagerClass::Free_All_Trees(void)
|
||||
{
|
||||
for (int treeidx=0; treeidx < MAX_TREES; treeidx++) {
|
||||
if (TreePtr[treeidx] != NULL) {
|
||||
delete TreePtr[treeidx];
|
||||
TreePtr[treeidx] = NULL;
|
||||
}
|
||||
}
|
||||
NumTrees = 0;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Free_All_Trees_With_Exclusion_List -- de-allocates all trees not in list *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/12/2002 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void HTreeManagerClass::Free_All_Trees_With_Exclusion_List(const W3DExclusionListClass & exclusion_list)
|
||||
{
|
||||
// For this system, since it is so simplistic, we simply loop over the array either deleting the tree
|
||||
// or copying it to the new tail index if it is excluded.
|
||||
int new_tail = 0;
|
||||
|
||||
for (int treeidx=0; treeidx < MAX_TREES; treeidx++) {
|
||||
if (TreePtr[treeidx] != NULL) {
|
||||
|
||||
if (exclusion_list.Is_Excluded(TreePtr[treeidx])) {
|
||||
|
||||
//WWDEBUG_SAY(("excluding tree %s\n",TreePtr[treeidx]->Get_Name()));
|
||||
TreePtr[new_tail] = TreePtr[treeidx];
|
||||
new_tail++;
|
||||
|
||||
} else {
|
||||
|
||||
//WWDEBUG_SAY(("deleting tree %s\n",TreePtr[treeidx]->Get_Name()));
|
||||
delete TreePtr[treeidx];
|
||||
TreePtr[treeidx] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
NumTrees = new_tail;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Load_Tree -- load a hierarchy tree from a file *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HTreeManagerClass::Load_Tree(ChunkLoadClass & cload)
|
||||
{
|
||||
WWMEMLOG(MEM_ANIMATION);
|
||||
HTreeClass * newtree = W3DNEW HTreeClass;
|
||||
|
||||
if (newtree == NULL) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
if (newtree->Load_W3D(cload) != HTreeClass::OK) {
|
||||
|
||||
// load failed, delete and return error
|
||||
delete newtree;
|
||||
goto Error;
|
||||
|
||||
} else if (Get_Tree_ID(newtree->Get_Name()) != -1) {
|
||||
|
||||
// tree with this name already exists, reject it!
|
||||
delete newtree;
|
||||
goto Error;
|
||||
|
||||
} else {
|
||||
|
||||
// ok, accept this hierarchy tree!
|
||||
TreePtr[NumTrees] = newtree;
|
||||
NumTrees++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Get_Tree_ID -- look up the ID of a named hierarchy tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
int HTreeManagerClass::Get_Tree_ID(const char * name)
|
||||
{
|
||||
for (int i=0; i<NumTrees; i++) {
|
||||
if (TreePtr[i] && (stricmp(name,TreePtr[i]->Get_Name()) == 0)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Get_Tree_Name -- look up the name of a id'd hierarchy tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
char *HTreeManagerClass::Get_Tree_Name(const int idx)
|
||||
{
|
||||
if ((idx < NumTrees) && TreePtr[idx]) {
|
||||
if (TreePtr[idx]) {
|
||||
return (char *)TreePtr[idx]->Get_Name();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Get_Tree -- get a pointer to the specified hierarchy tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HTreeClass * HTreeManagerClass::Get_Tree(const char * name)
|
||||
{
|
||||
for (int i=0; i<NumTrees; i++) {
|
||||
if (TreePtr[i] && (stricmp(name,TreePtr[i]->Get_Name()) == 0)) {
|
||||
|
||||
return TreePtr[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* HTreeManagerClass::Get_Tree -- get a pointer to the specified hierarchy tree *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
HTreeClass * HTreeManagerClass::Get_Tree(int id)
|
||||
{
|
||||
if ((id >= 0) && (id < NumTrees)) {
|
||||
return TreePtr[id];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user