/*
** 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 .
*/
/***********************************************************************************************
*** 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;vEngine_Refs());
index_buffer->Add_Ref();
switch (index_buffer->Type()) {
case BUFFER_TYPE_DX8:
DX8_Assert();
DX8_ErrorCode(static_cast(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(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(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(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(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(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(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(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(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_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