You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
530 lines
18 KiB
530 lines
18 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, 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/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
/////////////////////////////////////////////////////////////////////////////// |
|
// // |
|
// plDXDeviceRefs.cpp - Functions for the various DX DeviceRef classes // |
|
// Cyan, Inc. // |
|
// // |
|
//// Version History ////////////////////////////////////////////////////////// |
|
// // |
|
// 4.25.2001 mcn - Created. // |
|
// // |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include "hsTypes.h" |
|
|
|
#include <d3d9.h> |
|
#include <ddraw.h> |
|
|
|
#include "hsWinRef.h" |
|
|
|
#include "plDXPipeline.h" |
|
#include "plDXDeviceRef.h" |
|
#include "plDXBufferRefs.h" |
|
#include "plDXLightRef.h" |
|
#include "plDXTextureRef.h" |
|
#include "plDXRenderTargetRef.h" |
|
#include "plGBufferGroup.h" |
|
#include "plDrawable/plGeometrySpan.h" |
|
#include "plDrawable/plDrawableSpans.h" |
|
#include "plGLight/plLightInfo.h" |
|
#include "plRenderTarget.h" |
|
#include "plCubicRenderTarget.h" |
|
#include "plDynamicEnvMap.h" |
|
|
|
#include "plProfile.h" |
|
#include "plStatusLog/plStatusLog.h" |
|
|
|
plProfile_CreateMemCounter("Vertices", "Memory", MemVertex); |
|
plProfile_CreateMemCounter("Indices", "Memory", MemIndex); |
|
plProfile_CreateMemCounter("Textures", "Memory", MemTexture); |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Generic plDXDeviceRef Functions ///////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
plDXDeviceRef::plDXDeviceRef() |
|
{ |
|
fNext = nil; |
|
fBack = nil; |
|
} |
|
|
|
plDXDeviceRef::~plDXDeviceRef() |
|
{ |
|
if( fNext != nil || fBack != nil ) |
|
Unlink(); |
|
} |
|
|
|
void plDXDeviceRef::Unlink( void ) |
|
{ |
|
hsAssert( fBack, "plDXDeviceRef not in list" ); |
|
if( fNext ) |
|
fNext->fBack = fBack; |
|
*fBack = fNext; |
|
|
|
fBack = nil; |
|
fNext = nil; |
|
} |
|
|
|
void plDXDeviceRef::Link( plDXDeviceRef **back ) |
|
{ |
|
hsAssert( fNext == nil && fBack == nil, "Trying to link a plDXDeviceRef that's already linked" ); |
|
|
|
fNext = *back; |
|
if( *back ) |
|
(*back)->fBack = &fNext; |
|
fBack = back; |
|
*back = this; |
|
} |
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// plDXVertex/IndexBufferRef Funktions ///////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// Destructors ////////////////////////////////////////////////////////////// |
|
|
|
plDXVertexBufferRef::~plDXVertexBufferRef() |
|
{ |
|
Release(); |
|
} |
|
|
|
plDXIndexBufferRef::~plDXIndexBufferRef() |
|
{ |
|
Release(); |
|
} |
|
|
|
//// Releases ///////////////////////////////////////////////////////////////// |
|
|
|
void plDXVertexBufferRef::Release( void ) |
|
{ |
|
if( fD3DBuffer != nil ) |
|
{ |
|
ReleaseObject(fD3DBuffer); |
|
if (!Volatile()) |
|
{ |
|
plProfile_DelMem(MemVertex, fCount * fVertexSize); |
|
PROFILE_POOL_MEM(D3DPOOL_MANAGED, fCount * fVertexSize, false, "VtxBuff"); |
|
plDXPipeline::FreeManagedVertex(fCount * fVertexSize); |
|
} |
|
} |
|
delete [] fData; |
|
fData = nil; |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
void plDXIndexBufferRef::Release( void ) |
|
{ |
|
if( fD3DBuffer != nil ) |
|
{ |
|
plProfile_DelMem(MemIndex, fCount * sizeof(uint16_t)); |
|
PROFILE_POOL_MEM(fPoolType, fCount * sizeof(uint16_t), false, "IndexBuff"); |
|
ReleaseObject( fD3DBuffer ); |
|
} |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// plDXTextureRef Funktions //////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// Set ////////////////////////////////////////////////////////////////////// |
|
|
|
plDXTextureRef& plDXTextureRef::Set( D3DFORMAT ft, uint32_t ml, uint32_t mw, uint32_t mh, uint32_t np, |
|
uint32_t sz, uint32_t manSize, uint32_t* lSz, void* pd, hsBool ed, hsBool renderTarget ) |
|
{ |
|
if( fDataSize > 0 ) |
|
plProfile_DelMem(MemTexture, fDataSize + sizeof(plDXTextureRef)); |
|
|
|
if( ( fFormatType != ft || fMMLvs != ml || fMaxWidth != mw || fMaxHeight != mh ) && fD3DTexture != nil ) |
|
ReleaseObject( fD3DTexture ); |
|
if( !fD3DTexture ) |
|
fUseTime = 0; |
|
|
|
fFormatType = ft; |
|
fMMLvs = ml; |
|
fMaxWidth = mw; |
|
fMaxHeight = mh; |
|
fNumPix = np; |
|
fDataSize = manSize; |
|
if( fLevelSizes != nil ) |
|
delete [] fLevelSizes; |
|
if( lSz ) |
|
fLevelSizes = lSz; |
|
else |
|
{ |
|
fLevelSizes = TRACKED_NEW uint32_t[1]; |
|
fLevelSizes[0] = sz; |
|
} |
|
fData = pd; |
|
fFlags = ( ed ? kExternData : 0 ) | ( renderTarget ? kRenderTarget : 0 ); |
|
|
|
plProfile_NewMem(MemTexture, fDataSize + sizeof(plDXTextureRef)); |
|
|
|
return *this; |
|
} |
|
|
|
//// Constructor & Destructor ///////////////////////////////////////////////// |
|
|
|
plDXTextureRef::plDXTextureRef( D3DFORMAT ft, uint32_t ml, uint32_t mw, uint32_t mh, uint32_t np, |
|
uint32_t sz, uint32_t manSize, uint32_t* lSz, void* pd, hsBool ed, hsBool renderTarget ) |
|
{ |
|
fLevelSizes = nil; |
|
fOwner = nil; |
|
fD3DTexture = nil; |
|
fDataSize = 0; |
|
fFlags = 0; |
|
fFormatType = D3DFMT_UNKNOWN; |
|
fMMLvs = 0; |
|
fMaxWidth = 0; |
|
fMaxHeight = 0; |
|
Set( ft, ml, mw, mh, np, sz, manSize, lSz, pd, ed, renderTarget ); |
|
} |
|
|
|
plDXTextureRef::~plDXTextureRef() |
|
{ |
|
Release(); |
|
|
|
delete [] fLevelSizes; |
|
} |
|
|
|
//// Release ////////////////////////////////////////////////////////////////// |
|
|
|
void plDXTextureRef::Release( void ) |
|
{ |
|
plProfile_DelMem(MemTexture, fDataSize + sizeof(plDXTextureRef)); |
|
plProfile_Extern(ManagedMem); |
|
PROFILE_POOL_MEM(D3DPOOL_MANAGED, fDataSize, false, (fOwner ? fOwner->GetKey() ? fOwner->GetKey()->GetUoid().GetObjectName() : "(UnknownTexture)" : "(UnknownTexture)")); |
|
plDXPipeline::FreeManagedTexture(fDataSize); |
|
fDataSize = 0; |
|
|
|
ReleaseObject( fD3DTexture ); |
|
SetDirty( true ); |
|
} |
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// plDXLightRef Funktions ////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// UpdateD3DInfo //////////////////////////////////////////////////////////// |
|
|
|
#define SET_D3DCOLORVALUE( v, color ) { v.r = color.r; v.g = color.g; v.b = color.b; v.a = color.a; } |
|
|
|
void plDXLightRef::UpdateD3DInfo( IDirect3DDevice9 *dev, plDXLightSettings *settings ) |
|
{ |
|
plDirectionalLightInfo *dirOwner; |
|
plOmniLightInfo *omniOwner; |
|
plSpotLightInfo *spotOwner; |
|
const float maxRange = 32767.f; |
|
|
|
|
|
/// Properties that are set for all types |
|
fD3DDevice = dev; |
|
fParentSettings = settings; |
|
|
|
memset( &fD3DInfo, 0, sizeof( D3DLIGHT9 ) ); |
|
SET_D3DCOLORVALUE( fD3DInfo.Diffuse, fOwner->GetDiffuse() ); |
|
SET_D3DCOLORVALUE( fD3DInfo.Ambient, fOwner->GetAmbient() ); |
|
SET_D3DCOLORVALUE( fD3DInfo.Specular, fOwner->GetSpecular() ); |
|
|
|
if( ( omniOwner = plOmniLightInfo::ConvertNoRef( fOwner ) ) != nil ) |
|
{ |
|
fD3DInfo.Type = D3DLIGHT_POINT; |
|
|
|
hsPoint3 position = omniOwner->GetWorldPosition(); |
|
fD3DInfo.Position.x = position.fX; |
|
fD3DInfo.Position.y = position.fY; |
|
fD3DInfo.Position.z = position.fZ; |
|
|
|
if( omniOwner->GetRadius() == 0 ) |
|
fD3DInfo.Range = maxRange; |
|
else |
|
fD3DInfo.Range = omniOwner->GetRadius(); |
|
fD3DInfo.Attenuation0 = omniOwner->GetConstantAttenuation(); |
|
fD3DInfo.Attenuation1 = omniOwner->GetLinearAttenuation(); |
|
fD3DInfo.Attenuation2 = omniOwner->GetQuadraticAttenuation(); |
|
|
|
// If the light is a spot, but it has a projected texture, then |
|
// the cone attenuation is handled by the texture. We're only using |
|
// the D3D light for distance attenuation and the N*L term. So |
|
// we can just leave the D3D light as the cheaper and more stable |
|
// Omni light. This sort of obviates the change below. - mf |
|
if( !omniOwner->GetProjection() |
|
&& (spotOwner = plSpotLightInfo::ConvertNoRef(fOwner)) ) |
|
{ |
|
fD3DInfo.Type = D3DLIGHT_SPOT; |
|
|
|
hsVector3 direction = spotOwner->GetWorldDirection(); |
|
fD3DInfo.Direction.x = direction.fX; |
|
fD3DInfo.Direction.y = direction.fY; |
|
fD3DInfo.Direction.z = direction.fZ; |
|
|
|
fD3DInfo.Falloff = spotOwner->GetFalloff(); |
|
fD3DInfo.Theta = spotOwner->GetSpotInner() * 2; |
|
// fD3DInfo.Phi = spotOwner->GetProjection() ? M_PI : spotOwner->GetSpotOuter() * 2; |
|
// D3D doesn't seem to like a Phi of PI, even though that's supposed to be the |
|
// largest legal value. Symptom is an erratic, intermitant, unpredictable failure |
|
// of the light to light, with bizarreness like lighting one object but not the object |
|
// next to it, alternating which object it fails on each frame (or less often). |
|
// So, whatever. - mf |
|
fD3DInfo.Phi = spotOwner->GetSpotOuter() * 2; |
|
} |
|
} |
|
else if( ( dirOwner = plDirectionalLightInfo::ConvertNoRef( fOwner ) ) != nil ) |
|
{ |
|
fD3DInfo.Type = D3DLIGHT_DIRECTIONAL; |
|
|
|
hsVector3 direction = dirOwner->GetWorldDirection(); |
|
fD3DInfo.Direction.x = direction.fX; |
|
fD3DInfo.Direction.y = direction.fY; |
|
fD3DInfo.Direction.z = direction.fZ; |
|
} |
|
else |
|
{ |
|
hsAssert( false, "Unrecognized light type passed to plDXLightRef::UpdateD3DInfo()" ); |
|
return; |
|
} |
|
|
|
fD3DDevice->SetLight( fD3DIndex, &fD3DInfo ); |
|
fScale = 1.f; |
|
} |
|
|
|
//// Destructor /////////////////////////////////////////////////////////////// |
|
|
|
plDXLightRef::~plDXLightRef() |
|
{ |
|
Release(); |
|
} |
|
|
|
//// Release ////////////////////////////////////////////////////////////////// |
|
|
|
void plDXLightRef::Release( void ) |
|
{ |
|
// Ensure that this light is disabled |
|
if( fD3DDevice ) |
|
{ |
|
fD3DDevice->LightEnable( fD3DIndex, false ); |
|
fD3DDevice = nil; |
|
} |
|
|
|
if( fParentSettings ) |
|
{ |
|
fParentSettings->fEnabledFlags.SetBit( fD3DIndex, false ); |
|
fParentSettings->ReleaseD3DIndex( fD3DIndex ); |
|
fParentSettings = nil; |
|
} |
|
fD3DIndex = 0; |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// plDXRenderTargetRef Functions /////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// Constructor ////////////////////////////////////////////////////////////// |
|
|
|
plDXRenderTargetRef::plDXRenderTargetRef( D3DFORMAT tp, uint32_t ml, plRenderTarget *owner, hsBool releaseDepthOnDelete ) |
|
: plDXTextureRef( tp, ml, owner->GetWidth(), owner->GetHeight(), |
|
owner->GetWidth() * owner->GetHeight(), |
|
owner->GetWidth() * owner->GetHeight() * ( owner->GetPixelSize() >> 3 ), |
|
0, |
|
nil, |
|
nil, true, true ) |
|
{ |
|
fD3DColorSurface = nil; |
|
fD3DDepthSurface = nil; |
|
fReleaseDepth = releaseDepthOnDelete; |
|
fOwner = owner; |
|
|
|
if( owner->GetFlags() & plRenderTarget::kIsTexture ) |
|
fFlags |= kOffscreenRT; |
|
|
|
if( owner->GetFlags() & plRenderTarget::kIsProjected ) |
|
{ |
|
if( owner->GetFlags() & plRenderTarget::kIsOrtho ) |
|
fFlags |= kOrthoProjection; |
|
else |
|
fFlags |= kPerspProjection; |
|
} |
|
|
|
if( plCubicRenderTarget::ConvertNoRef( owner ) != nil ) |
|
fFlags |= kCubicMap; |
|
} |
|
|
|
//// Set ////////////////////////////////////////////////////////////////////// |
|
|
|
plDXRenderTargetRef& plDXRenderTargetRef::Set( D3DFORMAT tp, uint32_t ml, plRenderTarget *owner ) |
|
{ |
|
fOwner = owner; |
|
|
|
plDXTextureRef::Set( tp, ml, owner->GetWidth(), owner->GetHeight(), |
|
owner->GetWidth() * owner->GetHeight(), |
|
owner->GetWidth() * owner->GetHeight() * ( owner->GetPixelSize() >> 3 ), |
|
0, |
|
nil, |
|
nil, true, true ); |
|
|
|
if( owner->GetFlags() & plRenderTarget::kIsTexture ) |
|
fFlags |= kOffscreenRT; |
|
|
|
if( owner->GetFlags() & plRenderTarget::kIsProjected ) |
|
{ |
|
if( owner->GetFlags() & plRenderTarget::kIsOrtho ) |
|
fFlags |= kOrthoProjection; |
|
else |
|
fFlags |= kPerspProjection; |
|
} |
|
|
|
if( plCubicRenderTarget::ConvertNoRef( owner ) != nil ) |
|
fFlags |= kCubicMap; |
|
|
|
return *this; |
|
} |
|
|
|
//// SetTexture /////////////////////////////////////////////////////////////// |
|
|
|
void plDXRenderTargetRef::SetTexture( IDirect3DSurface9 *surface, IDirect3DSurface9 *depth ) |
|
{ |
|
fD3DColorSurface = surface; |
|
fD3DTexture = nil; |
|
fD3DDepthSurface = depth; |
|
} |
|
|
|
void plDXRenderTargetRef::SetTexture( IDirect3DTexture9 *surface, IDirect3DSurface9 *depth ) |
|
{ |
|
fD3DTexture = surface; |
|
fD3DColorSurface = nil; |
|
fD3DDepthSurface = depth; |
|
} |
|
|
|
void plDXRenderTargetRef::SetTexture( IDirect3DCubeTexture9 *surface, IDirect3DSurface9 *depth ) |
|
{ |
|
int i; |
|
IDirect3DSurface9 *surf; |
|
plDXRenderTargetRef *ref; |
|
plCubicRenderTarget *cubic; |
|
D3DCUBEMAP_FACES faces[ 6 ] = { D3DCUBEMAP_FACE_NEGATIVE_X, // Left |
|
D3DCUBEMAP_FACE_POSITIVE_X, // Right |
|
D3DCUBEMAP_FACE_POSITIVE_Z, // Front |
|
D3DCUBEMAP_FACE_NEGATIVE_Z, // Back |
|
D3DCUBEMAP_FACE_POSITIVE_Y, // Top |
|
D3DCUBEMAP_FACE_NEGATIVE_Y }; // Bottom |
|
|
|
|
|
fD3DTexture = surface; |
|
fD3DDepthSurface = depth; |
|
fD3DColorSurface = nil; |
|
|
|
/// Get the faces and assign to each of the child targets |
|
cubic = plCubicRenderTarget::ConvertNoRef( fOwner ); |
|
for( i = 0; i < 6; i++ ) |
|
{ |
|
if( surface->GetCubeMapSurface( faces[ i ], 0, &surf ) != D3D_OK ) |
|
{ |
|
hsAssert( false, "Unable to get cube map surface" ); |
|
continue; |
|
} |
|
ref = (plDXRenderTargetRef *)cubic->GetFace( i )->GetDeviceRef(); |
|
|
|
ref->SetTexture( surf, depth ); |
|
} |
|
} |
|
|
|
//// Destructor /////////////////////////////////////////////////////////////// |
|
|
|
plDXRenderTargetRef::~plDXRenderTargetRef() |
|
{ |
|
Release(); |
|
} |
|
|
|
//// Release ////////////////////////////////////////////////////////////////// |
|
|
|
void plDXRenderTargetRef::Release( void ) |
|
{ |
|
int i; |
|
plCubicRenderTarget *cubic; |
|
plDXRenderTargetRef *ref; |
|
|
|
|
|
/// Get rid of the children's deviceRefs |
|
if( fFlags & kCubicMap ) |
|
{ |
|
cubic = plCubicRenderTarget::ConvertNoRef( fOwner ); |
|
for( i = 0; i < 6; i++ ) |
|
{ |
|
ref = (plDXRenderTargetRef *)cubic->GetFace( i )->GetDeviceRef(); |
|
ref->Release(); |
|
ref->SetDirty( true ); |
|
} |
|
// No need to call D3DSURF_MEMDEL on our fD3DTexture. It'll get |
|
// accounted for by our children's surfaces. |
|
} |
|
else |
|
{ |
|
// We do internal accounting here. Actual release of fD3DTexture |
|
// happens in plDXTextureRef::Release() |
|
D3DSURF_MEMDEL((IDirect3DTexture9*)fD3DTexture); |
|
} |
|
|
|
D3DSURF_MEMDEL(fD3DColorSurface); |
|
ReleaseObject( fD3DColorSurface ); |
|
if( fReleaseDepth ) |
|
{ |
|
// TODO: |
|
// We don't know who all is sharing this depth surface, so we can't |
|
// confidently say this memory is free now. We're reffing and releasing |
|
// it properly as far as DirectX is concerned, but our internal memory |
|
// counter is ignoring it. |
|
//D3DSURF_MEMDEL(fD3DDepthSurface); |
|
ReleaseObject( fD3DDepthSurface ); |
|
} |
|
|
|
plDXTextureRef::Release(); |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
|