Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS

Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
This commit is contained in:
Cyd
2026-06-24 21:28:16 -05:00
commit 2b8ca921cb
66341 changed files with 7923174 additions and 0 deletions
@@ -0,0 +1,538 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ArrangeMegatexturesProcess::ArrangeMegatexturesProcess(NotationFile *mega_file):
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ArrangeMegatexturesProcess::ArrangeMegatexturesProcess(
NotationFile *config_file,
NotationFile *mega_file
):
Process(config_file),
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(config_file);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ArrangeMegatexturesProcess::ProcessCallback(
int error,
const char* megatexture,
const char* texture
)
{
Check_Object(this);
Check_Pointer(megatexture);
switch (error)
{
case BadPageSize:
PAUSE(("[%s] has a bad PageSize!", megatexture));
break;
case BadTextureLine:
Check_Pointer(texture);
PAUSE(("[%s] has a bad Texture= specification!", megatexture));
break;
case BadTexture:
Check_Pointer(texture);
PAUSE(("[%s]%s is a bad texture!", megatexture, texture));
break;
case NotEnoughRoom:
Check_Pointer(texture);
PAUSE(("[%s] doesn't have enough room to hold %s!", megatexture, texture));
break;
case EmptyMegatexture:
PAUSE(("[%s] is empty!", megatexture));
break;
}
}
const int Offsets[32]=
{
0, 1, 4, 5,
16, 17, 20, 21,
64, 65, 68, 69,
80, 81, 84, 85,
256, 257, 260, 261,
272, 273, 276, 277,
320, 321, 324, 325,
336, 337, 340, 341
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::ArrangeMegatextures(ArrangeMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Get the mega texture data
//--------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
MString mega_name;
GetName(&mega_name);
Check_Object(&mega_name);
Vector2DOf<int> mega_size;
GetImageSize(&mega_size);
Verify(
mega_size.x >= 16 && mega_size.x <= 512
&& mega_size.y >= 16 && mega_size.y <= 512
&& mega_size.x == (mega_size.x & -mega_size.x)
&& mega_size.y == (mega_size.y & -mega_size.y)
&& mega_size.x == mega_size.y
);
TextureLibrary *library = GetTextureLibrary();
Check_Object(library);
//
//-------------------------------
// Create the various size arrays
//-------------------------------
//
Vector2DOf<int> cells(mega_size.x>>4, mega_size.y>>4);
DynamicArrayOf<bool> used(false, cells.x*cells.y);
//
//-------------------------------------------------
// Tell the application if the megatexture is empty
//-------------------------------------------------
//
Page *texture_page = mega_file->FindPage(mega_name);
ChainOf<Note*> *textures = NULL;
int texture_count = 0;
if (texture_page)
{
textures = texture_page->MakeNoteChain("Texture");
Register_Object(textures);
Page::NoteIterator texture_itr(textures);
texture_count = texture_itr.GetSize();
}
if (!texture_count)
{
process->ProcessCallback(
ArrangeMegatexturesProcess::EmptyMegatexture,
mega_name,
NULL
);
if (!process->continueProcess)
{
Unwind_1:
if (textures)
{
Unregister_Object(textures);
delete textures;
}
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
}
//
//----------------------------------------------------------------------
// Now start stepping through the entries for the page and skip the page
// size entry
//----------------------------------------------------------------------
//
DynamicArrayOf<Vector2DOf<int> >
offsets(texture_count),
sizes(texture_count);
DynamicArrayOf<TextureProxy*>
proxies(texture_count);
int errors = 0;
texture_count = -1;
Page::NoteIterator texture_itr(textures);
Note *entry;
while ((entry = texture_itr.ReadAndNext()) != NULL)
{
Check_Object(entry);
++texture_count;
Verify(texture_count >= 0);
//
//--------------------------------------------
// Extract the texture data from the tron file
//--------------------------------------------
//
const char* data;
entry->GetEntry(&data);
Check_Pointer(data);
char texture_name[80];
int param_count = sscanf(data, "%s", texture_name);
if (param_count != 1 || !strlen(texture_name))
{
process->ProcessCallback(
ArrangeMegatexturesProcess::BadTextureLine,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
continue;
}
}
//
//--------------------------
// Do the status check again
//--------------------------
//
process->ProcessCallback(
ArrangeMegatexturesProcess::StatusCheck,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
//
//-----------------------------------------------------------------
// We now have a texture name, so get the actual texture proxy from
// the library
//-----------------------------------------------------------------
//
proxies[texture_count] = library->UseTextureProxy(texture_name);
Check_Object(proxies[texture_count]);
//
//---------------------------
// Make sure the size is good
//---------------------------
//
proxies[texture_count]->GetImageSize(&sizes[texture_count]);
if (!sizes[texture_count].x && !sizes[texture_count].y)
{
process->ProcessCallback(
ArrangeMegatexturesProcess::BadTexture,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_2:
for (int i=0; i<=texture_count; ++i)
proxies[i]->DetachReference();
UNWIND();
#undef UNWIND
#define UNWIND() goto Unwind_2
}
else
{
++errors;
continue;
}
}
Verify(
sizes[texture_count].x >= 16 && sizes[texture_count].x <= 512
&& sizes[texture_count].y >= 16 && sizes[texture_count].y <= 512
&& sizes[texture_count].x == (sizes[texture_count].x & -sizes[texture_count].x)
&& sizes[texture_count].y == (sizes[texture_count].y & -sizes[texture_count].y)
);
//
//------------------------------------------------------------------------
// Find the parameters for the search, which is based upon an interleaving
// scheme using a bit-wise mix of the x and y index values
//------------------------------------------------------------------------
//
Vector2DOf<int>
units(sizes[texture_count].x>>4, sizes[texture_count].y>>4);
Verify(units.x>0 && units.y>0);
int
increment,
run,
scale;
if (units.x < units.y)
{
run = units.y / units.x;
scale = units.x*units.x;
increment = scale * run*run;
}
else
{
run = units.x / units.y;
scale = units.y*units.y;
increment = scale * run*run;
scale *= 2;
}
//
//--------------------------------------------------------------------
// We search the array associated with the step, looking for the first
// empty slot that matches
//--------------------------------------------------------------------
//
int index;
int i;
for (index=0; index<used.GetLength(); index += increment)
{
for (i=0; i<run; ++i)
{
int sub_index = scale*Offsets[i];
if (!used[index + sub_index])
{
index += sub_index;
break;
}
}
if (i!=run)
break;
}
//
//-----------------------------------------------------
// If we don't find any empty slots, do the error thing
//-----------------------------------------------------
//
if (index == used.GetLength())
{
process->ProcessCallback(
ArrangeMegatexturesProcess::NotEnoughRoom,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
continue;
}
}
//
//--------------------
// Mark the used cells
//--------------------
//
int x,y;
for (y=0; y<units.y; ++y)
for (x=0; x<units.x; ++x)
{
Verify(!used[index + Offsets[y]*2 + Offsets[x]]);
used[index + Offsets[y]*2 + Offsets[x]] = true;
}
//
//----------------------------------------
// Extract the x,y location from the index
//----------------------------------------
//
int mask=1;
x = y = 0;
while (index)
{
if (index&1)
x |= mask;
index >>= 1;
if (index&1)
y |= mask;
index >>= 1;
mask <<= 1;
}
offsets[texture_count].x = x<<4;
offsets[texture_count].y = y<<4;
}
#undef UNWIND
#define UNWIND() goto Unwind_1
//
//------------------------------------------------------------------------
// If we don't have any errors, go ahead and save our data back out to the
// notation file. We first will have to erase the old texture entries
//------------------------------------------------------------------------
//
if (!errors)
{
Note* dummy;
texture_itr.First();
while ((dummy = texture_itr.ReadAndNext()) != NULL)
texture_page->DeleteNote(dummy->GetName());
int i;
for (i=0; i<=texture_count; ++i)
{
char buffer[80];
MString texture_name;
Check_Object(proxies[i]);
proxies[i]->GetName(&texture_name);
sprintf(
buffer,
"%s %d %d %d %d",
static_cast<const char*>(texture_name),
offsets[i].x,
offsets[i].y,
sizes[i].x,
sizes[i].y
);
texture_page->AppendEntry("Texture", buffer);
}
//
//-----------------------------------------------
// Now tell the debug stream about the space left
//-----------------------------------------------
//
DynamicArrayOf<int> room(5);
int total=0;
for (i=0; i<5; ++i)
{
total <<= 2;
int shift = 8 - 2*i;
int range = 4 << (2*i);
int count=0;
for (int j=0; j<range; ++j)
if (!used[j<<shift])
++count;
room[i] = count - total;
total = count;
}
if (total)
{
SPEW(("ArrangeMegatextures", "\n[%s] has room for:", mega_name));
for (i=0; i<5; ++i)
{
if (room[i])
SPEW((
"ArrangeMegatextures",
"\t%d %dx%d textures",
room[i],
256 >> i,
256 >> i
));
}
}
}
//
//---------
// Clean up
//---------
//
for (int i=0; i<=texture_count; ++i)
proxies[i]->DetachReference();
UNWIND();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::ArrangeMegatextures(ArrangeMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------------------
// Get the page list from the mega file and process each page after making
// sure the app says it's OK
//------------------------------------------------------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
NotationFile::PageIterator *pages = mega_file->MakePageIterator();
Register_Object(pages);
Page *page;
while ((page = pages->ReadAndNext()) != NULL)
{
const char* mega_name = page->GetName();
Check_Pointer(mega_name);
process->ProcessCallback(
ArrangeMegatexturesProcess::StatusCheck,
mega_name,
NULL
);
if (!process->continueProcess)
break;
//
//----------------------------------------------------------------------
// For each page, get a list of all the entries. If the page is missing
// its PageSize page, it is a final uncoalesced texture, so skip it
//----------------------------------------------------------------------
//
const char* size_string;
if (!page->GetEntry("PageSize", &size_string))
continue;
//
//------------------------------
// Make sure the page size is OK
//------------------------------
//
Vector2DOf<int> mega_size;
#if defined(_ARMOR)
int param_count =
#endif
sscanf(size_string, "%d %d", &mega_size.x, &mega_size.y);
Verify(param_count);
if (
mega_size.x < 16 || mega_size.x > 512
|| mega_size.y < 16 || mega_size.y > 512
|| mega_size.x != (mega_size.x & -mega_size.x)
|| mega_size.y != (mega_size.y & -mega_size.y)
)
{
process->ProcessCallback(
ArrangeMegatexturesProcess::BadPageSize,
mega_name,
NULL
);
if (!process->continueProcess)
break;
else
continue;
}
//
//---------------------------------------------------
// Create the megatexture proxy run the process on it
//---------------------------------------------------
//
TextureProxy *mega_texture =
TextureProxy::MakeProxy(mega_name, mega_size, this);
Register_Object(mega_texture);
mega_texture->ArrangeMegatextures(process);
mega_texture->DetachReference();
//
//---------
// Clean up
//---------
//
if (!process->continueProcess)
break;
}
//
//-----------------------
// Clean up the page list
//-----------------------
//
Unregister_Object(pages);
delete pages;
}
@@ -0,0 +1,38 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class ArrangeMegatexturesProcess:
public Process
{
public:
ArrangeMegatexturesProcess(Stuff::NotationFile *mega_file);
ArrangeMegatexturesProcess(
Stuff::NotationFile *config_file,
Stuff::NotationFile *mega_file
);
enum {
StatusCheck,
BadPageSize,
BadTextureLine,
BadTexture,
NotEnoughRoom,
EmptyMegatexture
};
virtual void
ProcessCallback(
int error,
const char* megatexture,
const char* texture
);
Stuff::NotationFile
*megaFile;
};
}
@@ -0,0 +1,456 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BinSortProcess::BinSortProcess(NotationFile *data_file):
Process(data_file)
{
Check_Object(data_file);
binSize = 20;
Page *page = data_file->FindPage("BinSort");
if (page)
page->GetEntry("BinSize", reinterpret_cast<int*>(&binSize));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::BinSort(BinSortProcess *process)
{
Check_Object(this);
Check_Object(process);
process->BinSortCallback(this);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::BinSort(BinSortProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->BinSortCallback(this);
if (!process->continueProcess)
return true;
//
//------------------------------------------------------------------------
// Make a list of all the polygons, and if its empty, destroy the mesh and
// return
//------------------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> polygons;
UsePolygonArray(&polygons);
unsigned polygon_count = polygons.GetLength();
if (!polygon_count)
{
Destroy();
return false;
}
//
//---------------------------------------------------------
// If the polygon mesh is already small enough, just return
//---------------------------------------------------------
//
if (polygon_count <= process->binSize)
{
DetachArrayReferences(&polygons);
return true;
}
//
//---------------------------------
// Make a list of all the centroids
//---------------------------------
//
DynamicArrayOf<Point3D> centroids(polygon_count);
unsigned i;
PolygonProxy *polygon;
for (i=0; i<polygon_count; ++i)
{
polygon = polygons[i];
Check_Object(polygon);
Scalar area = polygon->GetSurfaceAreaAndCentroid(&centroids[i]);
if (area > SMALL)
centroids[i] /= area;
}
//
//------------------------------------------------------------------------
// Calculate the dividing plane, and if none can be found, don't do nothin
//------------------------------------------------------------------------
//
Plane plane;
if (!plane.ComputeBestDividingPlane(centroids))
{
DetachArrayReferences(&polygons);
return true;
}
//
//-------------------------------------------------------------------------
// The mesh is too big, so we have to cut it up. Make a group proxy to
// hold the new mesh collection
//-------------------------------------------------------------------------
//
GroupProxy *parent = GetParentGroupProxy();
GroupProxy *group;
if (parent)
{
Check_Object(parent);
group = parent->AppendNewGroupProxy();
}
else
group = GetSceneProxy()->AppendNewGroupProxy();
//
//----------------------------------
// Set the position of the group
//----------------------------------
//
LinearMatrix4D m;
if (GetLocalToParent(&m))
{
SetLocalToParent(LinearMatrix4D::Identity);
group->SetLocalToParent(m);
}
MString name;
if (GetName(&name))
{
SetName(NULL);
group->SetName(name);
}
//
//-----------------------------------------------------------------------
// Create two new meshes under the group for the mesh to be split up into
//-----------------------------------------------------------------------
//
PolygonMeshProxy *bin_a = group->AppendNewPolygonMeshProxy();
Check_Object(bin_a);
PolygonMeshProxy *bin_b = group->AppendNewPolygonMeshProxy();
Check_Object(bin_b);
DynamicArrayOf<PolygonProxy*>
group_a(polygon_count),
group_b(polygon_count);
unsigned
count_a = 0,
count_b = 0;
//
//------------------------------------------------------------------
// Sort each of the centroids against the plane into one of two bins
//------------------------------------------------------------------
//
for (i=0; i<polygon_count; ++i)
{
polygon = polygons[i];
Check_Object(polygon);
if (plane.GetDistanceTo(centroids[i]) < 0.0f)
group_b[count_b++] = polygon;
else
group_a[count_a++] = polygon;
}
//
//---------------------------------
// Now add the polygons to each bin
//---------------------------------
//
Verify(count_a>0);
group_a.SetLength(count_a);
bin_a->AddPolygons(process, group_a);
Verify(count_b>0);
group_b.SetLength(count_b);
bin_b->AddPolygons(process, group_b);
//
//-------------------------------------------------------------------
// Now that the mesh has been split up, Bin_Sort each smaller mesh and
// destroy this mesh
//-------------------------------------------------------------------
//
if (bin_a->BinSort(process))
bin_a->DetachReference();
if (!process->continueProcess)
{
bin_b->DetachReference();
group->DetachReference();
DetachArrayReferences(&polygons);
Destroy();
return false;
}
if (bin_b->BinSort(process))
bin_b->DetachReference();
//
//-----------------------------------------
// Now set the bounding sphere of the group
//-----------------------------------------
//
group->DetachReference();
DetachArrayReferences(&polygons);
Destroy();
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::BinSort(BinSortProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->BinSortCallback(this);
if (!process->continueProcess)
return true;
//
//-----------------------------------------------------------------------
// If this group has two or fewer children, we won't have to split it, so
// just return
//-----------------------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
unsigned i;
if (child_count <= 2)
{
for (i=0; child; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->BinSort(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
Check_Object(child);
child->DetachReference();
break;
}
}
}
return true;
}
//
//---------------------------------
// Make a list of all the centroids
//---------------------------------
//
DynamicArrayOf<Point3D> centroids(child_count);
for (i=0; child; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
Point3D local_centroid;
child->GetCentroid(&local_centroid);
LinearMatrix4D m;
child->GetLocalToParent(&m);
centroids[i].Multiply(local_centroid, m);
child->DetachReference();
child = next;
}
Verify(!child);
//
//------------------------------------------------------------------------
// Calculate the dividing plane, and if none can be found, don't do nothin
//------------------------------------------------------------------------
//
Plane plane;
if (!plane.ComputeBestDividingPlane(centroids))
return true;
//
//----------------------------------------------------------------------
// The collection is too big, so we have to cut it up. Make a group
// proxy to hold the new collection
//----------------------------------------------------------------------
//
GroupProxy *group_a = AppendNewGroupProxy();
GroupProxy *group_b = AppendNewGroupProxy();
//
//------------------------------------------------------------------
// Calculate the dividing plane, and then sort each of the centroids
// against the plane
//------------------------------------------------------------------
//
child = UseFirstChildProxy();
for (i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
Scalar distance = plane.GetDistanceTo(centroids[i]);
if (distance > SMALL)
child->TransferAndAppendToParentGroup(group_b);
else
child->TransferAndAppendToParentGroup(group_a);
child->DetachReference();
child = next;
}
if (child)
child->DetachReference();
//
//------------------------------------------------------------------------
// Now that the group has been split up, Bin_Sort each smaller mesh and
// destroy this mesh
//------------------------------------------------------------------------
//
Verify(group_a->GetChildCount() > 0);
if (group_a->BinSort(process))
group_a->DetachReference();
if (!process->continueProcess)
{
group_b->DetachReference();
return true;
}
Verify(group_b->GetChildCount() > 0);
if (group_b->BinSort(process))
group_b->DetachReference();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::BinSort(BinSortProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->BinSortCallback(this);
if (!process->continueProcess)
return;
//
//------------------------------------------------------------------------
// If this group has two or fewer children, we won't have to split it,
// so just return
//------------------------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
unsigned i;
if (child_count <= 2)
{
for (i=0; child; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->BinSort(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
Check_Object(child);
child->DetachReference();
break;
}
}
}
return;
}
//
//---------------------------------
// Make a list of all the centroids
//---------------------------------
//
DynamicArrayOf<Point3D> centroids(child_count);
for (i=0; child; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
Point3D local_centroid;
child->GetCentroid(&local_centroid);
LinearMatrix4D m;
child->GetLocalToParent(&m);
centroids[i].Multiply(local_centroid, m);
child->DetachReference();
child = next;
}
Verify(!child);
//
//------------------------------------------------------------------------
// Calculate the dividing plane, and if none can be found, don't do nothin
//------------------------------------------------------------------------
//
Plane plane;
if (!plane.ComputeBestDividingPlane(centroids))
return;
//
//----------------------------------------------------------------------
// Create two new meshes under the group for the mesh to be split up
// into
//----------------------------------------------------------------------
//
GroupProxy *a = AppendNewGroupProxy();
GroupProxy *b = AppendNewGroupProxy();
//
//------------------------------------------------------------------
// Calculate the dividing plane, and then sort each of the centroids
// against the plane
//------------------------------------------------------------------
//
child = UseFirstChildProxy();
for (i=0; i<child_count; ++i)
{
ChildProxy *next = child->UseNextSiblingProxy();
if (plane.GetDistanceTo(centroids[i]) > SMALL)
child->TransferAndAppendToParentGroup(a);
else
child->TransferAndAppendToParentGroup(b);
child->DetachReference();
child = next;
}
child->DetachReference();
//
//------------------------------------------------------------------------
// Now that the group has been split up, Bin_Sort each smaller mesh and
// destroy this mesh
//------------------------------------------------------------------------
//
Verify(a->GetChildCount() > 0);
if (a->BinSort(process))
a->DetachReference();
if (!process->continueProcess)
b->DetachReference();
else
{
Verify(b->GetChildCount() > 0);
if (b->BinSort(process))
b->DetachReference();
}
}
@@ -0,0 +1,25 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class BinSortProcess:
public Process
{
public:
BinSortProcess(unsigned bin_size):
binSize(bin_size)
{}
BinSortProcess(Stuff::NotationFile *data_file);
virtual void
BinSortCallback(GenericProxy* proxy)
{}
unsigned
binSize;
};
}
@@ -0,0 +1,562 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BuildMegatexturesProcess::BuildMegatexturesProcess(NotationFile *mega_file):
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BuildMegatexturesProcess::BuildMegatexturesProcess(
NotationFile *config_file,
NotationFile *mega_file
):
Process(config_file),
megaFile(mega_file)
{
Check_Pointer(this);
Check_Object(config_file);
Check_Object(megaFile);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BuildMegatexturesProcess::ProcessCallback(
int error,
const char* megatexture,
const char* texture
)
{
Check_Object(this);
Check_Pointer(megatexture);
switch (error)
{
case BadPageSize:
PAUSE(("[%s] has a bad PageSize!", megatexture));
break;
case BadTextureLine:
Check_Pointer(texture);
PAUSE(("[%s] has a bad Texture= specification!", megatexture));
break;
case SizesDontMatch:
Check_Pointer(texture);
PAUSE(("[%s]%s does not match its stated size!", megatexture, texture));
break;
case BadTexture:
Check_Pointer(texture);
PAUSE(("[%s]%s is a bad texture!", megatexture, texture));
break;
case TextureDoesntFit:
Check_Pointer(texture);
PAUSE(("[%s]%s doesn't fit!", megatexture, texture));
break;
case TextureOverlap:
Check_Pointer(texture);
PAUSE(("[%s]%s overlaps a previous texture!", megatexture, texture));
break;
case EmptyMegatexture:
PAUSE(("[%s] is empty!", megatexture));
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::BuildMegatextures(BuildMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Get the mega texture data
//--------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
MString mega_name;
GetName(&mega_name);
Check_Object(&mega_name);
Vector2DOf<int> mega_size;
GetImageSize(&mega_size);
Verify(
mega_size.x >= 16 && mega_size.x <= 512
&& mega_size.y >= 16 && mega_size.y <= 512
&& mega_size.x == (mega_size.x & -mega_size.x)
&& mega_size.y == (mega_size.y & -mega_size.y)
);
TextureLibrary *library = GetTextureLibrary();
Check_Object(library);
//
//-----------------------------------------------------------------
// Create the megatexture proxy and clear it out to invisible black
//-----------------------------------------------------------------
//
unsigned channel_size = mega_size.x*mega_size.y;
DynamicArrayOf<BYTE>
red(channel_size),
green(channel_size),
blue(channel_size),
alpha(channel_size);
memset(red.GetData(), 0, channel_size);
memset(green.GetData(), 0, channel_size);
memset(blue.GetData(), 0, channel_size);
memset(alpha.GetData(), 0, channel_size);
DynamicArrayOf<bool>
used(false, channel_size);
//
//----------------------------------------------------------------------
// Now start stepping through the entries for the page and skip the page
// size entry
//----------------------------------------------------------------------
//
bool alpha_used = false;
int texture_count = 0;
ChainOf<Note*> *textures = NULL;
Note *entry = NULL;
unsigned errors = 0;
Page *mega_page = mega_file->FindPage(mega_name);
if (mega_page)
{
textures = mega_page->MakeNoteChain("Texture");
Check_Object(textures);
Page::NoteIterator texture_itr(textures);
while ((entry = texture_itr.ReadAndNext()) != NULL)
{
Check_Object(entry);
//
//--------------------------------------------
// Extract the texture data from the tron file
//--------------------------------------------
//
const char* data;
entry->GetEntry(&data);
Check_Pointer(data);
Vector2DOf<int> offset, size(0,0);
char texture_name[80];
int param_count =
sscanf(
data,
"%s %d %d %d %d",
texture_name,
&offset.x,
&offset.y,
&size.x,
&size.y
);
if (param_count != 5 || !strlen(texture_name))
{
process->ProcessCallback(
BuildMegatexturesProcess::BadTextureLine,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_1:
Check_Object(textures);
delete textures;
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
else
{
++errors;
continue;
}
}
//
//--------------------------
// Do the status check again
//--------------------------
//
process->ProcessCallback(
BuildMegatexturesProcess::StatusCheck,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
//
//-----------------------------------------------------------------
// We now have a texture name, so get the actual texture proxy from
// the library
//-----------------------------------------------------------------
//
TextureProxy *texture = library->UseTextureProxy(texture_name);
Check_Object(texture);
//
//---------------------------
// Make sure the size is good
//---------------------------
//
Vector2DOf<int> texture_size;
texture->GetImageSize(&texture_size);
if (!texture_size.x && !texture_size.y)
{
process->ProcessCallback(
BuildMegatexturesProcess::BadTexture,
mega_name,
texture_name
);
if (!process->continueProcess)
{
Unwind_2:
texture->DetachReference();
UNWIND();
#undef UNWIND
#define UNWIND() goto Unwind_2
}
else
{
texture->DetachReference();
++errors;
continue;
}
}
//
//-----------------------------------------------
// Make sure the size matches what is in the file
//-----------------------------------------------
//
if (size != texture_size)
{
process->ProcessCallback(
BuildMegatexturesProcess::SizesDontMatch,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
texture->DetachReference();
++errors;
continue;
}
}
++texture_count;
//
//--------------------------------------------------------------
// Figure out where this texture wishes to be in the megatexture
//--------------------------------------------------------------
//
if (
offset.x < 0 || offset.x+size.x > mega_size.x
|| offset.y < 0 || offset.y+size.y > mega_size.y
)
{
process->ProcessCallback(
BuildMegatexturesProcess::TextureDoesntFit,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
texture->DetachReference();
continue;
}
}
//
//-----------------------
// Get the texture depths
//-----------------------
//
unsigned
red_depth,
green_depth,
blue_depth,
alpha_depth;
texture->GetChannelDepth(
&red_depth,
&green_depth,
&blue_depth,
&alpha_depth
);
if (alpha_depth)
alpha_used = true;
//
//---------------------
// Get the texture data
//---------------------
//
DynamicArrayOf<BYTE>
r,
g,
b,
a;
if (alpha_depth)
texture->GetChannels(&r, &g, &b, &a);
else
{
texture->GetChannels(&r, &g, &b, NULL);
alpha_depth = 0;
}
//
//-------------------------
// Copy the data row by row
//-------------------------
//
Vector2DOf<int> source(0,0);
for (source.y=0; source.y<size.y; ++source.y)
{
Vector2DOf<int> dest;
dest.Add(offset, source);
unsigned source_pixel = texture->GetPixelIndex(source);
unsigned dest_pixel = GetPixelIndex(dest);
//
//--------------------
// Look for an overlap
//--------------------
//
void *overlap = memchr(&used[dest_pixel], true, size.x);
if (overlap)
{
process->ProcessCallback(
BuildMegatexturesProcess::TextureOverlap,
mega_name,
texture_name
);
if (!process->continueProcess)
UNWIND();
else
{
++errors;
source.y = size.y;
continue;
}
}
memset(&used[dest_pixel], true, size.x);
//
//---------------------
// Copy the row of data
//---------------------
//
Mem_Copy(
&red[dest_pixel],
&r[source_pixel],
size.x,
red.GetLength() - dest_pixel
);
Mem_Copy(
&green[dest_pixel],
&g[source_pixel],
size.x,
green.GetLength() - dest_pixel
);
Mem_Copy(
&blue[dest_pixel],
&b[source_pixel],
size.x,
blue.GetLength() - dest_pixel
);
//
//----------------------------------------------------------------
// Copy the alpha data if enabled, otherwise just set it to opaque
//----------------------------------------------------------------
//
if (alpha_depth)
{
Mem_Copy(
&alpha[dest_pixel],
&a[source_pixel],
size.x,
alpha.GetLength() - dest_pixel
);
}
else
memset(&alpha[dest_pixel], static_cast<BYTE>(255), size.x);
}
//
//---------------------
// Clean up the texture
//---------------------
//
texture->DetachReference();
}
}
//
//-------------------------------------------------
// Tell the application if the megatexture is empty
//-------------------------------------------------
//
if (!texture_count)
{
process->ProcessCallback(
BuildMegatexturesProcess::EmptyMegatexture,
mega_name,
NULL
);
if (!process->continueProcess)
{
Check_Object(textures);
delete textures;
}
}
//
//---------------------------------------------------------------------
// If we didn't have any errors and aren't empty, copy the texture into
// the texture library
//---------------------------------------------------------------------
//
else if (!errors)
{
SetChannels(
&red,
&green,
&blue,
(alpha_used) ? &alpha : NULL
);
TextureProxy *proxy = library->UseMatchingTextureProxy(this);
Check_Object(proxy);
Verify(IsEqualTo(proxy));
proxy->DetachReference();
}
//
//---------
// Clean up
//---------
//
Check_Object(textures);
delete textures;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::BuildMegatextures(BuildMegatexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------------------
// Get the page list from the mega file and process each page after making
// sure the app says it's OK
//------------------------------------------------------------------------
//
NotationFile *mega_file = process->megaFile;
Check_Object(mega_file);
NotationFile::PageIterator *pages = mega_file->MakePageIterator();
Check_Object(pages);
Page *page;
while ((page = pages->ReadAndNext()) != NULL)
{
Check_Object(page);
const char* mega_name = page->GetName();
Check_Pointer(mega_name);
process->ProcessCallback(
BuildMegatexturesProcess::StatusCheck,
mega_name,
NULL
);
if (!process->continueProcess)
{
Unwind_1:
Check_Object(pages);
delete pages;
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
//
//----------------------------------------------------------------------
// For each page, get a list of all the entries. If the page is missing
// its PageSize page, it is a final uncoalesced texture, so skip it
//----------------------------------------------------------------------
//
const char* size_string;
if (!page->GetEntry("PageSize", &size_string))
continue;
//
//------------------------------
// Make sure the page size is OK
//------------------------------
//
Vector2DOf<int> mega_size;
#if defined(_ARMOR)
int param_count =
#endif
sscanf(size_string, "%d %d", &mega_size.x, &mega_size.y);
Verify(param_count);
if (
mega_size.x < 16 || mega_size.x > 512
|| mega_size.y < 16 || mega_size.y > 512
|| mega_size.x != (mega_size.x & -mega_size.x)
|| mega_size.y != (mega_size.y & -mega_size.y)
)
{
process->ProcessCallback(
BuildMegatexturesProcess::BadPageSize,
mega_name,
NULL
);
if (!process->continueProcess)
UNWIND();
else
continue;
}
//
//---------------------------------------------------
// Create the megatexture proxy run the process on it
//---------------------------------------------------
//
TextureProxy *mega_texture =
TextureProxy::MakeProxy(mega_name, mega_size, this);
Check_Object(mega_texture);
mega_texture->BuildMegatextures(process);
mega_texture->DetachReference();
if (!process->continueProcess)
UNWIND();
}
//
//-----------------------
// Clean up the page list
//-----------------------
//
Check_Object(pages);
delete pages;
}
@@ -0,0 +1,40 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class BuildMegatexturesProcess:
public Process
{
public:
BuildMegatexturesProcess(Stuff::NotationFile *mega_file);
BuildMegatexturesProcess(
Stuff::NotationFile *config_file,
Stuff::NotationFile *mega_file
);
enum {
StatusCheck,
BadPageSize,
BadTextureLine,
SizesDontMatch,
BadTexture,
TextureDoesntFit,
TextureOverlap,
EmptyMegatexture
};
virtual void
ProcessCallback(
int error,
const char* megatexture,
const char* texture
);
Stuff::NotationFile
*megaFile;
};
}
@@ -0,0 +1,529 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BurnLightsProcess::BurnLightsProcess():
materialsAreWhite(true),
lightsToBurn(NULL),
matrixStack(30, 20, "Light Burning Stack")
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BurnLightsProcess::BurnLightsProcess(NotationFile *data_file):
Process(data_file),
lightsToBurn(NULL),
matrixStack(30, 20, "Light Burning Stack")
{
Check_Object(data_file);
Page *page = data_file->FindPage("BurnLights");
if (page)
page->GetEntry("MaterialsAreWhite", &materialsAreWhite);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
process->FindLightsCallback(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//---------------------------------------------------
// If the proxy is a group, look in it for lights
//---------------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->FindLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------------------
// If the proxy is a light, add it to the light list
//--------------------------------------------------
//
AttachReference();
process->lightsToBurn.Add(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::FindLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->FindLightsCallback(this);
if (!process->continueProcess)
return;
//
//-----------------------------------------------
// If the proxy is a scene, look in it for lights
//-----------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->FindLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::BurnLights(
BurnLightsProcess *process,
DynamicArrayOf<TransformedLight> &lights
)
{
Check_Object(this);
Check_Object(process);
Check_Object(&lights);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-------------------------------------------------------------
// Make sure that this vertex can be lit (i.e. it has a normal)
//-------------------------------------------------------------
//
Normal3D normal;
if (!GetNormal(&normal))
return;
//
//--------------------------------------------------------------------
// Get the current color for its alpha, then initialize to the ambient
// color
//--------------------------------------------------------------------
//
unsigned light_count = lights.GetLength();
RGBAColor total_color;
GetColor(&total_color);
total_color.red = 0.0f;
total_color.green = 0.0f;
total_color.blue = 0.0f;
//
//-----------------------------------
// Test each light against the vertex
//-----------------------------------
//
for (unsigned i=0; i<light_count; ++i)
{
LightProxy *light = lights[i].lightProxy;
Check_Object(light);
//
//----------------------------------------------------------------
// Get the light color and if it is an ambient light, just add the
// light color
//----------------------------------------------------------------
//
RGBColor light_color;
light->GetColor(&light_color);
if (light->IsAmbient())
{
total_color.red += light_color.red;
total_color.green += light_color.green;
total_color.blue += light_color.blue;
continue;
}
//
//---------------------------------------------------------------------
// Get the falloff distances. If there are no falloff distances, it is
// an infinite light, so set the light normal directly from the matrix
//---------------------------------------------------------------------
//
Scalar n,f;
UnitVector3D light_z;
if (!light->GetFalloffDistance(&n, &f))
lights[i].lightToLocal.GetLocalForwardInWorld(&light_z);
//
//---------------------------------------------------------------
// Otherwise, it will be a point or spot light, in which case the
// translation component of the lightToLocal matrix contains the
// vertex to light vector
//---------------------------------------------------------------
//
else
{
Point3D vertex_to_light;
vertex_to_light = lights[i].lightToLocal;
Point3D position;
GetPosition(&position);
vertex_to_light -= position;
//
//--------------------------------------------------------------
// If the distance to the vertex is zero, the light will not
// contribute to the vertex coloration. Otherwise, decrease the
// light level as appropriate to the distance
//--------------------------------------------------------------
//
Scalar length = vertex_to_light.GetLength();
if (Small_Enough(length) || length>=f)
continue;
else if (length > n)
{
Verify(f - n > SMALL);
Scalar falloff = (length - n) / (f - n);
light_color.red *= falloff;
light_color.green *= falloff;
light_color.blue *= falloff;
}
//
//--------------------------------------------------------------
// If this is a point light, set the light vector to the negated
// normal of vertex to light
//--------------------------------------------------------------
//
Radian spread_angle;
if (!light->GetSpreadAngle(&spread_angle))
{
length = -1.0f / length;
light_z.Vector3D::Multiply(vertex_to_light, length);
}
//
//---------------------------------------------------------------
// Otherwise, this is a spotlight, so we need to reduce the light
// level further based upon the spread angle of the light
//---------------------------------------------------------------
//
else
{
lights[i].lightToLocal.GetLocalForwardInWorld(&light_z);
length = -1.0f / length;
vertex_to_light *= length;
Scalar spread = Cos(spread_angle);
Scalar t = vertex_to_light * light_z;
if (t <= spread)
{
continue;
}
Verify(!Close_Enough(spread, 1.0f));
spread = 1.0f - ((1.0f - t) / (1.0f - spread));
light_color.red *= spread;
light_color.green *= spread;
light_color.blue *= spread;
light_z.x = vertex_to_light.x;
light_z.y = vertex_to_light.y;
light_z.z = vertex_to_light.z;
}
}
//
//-------------------------------------------------------------------
// Now we reduce the light level falling on the vertex based upon the
// cosine of the angle between light and normal
//-------------------------------------------------------------------
//
Scalar cosine = -(light_z * normal);
if (cosine > SMALL)
{
light_color.red *= cosine;
light_color.green *= cosine;
light_color.blue *= cosine;
total_color.red += light_color.red;
total_color.green += light_color.green;
total_color.blue += light_color.blue;
}
}
//
//-----------------------------------------------------------------
// We now have the total color on the vertex established, so set it
//-----------------------------------------------------------------
//
Clamp(total_color.red, 0.0f, 1.0f);
Clamp(total_color.green, 0.0f, 1.0f);
Clamp(total_color.blue, 0.0f, 1.0f);
SetColor(total_color);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
process->BurnLightsCallback(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-----------------------------------------------------------------
// Apply the local to parent matrix to the stack, then invert it in
// preparation for the polygon meshes
//-----------------------------------------------------------------
//
LinearMatrix4D local_to_parent;
GetLocalToParent(&local_to_parent);
process->matrixStack.Concatenate(local_to_parent);
LinearMatrix4D world_to_local;
world_to_local.Invert(process->matrixStack);
//
//-----------------
// Count the lights
//-----------------
//
ChainIteratorOf<LightProxy*> light_itr(&process->lightsToBurn);
LightProxy* light;
int light_count = 0;
while ((light = light_itr.ReadAndNext()) != NULL)
{
Check_Object(light);
++light_count;
}
//
//------------------------------------------
// transform all the lights into local space
//------------------------------------------
//
DynamicArrayOf<TransformedLight> lights(light_count);
light_itr.First();
unsigned i;
for (i=0; i<light_count; ++i)
{
light = light_itr.ReadAndNext();
lights[i].lightProxy = light;
LinearMatrix4D light_to_world;
light->GetLocalToWorld(&light_to_world);
lights[i].lightToLocal.Multiply(light_to_world, world_to_local);
}
//
//------------------------------------------
// Recurse the children, and stop if told to
//------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
Verify(vertex_count == vertices.GetLength());
for (i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
vertex->BurnLights(process, lights);
if (!process->continueProcess)
break;
}
DetachArrayReferences(&vertices);
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//----------------------------------------------
// Apply the local to parent matrix to the stack
//----------------------------------------------
//
LinearMatrix4D local_to_parent;
GetLocalToParent(&local_to_parent);
process->matrixStack.Concatenate(local_to_parent);
//
//------------------------------------------
// Recurse the children, and stop if told to
//------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->BurnLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::BurnLights(BurnLightsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Call the control callback
//--------------------------
//
process->BurnLightsCallback(this);
if (!process->continueProcess)
return;
//
//-------------------------------------------------------------
// Get the ambient color and put a identity matrix on the stack
//-------------------------------------------------------------
//
process->matrixStack.Push(LinearMatrix4D::Identity);
//
//---------------------------------------------
// Burn the lights into each child of the scene
//---------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->BurnLights(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-----------------------
// Remove the last matrix
//-----------------------
//
process->matrixStack.Pop();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BurnLightsProcess::DiscardLights()
{
Check_Object(this);
ChainIteratorOf<LightProxy*> lights(&lightsToBurn);
LightProxy* light;
while ((light = lights.ReadAndNext()) != NULL)
{
Check_Object(light);
light->DetachReference();
}
}
@@ -0,0 +1,38 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies
{
class GenericProxy;
class LightProxy;
class BurnLightsProcess:
public Process
{
public:
BurnLightsProcess();
BurnLightsProcess(Stuff::NotationFile *data_file);
virtual void
FindLightsCallback(GenericProxy *proxy)
{}
virtual void
BurnLightsCallback(GenericProxy *proxy)
{}
void
DiscardLights();
bool
materialsAreWhite;
Stuff::ChainOf<LightProxy*>
lightsToBurn;
Stuff::LinearMatrix4DStack
matrixStack;
};
}
@@ -0,0 +1,181 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//######################## ChildProxy ###########################
//############################################################################
//
ChildProxy::ClassData*
ChildProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
ChildProxyClassID,
"ChildProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy::ChildProxy(
ClassData *data,
SceneProxy *scene,
GroupProxy *parent
):
GenericProxy(data),
sceneProxy(scene),
parentProxy(parent)
{
Check_Pointer(this);
//
//-----------------------------------------------------------------------
// If we have a parent proxy, bump its reference count and add ourself to
// its active list. If no parent, add to the scene list
//-----------------------------------------------------------------------
//
Check_Object(sceneProxy);
if (parentProxy)
{
sceneProxy->AttachReference();
Check_Object(parentProxy);
parentProxy->AttachChildProxy(this);
}
else
sceneProxy->AttachChildProxy(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy::~ChildProxy()
{
Check_Object(this);
//
//-----------------------------------------------------------------------
// If we have a parent proxy, bump its reference count and add ourself to
// its active list. If no parent, add to the scene list
//-----------------------------------------------------------------------
//
Check_Object(sceneProxy);
if (parentProxy)
{
Check_Object(parentProxy);
parentProxy->DetachChildProxy(this);
sceneProxy->DetachReference();
}
else
sceneProxy->DetachChildProxy(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
Check_Object(sceneProxy);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::GetLocalToWorld(LinearMatrix4D *matrix)
{
Check_Object(this);
Check_Pointer(matrix);
//
//------------------------------------------------------------------
// If we don't have a parent, just return our local to parent matrix
//------------------------------------------------------------------
//
GroupProxy *parent = GetParentGroupProxy();
if (!parent)
{
GetLocalToParent(matrix);
return;
}
//
//------------------------------------------------------------------------
// If we have the identity matrix, just return our parent's local to world
//------------------------------------------------------------------------
//
Check_Object(parent);
LinearMatrix4D local_to_parent;
if (!GetLocalToParent(&local_to_parent))
{
parent->GetLocalToWorld(matrix);
return;
}
//
//----------------------------------
// Concatenate and return the matrix
//----------------------------------
//
LinearMatrix4D parent_to_world;
parent->GetLocalToWorld(&parent_to_world);
Check_Object(&parent_to_world);
matrix->Multiply(local_to_parent, parent_to_world);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::TransformLocalToParent(const LinearMatrix4D &matrix)
{
Check_Object(this);
Check_Object(&matrix);
//
//---------------------------
// Ignore identity transforms
//---------------------------
//
if (matrix == LinearMatrix4D::Identity)
return;
//
//--------------------------------------------------------------------
// Get our old matrix, and if it was identity, replace it with the new
// matrix
//--------------------------------------------------------------------
//
LinearMatrix4D old;
if (!GetLocalToParent(&old))
{
SetLocalToParent(matrix);
return;
}
//
//----------------------------------------------------------
// We now have to multiply the matrices and store the result
//----------------------------------------------------------
//
LinearMatrix4D transformed;
transformed.Multiply(old, matrix);
SetLocalToParent(transformed);
}
@@ -0,0 +1,149 @@
#pragma once
#include "Proxies.hpp"
#include "GenericProxy.hpp"
namespace Proxies {
class SceneProxy;
class GroupProxy;
class BinSortProcess;
class BurnLightsProcess;
class CleanHierarchyProcess;
class CopyProcess;
class FindErrorsProcess;
class FlattenHierarchyProcess;
class SplitByStateProcess;
class GetInfoProcess;
class MakeSingleSidedProcess;
class OptimizeFlatShadingProcess;
//
//#########################################################################
//########################## ChildProxy #############################
//#########################################################################
//
class _declspec(novtable) ChildProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
ChildProxy(
ClassData *data,
SceneProxy *scene,
GroupProxy *parent
);
~ChildProxy();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual bool
BinSort(BinSortProcess *process);
virtual void
BurnLights(BurnLightsProcess *process);
virtual bool
CleanHierarchy(CleanHierarchyProcess *process);
virtual int
FindErrors(FindErrorsProcess *process);
virtual void
FindLights(BurnLightsProcess *process);
virtual bool
FlattenHierarchy(FlattenHierarchyProcess *process);
virtual bool
SplitByState(SplitByStateProcess *process);
virtual bool
MakeSingleSided(MakeSingleSidedProcess *process);
virtual bool
OptimizeFlatShading(OptimizeFlatShadingProcess *process);
virtual void
GetInfo(GetInfoProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Position management functions
//
public:
//
// Position traversal functions
//
SceneProxy*
GetSceneProxy()
{Check_Object(this); return sceneProxy;}
GroupProxy*
GetParentGroupProxy()
{Check_Object(this); return parentProxy;}
virtual void
TransferAndAppendToParentGroup(GroupProxy *parent) = 0;
virtual ChildProxy*
UseNextSiblingProxy()=0;
virtual ChildProxy*
UsePreviousSiblingProxy()=0;
protected:
SceneProxy
*sceneProxy;
GroupProxy
*parentProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Matrix functions
//
public:
//
// Matrix functions
//
virtual bool
GetLocalToParent(Stuff::LinearMatrix4D *matrix) = 0;
virtual void
GetLocalToWorld(Stuff::LinearMatrix4D *matrix);
virtual void
SetLocalToParent(const Stuff::LinearMatrix4D &matrix) = 0;
virtual void
TransformLocalToParent(const Stuff::LinearMatrix4D &matrix);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bounding functions
//
// GetBoundingSphere should be used only after GetOBB has returned a false
//
public:
virtual bool
GetOBB(Stuff::OBB *obb) = 0;
virtual void
SetOBB(const Stuff::OBB &obb) = 0;
virtual bool
GetBoundingSphere(Stuff::Sphere *sphere) = 0;
virtual void
SetBoundingSphere(const Stuff::Sphere &sphere) = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon functions
//
public:
virtual void
GetCentroid(Stuff::Point3D *center) = 0;
};
}
@@ -0,0 +1,186 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::CleanHierarchy(CleanHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
process->CleanHierarchyCallback(this);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::CleanHierarchy(CleanHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->CleanHierarchyCallback(this);
if (!process->continueProcess)
return true;
//
//-----------------------------------------------------------------------
// Calculate our best fit bounding sphere ignoring any that already exist
//-----------------------------------------------------------------------
//
OBB obb;
if (GetOBB(&obb))
{
STOP(("Not implemented"));
}
else
{
Sphere bounds;
PolygonMeshProxy::GetBoundingSphere(&bounds);
SetBoundingSphere(bounds);
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::CleanHierarchy(CleanHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->CleanHierarchyCallback(this);
if (!process->continueProcess)
return true;
//
//---------------------------------------------------------
// First, allow each child hierarchy to remove redundancies
//---------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->CleanHierarchy(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
Check_Object(child);
child->DetachReference();
}
return true;
}
}
if (child)
child->DetachReference();
//
//-----------------------------------------------------------------------
// Now, check to see if we are a redundant hierarchy. If we have a name,
// or if we have two or more children, we are not redundant. If we are,
// we need to push our transform down into our child, and then attach our
// child to our parent
//-----------------------------------------------------------------------
//
child_count = GetChildCount();
MString name;
if (!GetName(&name) && child_count <= 1)
{
LinearMatrix4D matrix;
GetLocalToParent(&matrix);
child = UseFirstChildProxy();
Verify(child_count < 2);
if (child)
{
Check_Object(child);
child->TransformLocalToParent(matrix);
child->TransferAndAppendToParentGroup(GetParentGroupProxy());
child->DetachReference();
}
Destroy();
return false;
}
//
//-----------------------------------------------------------------------
// Calculate our best fit bounding sphere ignoring any that already exist
//-----------------------------------------------------------------------
//
OBB obb;
if (GetOBB(&obb))
{
STOP(("Not implemented"));
}
else
{
Sphere bounds;
GroupProxy::GetBoundingSphere(&bounds);
SetBoundingSphere(bounds);
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
SceneProxy::CleanHierarchy(CleanHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->CleanHierarchyCallback(this);
if (!process->continueProcess)
return true;
//
//---------------------
// Handle a scene proxy
//---------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->CleanHierarchy(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
Check_Object(child);
child->DetachReference();
}
return true;
}
}
if (child)
child->DetachReference();
return true;
}
@@ -0,0 +1,27 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class CleanHierarchyProcess:
public Process
{
public:
CleanHierarchyProcess()
{}
CleanHierarchyProcess(
Stuff::NotationFile *data_file,
bool bSuppress = true,
void* fcn = NULL
):
Process(data_file,bSuppress,fcn)
{}
virtual void
CleanHierarchyCallback(GenericProxy* proxy)
{}
};
}
@@ -0,0 +1,408 @@
#include "ProxyHeaders.hpp"
typedef int (*LPERROR_CALLBACKFN)(char *,bool);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
bool bSuppress,
void* fcn
) :
Process(NULL,bSuppress,fcn),
megatextureFile(megatexture_file)
{
if (megatexture_list)
{
megatextureList = MakeMegatextureChain(megatexture_list);
Register_Object(megatextureList);
Check_Object(megatextureFile);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
Stuff::NotationFile *config_file,
bool bSuppress,
void* fcn
):
Process(config_file,bSuppress,fcn),
megatextureFile(megatexture_file)
{
if (megatexture_list)
{
megatextureList = MakeMegatextureChain(megatexture_list);
Register_Object(megatextureList);
Check_Object(megatextureFile);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CoalesceTexturesProcess::~CoalesceTexturesProcess()
{
if (megatextureList)
{
MStringChainIterator iterator(megatextureList);
iterator.DeletePlugs();
Unregister_Object(megatextureList);
delete megatextureList;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MStringChain*
CoalesceTexturesProcess::MakeMegatextureChain(const char* list)
{
Check_Pointer(list);
//
//--------------------------------------------
// If the string is empty, don't make anything
//--------------------------------------------
//
MStringChain *chain = NULL;
const char* begin = list;
do
{
//
//-------------------------------------------------------------------
// If we can't find a comma, the remainder of the string is the token
//-------------------------------------------------------------------
//
const char* end = strchr(begin, ',');
MString token = begin;
if (!end)
begin = NULL;
//
//------------------------------------------------------
// Otherwise, clip the token to where we found the comma
//------------------------------------------------------
//
else
{
int len = end - begin;
token[len] = '\0';
begin = end;
while (*begin == ',')
++begin;
if (!*begin)
begin = NULL;
}
//
//----------------------------
// Put this token in the chain
//----------------------------
//
if (!chain)
chain = new MStringChain(NULL);
PlugOf<MString> *plug = new PlugOf<MString>(token);
Register_Object(plug);
chain->Add(plug);
//
//----------------------------------
// Skip to the next token until done
//----------------------------------
//
} while (begin);
return chain;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::CoalesceTextures(CoalesceTexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->CoalesceTexturesCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------
// See if this will be a trivial process
//--------------------------------------
//
if (!process->megatextureList)
return;
Check_Object(process->megatextureFile);
Check_Object(process->megatextureFile);
//
//------------------------------------------------------------------------
// Get the state arrays for this mesh and make sure that they have already
// been split
//------------------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> polygons;
unsigned polygon_count = UsePolygonArray(&polygons);
if (!polygon_count)
return;
DynamicArrayOf<MultiState*> states;
DynamicArrayOf<unsigned> index;
DynamicArrayOf<unsigned> count;
#if defined(_ARMOR)
unsigned unique_states =
#endif
UseMultiStateArray(&states, &index, &count, polygons);
Verify(unique_states==1 && count[0]==polygon_count);
//
//----------------------------------------------------------------------
// If this mesh is not textured, we can just return. Otherwise, get the
// texture name
//----------------------------------------------------------------------
//
Check_Object(states[0]);
unsigned state_count = states[0]->GetLength();
for(unsigned state_loop=0;state_loop<state_count;++state_loop)
{
TextureProxy *texture = (*states[0])[state_loop]->UseTextureProxy();
if (!texture)
{
Unwind_1:
DetachArrayReferences(&states);
DetachArrayReferences(&polygons);
return;
#undef UNWIND
#define UNWIND() goto Unwind_1
}
MString name;
texture->GetName(&name);
Vector2DOf<int> texture_size;
texture->GetImageSize(&texture_size);
texture->DetachReference();
//
//------------------------------------------------------------------------
// Look through each of the listed megatextures to try and find where this
// texture should be rerouted
//------------------------------------------------------------------------
//
MStringChainIterator megatextures(process->megatextureList);
PlugOf<MString> *string;
Vector2DOf<Scalar> offset;
offset.x = offset.y = 0.0f;
const char* mega_name = NULL;
while ((string = megatextures.ReadAndNext()) != NULL)
{
mega_name = string->GetItem();
Check_Pointer(mega_name);
const char *offset_string;
Page *page = process->megatextureFile->FindPage(mega_name);
if (page)
{
if (page->GetEntry(name, &offset_string))
{
Check_Pointer(offset_string);
#if defined(_ARMOR)
int count =
#endif
sscanf(offset_string, "%f %f", &offset.x, &offset.y);
Verify(count == 2);
break;
}
}
// Look for alias
page = process->megatextureFile->FindPage(name);
if (page)
{
const char *alias_name;
if (page->GetEntry("alias",&alias_name))
{
page = process->megatextureFile->FindPage(alias_name);
if (page)
{
if (page->GetEntry(name, &offset_string))
{
Check_Pointer(offset_string);
#if defined(_ARMOR)
int count =
#endif
sscanf(offset_string, "%f %f", &offset.x, &offset.y);
Verify(count == 2);
break;
}
}
}
}
}
//
//-----------------------------------------------------------------------
// If no megatexture has this texture in its entries, this texture should
// be left alone
//-----------------------------------------------------------------------
//
if (!string)
UNWIND();
//
//-----------------------------------------------------------------------
// Now, get the megatexture from the library. If it isn't already there,
// an empty one will be created
//-----------------------------------------------------------------------
//
SceneProxy *scene = GetSceneProxy();
Check_Object(scene);
StateLibrary *state_library = scene->GetStateLibrary();
Check_Object(state_library);
TextureLibrary *textures = state_library->GetTextureLibrary();
Check_Object(textures);
TextureProxy *mega_texture = textures->UseTextureProxy(mega_name);
//
//----------------------------------------
// Read the size from the megatexture page
//----------------------------------------
//
const char* size_string;
Page *page = process->megatextureFile->GetPage(mega_name);
Check_Object(page);
page->GetEntry("PageSize", &size_string);
Vector2DOf<int> mega_size;
#if defined(_ARMOR)
int param_count =
#endif
sscanf(size_string, "%d %d", &mega_size.x, &mega_size.y);
Verify(param_count == 2);
//
//---------------------------------------------
// Compute the new scale and offset for our uvs
//---------------------------------------------
//
Vector2DOf<Scalar>
pixel_size(1.0f/mega_size.x, 1.0f/mega_size.y),
pixel_count(
static_cast<Scalar>(texture_size.x),
static_cast<Scalar>(texture_size.y)
);
//
//--------------------------------------------------------------------
// Get the array of vertices, then go through each one and set the UVs
// according to the coalesced values
//--------------------------------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
for (unsigned i=0; i<vertex_count; ++i)
{
Check_Object(vertices[i]);
DynamicArrayOf<Vector2DOf<Scalar> > uv;
vertices[i]->GetUVs(&uv);
uv[state_loop].x = (uv[state_loop].x*pixel_count.x + offset.x) * pixel_size.x;
uv[state_loop].y = (uv[state_loop].y*pixel_count.y + offset.y) * pixel_size.y;
vertices[i]->SetUVs(uv);
// If uv are wrapped for more than 4 pixels
if (uv[state_loop].x < -4.0/texture_size.x || uv[state_loop].x > 1+4.0/texture_size.x ||
uv[state_loop].y < -4.0/texture_size.y || uv[state_loop].y > 1+4.0/texture_size.y )
{
if (process->errorfn)
{
char buffer[200];
sprintf(buffer, "CoalesceTextures: %s has UV's wrapped (%f %f)!", (char*)name, uv[state_loop].x, uv[state_loop].y);
LPERROR_CALLBACKFN fcn = (LPERROR_CALLBACKFN)process->errorfn;
fcn(buffer,process->suppress);
}
}
}
DetachArrayReferences(&vertices);
//
//--------------------------------------------------------------------
// Now change the states of the polygons so that they point at the new
// megatextures
//--------------------------------------------------------------------
//
(*states[0])[state_loop]->SetToMatchTextureProxy(mega_texture);
//
//---------
// Clean up
//---------
//
mega_texture->DetachReference();
DetachArrayReferences(&polygons);
}
SetToMatchMultiState(states[0]);
DetachArrayReferences(&states);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::CoalesceTextures(CoalesceTexturesProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CoalesceTexturesCallback(this);
if (!process->continueProcess)
return;
//
//--------------------------------------
// See if this will be a trivial process
//--------------------------------------
//
if (!process->megatextureList)
return;
//
//------------------------------------------------------------------
// Coalesce the children. At this point, they must all be flattened
//------------------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
PolygonMeshProxy *mesh = Cast_Object(PolygonMeshProxy*, child);
mesh->CoalesceTextures(process);
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
}
@@ -0,0 +1,40 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GenericProxy;
class CoalesceTexturesProcess:
public Process
{
public:
CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
bool s = true,
void* fcn = NULL
);
CoalesceTexturesProcess(
Stuff::NotationFile *megatexture_file,
const char *megatexture_list,
Stuff::NotationFile *config_file,
bool s = true,
void* fcn = NULL
);
~CoalesceTexturesProcess();
virtual void
CoalesceTexturesCallback(GenericProxy* proxy)
{}
static MStringChain*
MakeMegatextureChain(const char* megatexture_list);
Stuff::NotationFile
*megatextureFile;
MStringChain
*megatextureList;
};
}
@@ -0,0 +1,536 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::Copy(
CopyProcess *process,
TextureProxy *texture
)
{
Check_Object(this);
Check_Object(process);
Check_Object(texture);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(texture);
if (!process->continueProcess)
return;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (texture->GetName(&name))
SetName(name);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateProxy::Copy(
CopyProcess *process,
StateProxy *state
)
{
Check_Object(this);
Check_Object(process);
Check_Object(state);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(state);
if (!process->continueProcess)
return;
bool onOff;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (state->GetName(&name))
SetName(name);
AlphaMode alphaMode;
if(state->GetAlpha(&alphaMode))
SetAlpha(alphaMode);
SetAlphaChildPermission(state->GetAlphaChildPermission());
FilterMode filterMode;
if(state->GetFilter(&filterMode))
SetFilter(filterMode);
SetFilterChildPermission(state->GetFilterChildPermission());
FogMode fogMode;
if(state->GetFog(&fogMode))
SetFog(fogMode);
SetFogChildPermission(state->GetFogChildPermission());
if(state->GetDither(&onOff))
SetDither(onOff);
SetDitherChildPermission(state->GetDitherChildPermission());
if(state->GetSpecular(&onOff))
SetSpecular(onOff);
SetSpecularChildPermission(state->GetSpecularChildPermission());
if(state->GetTextureCorrection(&onOff))
SetTextureCorrection(onOff);
SetTextureCorrectionChildPermission(state->GetTextureCorrectionChildPermission());
TextureWrapMode textureWrapMode;
if(state->GetTextureWrap(&textureWrapMode))
SetTextureWrap(textureWrapMode);
SetTextureWrapChildPermission(state->GetTextureWrapChildPermission());
WireFrameMode wireFrameMode;
if(state->GetWireFrame(&wireFrameMode))
SetWireFrame(wireFrameMode);
SetWireFrameChildPermission(state->GetWireFrameChildPermission());
if(state->GetZBufferCompare(&onOff))
SetZBufferCompare(onOff);
SetZBufferCompareChildPermission(state->GetZBufferCompareChildPermission());
if(state->GetZBufferWrite(&onOff))
SetZBufferWrite(onOff);
SetZBufferWriteChildPermission(state->GetZBufferWriteChildPermission());
if(state->GetFlatColoring(&onOff))
SetFlatColoring(onOff);
SetFlatColoringChildPermission(state->GetFlatColoringChildPermission());
if(state->GetBackface(&onOff))
SetBackface(onOff);
SetBackfaceChildPermission(state->GetBackfaceChildPermission());
int priority;
if(state->GetPriority(&priority))
SetPriority(priority);
SetPriorityChildPermission(state->GetPriorityChildPermission());
int lightingMode;
if(state->GetLighting(&lightingMode))
SetLighting(lightingMode);
SetLightingChildPermission(state->GetLightingChildPermission());
bool bFlatColor;
if (state->GetFlatColoring(&bFlatColor))
SetFlatColoring(bFlatColor);
//
//------------------------
// Copy the specular color
//------------------------
//
RGBColor color;
if (state->GetSpecularColor(&color))
{
SetSpecularColor(color);
SetSpecularShininess(state->GetSpecularShininess());
}
//
//-----------------
// Copy the texture
//-----------------
//
TextureProxy *texture = state->UseTextureProxy();
if (texture)
{
TextureProxy *our_texture = SetToMatchTextureProxy(texture);
our_texture->DetachReference();
texture->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::Copy(
CopyProcess *process,
GroupProxy *group
)
{
Check_Object(this);
Check_Object(process);
Check_Object(group);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(group);
if (!process->continueProcess)
return;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (group->GetName(&name))
SetName(name);
//
//-------------------
// Copy the transform
//-------------------
//
LinearMatrix4D matrix;
if (group->GetLocalToParent(&matrix))
SetLocalToParent(matrix);
//
//---------------------------------------------------------
// For each child in the source, copy it to the destination
//---------------------------------------------------------
//
ChildProxy *child = group->UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *proxy = AppendMatchingChildProxy(process, child);
if (proxy)
proxy->DetachReference();
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (process->continueProcess)
child = next;
else if (next)
{
Check_Object(next);
next->DetachReference();
break;
}
else
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::Copy(
CopyProcess *process,
LightProxy *light
)
{
Check_Object(this);
Check_Object(process);
Check_Object(light);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(light);
if (!process->continueProcess)
return;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (light->GetName(&name))
SetName(name);
//
//---------------
// Copy the color
//---------------
//
RGBColor color;
light->GetColor(&color);
SetColor(color);
//
//------------------------
// Handle the ambient case
//------------------------
//
if (light->IsAmbient())
SetAmbient(true);
//
//-------------------
// Copy the transform
//-------------------
//
else
{
LinearMatrix4D matrix;
if (light->GetLocalToParent(&matrix))
SetLocalToParent(matrix);
//
//----------------------------------------------------------------------
// Deal with falloff. Only lights with falloff can have a spread angle,
// and if the light has no falloff, it must be infinite
//----------------------------------------------------------------------
//
Scalar n, f;
if (light->GetFalloffDistance(&n, &f))
{
SetFalloffDistance(n, f);
Radian spread;
if (light->GetSpreadAngle(&spread))
SetSpreadAngle(spread);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::Copy(
CopyProcess *process,
VertexProxy *vertex
)
{
Check_Object(this);
Check_Object(process);
Check_Object(vertex);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(vertex);
if (!process->continueProcess)
return;
//
//------------------
// Copy the position
//------------------
//
Point3D position;
vertex->GetPosition(&position);
SetPosition(position);
//
//-------------------------------
// Copy the color if there is one
//-------------------------------
//
RGBAColor color;
if (vertex->GetColor(&color))
SetColor(color);
//
//--------------------------------
// Copy the normal if there is one
//--------------------------------
//
Normal3D normal;
if (vertex->GetNormal(&normal))
SetNormal(normal);
//
//--------------------------------
// Copy the uv if there is one
//--------------------------------
//
Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > uv;
if (vertex->GetUVs(&uv))
SetUVs(uv);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::Copy(
CopyProcess *process,
PolygonMeshProxy *mesh
)
{
Check_Object(this);
Check_Object(mesh);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(mesh);
if (!process->continueProcess)
return;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (mesh->GetName(&name))
{
SetName(name);
}
//
//-------------------
// Copy the transform
//-------------------
//
LinearMatrix4D matrix;
if (mesh->GetLocalToParent(&matrix))
{
SetLocalToParent(matrix);
}
//
//---------------------------------------------------------------
// Get the polygons of the source mesh, then analyze their states
//---------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> source_polygons;
#if defined(_ARMOR)
unsigned total_polys =
#endif
mesh->UsePolygonArray(&source_polygons);
Verify(total_polys == source_polygons.GetLength());
AddPolygons(process, source_polygons);
mesh->DetachArrayReferences(&source_polygons);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::Copy(
CopyProcess *process,
TextureLibrary *library
)
{
Check_Object(this);
Check_Object(process);
Check_Object(library);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(this);
if (!process->continueProcess)
return;
//
//------------------------------------------------------------------
// For each texture, copy the source mesh texture to the destination
//------------------------------------------------------------------
//
TextureProxy *other_texture = library->UseFirstTextureProxy();
while (other_texture)
{
Check_Object(other_texture);
TextureProxy *texture = UseMatchingTextureProxy(other_texture);
texture->DetachReference();
TextureProxy *next = other_texture->UseNextTextureProxyInLibrary();
other_texture->DetachReference();
if (process->continueProcess)
other_texture = next;
else if (next)
{
Check_Object(next);
next->DetachReference();
break;
}
else
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::Copy(
CopyProcess *process,
SceneProxy *scene
)
{
Check_Object(this);
Check_Object(process);
Check_Object(scene);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->CopyCallback(scene);
if (!process->continueProcess)
return;
//
//--------------
// Copy the name
//--------------
//
MString name;
if (scene->GetName(&name))
SetName(name);
//
//---------------------------------------------------------
// For each child in the source, copy it to the destination
//---------------------------------------------------------
//
ChildProxy *child = scene->UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *proxy = AppendMatchingChildProxy(process, child);
if (proxy)
proxy->DetachReference();
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (process->continueProcess)
child = next;
else if (next)
{
Check_Object(next);
next->DetachReference();
break;
}
else
break;
}
}
@@ -0,0 +1,27 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class CopyProcess:
public Process
{
public:
CopyProcess()
{}
CopyProcess(
Stuff::NotationFile *data_file,
bool bSuppress = true,
void* fcn = NULL
):
Process(data_file,bSuppress,fcn)
{}
virtual void
CopyCallback(GenericProxy* proxy)
{}
};
}
@@ -0,0 +1,615 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
FindErrorsProcess::FindErrorsProcess():
enableDuplicateCheck(true),
enableDegenerateCheck(true),
enableCoplanarCheck(true),
enableColinearCheck(true),
enableConvexCheck(true)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
FindErrorsProcess::FindErrorsProcess(
Stuff::NotationFile *data_file,
bool bSuppress,
void* fcn
):
Process(data_file,bSuppress,fcn),
enableDuplicateCheck(true),
enableDegenerateCheck(true),
enableCoplanarCheck(true),
enableColinearCheck(true),
enableConvexCheck(true)
{
Check_Object(data_file);
Page *page = data_file->FindPage("FindErrors");
if (page)
{
page->GetEntry("DuplicateCheck", &enableDuplicateCheck);
page->GetEntry("DegenerateCheck", &enableDegenerateCheck);
page->GetEntry("CoplanarCheck", &enableCoplanarCheck);
page->GetEntry("ColinearCheck", &enableColinearCheck);
page->GetEntry("ConvexCheck", &enableConvexCheck);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
PolygonProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------------------------------------
// Get the area of the polygon. This will be used to scale some of the
// error process so they fit with larger polygons
//---------------------------------------------------------------------
//
Scalar area = GetArea();
Scalar area_edge = Sqrt(area);
Scalar plane_tolerance = process->planeThicknessTolerance * area_edge;
Scalar duplicate_tolerance = process->duplicateVertexTolerance;
Scalar colinear_tolerance = process->colinearTolerance;
int total = 0;
//
//--------------------------------------------
// Delete all the error groups on this polygon
//--------------------------------------------
//
MStringChain group_list(NULL);
GetCollections(&group_list);
MStringChainIterator group_itr(&group_list);
PlugOf<MString> *group;
while ((group = group_itr.ReadAndNext()) != NULL)
{
Check_Object(group);
const char* name = group->GetItem();
Check_Pointer(name);
if (!_strnicmp(name, "_ERROR_", 7))
RemoveFromCollection(name);
Unregister_Object(group);
delete group;
}
//
//------------------------------------------------------------------------
// The first task we have is to find the two longest consecutive edges.
// We will use these edges to compute the desired polygon normal and plane
// equation
//------------------------------------------------------------------------
//
Point3D
position_a,
position_b = Point3D::Identity,
position_c = Point3D::Identity;
VertexProxy
*vertex_a = NULL,
*vertex_b = NULL,
*vertex_c = NULL;
Vector3D
edge_1,
edge_2 = Vector3D::Identity;
Plane
plane;
//
//-----------------------------------------------------------------
// Put in checks to make sure that the colors, normals, and uvs are
// compatible for all the vertices in this polygon
//-----------------------------------------------------------------
//
bool
uv_there = false,
color_there = false,
normal_there = false;
//
//-----------------------------------
// Spin through, testing the vertices
//-----------------------------------
//
DynamicArrayOf<IndexProxy*> indices;
unsigned index_count = UseIndexArray(&indices);
Verify(index_count == indices.GetLength());
Verify(index_count >= 3);
unsigned end=2;
for (unsigned i=0; i<index_count; ++i)
{
//
//-----------------------------------------------
// Generate all the information on the first pass
//-----------------------------------------------
//
if (!i)
{
Check_Object(indices[0]);
vertex_a = indices[0]->GetVertexProxy();
Check_Object(vertex_a);
Check_Object(indices[1]);
vertex_b = indices[1]->GetVertexProxy();
Check_Object(vertex_b);
Check_Object(indices[2]);
vertex_c = indices[2]->GetVertexProxy();
Check_Object(vertex_c);
vertex_a->GetPosition(&position_a);
vertex_b->GetPosition(&position_b);
vertex_c->GetPosition(&position_c);
edge_1.Subtract(position_b, position_a);
edge_2.Subtract(position_c, position_b);
Normal3D normal;
if (vertex_c->GetNormal(&normal))
{
if (!Close_Enough(normal.Vector3D::GetLengthSquared(), 1.0f, 2e-5f))
{
AddToCollection("_ERROR_Bad_Normal");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Bad_Normal
);
break;
}
}
//
//---------------------------------
// Set up the additional attributes
//---------------------------------
//
RGBAColor color;
color_there = vertex_c->GetColor(&color);
DynamicArrayOf<Vector2DOf<Scalar> > uv;
uv_there = vertex_c->GetUVs(&uv);
normal_there = vertex_c->GetNormal(&normal);
}
//
//--------------------------------------------------------------
// Get the index info. If this is not the first pass, copy the
// information from last pass
//--------------------------------------------------------------
//
else
{
Check_Object(vertex_b);
vertex_a = vertex_b;
Check_Object(vertex_c);
vertex_b = vertex_c;
if (++end >= index_count)
end -= index_count;
Check_Object(indices[end]);
vertex_c = indices[end]->GetVertexProxy();
Check_Object(vertex_c);
position_a = position_b;
position_b = position_c;
vertex_c->GetPosition(&position_c);
edge_1 = edge_2;
edge_2.Subtract(position_c, position_b);
//
//--------------------------------
// Check the additional attributes
//--------------------------------
//
RGBAColor color;
if (color_there != vertex_c->GetColor(&color))
{
AddToCollection("_ERROR_Mismatched_Vertex_Colors");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Mismatched_Vertex_Colors
);
break;
}
DynamicArrayOf<Vector2DOf<Scalar> > uv;
if (uv_there != vertex_c->GetUVs(&uv))
{
AddToCollection("_ERROR_Mismatched_UVs");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Mismatched_UVs
);
break;
}
Normal3D normal;
if (normal_there != vertex_c->GetNormal(&normal))
{
AddToCollection("_ERROR_Mismatched_Normals");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Mismatched_Normals
);
break;
}
}
//
//-----------------------------------------------------------------
// Check the forward leg length to see if the polygon has duplicate
// points
//-----------------------------------------------------------------
//
Scalar length = edge_2.GetLengthSquared();
if (
Small_Enough(length, duplicate_tolerance)
&& process->enableDuplicateCheck
)
{
AddToCollection("_ERROR_Duplicate_Vertex");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Duplicate_Vertex
);
break;
}
//
//---------------------------------------------------------------------
// Compute the cross-product of the two legs and check for colinearness.
// This is not necessarily bad, as long as we are coplanar
//---------------------------------------------------------------------
//
Vector3D v;
v.Cross(edge_1, edge_2);
Scalar cross_len = v.GetLength();
if (Small_Enough(cross_len, colinear_tolerance))
{
if (!i && process->enableDegenerateCheck)
{
AddToCollection("_ERROR_Degenerate_Polygon");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Degenerate_Polygon
);
break;
}
else if (
!Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance)
&& process->enableCoplanarCheck
)
{
AddToCollection("_ERROR_Noncoplanar_Polygon");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Noncoplanar_Polygon
);
break;
}
continue;
}
//
//-------------------------------------------------------------------
// Normalize the cross. If this is the first pass, compute the plane
// equation for the polygon
//-------------------------------------------------------------------
//
cross_len = 1.0f / cross_len;
Normal3D edge_normal(v.x*cross_len, v.y*cross_len, v.z*cross_len);
if (!i)
{
plane.normal = edge_normal;
plane.offset = plane.normal * position_b;
}
else
{
//
//--------------------------
// Check for non-coplanarity
//--------------------------
//
if (
!Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance)
&& process->enableCoplanarCheck
)
{
AddToCollection("_ERROR_Noncoplanar_Polygon");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Noncoplanar_Polygon
);
break;
}
//
//----------------------
// Check for concaveness
//----------------------
//
Scalar cosine = plane.normal*edge_normal;
if (cosine < colinear_tolerance && process->enableConvexCheck)
{
AddToCollection("_ERROR_Nonconvex_Polygon");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Noncoplanar_Polygon
);
break;
}
}
}
#if 0
//
//--------------------------------
// Check for polygons w/o textures
//--------------------------------
//
if(stateArray.GetLength() < 1)
{
AddToCollection("_ERROR_Nontextured_Polygon");
++total;
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Nontextured_Polygon
);
}
#endif
//
//-----------------------------
// Delete the remaining proxies
//-----------------------------
//
DetachArrayReferences(&indices);
return total;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
TextureProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
if (!process->continueProcess)
return 1;
//
//---------------------------------------------------------
// Make sure that the texture is between 32 and 256 in size
//---------------------------------------------------------
//
Vector2DOf<int> size;
GetImageSize(&size);
if (size.x<32 || size.x>512 || size.y<32 || size.y>512)
{
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Bad_Texture_Size
);
return 1;
}
//
//--------------------------------------------------------
// Make sure that we are dealing with a power of 2 texture
//--------------------------------------------------------
//
size.x ^= size.x&(-size.x);
size.y ^= size.y&(-size.y);
if (size.x || size.y)
{
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Bad_Texture_Size
);
return 1;
}
return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
TextureLibrary::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------
// Handle the texture library
//---------------------------
//
int total = 0;
TextureProxy *texture = UseFirstTextureProxy();
while (texture)
{
Check_Object(texture);
total += texture->FindErrors(process);
TextureProxy *next = texture->UseNextTextureProxyInLibrary();
texture->DetachReference();
if (!process->continueProcess)
{
if (next)
next->DetachReference();
return total;
}
texture = next;
}
return total;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
ChildProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
return (!process->continueProcess) ? 1 : 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
GroupProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------------------
// Make sure that the process says its OK to continue
//---------------------------------------------------
//
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
if (!process->continueProcess)
return 1;
//
//-----------------------------------------------------
// Go through each child and count the number of errors
//-----------------------------------------------------
//
int total = 0;
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
total += child->FindErrors(process);
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (!process->continueProcess)
{
if (next)
next->DetachReference();
return total;
}
child = next;
}
return total;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
PolygonMeshProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------------------
// Make sure that the process says its OK to continue
//---------------------------------------------------
//
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
if (!process->continueProcess)
return 1;
//
//-----------------------------------
// Count the number of polygon errors
//-----------------------------------
//
int total = 0;
DynamicArrayOf<PolygonProxy*> polygons;
unsigned polygon_count = UsePolygonArray(&polygons);
Verify(polygon_count == polygons.GetLength());
if (polygon_count)
{
for (unsigned i=0; i<polygon_count; ++i)
{
PolygonProxy *polygon = polygons[i];
Check_Object(polygon);
total += polygon->FindErrors(process);
}
}
else
{
process->FindErrorsCallback(
this,
FindErrorsProcess::ERROR_Empty_Mesh
);
total = 1;
}
DetachArrayReferences(&polygons);
return total;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
SceneProxy::FindErrors(FindErrorsProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------------------
// Make sure that the process says its OK to continue
//---------------------------------------------------
//
process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck);
if (!process->continueProcess)
return 1;
//
//-------------------
// Check the textures
//-------------------
//
int total=0;
StateLibrary *states = GetStateLibrary();
Check_Object(states);
TextureLibrary *textures = states->GetTextureLibrary();
Check_Object(textures);
total += textures->FindErrors(process);
if (!process->continueProcess)
return total;
//
//-----------------
// Check each child
//-----------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
total += child->FindErrors(process);
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (!process->continueProcess)
{
if (next)
next->DetachReference();
break;
}
child = next;
}
return total;
}
@@ -0,0 +1,53 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GenericProxy;
class FindErrorsProcess:
public Process
{
public:
enum {
StatusCheck = 0,
ERROR_Bad_Normal,
ERROR_Mismatched_Vertex_Colors,
ERROR_Mismatched_UVs,
ERROR_Mismatched_Normals,
ERROR_Duplicate_Vertex,
ERROR_Degenerate_Polygon,
ERROR_Noncoplanar_Polygon,
ERROR_Nonconvex_Polygon,
ERROR_Bad_Texture_Size,
ERROR_Nontextured_Polygon,
ERROR_Too_Many_Vertices,
ERROR_Empty_Mesh,
ErrorsCount
};
FindErrorsProcess();
FindErrorsProcess(
Stuff::NotationFile *data_file,
bool bSuppress = true,
void* fcn = NULL
);
bool
enableDuplicateCheck,
enableDegenerateCheck,
enableCoplanarCheck,
enableColinearCheck,
enableConvexCheck;
virtual void
FindErrorsCallback(
GenericProxy* proxy,
int type
)
{}
};
}
@@ -0,0 +1,218 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->FlattenHierarchyCallback(this);
//
//-----------------------------------------------
// Tell whoever called us to detach the reference
//-----------------------------------------------
//
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->FlattenHierarchyCallback(this);
if (!process->continueProcess)
return true;
//
//---------------------------------------------------------------------
// If this is not the parent group, move the group's children up to the
// parent then destroy the proxy
//---------------------------------------------------------------------
//
if (this != process->parentGroup)
{
LinearMatrix4D matrix;
bool push = GetLocalToParent(&matrix);
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (push)
child->TransformLocalToParent(matrix);
if (child->FlattenHierarchy(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
Destroy();
return false;
}
//
//-------------------------------------------------------------------------
// This is the parent group, so just call flatten hierarchy on the children
//-------------------------------------------------------------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->FlattenHierarchy(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
child->DetachReference();
}
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//------------------------------------------------------------
// Make sure that the process says its OK to check the texture
//------------------------------------------------------------
//
process->FlattenHierarchyCallback(this);
if (!process->continueProcess)
return true;
//
//-------------------------------
// Transfer the mesh to the scene
//-------------------------------
//
TransferAndAppendToParentGroup(process->parentGroup);
//
//----------------------------------------------------------------------
// Adjust all the vertices so they are correct for an identity transform
//----------------------------------------------------------------------
//
LinearMatrix4D matrix;
GetLocalToParent(&matrix);
SetLocalToParent(LinearMatrix4D::Identity);
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
for (unsigned i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
Point3D old_position;
vertex->GetPosition(&old_position);
Point3D new_position;
new_position.Multiply(old_position, matrix);
vertex->SetPosition(new_position);
Normal3D old_normal;
if(vertex->GetNormal(&old_normal))
{
Normal3D new_normal;
new_normal.Multiply(old_normal, matrix);
vertex->SetNormal(new_normal);
}
}
DetachArrayReferences(&vertices);
//
//-----------------------------------------------
// Tell whoever called us to detach the reference
//-----------------------------------------------
//
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::FlattenHierarchy(FlattenHierarchyProcess *process)
{
Check_Object(this);
Check_Object(process);
Verify(!process->parentGroup);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->FlattenHierarchyCallback(this);
if (!process->continueProcess)
return;
//
//---------------------
// Flatten the children
//---------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->FlattenHierarchy(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
{
child->DetachReference();
}
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
}
@@ -0,0 +1,33 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class FlattenHierarchyProcess:
public Process
{
public:
FlattenHierarchyProcess(GroupProxy *parent_group=NULL):
parentGroup(parent_group)
{}
FlattenHierarchyProcess(
Stuff::NotationFile *data_file,
bool bSuppress = true,
void* fcn = NULL,
GroupProxy *parent_group=NULL
):
Process(data_file, bSuppress, fcn),
parentGroup(parent_group)
{}
virtual void
FlattenHierarchyCallback(GenericProxy* proxy)
{}
GroupProxy
*parentGroup;
};
}
@@ -0,0 +1,43 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//########################### GenericProxy #############################
//############################################################################
//
GenericProxy::ClassData*
GenericProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
GenericProxyClassID,
"GenericProxy",
Plug::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GenericProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
@@ -0,0 +1,93 @@
#pragma once
#include "Proxies.hpp"
namespace Proxies {
//
//#########################################################################
//######################## GenericProxy #############################
//#########################################################################
//
class _declspec(novtable) GenericProxy:
public Stuff::Plug
{
public:
static void
InitializeClass();
static void
TerminateClass();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
public:
virtual void
Destroy() = 0;
protected:
GenericProxy(ClassData *class_data):
Plug(class_data)
{referenceCount = 1;}
virtual ~GenericProxy()
{Check_Object(this); Verify(!referenceCount);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data Support
//
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Proxy name
//
public:
//
// Get the name of the proxy
//
virtual bool
GetName(Stuff::MString *name) = 0;
//
// Set the name of the proxy
//
virtual void
SetName(const char* name) = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Reference counting
//
public:
void
AttachReference()
{Check_Object(this); ++referenceCount;}
void
DetachReference()
{
Check_Object(this); Verify(referenceCount > 0);
if ((--referenceCount) == 0)
{
Unregister_Object(this);
delete this;
}
}
int
GetReferenceCount()
{return referenceCount;}
protected:
int
referenceCount;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
};
}
@@ -0,0 +1,445 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//############################ GroupProxy ##############################
//############################################################################
//
GroupProxy::ClassData*
GroupProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
GroupProxyClassID,
"GroupProxy",
ChildProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupProxy::GroupProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
):
ChildProxy(class_data, scene, parent),
activeChildProxies(NULL)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GroupProxy::~GroupProxy()
{
Check_Object(this);
Verify(activeChildProxies.IsEmpty());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::GetCentroid(Point3D *centroid)
{
Check_Object(this);
Check_Pointer(centroid);
//
//-----------------------------------------------
// If we have no children, just return our origin
//-----------------------------------------------
//
unsigned child_count = GetChildCount();
*centroid = Point3D::Identity;
if (!child_count)
return;
//
//--------------------------------------------
// Otherwise, just average our child centroids
//--------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
Point3D local_centroid;
child->GetCentroid(&local_centroid);
LinearMatrix4D m;
child->GetLocalToParent(&m);
Point3D world_centroid;
world_centroid.Multiply(local_centroid, m);
*centroid += world_centroid;
child->DetachReference();
child = next;
}
Verify(!child);
*centroid /= static_cast<Scalar>(child_count);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::Recenter()
{
Check_Object(this);
//
//-------------------------------------------------------------------------
// Now, get our centroid in our mesh space, and recenter the mesh around it
// in model space
//-------------------------------------------------------------------------
//
Point3D centroid;
GetCentroid(&centroid);
if (centroid != Point3D::Identity)
{
LinearMatrix4D matrix;
GetLocalToParent(&matrix);
matrix(3,0) += centroid.x;
matrix(3,1) += centroid.y;
matrix(3,2) += centroid.z;
SetLocalToParent(matrix);
//
//----------------------------------------------------------
// First, allow each child hierarchy to remove redundancies
//----------------------------------------------------------
//
matrix = LinearMatrix4D::Identity;
centroid.Negate(centroid);
matrix.BuildTranslation(centroid);
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
child->TransformLocalToParent(matrix);
child->DetachReference();
child = next;
}
if (child)
child->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::SortAndAddPolygons(
BinSortProcess *process,
Stuff::DynamicArrayOf<PolygonProxy*> &polygons
)
{
Check_Object(this);
Check_Object(process);
Check_Object(&polygons);
Verify(process->binSize > 0);
//
//---------------------------------------------------------------
// See if we can just directly add these polygons into a new mesh
//---------------------------------------------------------------
//
unsigned polygon_count = polygons.GetLength();
if (polygon_count <= process->binSize)
{
Copy_Mesh:
PolygonMeshProxy *mesh = AppendNewPolygonMeshProxy();
Check_Object(mesh);
mesh->AddPolygons(process, polygons);
mesh->DetachReference();
return;
}
//
//---------------------------------
// Make a list of all the centroids
//---------------------------------
//
DynamicArrayOf<Point3D> centroids(polygon_count);
unsigned i;
PolygonProxy *polygon;
for (i=0; i<polygon_count; ++i)
{
polygon = polygons[i];
Check_Object(polygon);
Scalar area = polygon->GetSurfaceAreaAndCentroid(&centroids[i]);
if (area > SMALL)
centroids[i] /= area;
}
//
//------------------------------------------------------------------------
// Calculate the dividing plane, and if none can be found, don't do nothin
//------------------------------------------------------------------------
//
Plane plane;
if (!plane.ComputeBestDividingPlane(centroids))
goto Copy_Mesh;
//
//-----------------------------------------------------------------------
// Create two new meshes under the group for the mesh to be split up into
//-----------------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*>
group_a(polygon_count),
group_b(polygon_count);
unsigned
count_a = 0,
count_b = 0;
//
//------------------------------------------------------------------
// Sort each of the centroids against the plane into one of two bins
//------------------------------------------------------------------
//
for (i=0; i<polygon_count; ++i)
{
polygon = polygons[i];
Check_Object(polygon);
if (plane.GetDistanceTo(centroids[i]) < 0.0f)
group_b[count_b++] = polygon;
else
group_a[count_a++] = polygon;
}
group_a.SetLength(count_a);
group_b.SetLength(count_b);
//
//------------------
// Now sort each bin
//------------------
//
SortAndAddPolygons(process, group_a);
SortAndAddPolygons(process, group_b);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::GetBoundingSphere(Sphere *sphere)
{
Check_Object(this);
Check_Pointer(sphere);
//
//---------------------------------------------------------------------
// Put the center of the sphere at the centroid, then set the radius to
// just contain the mesh
//---------------------------------------------------------------------
//
GetCentroid(&sphere->center);
sphere->radius = -1.0f;
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
//
//----------------------------------------------------------
// Transform's the child's bounding sphere into parent space
//----------------------------------------------------------
//
LinearMatrix4D child_to_parent;
child->GetLocalToParent(&child_to_parent);
Sphere child_sphere;
child->GetBoundingSphere(&child_sphere);
Point3D position;
position.Multiply(child_sphere.center, child_to_parent);
//
//-----------------------------------------------------------------
// Now stretch the radius of the bounding sphere so that it totally
// includes the child sphere
//-----------------------------------------------------------------
//
position -= sphere->center;
Scalar range = position.GetLength() + child_sphere.radius;
if (range > sphere->radius)
{
sphere->radius = range;
}
child->DetachReference();
child = next;
}
//
//-------------------------------------
// Make sure the radius is properly set
//-------------------------------------
//
if (sphere->radius == -1.0f)
{
sphere->radius = 0.0f;
return false;
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
GroupProxy::AppendMatchingChildProxy(
CopyProcess *process,
ChildProxy *child
)
{
Check_Object(this);
Check_Object(process);
Check_Object(child);
if (child->IsDerivedFrom(PolygonMeshProxy::DefaultData))
{
PolygonMeshProxy *proxy = AppendNewPolygonMeshProxy();
Check_Object(proxy);
proxy->Copy(process, Cast_Object(PolygonMeshProxy*, child));
return proxy;
}
else if (child->IsDerivedFrom(GroupProxy::DefaultData))
{
GroupProxy *proxy = AppendNewGroupProxy();
Check_Object(proxy);
proxy->Copy(process, Cast_Object(GroupProxy*, child));
return proxy;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
GroupProxy::InsertMatchingChildProxy(
CopyProcess *process,
ChildProxy *child,
ChildProxy *before
)
{
Check_Object(this);
Check_Object(process);
Check_Object(child);
Check_Object(before);
Verify(before->GetParentGroupProxy() == this);
STOP(("Not implemented"));
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::FindNamedChildren(
DynamicArrayOf<ChildProxy*> *children,
const char* prefix,
bool matching
)
{
Check_Object(this);
Check_Object(children);
Check_Pointer(prefix);
//
//----------------------
// Get the prefix length
//----------------------
//
int size = strlen(prefix);
//
//---------------------------------
// Find out how many children match
//---------------------------------
//
unsigned count = 0;
ChildProxy *child = UseFirstChildProxy();
while (child)
{
ChildProxy *next = child->UseNextSiblingProxy();
MString name;
if (child->GetName(&name))
{
if ((!_strnicmp(name, prefix, size)) == matching)
++count;
}
child->DetachReference();
child = next;
}
//
//------------------------------------------------------------------------
// Set the array length, and if we have any matching children, fill in the
// array with those proxies
//------------------------------------------------------------------------
//
children->SetLength(count);
if (count > 0)
{
child = UseFirstChildProxy();
count = 0;
while (child)
{
ChildProxy *next = child->UseNextSiblingProxy();
//
//-----------------------------------------------------------------
// If the child has a name and it matches what we are looking for,
// store it in the array and bump the reference count so it doesn't
// go away
//-----------------------------------------------------------------
//
MString name;
if (child->GetName(&name))
{
if ((!_strnicmp(name, prefix, size)) == matching)
{
(*children)[count++] = child;
child->AttachReference();
}
}
child->DetachReference();
child = next;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::DetachChildProxy(ChildProxy* proxy)
{
Check_Object(this);
activeChildProxies.RemovePlug(proxy);
Verify(referenceCount > 1);
DetachReference();
}
@@ -0,0 +1,175 @@
#pragma once
#include "Proxies.hpp"
#include "ChildProxy.hpp"
namespace Proxies {
class PolygonMeshProxy;
class PolygonProxy;
class StateProxy;
class Process;
class GetInfoProcess;
//
//#########################################################################
//####################### GroupProxy ############################
//#########################################################################
//
class _declspec(novtable) GroupProxy:
public ChildProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
GroupProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
);
~GroupProxy();
public:
//
// Copies the elements of a hierarchy into this hierarchy
//
virtual void
Copy(
CopyProcess *process,
GroupProxy *hierarchy
);
//
// gives informations about the group
//
virtual void
GetInfo(
GetInfoProcess *process
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
bool
BinSort(BinSortProcess *process);
void
BurnLights(BurnLightsProcess *process);
bool
CleanHierarchy(CleanHierarchyProcess *process);
int
FindErrors(FindErrorsProcess *process);
void
FindLights(BurnLightsProcess *process);
bool
FlattenHierarchy(FlattenHierarchyProcess *process);
bool
SplitByState(SplitByStateProcess *process);
bool
MakeSingleSided(MakeSingleSidedProcess *process);
bool
OptimizeFlatShading(OptimizeFlatShadingProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon functions
//
public:
void
GetCentroid(Stuff::Point3D *center);
void
Recenter();
void
SortAndAddPolygons(
BinSortProcess *process,
Stuff::DynamicArrayOf<PolygonProxy*> &polygons
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bounding functions
//
// GetBoundingSphere should be used only after GetOBB has returned a false
//
public:
bool
GetBoundingSphere(Stuff::Sphere *sphere);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hierarchy functions
//
public:
//
// Gets the current number of children
//
virtual unsigned
GetChildCount() = 0;
//
// Child creation functions
//
virtual GroupProxy*
AppendNewGroupProxy() = 0;
virtual GroupProxy*
InsertNewGroupProxy(ChildProxy *before) = 0;
virtual PolygonMeshProxy*
AppendNewPolygonMeshProxy() = 0;
virtual PolygonMeshProxy*
InsertNewPolygonMeshProxy(ChildProxy *before) = 0;
ChildProxy*
AppendMatchingChildProxy(
CopyProcess *process,
ChildProxy *child
);
ChildProxy*
InsertMatchingChildProxy(
CopyProcess *process,
ChildProxy *child,
ChildProxy *before
);
//
// Child traversal functions
//
virtual ChildProxy*
UseFirstChildProxy() = 0;
virtual ChildProxy*
UseLastChildProxy() = 0;
virtual void
FindNamedChildren(
Stuff::DynamicArrayOf<ChildProxy*> *children,
const char* prefix,
bool matching = true
);
void
AttachChildProxy(ChildProxy *child)
{
Check_Object(this);
AttachReference(); activeChildProxies.Add(child);
}
void
DetachChildProxy(ChildProxy* proxy);
protected:
Stuff::ChainOf<ChildProxy*>
activeChildProxies;
};
}
@@ -0,0 +1,116 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//######################## IndexProxy ##########################
//############################################################################
//
IndexProxy::ClassData*
IndexProxy::DefaultData = NULL;
MemoryBlock*
IndexProxy::AllocatedMemory = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
IndexProxy::InitializeClass()
{
Verify(!AllocatedMemory);
AllocatedMemory =
new MemoryBlock(
sizeof(IndexProxy),
100,
100,
"IndexProxy"
);
Register_Object(AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
IndexProxyClassID,
"IndexProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
IndexProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(AllocatedMemory);
delete AllocatedMemory;
AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
IndexProxy::IndexProxy(
ClassData *class_data,
PolygonProxy *polygon,
VertexProxy *index
):
GenericProxy(class_data),
polygonProxy(polygon),
vertexProxy(index)
{
Check_Pointer(this);
Check_Object(polygonProxy);
polygonProxy->AttachIndexProxy(this);
Check_Object(vertexProxy);
vertexProxy->AttachIndexProxy(this);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
IndexProxy::IndexProxy(
PolygonProxy *polygon,
VertexProxy *index
):
GenericProxy(DefaultData),
polygonProxy(polygon),
vertexProxy(index)
{
Check_Pointer(this);
Check_Object(polygonProxy);
polygonProxy->AttachIndexProxy(this);
Check_Object(vertexProxy);
vertexProxy->AttachIndexProxy(this);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
IndexProxy::~IndexProxy()
{
Check_Object(this);
Check_Object(polygonProxy);
polygonProxy->DetachIndexProxy(this);
vertexProxy->DetachIndexProxy(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
IndexProxy::Destroy()
{
Check_Object(this);
Verify(referenceCount == 1);
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
IndexProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
@@ -0,0 +1,98 @@
#pragma once
#include "Proxies.hpp"
#include "GenericProxy.hpp"
namespace Proxies {
class PolygonProxy;
//
//#########################################################################
//##################### IndexProxy ##########################
//#########################################################################
//
class IndexProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
IndexProxy(
ClassData *class_data,
PolygonProxy *polygon,
VertexProxy *index
);
IndexProxy(
PolygonProxy *polygon,
VertexProxy *index
);
~IndexProxy();
static Stuff::MemoryBlock
*AllocatedMemory;
public:
static IndexProxy*
MakeProxy(
PolygonProxy *polygon,
VertexProxy *index
)
{return new IndexProxy(polygon, index);}
void
Destroy();
void*
operator new(size_t)
{return AllocatedMemory->New();}
void
operator delete(void *where)
{AllocatedMemory->Delete(where);}
public:
bool
GetName(class Stuff::MString *name)
{Check_Object(this); Check_Object(name); return false;}
void
SetName(const char* name)
{Check_Object(this); Check_Pointer(name);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vertex management functions
//
public:
//
// Copies the elements of a polygon into this polygon
//
PolygonProxy*
GetPolygonProxy()
{Check_Object(this); return polygonProxy;}
VertexProxy*
GetVertexProxy()
{Check_Object(this); return vertexProxy;}
protected:
PolygonProxy
*polygonProxy;
VertexProxy
*vertexProxy;
};
}
@@ -0,0 +1,484 @@
#include "ProxyHeaders.hpp"
char *GetInfoProcess::names[InfoBitCount] =
{
"SceneProxy",
"GroupProxy",
"ChildProxy",
"PolyMeshProxy",
"PolygonProxy",
"StateProxy",
"TextureProxy",
"TextureLibraryProxy"
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::Reset()
{
int i;
for(i=0;i<InfoBitCount;i++)
{
nrOfProcessedItems[i] = 0;
}
hierarchyInfoLevel = 0;
hierarchyInfoSibling = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::InfoCallback(int mode)
{
int i;
int mask = 1;
for(i=0;i<InfoBitCount;i++)
{
if(mode & mask)
{
nrOfProcessedItems[i]++;
}
mask <<= 1;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::TellWhatYouKnow()
{
int i;
(*stream) << "\r\n" << "The Infoprocess has:" << "\r\n";
for(i=0;i<InfoBitCount;i++)
{
if(nrOfProcessedItems[i] > 0)
{
(*stream) << nrOfProcessedItems[i] << " " << names[i] << " " << "processed." << "\r\n";
}
}
(*stream) << "\r\n";
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::TellMyName(Stuff::MString *name, int mode)
{
int i;
for(i=0;i<hierarchyInfoLevel;i++)
{
(*stream) << '\t';
}
if(name->GetLength())
{
(*stream) << *name;
}
else
{
int mask = 1;
for(i=0;i<InfoBitCount;i++)
{
if(mode & mask)
{
break;
}
mask <<= 1;
}
Verify(i<InfoBitCount);
(*stream) << names[i] << " #" << nrOfProcessedItems[i];
}
if( mode & InfoSceneMode ||
mode & InfoGroupMode ||
mode & InfoChildMode ||
mode & InfoPolyMeshMode
)
{
(*stream) << " " << hierarchyInfoLevel << " " << hierarchyInfoSibling;
}
(*stream) << ":" << "\r\n";
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::TalkAboutATexLibrary(const char *path, const char *ext)
{
(*stream) << "Texture path: \"" << path << "\" Extention: \"" << ext << "\"\n";
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GetInfoProcess::TalkAboutAMesh(int nrOfPolys, int nrOfVertices, int nrOfIndices, int nrOfStates)
{
int i;
for(i=0;i<hierarchyInfoLevel;i++)
{
(*stream) << '\t';
}
(*stream) << "P: " << nrOfPolys
<< " V: " << nrOfVertices
<< " I: " << nrOfIndices
<< " I/V: " << (Scalar)nrOfIndices/(Scalar)nrOfVertices
<< " S: " << nrOfStates
<< "\r\n";
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoTextureMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoTextureMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoStateMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoStateMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
GroupProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoGroupMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoGroupMode);
//
//---------------------------------------------------------
// For each child in the source, copy it to the destination
//---------------------------------------------------------
//
int nrOfChildren = 0;
process->IncHierarchyLevel();
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
process->SetHierarchySibling(nrOfChildren++);
child->GetInfo(process);
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (process->continueProcess)
child = next;
else
{
if (child)
child->DetachReference();
break;
}
}
process->DecHierarchyLevel();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ChildProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoChildMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoChildMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoPolyMeshMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoPolyMeshMode);
//
//---------------------------------------------------------------
// Get the polygons of the source mesh, then analyze their states
//---------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> source_polygons;
DynamicArrayOf<VertexProxy*> source_vertices;
DynamicArrayOf<IndexProxy*> source_indices;
unsigned i, total_polys = UsePolygonArray(&source_polygons);
unsigned total_vertices = UseVertexArray(&source_vertices);
Verify(total_polys == source_polygons.GetLength());
Verify(total_vertices == source_vertices.GetLength());
//
//-----------------------------------------------------------------------
// We have to evaluate each polygon within the mesh to see how many have
// unique texture/material combinations, so set up arrays to hold proxies
// and matching indices
//-----------------------------------------------------------------------
//
DynamicArrayOf<unsigned> match;
DynamicArrayOf<unsigned> count;
DynamicArrayOf<MultiState*> source_states;
unsigned unique_states =
UseMultiStateArray(&source_states, &match, &count, source_polygons);
unsigned total_indices;
for(i=0,total_indices=0;i<total_polys;i++)
{
total_indices += source_polygons[i]->UseIndexArray(&source_indices);
source_polygons[i]->DetachArrayReferences(&source_indices);
}
DetachArrayReferences(&source_states);
DetachArrayReferences(&source_polygons);
DetachArrayReferences(&source_vertices);
process->TalkAboutAMesh(total_polys, total_vertices, total_indices, unique_states);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoTextureLibraryMode);
if (!process->continueProcess)
return;
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoTextureLibraryMode);
// process->TalkAboutATexLibrary(texturePath, ".tga");
//
//------------------------------------------------------------------
// For each texture, get the info
//------------------------------------------------------------------
//
TextureProxy *other_texture = UseFirstTextureProxy();
while (other_texture)
{
Check_Object(other_texture);
other_texture->GetInfo(process);
TextureProxy *next = other_texture->UseNextTextureProxyInLibrary();
other_texture->DetachReference();
if (process->continueProcess)
other_texture = next;
else
{
if (other_texture)
other_texture->DetachReference();
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::GetInfo(
GetInfoProcess *process
)
{
Check_Object(this);
Check_Object(process);
//
//---------------------------------------
// Make sure that the process says its OK
//---------------------------------------
//
process->InfoCallback(GetInfoProcess::InfoSceneMode);
if (!process->continueProcess)
return;
process->SetHierarchyLevel();
//
//-------------
// Get the info
//-------------
//
MString name;
GetName(&name);
process->TellMyName(&name, GetInfoProcess::InfoSceneMode);
GetStateLibrary()->GetTextureLibrary()->GetInfo(process);
//
//---------------------------------------------------------
// For each child in the source, copy it to the destination
//---------------------------------------------------------
//
int nrOfChildren = 0;
process->IncHierarchyLevel();
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
process->SetHierarchySibling(nrOfChildren++);
child->GetInfo(process);
ChildProxy *next = child->UseNextSiblingProxy();
child->DetachReference();
if (process->continueProcess)
child = next;
else
{
if (child)
child->DetachReference();
break;
}
}
process->DecHierarchyLevel();
}
@@ -0,0 +1,90 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GetInfoProcess:
public Process
{
public:
GetInfoProcess(Stuff::MemoryStream *s)
{ stream = s; Reset(); }
GetInfoProcess(
Stuff::NotationFile *data_file,
Stuff::MemoryStream *s
):
Process(data_file)
{ stream = s; Reset(); }
virtual void
InfoCallback(int);
void
Reset();
void
TellWhatYouKnow();
void
TellMyName(Stuff::MString *name, int);
void
TalkAboutATexLibrary(const char *, const char *);
void
TalkAboutAMesh(int, int, int, int);
void
SetHierarchyLevel(int nr=0)
{ hierarchyInfoLevel = nr; }
void
IncHierarchyLevel()
{ hierarchyInfoLevel++; }
void
DecHierarchyLevel()
{ hierarchyInfoLevel--; }
void
SetHierarchySibling(int nr=0)
{ hierarchyInfoSibling = nr; }
enum {
InfoSceneBit = 0,
InfoGroupBit,
InfoChildBit,
InfoPolyMeshBit,
InfoPolygonBit,
InfoStateBit,
InfoTextureBit,
InfoTextureLibraryBit,
InfoBitCount
};
enum InfoMode {
InfoSceneMode = 1<<InfoSceneBit,
InfoGroupMode = 1<<InfoGroupBit,
InfoChildMode = 1<<InfoChildBit,
InfoPolyMeshMode = 1<<InfoPolyMeshBit,
InfoPolygonMode = 1<<InfoPolygonBit,
InfoStateMode = 1<<InfoStateBit,
InfoTextureMode = 1<<InfoTextureBit,
InfoTextureLibraryMode = 1<<InfoTextureLibraryBit
};
protected:
//
// through the process accumulated data
//
int nrOfProcessedItems[InfoBitCount];
static char *names[InfoBitCount];
int hierarchyInfoLevel, hierarchyInfoSibling;
Stuff::MemoryStream *stream;
};
}
@@ -0,0 +1,86 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//############################# LightProxy #############################
//############################################################################
//
LightProxy::ClassData*
LightProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
LightProxyClassID,
"LightProxy",
ChildProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LightProxy::LightProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
):
ChildProxy(class_data, scene, parent)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LightProxy::~LightProxy()
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
Check_Object(sceneProxy);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::GetCentroid(Point3D *centroid)
{
Check_Object(this);
Check_Object(centroid);
*centroid = Point3D::Identity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
LightProxy::FitBoundingSphere(Sphere *sphere)
{
Check_Object(this);
Check_Object(sphere);
sphere->radius = 0.0f;
sphere->center = Point3D::Identity;
}
@@ -0,0 +1,112 @@
#pragma once
#include "Proxies.hpp"
#include "ChildProxy.hpp"
namespace Proxies {
class SceneProxy;
//
//#########################################################################
//######################### LightProxy ##############################
//#########################################################################
//
class _declspec(novtable) LightProxy:
public ChildProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
LightProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
);
~LightProxy();
public:
//
// Copies the elements of the given material into this material
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
void
FindLights(BurnLightsProcess *process);
virtual void
Copy(
CopyProcess *process,
LightProxy *light
);
void
GetCentroid(Stuff::Point3D *center);
void
FitBoundingSphere(Stuff::Sphere *sphere);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Light functions
//
public:
//
// ambient color functions
//
virtual void
GetColor(Stuff::RGBColor *color) = 0;
virtual void
SetColor(const Stuff::RGBColor &color) = 0;
//
// Ambience. If the light is ambient (it isn't by default), then its
// local to parent and local to world matrices are not valid
//
virtual bool
IsAmbient() = 0;
virtual void
SetAmbient(bool ambient) = 0;
//
// light falloff. The light is infinite if the GetFalloffDistance
// function return false. Lights default to infinite unless
// SetFalloffDistance is called
//
virtual bool
GetFalloffDistance(
Stuff::Scalar *n,
Stuff::Scalar *f
) = 0;
virtual void
SetFalloffDistance(
Stuff::Scalar n,
Stuff::Scalar f
) = 0;
//
// spotlight spread. This value is only valid if the light had falloff
//
virtual bool
GetSpreadAngle(Stuff::Radian *angle) = 0;
virtual void
SetSpreadAngle(const Stuff::Radian &radian) = 0;
};
}
@@ -0,0 +1,132 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::MakeSingleSided(MakeSingleSidedProcess *process)
{
Check_Object(this);
Check_Object(process);
process->MirrorCallback(this);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::MakeSingleSided(MakeSingleSidedProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->MirrorCallback(this);
if (!process->continueProcess)
return true;
STOP(("Not implemented"));
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::MakeSingleSided(MakeSingleSidedProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->MirrorCallback(this);
if (!process->continueProcess)
return true;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->MakeSingleSided(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::MakeSingleSided(MakeSingleSidedProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->MirrorCallback(this);
if (!process->continueProcess)
return;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
unsigned i;
for (i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->MakeSingleSided(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//------------------------------------------------------------------------
// Make sure to discard any remaining proxies, and bypass the second phase
// of the sort if the process has been aborted
//------------------------------------------------------------------------
//
if (child)
child->DetachReference();
}
@@ -0,0 +1,25 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GenericProxy;
class MakeSingleSidedProcess:
public Process
{
public:
MakeSingleSidedProcess()
{}
MakeSingleSidedProcess(Stuff::NotationFile *data_file):
Process(data_file)
{}
virtual void
MirrorCallback(GenericProxy* proxy)
{}
};
}
@@ -0,0 +1,132 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::OptimizeFlatShading(OptimizeFlatShadingProcess *process)
{
Check_Object(this);
Check_Object(process);
process->OptimizeCallback(this);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::OptimizeFlatShading(OptimizeFlatShadingProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->OptimizeCallback(this);
if (!process->continueProcess)
return true;
STOP(("Not implemented"));
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::OptimizeFlatShading(OptimizeFlatShadingProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->OptimizeCallback(this);
if (!process->continueProcess)
return true;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->OptimizeFlatShading(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::OptimizeFlatShading(OptimizeFlatShadingProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->OptimizeCallback(this);
if (!process->continueProcess)
return;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
unsigned i;
for (i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->OptimizeFlatShading(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//------------------------------------------------------------------------
// Make sure to discard any remaining proxies, and bypass the second phase
// of the sort if the process has been aborted
//------------------------------------------------------------------------
//
if (child)
child->DetachReference();
}
@@ -0,0 +1,25 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GenericProxy;
class OptimizeFlatShadingProcess:
public Process
{
public:
OptimizeFlatShadingProcess()
{}
OptimizeFlatShadingProcess(Stuff::NotationFile *data_file):
Process(data_file)
{}
virtual void
OptimizeCallback(GenericProxy* proxy)
{}
};
}
@@ -0,0 +1,444 @@
#include "ProxyHeaders.hpp"
struct AbstractVertex
{
Point3D position;
Normal3D normal;
Vector2DOf<Scalar> uv;
RGBAColor color;
};
//
//############################################################################
//######################### PolygonMeshProxy ###########################
//############################################################################
//
PolygonMeshProxy::ClassData*
PolygonMeshProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
PolygonMeshProxyClassID,
"PolygonMeshProxy",
ChildProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonMeshProxy::PolygonMeshProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
):
ChildProxy(class_data, scene, parent),
activePolygonProxies(NULL),
activeVertexProxies(NULL)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonMeshProxy::~PolygonMeshProxy()
{
Check_Object(this);
Verify(activePolygonProxies.IsEmpty());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::GetCentroid(Point3D *centroid)
{
Check_Object(this);
Check_Object(centroid);
//
//-------------------------------------------------------------------
// If we have no polygons, just return our local to world translation
//-------------------------------------------------------------------
//
DynamicArrayOf<PolygonProxy*> polygons;
unsigned polygon_count = UsePolygonArray(&polygons);
Verify(polygon_count == polygons.GetLength());
if (!polygon_count)
{
*centroid = Point3D::Identity;
return;
}
//
//---------------------------------------------
// Sum up all the polygon centroids and weights
//---------------------------------------------
//
*centroid = Point3D::Identity;
for (unsigned i=0; i<polygon_count; ++i)
{
PolygonProxy *polygon = polygons[i];
Check_Object(polygon);
Point3D center;
Scalar area = polygon->GetSurfaceAreaAndCentroid(&center);
if (area > SMALL)
center /= area;
*centroid += center;
}
*centroid /= static_cast<Scalar>(polygon_count);
DetachArrayReferences(&polygons);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::Recenter()
{
Check_Object(this);
//
//-------------------------------------------------------------------------
// Now, get our centroid in our mesh space, and recenter the mesh around it
// in model space
//-------------------------------------------------------------------------
//
Point3D centroid;
GetCentroid(&centroid);
if (centroid != Point3D::Identity)
{
LinearMatrix4D matrix;
GetLocalToParent(&matrix);
LinearMatrix4D shift(true);
shift.BuildTranslation(centroid);
LinearMatrix4D new_origin;
new_origin.Multiply(shift, matrix);
SetLocalToParent(new_origin);
//
//-----------------------------------------------------------
// Now we have to subtract the centroid from all our vertices
//-----------------------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
for (unsigned i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
Point3D position;
vertex->GetPosition(&position);
position -= centroid;
vertex->SetPosition(position);
}
DetachArrayReferences(&vertices);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
PolygonMeshProxy::UseMultiStateArray(
DynamicArrayOf<MultiState*> *states,
DynamicArrayOf<unsigned> *index,
DynamicArrayOf<unsigned> *count,
DynamicArrayOf<PolygonProxy*> &polygons
)
{
Check_Object(this);
Check_Object(index);
Check_Object(count);
Check_Object(states);
//
//----------------------------------------------------------------------
// We have to evaluate each polygon within the mesh to see how many have
// unique states, so set up arrays to hold proxies and matching indices
//----------------------------------------------------------------------
//
unsigned polygon_count = polygons.GetLength();
//
//-------------------------------------------------------
// Spin through the polygons, check for max. nr of states
//-------------------------------------------------------
//
unsigned poly;
states->SetLength(polygon_count);
index->SetLength(polygon_count);
count->SetLength(polygon_count);
unsigned i, j;
for (i=0; i<polygon_count; ++i)
(*count)[i] = 0;
unsigned unique_combinations = 0;
//
//------------------------------------------------------
// Spin through the polygons, looking for unique entries
//------------------------------------------------------
//
for (poly=0; poly < polygon_count; ++poly)
{
PolygonProxy *polygon = polygons[poly];
Check_Object(polygon);
MultiState poly_states;
polygon->UseMultiState(&poly_states);
//
//-------------------------------------------------------------------
// Get the state proxies, and see if they index one of
// the prior entries
//-------------------------------------------------------------------
//
for (i=0; i<unique_combinations;++i)
{
//
//--------------------------------------------------------------
// Make sure that the state combo has the same length
//--------------------------------------------------------------
//
unsigned state_count = (*states)[i]->GetLength();
if( poly_states.GetLength() != state_count)
{
continue;
}
//
//--------------------------------------------------------------
// Make sure that the state and texture exists in either both
// proxies or neither proxy
//--------------------------------------------------------------
//
for(j=0;j<state_count;++j)
{
if ((!poly_states[j] && (*(*states)[i])[j]) ||
(poly_states[j] && !(*(*states)[i])[j]))
{
break;
}
}
if(j<state_count)
{
continue;
}
//
//-----------------------------------------------
// Make sure that the state and textures index
//-----------------------------------------------
//
if(poly_states.IsEqualTo(*(*states)[i]))
{
break;
}
}
//
//-------------------------------------------------------------------
// If this is a new entry, bump the combo count and store the proxies
//-------------------------------------------------------------------
//
if (i == unique_combinations)
{
++unique_combinations;
(*states)[i] = new MultiState (poly_states);
// Verify((*states)[i]->GetLength() > 0);
}
//
//-------------------------
// Move to the next polygon
//-------------------------
//
(*index)[poly] = i;
++(*count)[i];
poly_states.DetachReferences();
}
//
//-------------------------------------
// Release the texture/state proxies
//-------------------------------------
//
states->SetLength(unique_combinations);
count->SetLength(unique_combinations);
return unique_combinations;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::GetBoundingSphere(Sphere *sphere)
{
Check_Object(this);
Check_Pointer(sphere);
//
//---------------------------------------------------------------------
// Put the center of the sphere at the centroid, then set the radius to
// just contain the mesh
//---------------------------------------------------------------------
//
DynamicArrayOf<VertexProxy*> vertices;
unsigned vertex_count = UseVertexArray(&vertices);
Verify(vertex_count == vertices.GetLength());
#if 1
DynamicArrayOf<Point3D> points;
points.SetLength(vertex_count);
for (unsigned i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
vertex->GetPosition(&points[i]);
}
DetachArrayReferences(&vertices);
sphere->ComputeBounds(points);
//
//-------------------------------------
// Make sure the radius is properly set
//-------------------------------------
//
if (sphere->radius == -1.0f)
{
sphere->radius = 0.0f;
return false;
}
return true;
#else
GetCentroid(&sphere->center);
sphere->radius = -1.0f;
for (unsigned i=0; i<vertex_count; ++i)
{
VertexProxy *vertex = vertices[i];
Check_Object(vertex);
Point3D position;
vertex->GetPosition(&position);
position -= sphere->center;
Scalar range = position.GetLengthSquared();
if (range > sphere->radius)
sphere->radius = range;
}
DetachArrayReferences(&vertices);
//
//-------------------------------------
// Make sure the radius is properly set
//-------------------------------------
//
if (sphere->radius == -1.0f)
{
sphere->radius = 0.0f;
return false;
}
sphere->radius = Sqrt(sphere->radius) + SMALL;
return true;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::DetachPolygonProxy(PolygonProxy* proxy)
{
Check_Object(this);
activePolygonProxies.RemovePlug(proxy);
Verify(referenceCount > 1);
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::DetachArrayReferences(
DynamicArrayOf<MultiState*> *states
)
{
Check_Object(states);
//
//------------------------------
// Add all the vertices together
//------------------------------
//
unsigned i, state_count = states->GetLength();
for (i=0; i<state_count; ++i)
{
Check_Object((*states)[i]);
(*states)[i]->DetachReferences();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::DetachArrayReferences(
DynamicArrayOf<PolygonProxy*> *polygons
)
{
Check_Object(polygons);
//
//------------------------------
// Add all the vertices together
//------------------------------
//
unsigned polygon_count = polygons->GetLength();
for (unsigned i=0; i<polygon_count; ++i)
{
Check_Object((*polygons)[i]);
(*polygons)[i]->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonMeshProxy::DetachArrayReferences(
DynamicArrayOf<VertexProxy*> *vertices
)
{
Check_Object(vertices);
//
//------------------------------
// Add all the vertices together
//------------------------------
//
unsigned vertex_count = vertices->GetLength();
for (unsigned i=0; i<vertex_count; ++i)
{
Check_Object((*vertices)[i]);
(*vertices)[i]->DetachReference();
}
}
@@ -0,0 +1,168 @@
#pragma once
#include "Proxies.hpp"
#include "ChildProxy.hpp"
namespace Proxies {
class VertexProxy;
class PolygonProxy;
class MultiState;
class Process;
class CopyProcess;
class CoalesceTexturesProcess;
//
//#########################################################################
//###################### PolygonMeshProxy ###########################
//#########################################################################
//
class _declspec(novtable) PolygonMeshProxy:
public ChildProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
PolygonMeshProxy(
ClassData *class_data,
SceneProxy *scene,
GroupProxy *parent
);
~PolygonMeshProxy();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
bool
BinSort(BinSortProcess *process);
void
BurnLights(BurnLightsProcess *process);
bool
CleanHierarchy(CleanHierarchyProcess *process);
virtual void
CoalesceTextures(CoalesceTexturesProcess *process);
virtual void
Copy(
CopyProcess *process,
Proxies::PolygonMeshProxy* mesh
);
virtual void
GetInfo(
GetInfoProcess *process
);
int
FindErrors(FindErrorsProcess *process);
bool
FlattenHierarchy(FlattenHierarchyProcess *process);
void
GetCentroid(Stuff::Point3D *center);
void
Recenter();
bool
SplitByState(SplitByStateProcess *process);
bool
MakeSingleSided(MakeSingleSidedProcess *process);
bool
OptimizeFlatShading(OptimizeFlatShadingProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bounding functions
//
// GetBoundingSphere should be used only after GetOBB has returned a false
//
public:
bool
GetBoundingSphere(Stuff::Sphere *sphere);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon Mesh functions
//
public:
unsigned
UseMultiStateArray(
Stuff::DynamicArrayOf<MultiState*> *states,
Stuff::DynamicArrayOf<unsigned> *index,
Stuff::DynamicArrayOf<unsigned> *count,
Stuff::DynamicArrayOf<PolygonProxy*> &polygons
);
static void
DetachArrayReferences(Stuff::DynamicArrayOf<MultiState*> *states);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon functions
//
public:
//
// Get the number of polygons in the mesh
//
virtual unsigned
UsePolygonArray(Stuff::DynamicArrayOf<PolygonProxy*> *polygons) = 0;
static void
DetachArrayReferences(Stuff::DynamicArrayOf<PolygonProxy*> *polygons);
virtual void
AddPolygons(
Process *process,
Stuff::DynamicArrayOf<PolygonProxy*> &polygons
) = 0;
virtual void
SetToMatchMultiState(MultiState* multi_state) = 0;
void
AttachPolygonProxy(PolygonProxy *proxy)
{
Check_Object(this);
AttachReference(); activePolygonProxies.Add(proxy);
}
void
DetachPolygonProxy(PolygonProxy* proxy);
protected:
Stuff::ChainOf<PolygonProxy*>
activePolygonProxies;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vertex functions
//
public:
//
// Get the number of vertices in the mesh
//
virtual unsigned
UseVertexArray(Stuff::DynamicArrayOf<VertexProxy*> *vertices) = 0;
static void
DetachArrayReferences(Stuff::DynamicArrayOf<VertexProxy*> *vertices);
void
AttachVertexProxy(VertexProxy *proxy)
{
Check_Object(this);
AttachReference(); activeVertexProxies.Add(proxy);
}
void
DetachVertexProxy(VertexProxy* proxy);
protected:
Stuff::ChainOf<VertexProxy*>
activeVertexProxies;
};
}
@@ -0,0 +1,757 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//########################### Multistate #############################
//############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MultiState::IsEqualTo(const MultiState& multi_state)
{
if(GetLength() != multi_state.GetLength())
{
return false;
}
for(unsigned i=0;i<GetLength();++i)
{
if(!((*this)[i]->IsEqualTo(multi_state[i])))
{
return false;
}
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MultiState::MultiState(const MultiState& multi_state)
{
Check_Object(this);
unsigned state_count = multi_state.GetLength();
SetLength(state_count);
for (unsigned i=0; i<state_count; ++i)
{
(*this)[i] = multi_state[i];
(*this)[i]->AttachReference();
}
isInverted = multi_state.isInverted;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MultiState&
MultiState::operator=(const MultiState& multi_state)
{
Check_Object(this);
unsigned state_count = multi_state.GetLength();
SetLength(state_count);
for (unsigned i=0; i<state_count; ++i)
{
(*this)[i] = multi_state[i];
(*this)[i]->AttachReference();
}
isInverted = multi_state.isInverted;
return *this;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
unsigned
MultiState::UseStateArray(MultiState *states)
{
Check_Object(this);
unsigned state_count = GetLength();
states->SetLength(state_count);
for (unsigned i=0; i<state_count; ++i)
{
(*states)[i] = (*this)[i];
(*states)[i]->AttachReference();
}
return state_count;
}
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MultiState::DetachReferences()
{
for(unsigned i=0;i<GetLength();++i)
{
(*this)[i]->DetachReference();
}
SetLength(0);
}
//
//############################################################################
//########################### PolygonProxy #############################
//############################################################################
//
PolygonProxy::ClassData*
PolygonProxy::DefaultData = NULL;
MemoryBlock*
PolygonProxy::AllocatedMemory = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::InitializeClass()
{
Verify(!AllocatedMemory);
AllocatedMemory =
new MemoryBlock(
sizeof(PolygonProxy),
100,
100,
"PolygonProxy"
);
Register_Object(AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
PolygonProxyClassID,
"PolygonProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(AllocatedMemory);
delete AllocatedMemory;
AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonProxy::PolygonProxy(
ClassData *class_data,
PolygonMeshProxy *mesh
):
GenericProxy(class_data),
meshProxy(mesh),
activeIndexProxies(NULL)
{
Check_Pointer(this);
Check_Object(meshProxy);
meshProxy->AttachPolygonProxy(this);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonProxy::PolygonProxy():
GenericProxy(DefaultData),
meshProxy(NULL),
activeIndexProxies(NULL)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
PolygonProxy::~PolygonProxy()
{
Check_Object(this);
//
//---------------------------------------
// Detach the state array if there is one
//---------------------------------------
//
unsigned i;
stateArray.DetachReferences();
//
//----------------------------------------
// Detach the vertex array if there is one
//----------------------------------------
//
unsigned vertex_count = vertexArray.GetLength();
for (i=0; i<vertex_count; ++i)
{
Verify(GetClassID() == PolygonProxyClassID);
Check_Object(vertexArray[i]);
vertexArray[i]->DetachReference();
}
//
//--------------------------------------
// Detach the mesh proxy if there is one
//--------------------------------------
//
if (meshProxy)
{
Check_Object(meshProxy);
Verify(activeIndexProxies.IsEmpty());
meshProxy->DetachPolygonProxy(this);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::Destroy()
{
Check_Object(this);
Verify(referenceCount == 1);
Verify(activeIndexProxies.IsEmpty());
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
PolygonProxy::UseMultiState(MultiState *states)
{
Check_Object(this);
Verify(GetClassID() == PolygonProxyClassID);
*states = stateArray;
return stateArray.GetLength();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::SetStatesToMatch(const MultiState &states)
{
Check_Object(this);
Verify(GetClassID() == PolygonProxyClassID);
Verify(states.GetLength() > 0);
stateArray = states;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::AddToCollection(const char *group)
{
Check_Object(this);
Check_Pointer(group);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::AddToCollections(MStringChain &group_list)
{
Check_Object(this);
Check_Object(&group_list);
MStringChainIterator groups(&group_list);
PlugOf<MString> *group;
while ((group = groups.ReadAndNext()) != NULL)
{
Check_Object(group);
AddToCollection(group->GetItem());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::RemoveFromCollection(const char *group)
{
Check_Object(this);
Check_Pointer(group);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::RemoveFromCollections(MStringChain &group_list)
{
Check_Object(this);
Check_Object(&group_list);
MStringChainIterator groups(&group_list);
PlugOf<MString> *group;
while ((group = groups.ReadAndNext()) != NULL)
{
Check_Object(group);
RemoveFromCollection(group->GetItem());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::GetCollections(MStringChain *group_list)
{
Check_Object(this);
Check_Pointer(group_list);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonProxy::IsMemberOf(const char* group)
{
Check_Object(this);
Check_Pointer(group);
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::DetachIndexProxy(IndexProxy* proxy)
{
Check_Object(this);
activeIndexProxies.RemovePlug(proxy);
Verify(referenceCount > 1);
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::GetNormal(Normal3D *normal)
{
Check_Object(this);
Check_Pointer(normal);
//
//-----------------
// Get the vertices
//-----------------
//
DynamicArrayOf<IndexProxy*> indices;
#if defined(_ARMOR)
unsigned index_count = UseIndexArray(&indices);
Verify(index_count == indices.GetLength());
Verify(index_count >= 3);
#endif
IndexProxy *index_a = indices[0];
Check_Object(index_a);
IndexProxy *index_b = indices[1];
Check_Object(index_b);
IndexProxy *index_c = indices[2];
Check_Object(index_c);
//
//------------------------------------------
// Get the positions and release the proxies
//------------------------------------------
//
VertexProxy *vertex = index_a->GetVertexProxy();
Check_Object(vertex);
Point3D position_a;
vertex->GetPosition(&position_a);
vertex = index_b->GetVertexProxy();
Check_Object(vertex);
Point3D position_b;
vertex->GetPosition(&position_b);
vertex = index_c->GetVertexProxy();
Check_Object(vertex);
Point3D position_c;
vertex->GetPosition(&position_c);
DetachArrayReferences(&indices);
//
//--------------------
// Get the leg vectors
//--------------------
//
Vector3D
leg_1,
leg_2;
leg_1.Subtract(position_b, position_a);
leg_2.Subtract(position_c, position_a);
//
//----------------------------------------------------------------------
// Compute the cross-product of the two legs to get the direction of the
// normal
//----------------------------------------------------------------------
//
Vector3D v;
v.Cross(leg_1, leg_2);
*normal = v;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
PolygonProxy::GetArea()
{
Check_Object(this);
//
//---------------------
// Set up the variables
//---------------------
//
Point3D
position_a = Point3D::Identity,
position_b,
position_c = Point3D::Identity;
VertexProxy
*vertex_a = NULL,
*vertex_b = NULL,
*vertex_c = NULL;
Vector3D
leg_1,
leg_2 = Vector3D::Identity;
//
//-----------------------------------
// Spin through, testing the vertices
//-----------------------------------
//
Scalar area = 0.0f;
DynamicArrayOf<IndexProxy*> indices;
unsigned index_count = UseIndexArray(&indices);
Verify(index_count == indices.GetLength());
Verify(index_count >= 3);
for (unsigned i=0; i<index_count-2; ++i)
{
//
//-----------------------------------------------
// Generate all the information on the first pass
//-----------------------------------------------
//
if (!i)
{
Check_Object(indices[0]);
vertex_a = indices[0]->GetVertexProxy();
Check_Object(vertex_a);
Check_Object(indices[1]);
vertex_b = indices[1]->GetVertexProxy();
Check_Object(vertex_b);
Check_Object(indices[2]);
vertex_c = indices[2]->GetVertexProxy();
Check_Object(vertex_c);
vertex_a->GetPosition(&position_a);
vertex_b->GetPosition(&position_b);
vertex_c->GetPosition(&position_c);
leg_1.Subtract(position_b, position_a);
leg_2.Subtract(position_c, position_a);
}
//
//--------------------------------------------------------------
// Get the index info. If this is not the first pass, copy the
// information from last pass
//--------------------------------------------------------------
//
else
{
Check_Object(vertex_c);
vertex_b = vertex_c;
Check_Object(indices[i+2]);
vertex_c = indices[i+2]->GetVertexProxy();
Check_Object(vertex_c);
position_b = position_c;
vertex_c->GetPosition(&position_c);
leg_1 = leg_2;
leg_2.Subtract(position_c, position_a);
}
//
//-----------------------------------------------------------------
// Compute the cross-product of the two legs to get the area of the
// triangle
//-----------------------------------------------------------------
//
Vector3D v;
v.Cross(leg_1, leg_2);
area += v.GetLength();
}
//
//-----------------------------
// Delete the remaining proxies
//-----------------------------
//
DetachArrayReferences(&indices);
return 0.5f * area;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::GetVertexCentroid(Point3D *center)
{
Check_Object(this);
Check_Pointer(center);
//
//------------------------------
// Add all the vertices together
//------------------------------
//
*center = Point3D::Identity;
DynamicArrayOf<IndexProxy*> indices;
unsigned index_count = UseIndexArray(&indices);
Verify(index_count >= 3);
Verify(index_count == indices.GetLength());
for (unsigned i=0; i<index_count; ++i)
{
IndexProxy *index = indices[i];
Check_Object(index);
VertexProxy *vertex = index->GetVertexProxy();
Check_Object(vertex);
Point3D position;
vertex->GetPosition(&position);
*center += position;
}
DetachArrayReferences(&indices);
//
//----------------------
// Now, average them all
//----------------------
//
*center /= static_cast<Scalar>(index_count);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
PolygonProxy::GetSurfaceAreaAndCentroid(Point3D *center)
{
Check_Object(this);
//
//---------------------
// Set up the variables
//---------------------
//
Point3D
position_a = Point3D::Identity,
position_b,
position_c = Point3D::Identity;
VertexProxy
*vertex_a = NULL,
*vertex_b = NULL,
*vertex_c = NULL;
Vector3D
leg_1,
leg_2 = Vector3D::Identity;
//
//-----------------------------------
// Spin through, testing the vertices
//-----------------------------------
//
Scalar area = 0.0f;
DynamicArrayOf<IndexProxy*> indices;
unsigned index_count = UseIndexArray(&indices);
Verify(index_count == indices.GetLength());
Verify(index_count >= 3);
*center = Point3D::Identity;
for (unsigned i=0; i<index_count-2; ++i)
{
//
//-----------------------------------------------
// Generate all the information on the first pass
//-----------------------------------------------
//
if (!i)
{
Check_Object(indices[0]);
vertex_a = indices[0]->GetVertexProxy();
Check_Object(vertex_a);
Check_Object(indices[1]);
vertex_b = indices[1]->GetVertexProxy();
Check_Object(vertex_b);
Check_Object(indices[2]);
vertex_c = indices[2]->GetVertexProxy();
Check_Object(vertex_c);
vertex_a->GetPosition(&position_a);
vertex_b->GetPosition(&position_b);
vertex_c->GetPosition(&position_c);
leg_1.Subtract(position_b, position_a);
leg_2.Subtract(position_c, position_a);
}
//
//--------------------------------------------------------------
// Get the index info. If this is not the first pass, copy the
// information from last pass
//--------------------------------------------------------------
//
else
{
Check_Object(vertex_c);
vertex_b = vertex_c;
Check_Object(indices[i+2]);
vertex_c = indices[i+2]->GetVertexProxy();
Check_Object(vertex_c);
position_b = position_c;
vertex_c->GetPosition(&position_c);
leg_1 = leg_2;
leg_2.Subtract(position_c, position_a);
}
//
//-----------------------------------------------------------------
// Compute the cross-product of the two legs to get the area of the
// triangle
//-----------------------------------------------------------------
//
Vector3D v;
v.Cross(leg_1, leg_2);
//
//-------------------------------------------------------------------
// Add the three triangle points together and multiply by the area of
// the triangle to give a weighted sum for the polygon centroid
//-------------------------------------------------------------------
//
Point3D centroid;
centroid.Add(position_a, position_b);
centroid += position_c;
Scalar wedge_area = v.GetLength() * 0.5f;
if (area <= SMALL)
{
if (wedge_area > SMALL)
{
area += wedge_area;
centroid *= wedge_area;
}
*center = centroid;
}
else
{
if (wedge_area > SMALL)
{
area += wedge_area;
centroid *= wedge_area;
*center += centroid;
}
}
}
//
//-----------------------------
// Delete the remaining proxies
//-----------------------------
//
DetachArrayReferences(&indices);
*center *= 1.0f/3.0f;
return area;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
PolygonProxy::UseIndexArray(Stuff::DynamicArrayOf<IndexProxy*> *indices)
{
Verify(GetClassID() == PolygonProxyClassID);
unsigned vertex_count = vertexArray.GetLength();
indices->SetLength(vertex_count);
for (unsigned i=0; i<vertex_count; ++i)
{
(*indices)[i] = IndexProxy::MakeProxy(this, vertexArray[i]);
Register_Object((*indices)[i]);
}
return vertex_count;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::DetachArrayReferences(DynamicArrayOf<IndexProxy*> *indices)
{
Check_Object(this);
Check_Object(indices);
unsigned index_count = indices->GetLength();
for (unsigned i=0; i<index_count; ++i)
{
Check_Object((*indices)[i]);
(*indices)[i]->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
PolygonProxy::SetPolygonIndices(
const Stuff::DynamicArrayOf<VertexProxy*> &vertices
)
{
Check_Object(this);
Check_Object(&vertices);
Verify(GetClassID() == PolygonProxyClassID);
//
//---------------------------------------
// Detach the index array if there is one
//---------------------------------------
//
unsigned vertex_count = vertexArray.GetLength();
unsigned i;
for (i=0; i<vertex_count; ++i)
{
Check_Object(vertexArray[i]);
vertexArray[i]->DetachReference();
}
//
//-------------------------------------------------------------------
// Set the length of the index array, then spin through and create an
// index proxy for each vertex
//-------------------------------------------------------------------
//
vertex_count = vertices.GetLength();
vertexArray.SetLength(vertex_count);
for (i=0; i<vertex_count; ++i)
{
Check_Object(vertices[i]);
vertexArray[i] = vertices[i];
vertexArray[i]->AttachReference();
}
}
@@ -0,0 +1,197 @@
#pragma once
#include "Proxies.hpp"
#include "GenericProxy.hpp"
namespace Proxies {
class IndexProxy;
class StateProxy;
class TextureProxy;
class PolygonMeshProxy;
//
//#########################################################################
//######################## MultiState #############################
//#########################################################################
//
class MultiState :
public Stuff::DynamicArrayOf<StateProxy*>
{
public:
MultiState() { isInverted = false; }
MultiState(const MultiState&);
~MultiState() { Check_Object(this); DetachReferences(); }
bool
IsEqualTo(const MultiState& multi_state);
// unsigned
// UseStateArray(MultiState *states);
void
DetachReferences();
MultiState&
operator=(const MultiState&);
bool isInverted;
};
//
//#########################################################################
//######################## PolygonProxy #############################
//#########################################################################
//
class PolygonProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
~PolygonProxy();
PolygonProxy();
PolygonProxy(
ClassData *class_data,
PolygonMeshProxy *mesh
);
static Stuff::MemoryBlock
*AllocatedMemory;
public:
static PolygonProxy*
MakeProxy()
{return new PolygonProxy;}
void
Destroy();
void*
operator new(size_t)
{return AllocatedMemory->New();}
void
operator delete(void *where)
{AllocatedMemory->Delete(where);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual int
FindErrors(FindErrorsProcess *process);
virtual void
GetNormal(Stuff::Normal3D *normal);
virtual Stuff::Scalar
GetArea();
virtual void
GetVertexCentroid(Stuff::Point3D *center);
virtual Stuff::Scalar
GetSurfaceAreaAndCentroid(Stuff::Point3D *center);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon management functions
//
public:
//
// Traversal functions
//
PolygonMeshProxy*
GetPolygonMeshProxy()
{Check_Object(this); return meshProxy;}
//
// polygons dont get names
//
bool
GetName(class Stuff::MString *name)
{Check_Object(this); Check_Object(name); return false;}
void
SetName(const char* name)
{Check_Object(this); Check_Pointer(name);}
protected:
PolygonMeshProxy
*meshProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// multi layer support
//
public:
virtual unsigned
UseMultiState(MultiState *states);
virtual void
SetStatesToMatch(
const MultiState &states
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon index functions
//
public:
//
// Get the number of vertices in the polygon
//
virtual unsigned
UseIndexArray(Stuff::DynamicArrayOf<IndexProxy*> *indices);
void
DetachArrayReferences(Stuff::DynamicArrayOf<IndexProxy*> *indices);
void
SetPolygonIndices(
const Stuff::DynamicArrayOf<VertexProxy*> &vertices
);
void
AttachIndexProxy(IndexProxy *proxy)
{
Check_Object(this);
AttachReference(); activeIndexProxies.Add(proxy);
}
void
DetachIndexProxy(IndexProxy* proxy);
protected:
Stuff::ChainOf<IndexProxy*>
activeIndexProxies;
Stuff::DynamicArrayOf<VertexProxy*>
vertexArray;
MultiState
stateArray;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon functions
//
public:
//
// group functions
//
virtual void
AddToCollection(const char *group);
virtual void
AddToCollections(MStringChain &group_list);
virtual void
RemoveFromCollection(const char *group);
virtual void
RemoveFromCollections(MStringChain &group_list);
virtual void
GetCollections(MStringChain *group_list);
virtual bool
IsMemberOf(const char *group);
};
}
@@ -0,0 +1,39 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Process::Process():
planeThicknessTolerance(1e-4f),
duplicateVertexTolerance(1e-4f),
colinearTolerance(1e-4f),
continueProcess(true),
suppress(true),
errorfn(NULL)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Process::Process(NotationFile *data_file,bool bSuppress,void* fcn):
suppress(bSuppress),
errorfn(fcn),
continueProcess(true)
{
if (data_file)
{
Check_Object(data_file);
planeThicknessTolerance = 1e-4f;
duplicateVertexTolerance = 1e-4f;
colinearTolerance = 1e-4f;
Page *page = data_file->FindPage("Process");
if (page)
{
Check_Object(page);
page->GetEntry("PlaneThickness", &planeThicknessTolerance);
page->GetEntry("DuplicateVertex", &duplicateVertexTolerance);
page->GetEntry("Colinear", &colinearTolerance);
}
}
}
@@ -0,0 +1,32 @@
#pragma once
#include "Proxies.hpp"
namespace Proxies {
class GenericProxy;
class Process
#if defined(_ARMOR)
: public Stuff::Signature
#endif
{
public:
Process();
Process(Stuff::NotationFile *data_file,bool bSuppress=true,void* fcn=NULL);
Stuff::Scalar
planeThicknessTolerance, // per meter of polygon area edge length
duplicateVertexTolerance, // per square meter of polygon area
colinearTolerance; // minimum edge cross product length
bool
continueProcess;
bool
suppress;
void*
errorfn;
void
TestInstance() const
{}
};
}
@@ -0,0 +1,43 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::InitializeClasses()
{
Verify(FirstFreeProxyClassID <= LastProxyClassID);
GenericProxy::InitializeClass();
SceneProxy::InitializeClass();
ChildProxy::InitializeClass();
GroupProxy::InitializeClass();
VertexProxy::InitializeClass();
PolygonMeshProxy::InitializeClass();
PolygonProxy::InitializeClass();
IndexProxy::InitializeClass();
StateProxy::InitializeClass();
TextureProxy::InitializeClass();
StateLibrary::InitializeClass();
TextureLibrary::InitializeClass();
LightProxy::InitializeClass();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::TerminateClasses()
{
LightProxy::TerminateClass();
TextureLibrary::TerminateClass();
StateLibrary::TerminateClass();
TextureProxy::TerminateClass();
StateProxy::TerminateClass();
IndexProxy::TerminateClass();
PolygonProxy::TerminateClass();
PolygonMeshProxy::TerminateClass();
VertexProxy::TerminateClass();
GroupProxy::TerminateClass();
ChildProxy::TerminateClass();
SceneProxy::TerminateClass();
GenericProxy::TerminateClass();
}
@@ -0,0 +1,377 @@
# Microsoft Developer Studio Project File - Name="Proxies" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=Proxies - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Proxies.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Proxies.mak" CFG="Proxies - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Proxies - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "Proxies - Win32 Profile" (based on "Win32 (x86) Static Library")
!MESSAGE "Proxies - Win32 Armor" (based on "Win32 (x86) Static Library")
!MESSAGE "Proxies - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Proxies - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /Zp4 /MD /W4 /GR /Zi /Ox /Ot /Oa /Og /Oi /Gy /I "..\..\Libraries" /I "..\..\..\CoreTech\Libraries" /D "NDEBUG" /D "RELEASE" /D "WIN32" /D "_WINDOWS" /D "USE_PROTOTYPES" /D "STRICT" /Yu"ProxyHeaders.hpp" /Zl /FD /GF /c
# SUBTRACT CPP /WX /Gf
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "Proxies - Win32 Profile"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Profile"
# PROP BASE Intermediate_Dir "Profile"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Profile"
# PROP Intermediate_Dir "Profile"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /Zp4 /MD /W4 /GR /Zi /Ox /Ot /Oa /Og /Oi /Gy /I "..\..\Libraries" /I "..\..\..\CoreTech\Libraries" /D "LAB_ONLY" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_PROTOTYPES" /D "STRICT" /Yu"ProxyHeaders.hpp" /Zl /FD /GF /c
# SUBTRACT CPP /WX /Gf
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "Proxies - Win32 Armor"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Armor"
# PROP BASE Intermediate_Dir "Armor"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Armor"
# PROP Intermediate_Dir "Armor"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /Zp4 /MD /W4 /GR /Zi /Ox /Ot /Oa /Og /Oi /Gy /I "..\..\Libraries" /I "..\..\..\CoreTech\Libraries" /D "LAB_ONLY" /D "NDEBUG" /D "_ARMOR" /D "WIN32" /D "_WINDOWS" /D "USE_PROTOTYPES" /D "STRICT" /Yu"ProxyHeaders.hpp" /Zl /FD /GF /c
# SUBTRACT CPP /WX /Gf
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "Proxies - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /G6 /Zp4 /MDd /W4 /GR /Zi /Od /I "..\..\Libraries" /I "..\..\..\CoreTech\Libraries" /D "LAB_ONLY" /D "_DEBUG" /D "_ARMOR" /D "WIN32" /D "_WINDOWS" /D "USE_PROTOTYPES" /D "STRICT" /Yu"ProxyHeaders.hpp" /Zl /FD /c
# SUBTRACT CPP /WX
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "Proxies - Win32 Release"
# Name "Proxies - Win32 Profile"
# Name "Proxies - Win32 Armor"
# Name "Proxies - Win32 Debug"
# Begin Group "Proxies"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\ChildProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\ChildProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\GenericProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\GenericProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\GroupProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\GroupProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\IndexProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\IndexProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\LightProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\LightProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\PolygonMeshProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\PolygonMeshProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\PolygonProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\PolygonProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\SceneProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\SceneProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\StateProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\StateProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\TextureProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\TextureProxy.hpp
# End Source File
# Begin Source File
SOURCE=.\VertexProxy.cpp
# End Source File
# Begin Source File
SOURCE=.\VertexProxy.hpp
# End Source File
# End Group
# Begin Group "Bitmap formats"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Targa.cpp
# End Source File
# Begin Source File
SOURCE=.\Targa.hpp
# End Source File
# End Group
# Begin Group "Processes"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\ArrangeMegatextures.cpp
# End Source File
# Begin Source File
SOURCE=.\ArrangeMegatextures.hpp
# End Source File
# Begin Source File
SOURCE=.\BinSort.cpp
# End Source File
# Begin Source File
SOURCE=.\BinSort.hpp
# End Source File
# Begin Source File
SOURCE=.\BuildMegatextures.cpp
# End Source File
# Begin Source File
SOURCE=.\BuildMegatextures.hpp
# End Source File
# Begin Source File
SOURCE=.\BurnLights.cpp
# End Source File
# Begin Source File
SOURCE=.\BurnLights.hpp
# End Source File
# Begin Source File
SOURCE=.\CleanHierarchy.cpp
# End Source File
# Begin Source File
SOURCE=.\CleanHierarchy.hpp
# End Source File
# Begin Source File
SOURCE=.\CoalesceTextures.cpp
# End Source File
# Begin Source File
SOURCE=.\CoalesceTextures.hpp
# End Source File
# Begin Source File
SOURCE=.\Copy.cpp
# End Source File
# Begin Source File
SOURCE=.\Copy.hpp
# End Source File
# Begin Source File
SOURCE=.\FindErrors.cpp
# End Source File
# Begin Source File
SOURCE=.\FindErrors.hpp
# End Source File
# Begin Source File
SOURCE=.\FlattenHierarchy.cpp
# End Source File
# Begin Source File
SOURCE=.\FlattenHierarchy.hpp
# End Source File
# Begin Source File
SOURCE=.\Info.cpp
# End Source File
# Begin Source File
SOURCE=.\Info.hpp
# End Source File
# Begin Source File
SOURCE=.\MakeSingleSided.cpp
# End Source File
# Begin Source File
SOURCE=.\MakeSingleSided.hpp
# End Source File
# Begin Source File
SOURCE=.\OptimizeFlatShading.cpp
# End Source File
# Begin Source File
SOURCE=.\OptimizeFlatShading.hpp
# End Source File
# Begin Source File
SOURCE=.\Process.cpp
# End Source File
# Begin Source File
SOURCE=.\Process.hpp
# End Source File
# Begin Source File
SOURCE=.\StateSort.cpp
# End Source File
# Begin Source File
SOURCE=.\StateSort.hpp
# End Source File
# End Group
# Begin Source File
SOURCE=.\Proxies.cpp
# End Source File
# Begin Source File
SOURCE=.\Proxies.hpp
# End Source File
# Begin Source File
SOURCE=.\ProxyHeaders.cpp
# ADD CPP /Yc"ProxyHeaders.hpp"
# End Source File
# Begin Source File
SOURCE=.\ProxyHeaders.hpp
# End Source File
# End Target
# End Project
@@ -0,0 +1,69 @@
//===========================================================================//
// File: munga.hpp //
// Project: Adept Brick: ??? //
// Contents: ??? //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 00/00/00 XXX Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995-1996, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#if !defined(PROXIES_PROXIES_HPP)
#define PROXIES_PROXIES_HPP
#if !defined(STUFF_STUFF_HPP)
#include <Stuff\Stuff.hpp>
#endif
namespace Proxies {
//
//--------------
// Stuff classes
//--------------
//
enum
{
GenericProxyClassID = Stuff::FirstProxyClassID,
SceneProxyClassID,
ChildProxyClassID,
GroupProxyClassID,
PolygonMeshProxyClassID,
PolygonProxyClassID,
VertexProxyClassID,
IndexProxyClassID,
StateProxyClassID,
TextureProxyClassID,
LightProxyClassID,
StateLibraryClassID,
TextureLibraryClassID,
BSPProxyClassID,
FirstFreeProxyClassID
};
extern void InitializeClasses();
extern void TerminateClasses();
typedef Stuff::ChainOf<Stuff::PlugOf<Stuff::MString>*> MStringChain;
typedef Stuff::ChainIteratorOf<Stuff::PlugOf<Stuff::MString>*>
MStringChainIterator;
}
#include "GenericProxy.hpp"
#include "ChildProxy.hpp"
#include "GroupProxy.hpp"
#include "LightProxy.hpp"
#include "StateProxy.hpp"
#include "PolygonMeshProxy.hpp"
#include "VertexProxy.hpp"
#include "PolygonProxy.hpp"
#include "IndexProxy.hpp"
#include "SceneProxy.hpp"
#include "TextureProxy.hpp"
#endif
@@ -0,0 +1,3 @@
#include "ProxyHeaders.hpp"
// This file does nothing but make the pch file
@@ -0,0 +1,28 @@
#if !defined(PROXIES_PROXYHEADERS_HPP)
#define PROXIES_PROXYHEADERS_HPP
#if !defined(PROXIES_PROXIES_HPP)
#include "Proxies.hpp"
#endif
#include "Targa.hpp"
#include "FindErrors.hpp"
#include "FlattenHierarchy.hpp"
#include "StateSort.hpp"
#include "BinSort.hpp"
#include "CleanHierarchy.hpp"
#include "BurnLights.hpp"
#include "Copy.hpp"
#include "BuildMegaTextures.hpp"
#include "CoalesceTextures.hpp"
#include "ArrangeMegaTextures.hpp"
#include "MakeSingleSided.hpp"
#include "OptimizeFlatShading.hpp"
#include "Info.hpp"
using namespace Stuff;
using namespace Proxies;
#endif
@@ -0,0 +1,302 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//############################ SceneProxy ##############################
//############################################################################
//
SceneProxy::ClassData*
SceneProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
SceneProxyClassID,
"SceneProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SceneProxy::SceneProxy(ClassData *class_data):
GenericProxy(class_data),
activeChildProxies(NULL)
{
Check_Object(this);
stateLibrary = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SceneProxy::~SceneProxy()
{
Check_Object(this);
Verify(activeChildProxies.IsEmpty());
Verify(!stateLibrary);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::GetCentroid(Point3D *centroid)
{
Check_Object(this);
Check_Pointer(centroid);
//
//-----------------------------------------------
// If we have no children, just return our origin
//-----------------------------------------------
//
unsigned child_count = GetChildCount();
*centroid = Point3D::Identity;
if (!child_count)
return;
//
//--------------------------------------------
// Otherwise, just average our child centroids
//--------------------------------------------
//
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
Point3D local_centroid;
child->GetCentroid(&local_centroid);
LinearMatrix4D m;
child->GetLocalToParent(&m);
Point3D world_centroid;
world_centroid.Multiply(local_centroid, m);
*centroid += world_centroid;
child->DetachReference();
child = next;
}
Verify(!child);
*centroid /= static_cast<Scalar>(child_count);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
SceneProxy::GetBoundingSphere(Sphere *sphere)
{
Check_Object(this);
Check_Pointer(sphere);
//
//---------------------------------------------------------------------
// Put the center of the sphere at the centroid, then set the radius to
// just contain the mesh
//---------------------------------------------------------------------
//
GetCentroid(&sphere->center);
sphere->radius = -1.0f;
ChildProxy *child = UseFirstChildProxy();
while (child)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
//
//----------------------------------------------------------
// Transform's the child's bounding sphere into parent space
//----------------------------------------------------------
//
LinearMatrix4D child_to_parent;
child->GetLocalToParent(&child_to_parent);
Sphere child_sphere;
child->GetBoundingSphere(&child_sphere);
Point3D position;
position.Multiply(child_sphere.center, child_to_parent);
//
//-----------------------------------------------------------------
// Now stretch the radius of the bounding sphere so that it totally
// includes the child sphere
//-----------------------------------------------------------------
//
position -= sphere->center;
Scalar range = position.GetLength() + child_sphere.radius;
if (range > sphere->radius)
{
sphere->radius = range;
}
child->DetachReference();
child = next;
}
//
//-------------------------------------
// Make sure the radius is properly set
//-------------------------------------
//
if (sphere->radius == -1.0f)
{
sphere->radius = 0.0f;
return false;
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
SceneProxy::AppendMatchingChildProxy(
CopyProcess *process,
ChildProxy *child
)
{
Check_Object(this);
Check_Object(process);
Check_Object(child);
if (child->IsDerivedFrom(PolygonMeshProxy::DefaultData))
{
PolygonMeshProxy *proxy = AppendNewPolygonMeshProxy();
Check_Object(proxy);
proxy->Copy(process, Cast_Object(PolygonMeshProxy*, child));
return proxy;
}
else if (child->IsDerivedFrom(GroupProxy::DefaultData))
{
GroupProxy *proxy = AppendNewGroupProxy();
Check_Object(proxy);
proxy->Copy(process, Cast_Object(GroupProxy*, child));
return proxy;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ChildProxy*
SceneProxy::InsertMatchingChildProxy(
CopyProcess *process,
ChildProxy *child,
ChildProxy *before
)
{
Check_Object(this);
Check_Object(process);
Check_Object(child);
Check_Object(before);
Verify(!before->GetParentGroupProxy());
STOP(("Not implemented"));
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::FindNamedChildren(
DynamicArrayOf<ChildProxy*> *children,
const char* prefix,
bool matching
)
{
Check_Object(this);
Check_Object(children);
Check_Pointer(prefix);
//
//----------------------
// Get the prefix length
//----------------------
//
int size = strlen(prefix);
//
//---------------------------------
// Find out how many children match
//---------------------------------
//
unsigned count = 0;
ChildProxy *child = UseFirstChildProxy();
while (child)
{
ChildProxy *next = child->UseNextSiblingProxy();
MString name;
if (child->GetName(&name))
{
if ((!_strnicmp(name, prefix, size)) == matching)
++count;
}
child->DetachReference();
child = next;
}
//
//------------------------------------------------------------------------
// Set the array length, and if we have any matching children, fill in the
// array with those proxies
//------------------------------------------------------------------------
//
children->SetLength(count);
if (count > 0)
{
child = UseFirstChildProxy();
count = 0;
while (child)
{
ChildProxy *next = child->UseNextSiblingProxy();
//
//-----------------------------------------------------------------
// If the child has a name and it matches what we are looking for,
// store it in the array and bump the reference count so it doesn't
// go away
//-----------------------------------------------------------------
MString name;
if (child->GetName(&name))
{
if ((!_strnicmp(name, prefix, size)) == matching)
{
(*children)[count++] = child;
child->AttachReference();
}
}
child->DetachReference();
child = next;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::DetachChildProxy(ChildProxy* proxy)
{
Check_Object(this);
activeChildProxies.RemovePlug(proxy);
Verify(referenceCount > 1);
DetachReference();
}
@@ -0,0 +1,176 @@
#pragma once
#include "Proxies.hpp"
#include "GenericProxy.hpp"
namespace Proxies {
class PolygonMeshProxy;
class GroupProxy;
class ChildProxy;
class TextureLibrary;
class StateLibrary;
class CoalesceTexturesProcess;
//
//#########################################################################
//######################### SceneProxy ##############################
//#########################################################################
//
class _declspec(novtable) SceneProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
SceneProxy(ClassData *class_data);
~SceneProxy();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual void
BinSort(BinSortProcess *process);
virtual void
BurnLights(BurnLightsProcess *process);
virtual bool
CleanHierarchy(CleanHierarchyProcess *process);
virtual void
CoalesceTextures(CoalesceTexturesProcess *process);
virtual void
Copy(
CopyProcess *process,
SceneProxy *scene
);
virtual void
GetInfo(
GetInfoProcess *process
);
virtual int
FindErrors(FindErrorsProcess *process);
virtual void
FindLights(BurnLightsProcess *process);
virtual void
FlattenHierarchy(FlattenHierarchyProcess *process);
virtual void
SplitByState(SplitByStateProcess *process);
virtual void
MakeSingleSided(MakeSingleSidedProcess *process);
virtual void
OptimizeFlatShading(OptimizeFlatShadingProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Library functions
//
public:
virtual StateLibrary*
GetStateLibrary() = 0;
protected:
StateLibrary*
stateLibrary;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bounding functions
//
// GetBoundingSphere should be used only after GetOBB has returned a false
//
public:
virtual bool
GetOBB(Stuff::OBB *obb) = 0;
virtual void
SetOBB(const Stuff::OBB &obb) = 0;
virtual bool
GetBoundingSphere(Stuff::Sphere *sphere);
virtual void
SetBoundingSphere(const Stuff::Sphere &sphere) = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Polygon functions
//
public:
virtual void
GetCentroid(Stuff::Point3D *center);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Child functions
//
public:
//
// Gets the current number of children
//
virtual unsigned
GetChildCount() = 0;
//
// Child creation functions
//
virtual GroupProxy*
AppendNewGroupProxy() = 0;
virtual GroupProxy*
InsertNewGroupProxy(ChildProxy *before) = 0;
virtual PolygonMeshProxy*
AppendNewPolygonMeshProxy() = 0;
virtual PolygonMeshProxy*
InsertNewPolygonMeshProxy(ChildProxy *before) = 0;
ChildProxy*
AppendMatchingChildProxy(
CopyProcess *process,
ChildProxy *child
);
ChildProxy*
InsertMatchingChildProxy(
CopyProcess *process,
ChildProxy *child,
ChildProxy *before
);
//
// Child traversal functions
//
virtual ChildProxy*
UseFirstChildProxy() = 0;
virtual ChildProxy*
UseLastChildProxy() = 0;
virtual void
FindNamedChildren(
Stuff::DynamicArrayOf<ChildProxy*> *children,
const char* prefix,
bool matching = true
);
void
AttachChildProxy(ChildProxy* proxy)
{
Check_Object(this);
AttachReference(); activeChildProxies.Add(proxy);
}
void
DetachChildProxy(ChildProxy* proxy);
protected:
Stuff::ChainOf<ChildProxy*>
activeChildProxies;
};
}
@@ -0,0 +1,597 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//########################### StateProxy ############################
//############################################################################
//
StateProxy::ClassData*
StateProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateProxy::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
StateProxyClassID,
"StateProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateProxy::StateProxy(
ClassData *class_data,
StateLibrary *library
):
GenericProxy(class_data),
libraryProxy(library)
{
Check_Pointer(this);
Check_Object(libraryProxy);
libraryProxy->AttachStateProxy(this);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateProxy::~StateProxy()
{
Check_Object(this);
Check_Object(libraryProxy);
libraryProxy->DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
StateProxy::IsEqualTo(StateProxy *state)
{
Check_Object(this);
Check_Object(state);
//
//-------------------------------
// We are always equal to ourself
//-------------------------------
//
if (this == state)
return true;
//
//-------------------------------------
// Compare the specular color and value
//-------------------------------------
//
RGBColor color, other_color;
bool them = state->GetSpecularColor(&other_color);
bool us = GetSpecularColor(&color);
if (them != us)
return false;
if (them && us)
{
if (
!Close_Enough(color, other_color)
||
!Close_Enough(
GetSpecularShininess(),
state->GetSpecularShininess()
)
)
return false;
}
bool themOnOff, usOnOff;
//
//-----------------------------
// Compare the alpha proxies
//-----------------------------
//
AlphaMode themAlpha, usAlpha;
themOnOff = state->GetAlpha(&themAlpha);
usOnOff = GetAlpha(&usAlpha);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themAlpha != usAlpha) )
{
return false;
}
themOnOff = state->GetAlphaChildPermission();
usOnOff = GetAlphaChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the Filter proxies
//-----------------------------
//
FilterMode themFilter, usFilter;
themOnOff = state->GetFilter(&themFilter);
usOnOff = GetFilter(&usFilter);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themFilter != usFilter) )
{
return false;
}
themOnOff = state->GetFilterChildPermission();
usOnOff = GetFilterChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the Fog proxies
//-----------------------------
//
FogMode themFog, usFog;
themOnOff = state->GetFog(&themFog);
usOnOff = GetFog(&usFog);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themFog != usFog) )
{
return false;
}
themOnOff = state->GetFogChildPermission();
usOnOff = GetFogChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the Dither proxies
//-----------------------------
//
bool themDither, usDither;
themOnOff = state->GetDither(&themDither);
usOnOff = GetDither(&usDither);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themDither != usDither) )
{
return false;
}
themOnOff = state->GetDitherChildPermission();
usOnOff = GetDitherChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the Specular proxies
//-----------------------------
//
bool themSpecular, usSpecular;
themOnOff = state->GetSpecular(&themSpecular);
usOnOff = GetSpecular(&usSpecular);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themSpecular != usSpecular) )
{
return false;
}
themOnOff = state->GetSpecularChildPermission();
usOnOff = GetSpecularChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the TextureCorrection proxies
//-----------------------------
//
bool themTextureCorrection, usTextureCorrection;
themOnOff = state->GetTextureCorrection(&themTextureCorrection);
usOnOff = GetTextureCorrection(&usTextureCorrection);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themTextureCorrection != usTextureCorrection) )
{
return false;
}
themOnOff = state->GetTextureCorrectionChildPermission();
usOnOff = GetTextureCorrectionChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the TextureWrap proxies
//-----------------------------
//
TextureWrapMode themTextureWrap, usTextureWrap;
themOnOff = state->GetTextureWrap(&themTextureWrap);
usOnOff = GetTextureWrap(&usTextureWrap);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themTextureWrap != usTextureWrap) )
{
return false;
}
themOnOff = state->GetTextureWrapChildPermission();
usOnOff = GetTextureWrapChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the WireFrame proxies
//-----------------------------
//
WireFrameMode themWireFrame, usWireFrame;
themOnOff = state->GetWireFrame(&themWireFrame);
usOnOff = GetWireFrame(&usWireFrame);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themWireFrame != usWireFrame) )
{
return false;
}
themOnOff = state->GetWireFrameChildPermission();
usOnOff = GetWireFrameChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the ZBufferCompare proxies
//-----------------------------
//
bool themZBufferCompare, usZBufferCompare;
themOnOff = state->GetZBufferCompare(&themZBufferCompare);
usOnOff = GetZBufferCompare(&usZBufferCompare);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themZBufferCompare != usZBufferCompare) )
{
return false;
}
themOnOff = state->GetZBufferCompareChildPermission();
usOnOff = GetZBufferCompareChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Write the ZBufferWrite proxies
//-----------------------------
//
bool themZBufferWrite, usZBufferWrite;
themOnOff = state->GetZBufferWrite(&themZBufferWrite);
usOnOff = GetZBufferWrite(&usZBufferWrite);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themZBufferWrite != usZBufferWrite) )
{
return false;
}
themOnOff = state->GetZBufferWriteChildPermission();
usOnOff = GetZBufferWriteChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Write the FlatColoring proxies
//-----------------------------
//
bool themFlatColoring, usFlatColoring;
themOnOff = state->GetFlatColoring(&themFlatColoring);
usOnOff = GetFlatColoring(&usFlatColoring);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themFlatColoring != usFlatColoring) )
{
return false;
}
themOnOff = state->GetFlatColoringChildPermission();
usOnOff = GetFlatColoringChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the two-sided proxies
//-----------------------------
//
bool themTSoverride, usTSoverride;
themOnOff = state->GetMatTwoSided(&themTSoverride);
usOnOff = GetMatTwoSided(&usTSoverride);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themTSoverride != usTSoverride) )
{
return false;
}
themOnOff = state->GetMatTwoSidedChildPermission();
usOnOff = GetMatTwoSidedChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Compare the backface proxies
//-----------------------------
//
bool themBFoverride, usBFoverride;
themOnOff = state->GetBackface(&themBFoverride);
usOnOff = GetBackface(&usBFoverride);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themBFoverride != usBFoverride) )
{
return false;
}
themOnOff = state->GetBackfaceChildPermission();
usOnOff = GetBackfaceChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Write the Priority proxies
//-----------------------------
//
int themPriority, usPriority;
themOnOff = state->GetPriority(&themPriority);
usOnOff = GetPriority(&usPriority);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themPriority != usPriority) )
{
return false;
}
themOnOff = state->GetPriorityChildPermission();
usOnOff = GetPriorityChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//-----------------------------
// Write the Lighting proxies
//-----------------------------
//
int themLighting, usLighting;
themOnOff = state->GetLighting(&themLighting);
usOnOff = GetLighting(&usLighting);
if(themOnOff != usOnOff)
{
return false;
}
if(usOnOff && (themLighting != usLighting) )
{
return false;
}
themOnOff = state->GetLightingChildPermission();
usOnOff = GetLightingChildPermission();
if(themOnOff != usOnOff)
{
return false;
}
//
//----------------------------
// Compare the texture proxies
//----------------------------
//
TextureProxy *texture = state->UseTextureProxy();
TextureProxy *our_texture = UseTextureProxy();
if (!texture && !our_texture)
return true;
bool result = false;
if (texture && our_texture)
result = texture->IsEqualTo(our_texture);
if (our_texture)
our_texture->DetachReference();
if (texture)
texture->DetachReference();
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//
//############################################################################
//###################### StateLibrary ##########################
//############################################################################
//
StateLibrary::ClassData*
StateLibrary::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateLibrary::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
StateLibraryClassID,
"StateLibrary",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateLibrary::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateLibrary::StateLibrary(
ClassData *class_data,
SceneProxy *scene
):
GenericProxy(class_data),
sceneProxy(scene),
activeStateProxies(NULL)
{
Check_Object(this);
textureLibrary = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateLibrary::~StateLibrary()
{
Check_Object(this);
Verify(activeStateProxies.IsEmpty());
Verify(!textureLibrary);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StateLibrary::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
@@ -0,0 +1,405 @@
#pragma once
#include "Proxies.hpp"
#include "TextureProxy.hpp"
namespace Proxies {
class SceneProxy;
class StateLibrary;
//
//#########################################################################
//####################### StateProxy #############################
//#########################################################################
//
class _declspec(novtable) StateProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
StateProxy(
ClassData *class_data,
StateLibrary *library
);
~StateProxy();
public:
//
// Copies the elements of the given material into this material
//
virtual void
Copy(
CopyProcess *copy,
StateProxy *state
);
//
// gives informations about this state
//
virtual void
GetInfo(
GetInfoProcess *process
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data Support
//
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Material management functions
//
public:
StateLibrary*
GetStateLibrary()
{Check_Object(this); return libraryProxy;}
virtual bool
IsEqualTo(StateProxy *material);
protected:
StateLibrary
*libraryProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State functions
//
public:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Render state
//
enum AlphaMode {
OneZeroMode = 0,
OneOneMode,
AlphaOneMode,
OneAlphaMode,
AlphaInvAlphaMode,
OneInvAlphaMode,
KeyedAlphaMode
};
virtual bool
GetAlpha(AlphaMode*) = 0;
virtual void
SetAlpha(AlphaMode) = 0;
virtual bool
GetAlphaChildPermission() = 0;
virtual void
SetAlphaChildPermission(bool override) = 0;
enum FilterMode {
NoFilterMode = 0,
BiLinearFilterMode,
TriLinearFilterMode
};
virtual bool
GetFilter(FilterMode*) = 0;
virtual void
SetFilter(FilterMode) = 0;
virtual bool
GetFilterChildPermission() = 0;
virtual void
SetFilterChildPermission(bool override) = 0;
enum FogMode {
DisableFogMode = 0,
GeneralFogMode,
LightFogMode,
CustomFogMode
};
virtual bool
GetFog(FogMode*) = 0;
virtual void
SetFog(FogMode) = 0;
virtual bool
GetFogChildPermission() = 0;
virtual void
SetFogChildPermission(bool override) = 0;
virtual bool
GetDither(bool*) = 0;
virtual void
SetDither(bool) = 0;
virtual bool
GetDitherChildPermission() = 0;
virtual void
SetDitherChildPermission(bool override) = 0;
virtual bool
GetSpecular(bool*) = 0;
virtual void
SetSpecular(bool) = 0;
virtual bool
GetSpecularChildPermission() = 0;
virtual void
SetSpecularChildPermission(bool override) = 0;
virtual bool
GetTextureCorrection(bool*) = 0;
virtual void
SetTextureCorrection(bool) = 0;
virtual bool
GetTextureCorrectionChildPermission() = 0;
virtual void
SetTextureCorrectionChildPermission(bool override) = 0;
enum TextureWrapMode {
TextureWrap = 0,
TextureClamp
};
virtual bool
GetTextureWrap(TextureWrapMode*) = 0;
virtual void
SetTextureWrap(TextureWrapMode) = 0;
virtual bool
GetTextureWrapChildPermission() = 0;
virtual void
SetTextureWrapChildPermission(bool override) = 0;
enum WireFrameMode {
WireFrameOffMode = 0,
WireFrameOnlyMode,
WireFrameAddMode
};
virtual bool
GetWireFrame(WireFrameMode*) = 0;
virtual void
SetWireFrame(WireFrameMode) = 0;
virtual bool
GetWireFrameChildPermission() = 0;
virtual void
SetWireFrameChildPermission(bool override) = 0;
virtual bool
GetZBufferCompare(bool*) = 0;
virtual void
SetZBufferCompare(bool) = 0;
virtual bool
GetZBufferCompareChildPermission() = 0;
virtual void
SetZBufferCompareChildPermission(bool override) = 0;
virtual bool
GetZBufferWrite(bool*) = 0;
virtual void
SetZBufferWrite(bool) = 0;
virtual bool
GetZBufferWriteChildPermission() = 0;
virtual void
SetZBufferWriteChildPermission(bool override) = 0;
virtual bool
GetFlatColoring(bool*) = 0;
virtual void
SetFlatColoring(bool) = 0;
virtual bool
GetFlatColoringChildPermission() = 0;
virtual void
SetFlatColoringChildPermission(bool override) = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process state
//
virtual bool
GetMatTwoSided(bool *onOff) = 0;
virtual void
SetMatTwoSided(bool onOff) = 0;
virtual bool
GetMatTwoSidedChildPermission() = 0;
virtual void
SetMatTwoSidedChildPermission(bool override) = 0;
virtual bool
GetBackface(bool *onOff) = 0;
virtual void
SetBackface(bool onOff) = 0;
virtual bool
GetBackfaceChildPermission() = 0;
virtual void
SetBackfaceChildPermission(bool override) = 0;
enum {
DefaultPriority = 0,
DetailPrority,
AlphaPriority,
EffectPriority0=4,
EffectPriority1,
EffectPriority2,
EffectPriority3,
WeatherPriority,
CagePriority,
CageEffectsPriority,
FlarePriority,
HUDPriority0,
HUDPriority1,
HUDPriority2,
HUDPriority3,
PriorityCount
};
virtual bool
GetPriority(int*) = 0;
virtual void
SetPriority(int) = 0;
virtual bool
GetPriorityChildPermission() = 0;
virtual void
SetPriorityChildPermission(bool override) = 0;
enum LightingMode {
LightingOffMode = 0,
LightingLightMapMode=1,
LightingVertexMode=2,
LightingLookupMode=4,
LightingFaceMode=8
};
virtual bool
GetLighting(int*) = 0;
virtual void
SetLighting(int) = 0;
virtual bool
GetLightingChildPermission() = 0;
virtual void
SetLightingChildPermission(bool override) = 0;
//
// specular color functions
//
virtual bool
GetSpecularColor(Stuff::RGBColor *color) = 0;
virtual void
SetSpecularColor(const Stuff::RGBColor &color) = 0;
virtual Stuff::Scalar
GetSpecularShininess() = 0;
virtual void
SetSpecularShininess(Stuff::Scalar shininess) = 0;
//
// texture functions
//
virtual TextureProxy*
UseTextureProxy() = 0;
virtual TextureProxy*
SetToMatchTextureProxy(TextureProxy *texture) = 0;
};
//
//#########################################################################
//###################### StateLibrary ############################
//#########################################################################
//
class _declspec(novtable) StateLibrary:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
StateLibrary(
ClassData *class_data,
SceneProxy *scene
);
~StateLibrary();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class Data Support
//
public:
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Material management functions
//
public:
SceneProxy*
GetSceneProxy()
{Check_Object(this); return sceneProxy;}
protected:
SceneProxy
*sceneProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Material functions
//
public:
//
// name functions
//
bool
GetName(Stuff::MString *name)
{return false;}
void
SetName(const char* name)
{}
//
// state functions
//
virtual StateProxy*
UseMatchingStateProxy(
StateProxy *material,
TextureProxy *texture=NULL
) = 0;
TextureLibrary*
GetTextureLibrary()
{Check_Object(this); return textureLibrary;}
void
AttachStateProxy(StateProxy *proxy)
{
Check_Object(this);
AttachReference(); activeStateProxies.Add(proxy);
}
void
DetachStateProxy(StateProxy* proxy);
protected:
TextureLibrary*
textureLibrary;
Stuff::ChainOf<StateProxy*>
activeStateProxies;
};
}
@@ -0,0 +1,238 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
ChildProxy::SplitByState(SplitByStateProcess *process)
{
Check_Object(this);
Check_Object(process);
process->SplitCallback(this, SplitByStateProcess::StatusCheck);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
PolygonMeshProxy::SplitByState(SplitByStateProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->SplitCallback(this, SplitByStateProcess::StatusCheck);
if (!process->continueProcess)
return true;
//
//-----------------------------------------------------------------------
// We have to evaluate each polygon within the mesh to see how many have
// unique texture/material combinations, so set up arrays to hold proxies
// and matching indices
//-----------------------------------------------------------------------
//
DynamicArrayOf<unsigned> match;
DynamicArrayOf<unsigned> count;
DynamicArrayOf<MultiState*> states;
DynamicArrayOf<PolygonProxy*> polygons;
UsePolygonArray(&polygons);
unsigned unique_combinations =
UseMultiStateArray(&states, &match, &count, polygons);
//
//-------------------------------------------------------------------------
// If there are no unique entries, than this is a spurious polygon mesh and
// should be destroyed
//-------------------------------------------------------------------------
//
if (!unique_combinations)
{
Destroy();
return false;
}
//
//---------------------------------------------------------
// If there is only one unique entry, this mesh is OK as is
//---------------------------------------------------------
//
if (unique_combinations == 1)
{
DetachArrayReferences(&polygons);
states[0]->DetachReferences();
return true;
}
//
//-----------------------------------------------------------------------
// There were more than one entry, so this mesh must be split up, so find
// the parent and get the local to parent transform of the base mesh
//-----------------------------------------------------------------------
//
GroupProxy *parent = GetParentGroupProxy();
LinearMatrix4D m;
GetLocalToParent(&m);
//
//------------------------------------------------------------------------
// For each unique combination, create a new polygon mesh, and give it the
// same transform as the original polygon mesh
//------------------------------------------------------------------------
//
unsigned total_polys = polygons.GetLength();
for (unsigned i=0; i<unique_combinations; ++i)
{
PolygonMeshProxy *mesh;
if (parent)
{
Check_Object(parent);
mesh = parent->AppendNewPolygonMeshProxy();
}
else
mesh = GetSceneProxy()->AppendNewPolygonMeshProxy();
mesh->SetLocalToParent(m);
//
//--------------------------------------------------------------------
// For each unique combination, we need to create the mesh data
// structures, so we need to first identify the polygons to be grouped
// together
//--------------------------------------------------------------------
//
Verify(count[i]>0);
DynamicArrayOf<PolygonProxy*> new_polys(count[i]);
unsigned poly_count = 0;
for (unsigned j=0; j<total_polys && poly_count<count[i]; ++j)
{
PolygonProxy *polygon = polygons[j];
Check_Object(polygon);
if (match[j] == i)
new_polys[poly_count++] = polygon;
}
Verify(poly_count == count[i]);
//
//----------------------------------------------------------------------
// Now that we have the appropriate polygons sorted out, put them in the
// mesh
//----------------------------------------------------------------------
//
mesh->AddPolygons(process, new_polys);
states[i]->DetachReferences();
mesh->DetachReference();
}
//
//---------------------
// Clean up the proxies
//---------------------
//
DetachArrayReferences(&polygons);
Destroy();
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
GroupProxy::SplitByState(SplitByStateProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->SplitCallback(this, SplitByStateProcess::StatusCheck);
if (!process->continueProcess)
return true;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
for (unsigned i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->SplitByState(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//-------------------------------------------
// Make sure to discard any remaining proxies
//-------------------------------------------
//
if (child)
child->DetachReference();
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SceneProxy::SplitByState(SplitByStateProcess *process)
{
Check_Object(this);
Check_Object(process);
//
//--------------------------
// Make sure we can continue
//--------------------------
//
process->SplitCallback(this, SplitByStateProcess::StatusCheck);
if (!process->continueProcess)
return;
//
//-------------------
// Split the children
//-------------------
//
unsigned child_count = GetChildCount();
ChildProxy *child = UseFirstChildProxy();
unsigned i;
for (i=0; i<child_count; ++i)
{
Check_Object(child);
ChildProxy *next = child->UseNextSiblingProxy();
if (child->SplitByState(process))
child->DetachReference();
child = next;
if (!process->continueProcess)
{
if (child)
child->DetachReference();
break;
}
}
//
//------------------------------------------------------------------------
// Make sure to discard any remaining proxies, and bypass the second phase
// of the sort if the process has been aborted
//------------------------------------------------------------------------
//
if (child)
child->DetachReference();
}
@@ -0,0 +1,35 @@
#pragma once
#include "Proxies.hpp"
#include "Process.hpp"
namespace Proxies {
class GenericProxy;
class SplitByStateProcess:
public Process
{
public:
enum {
StatusCheck = 0,
WARNING_MultipleStates,
ErrorsCount
};
SplitByStateProcess()
{}
SplitByStateProcess(
Stuff::NotationFile *data_file,
bool bSuppress = true,
void* fcn = NULL
):
Process(data_file, bSuppress, fcn)
{}
virtual void
SplitCallback(GenericProxy* proxy, int type)
{}
};
}
@@ -0,0 +1,694 @@
#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::WriteTargaFile(
const char* filename,
int width,
int height,
DynamicArrayOf<TargaColor> &data
)
{
Check_Pointer(filename);
Check_Object(&data);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
TargaHeader targa_header;
memset(&targa_header, 0, sizeof(targa_header));
targa_header.widthLow = static_cast<unsigned char>(width & 255);
targa_header.widthHigh = static_cast<unsigned char>(width >> 8);
targa_header.heightLow = static_cast<unsigned char>(height & 255);
targa_header.heightHigh = static_cast<unsigned char>(height >> 8);
targa_header.imageType = TargaHeader::RLERGB;
targa_header.pixelSize = 24;
targa_header.flags = TargaHeader::YReversed;
//
//---------------------
// Write out the header
//---------------------
//
Check_Object(FileStreamManager::Instance);
FileStream targa_file(filename, FileStream::WriteOnly);
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
//
//----------------------------------------------
// See if we need to deal with the alpha channel
//----------------------------------------------
//
unsigned channel_size = height * width;
Verify(channel_size == data.GetLength());
unsigned pixel_size = 3;
unsigned buffer_size = channel_size * pixel_size;
DynamicArrayOf<BYTE> buffer(buffer_size);
unsigned p = 0;
unsigned max_row = Min(width, 128);
//
//-------------------------------------
// Start trying to make an RLE encoding
//-------------------------------------
//
int i=0;
while (i<channel_size)
{
unsigned rle_count;
int rle_type = 0;
unsigned j = i+1;
unsigned base = i;
unsigned max_run = max_row - (i%max_row);
for (rle_count = 1; rle_count<max_run && j<channel_size; ++rle_count, ++j)
{
//
//-------------------------------------
// See if the next pixel matches or not
//-------------------------------------
//
bool match =
data[j].red == data[base].red
&& data[j].blue == data[base].blue
&& data[j].green == data[base].green;
//
//----------------------------------------------------------------
// If it matches, we break the run if this is a singleton run. We
// will always try to match matching pixels in a run
//----------------------------------------------------------------
//
if (match)
{
if (rle_type == -1)
{
--j;
--rle_count;
break;
}
//
//----------------------------------------------------
// Matching runs can go one longer than singleton runs
//----------------------------------------------------
//
else if (!rle_type)
rle_type = 1;
}
//
//-------------------------------------------------------
// It didn't match, so we better not be in a matching run. If we
// aren't, reset the base to this pixel
//-------------------------------------------------------
//
else
{
if (rle_type == 1)
break;
base = j;
rle_type = -1;
}
}
//
//----------------------------------------------------------------------
// Write out the run based upon its type after making sure that there is
// enough room in the buffer
//----------------------------------------------------------------------
//
if (rle_type == 1)
{
if (buffer_size-p < pixel_size+1)
goto No_RLE;
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count + 127);
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
i = j;
}
//
//-------------------------------------------------------------
// This is a singleton run, so check out its space requirements
//-------------------------------------------------------------
//
else
{
if (buffer_size-p < (pixel_size*rle_count)+1)
goto No_RLE;
//
//---------------
// Write them out
//---------------
//
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count-1);
for (; i<j; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
}
}
}
goto Write_File;
//
//-----------------------------------------------------------------------
// Interleave the channels w/no RLE. This should only be used if the RLE
// takes more space than the buffer allows
//-----------------------------------------------------------------------
//
No_RLE:
targa_file.Close();
targa_file.Open(filename, FileStream::WriteOnly);
targa_header.imageType = TargaHeader::RGB;
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
for (i=0,p=0; i<channel_size; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
}
goto Write_File;
//
//------------------------------------
// Write out the buffer and discard it
//------------------------------------
//
Write_File:
Verify(i == channel_size);
Verify(p <= buffer_size);
targa_file.WriteBytes(&buffer[0], p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::WriteTargaFile(
const char* filename,
int width,
int height,
DynamicArrayOf<TargaColorA> &data
)
{
Check_Pointer(filename);
Check_Object(&data);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
TargaHeader targa_header;
memset(&targa_header, 0, sizeof(targa_header));
targa_header.widthLow = static_cast<unsigned char>(width & 255);
targa_header.widthHigh = static_cast<unsigned char>(width >> 8);
targa_header.heightLow = static_cast<unsigned char>(height & 255);
targa_header.heightHigh = static_cast<unsigned char>(height >> 8);
targa_header.imageType = TargaHeader::RLERGB;
targa_header.pixelSize = 32;
targa_header.flags = TargaHeader::YReversed;
//
//---------------------
// Write out the header
//---------------------
//
Check_Object(FileStreamManager::Instance);
FileStream targa_file(filename, FileStream::WriteOnly);
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
//
//----------------------------------------------
// See if we need to deal with the alpha channel
//----------------------------------------------
//
unsigned channel_size = height * width;
Verify(channel_size == data.GetLength());
unsigned pixel_size = 4;
unsigned buffer_size = channel_size * pixel_size;
DynamicArrayOf<BYTE> buffer(buffer_size);
unsigned p = 0;
unsigned max_row = Min(width, 128);
//
//-------------------------------------
// Start trying to make an RLE encoding
//-------------------------------------
//
int i=0;
while (i<channel_size)
{
unsigned rle_count;
int rle_type = 0;
unsigned j = i+1;
unsigned base = i;
unsigned max_run = max_row - (i%max_row);
for (rle_count = 1; rle_count<max_run && j<channel_size; ++rle_count, ++j)
{
//
//-------------------------------------
// See if the next pixel matches or not
//-------------------------------------
//
bool match =
data[j].red == data[base].red
&& data[j].blue == data[base].blue
&& data[j].green == data[base].green
&& data[j].alpha == data[base].alpha;
//
//----------------------------------------------------------------
// If it matches, we break the run if this is a singleton run. We
// will always try to match matching pixels in a run
//----------------------------------------------------------------
//
if (match)
{
if (rle_type == -1)
{
--j;
--rle_count;
break;
}
//
//----------------------------------------------------
// Matching runs can go one longer than singleton runs
//----------------------------------------------------
//
else if (!rle_type)
rle_type = 1;
}
//
//-------------------------------------------------------
// It didn't match, so we better not be in a matching run. If we
// aren't, reset the base to this pixel
//-------------------------------------------------------
//
else
{
if (rle_type == 1)
break;
base = j;
rle_type = -1;
}
}
//
//----------------------------------------------------------------------
// Write out the run based upon its type after making sure that there is
// enough room in the buffer
//----------------------------------------------------------------------
//
if (rle_type == 1)
{
if (buffer_size-p < pixel_size+1)
goto No_RLE;
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count + 127);
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
i = j;
}
//
//-------------------------------------------------------------
// This is a singleton run, so check out its space requirements
//-------------------------------------------------------------
//
else
{
if (buffer_size-p < (pixel_size*rle_count)+1)
goto No_RLE;
//
//---------------
// Write them out
//---------------
//
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count-1);
for (; i<j; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
}
}
}
goto Write_File;
//
//-----------------------------------------------------------------------
// Interleave the channels w/no RLE. This should only be used if the RLE
// takes more space than the buffer allows
//-----------------------------------------------------------------------
//
No_RLE:
targa_file.Close();
targa_file.Open(filename, FileStream::WriteOnly);
targa_header.imageType = TargaHeader::RGB;
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
for (i=0,p=0; i<channel_size; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
}
goto Write_File;
//
//------------------------------------
// Write out the buffer and discard it
//------------------------------------
//
Write_File:
Verify(i == channel_size);
Verify(p <= buffer_size);
targa_file.WriteBytes(&buffer[0], p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaHeader(
TargaHeader *header,
MemoryStream *file,
int *width,
int *height,
unsigned *red_depth,
unsigned *green_depth,
unsigned *blue_depth,
unsigned *alpha_depth
)
{
Check_Pointer(header);
Check_Object(file);
Check_Pointer(width);
Check_Pointer(height);
Check_Pointer(red_depth);
Check_Pointer(green_depth);
Check_Pointer(blue_depth);
Check_Pointer(alpha_depth);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
file->ReadBytes(header, sizeof(*header));
*width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
*height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
Verify(header->pixelSize == 24 || header->pixelSize == 32);
*red_depth = 8;
*green_depth = 8;
*blue_depth = 8;
*alpha_depth = (header->pixelSize == 24) ? 0 : 8;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaChannels(
MemoryStream *file,
TargaHeader *header,
DynamicArrayOf<TargaColor> *data
)
{
Check_Object(file);
Check_Pointer(header);
Check_Object(data);
//
//----------------------------
// Read the file into a buffer
//----------------------------
//
unsigned len = file->GetBytesRemaining();
DynamicArrayOf<BYTE> buffer(len);
file->ReadBytes(&buffer[0], len);
//
//-----------------------------
// Set up the process variables
//-----------------------------
//
bool
x_reversed = ((header->flags & TargaHeader::XReversed) != 0),
y_reversed = ((header->flags & TargaHeader::YReversed) != 0),
compressed = (header->imageType == TargaHeader::RLERGB);
unsigned width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
unsigned height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
BYTE
run_count = 0,
copy_count = 0,
control_byte = 0,
red = 0,
green = 0,
blue = 0;
unsigned
dest = ((y_reversed) ? 0 : width * (height-1)),
source = 0;
if (x_reversed)
dest += width;
//
//------------------------
// Spin through each texel
//------------------------
//
for (unsigned y=0; y<height; ++y)
{
for (unsigned x=0; x<width; ++x)
{
Verify(
dest == ((y_reversed)?y:(height-1-y))*width + (x_reversed)?(width-x):x
);
//
//-----------------------------------------
// Handle the control bytes for compression
//-----------------------------------------
//
if (compressed)
{
if (!copy_count && !run_count)
control_byte=buffer[source++];
if (!run_count)
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
}
if (!copy_count && !run_count)
{
if (control_byte >= 128)
run_count = static_cast<BYTE>(control_byte-128);
else
copy_count = control_byte;
}
else if (run_count)
run_count--;
else if (copy_count)
copy_count--;
}
//
//-----------------------------------
// Otherwise, just get the next color
//-----------------------------------
//
else
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
}
//
//------------------------------
// Put the color in the channels
//------------------------------
//
if (x_reversed)
{
(*data)[--dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
}
else
{
(*data)[dest].red = red;
(*data)[dest].green = green;
(*data)[dest++].blue = blue;
}
}
//
//-----------------------------
// Move the destination pointer
//-----------------------------
//
if (x_reversed == y_reversed)
dest += ((y_reversed) ? 2 : -2) * width;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaChannels(
MemoryStream *file,
TargaHeader *header,
DynamicArrayOf<TargaColorA> *data
)
{
Check_Object(file);
Check_Pointer(header);
Check_Object(data);
//
//----------------------------
// Read the file into a buffer
//----------------------------
//
unsigned len = file->GetBytesRemaining();
DynamicArrayOf<BYTE> buffer(len);
file->ReadBytes(&buffer[0], len);
//
//-----------------------------
// Set up the process variables
//-----------------------------
//
bool
x_reversed = ((header->flags & TargaHeader::XReversed) != 0),
y_reversed = ((header->flags & TargaHeader::YReversed) != 0),
compressed = (header->imageType == TargaHeader::RLERGB);
unsigned width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
unsigned height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
BYTE
run_count = 0,
copy_count = 0,
control_byte = 0,
red = 0,
green = 0,
blue = 0,
alpha = 0;
unsigned
dest = ((y_reversed) ? 0 : width * (height-1)),
source = 0;
if (x_reversed)
dest += width;
//
//------------------------
// Spin through each texel
//------------------------
//
for (unsigned y=0; y<height; ++y)
{
for (unsigned x=0; x<width; ++x)
{
Verify(
dest == ((y_reversed)?y:(height-1-y))*width + (x_reversed)?(width-x):x
);
//
//-----------------------------------------
// Handle the control bytes for compression
//-----------------------------------------
//
if (compressed)
{
if (!copy_count && !run_count)
control_byte=buffer[source++];
if (!run_count)
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
alpha = buffer[source++];
}
if (!copy_count && !run_count)
{
if (control_byte >= 128)
run_count = static_cast<BYTE>(control_byte-128);
else
copy_count = control_byte;
}
else if (run_count)
run_count--;
else if (copy_count)
copy_count--;
}
//
//-----------------------------------
// Otherwise, just get the next color
//-----------------------------------
//
else
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
alpha = buffer[source++];
}
//
//------------------------------
// Put the color in the channels
//------------------------------
//
if (x_reversed)
{
(*data)[--dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
(*data)[dest].alpha = alpha;
}
else
{
(*data)[dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
(*data)[dest++].alpha = alpha;
}
}
//
//-----------------------------
// Move the destination pointer
//-----------------------------
//
if (x_reversed == y_reversed)
dest += ((y_reversed) ? 2 : -2) * width;
}
}
@@ -0,0 +1,96 @@
#pragma once
#include "Proxies.hpp"
namespace Proxies {
struct TargaHeader {
unsigned char
idLength,
colorMapType,
imageType,
indexLow,
indexHigh,
lengthLow,
lengthHigh,
colorEntrySize,
xOriginLow,
xOriginHigh,
yOriginLow,
yOriginHigh,
widthLow,
widthHigh,
heightLow,
heightHigh,
pixelSize,
flags;
enum {
RGB=2,
RLERGB=10,
XReversed=16,
YReversed=32
};
};
struct TargaColor
{
BYTE
blue,
green,
red;
};
struct TargaColorA
{
BYTE
blue,
green,
red,
alpha;
};
void
WriteTargaFile(
const char* filename,
int width,
int height,
Stuff::DynamicArrayOf<TargaColor> &data
);
void
WriteTargaFile(
const char* filename,
int width,
int height,
Stuff::DynamicArrayOf<TargaColorA> &data
);
void
ReadTargaHeader(
TargaHeader *header,
Stuff::MemoryStream *file,
int *width,
int *height,
unsigned *red_depth,
unsigned *green_depth,
unsigned *blue_depth,
unsigned *alpha_depth
);
void
ReadTargaChannels(
Stuff::MemoryStream *file,
TargaHeader *header,
Stuff::DynamicArrayOf<TargaColor> *data
);
void
ReadTargaChannels(
Stuff::MemoryStream *file,
TargaHeader *header,
Stuff::DynamicArrayOf<TargaColorA> *data
);
}
@@ -0,0 +1,817 @@
#include "ProxyHeaders.hpp"
#include <imagelib\image.h>
#include <GameOs\PNG\png.h>
#include <GameOS\ToolOS.hpp>
//
//############################################################################
//########################### TextureProxy ############################
//############################################################################
//
MemoryBlock*
TextureProxy::AllocatedMemory = NULL;
TextureProxy::ClassData*
TextureProxy::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::InitializeClass()
{
Verify(!AllocatedMemory);
AllocatedMemory =
new MemoryBlock(
sizeof(TextureProxy),
10,
10,
"TextureProxy"
);
Register_Object(AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
TextureProxyClassID,
"TextureProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(AllocatedMemory);
delete AllocatedMemory;
AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureProxy::TextureProxy(
ClassData *class_data,
TextureLibrary *library
):
GenericProxy(class_data),
libraryProxy(library)
{
Check_Pointer(this);
Check_Object(libraryProxy);
libraryProxy->AttachTextureProxy(this);
textureSize.x = textureSize.y = 0;
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureProxy::TextureProxy(
const char* name,
const Vector2DOf<int> &size,
TextureLibrary *library
):
GenericProxy(DefaultData),
libraryProxy(library),
textureName(name),
textureSize(size)
{
Check_Pointer(this);
Verify(GetClassID() == TextureProxyClassID);
redDepth = greenDepth = blueDepth = alphaDepth = 0;
libraryProxy->AttachReference();
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureProxy::~TextureProxy()
{
Check_Object(this);
if (libraryProxy)
{
Check_Object(libraryProxy);
libraryProxy->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::Destroy()
{
Check_Object(this);
Verify(referenceCount == 1);
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
TextureProxy::IsEqualTo(TextureProxy *texture)
{
Check_Object(this);
Check_Object(texture);
//
//-----------------------------------------
// Make sure we aren't comparing to ourself
//-----------------------------------------
//
if (this == texture)
return true;
//
//------------------
// Compare the names
//------------------
//
MString filename_1;
if (GetName(&filename_1))
{
MString filename_2;
if (texture->GetName(&filename_2))
return filename_1 == filename_2;
return false;
}
return !texture->GetName(&filename_1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureProxy*
TextureProxy::UseNextTextureProxyInLibrary()
{
Check_Object(this);
Verify(GetClassID() == TextureProxyClassID);
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureProxy*
TextureProxy::UsePreviousTextureProxyInLibrary()
{
Check_Object(this);
Verify(GetClassID() == TextureProxyClassID);
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
TextureProxy::GetName(MString *filename)
{
Check_Object(this);
Check_Pointer(filename);
Verify(GetClassID() == TextureProxyClassID);
//
//------------------------
// Set the name and return
//------------------------
//
*filename = textureName;
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::SetName(const char* filename)
{
Check_Object(this);
Check_Pointer(filename);
Verify(GetClassID() == TextureProxyClassID);
textureName = filename;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::GetImageSize(Vector2DOf<int> *size)
{
Check_Object(this);
Check_Pointer(size);
Verify(GetClassID() == TextureProxyClassID);
*size = textureSize;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::GetChannelDepth(
unsigned *red_depth,
unsigned *blue_depth,
unsigned *green_depth,
unsigned *alpha_depth
)
{
Check_Object(this);
Check_Pointer(red_depth);
Check_Pointer(blue_depth);
Check_Pointer(green_depth);
Check_Pointer(alpha_depth);
Verify(GetClassID() == TextureProxyClassID);
//
//--------------------------------------------------------
// Get the texture attribute, and find out if we got alpha
//--------------------------------------------------------
//
*red_depth = redDepth;
*blue_depth = blueDepth;
*green_depth = greenDepth;
*alpha_depth = alphaDepth;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::GetChannels(
Stuff::DynamicArrayOf<BYTE> *red,
Stuff::DynamicArrayOf<BYTE> *green,
Stuff::DynamicArrayOf<BYTE> *blue,
Stuff::DynamicArrayOf<BYTE> *alpha
)
{
Check_Object(this);
Check_Object(red);
Check_Object(green);
Check_Object(blue);
Verify(GetClassID() == TextureProxyClassID);
//
//---------------------
// Now copy the channel
//---------------------
//
*red = redChannel;
*green = greenChannel;
*blue = blueChannel;
if (alpha)
{
Check_Object(alpha);
*alpha = alphaChannel;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::SetChannels(
const DynamicArrayOf<BYTE> *red,
const DynamicArrayOf<BYTE> *green,
const DynamicArrayOf<BYTE> *blue,
const DynamicArrayOf<BYTE> *alpha
)
{
Check_Object(this);
Verify(GetClassID() == TextureProxyClassID);
Check_Object(red);
Check_Object(green);
Check_Object(blue);
//
//---------------------
// Now copy the channel
//---------------------
//
Verify(red->GetLength() == textureSize.x*textureSize.y);
redChannel = *red;
redDepth = 8;
Verify(green->GetLength() == textureSize.x*textureSize.y);
greenChannel = *green;
greenDepth = 8;
Verify(blue->GetLength() == textureSize.x*textureSize.y);
blueChannel = *blue;
blueDepth = 8;
if (alpha)
{
Check_Object(alpha);
alphaChannel = *alpha;
alphaDepth = 8;
}
else
{
alphaChannel.SetLength(0);
alphaDepth = 0;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::SaveAsTarga(const char* filename)
{
Check_Object(this);
Check_Pointer(filename);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
Vector2DOf<int> size;
GetImageSize(&size);
Verify(size.x > 0 && size.y > 0);
//
//----------------------------
// Analyze the type of texture
//----------------------------
//
unsigned
red_depth,
green_depth,
blue_depth,
alpha_depth;
GetChannelDepth(
&red_depth,
&green_depth,
&blue_depth,
&alpha_depth
);
Verify(red_depth == 8 && green_depth == 8 && blue_depth == 8);
Verify(!alpha_depth || alpha_depth == 8);
unsigned channel_size = size.x * size.y;
if (::gos_FileReadOnly(filename))
{
MString str;
str = MString(filename) + " is READ-ONLY. Remove the Read-Only permission and save?";
if (IDNO == MessageBox(NULL,str,"Save TGA",MB_YESNO))
{
return;
}
::gos_FileSetReadWrite(filename);
}
//
//----------------------------------------------------------------------
// If this is an alpha texture, write out an alpha TGA after compositing
// the colors for it
//----------------------------------------------------------------------
//
DynamicArrayOf<BYTE> red;
DynamicArrayOf<BYTE> green;
DynamicArrayOf<BYTE> blue;
DynamicArrayOf<BYTE> alpha;
if (alpha_depth == 8)
{
GetChannels(&red, &green, &blue, &alpha);
Verify(red.GetLength() == channel_size);
Verify(green.GetLength() == channel_size);
Verify(blue.GetLength() == channel_size);
Verify(alpha.GetLength() == channel_size);
DynamicArrayOf<TargaColorA> buffer(channel_size);
for (int i=0; i<channel_size; ++i)
{
buffer[i].red = red[i];
buffer[i].green = green[i];
buffer[i].blue = blue[i];
buffer[i].alpha = alpha[i];
}
WriteTargaFile(
filename,
size.x,
size.y,
buffer
);
}
//
//--------------------------------------------------------------------
// This is not an alpha texture, so just write out a regular TGA after
// compositing
//--------------------------------------------------------------------
//
else
{
GetChannels(&red, &green, &blue, NULL);
Verify(red.GetLength() == channel_size);
Verify(green.GetLength() == channel_size);
Verify(blue.GetLength() == channel_size);
DynamicArrayOf<TargaColor> buffer(channel_size);
for (int i=0; i<channel_size; ++i)
{
buffer[i].red = red[i];
buffer[i].green = green[i];
buffer[i].blue = blue[i];
}
WriteTargaFile(
filename,
size.x,
size.y,
buffer
);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::ReadTarga(
const char* filename,
unsigned *red_depth,
unsigned *blue_depth,
unsigned *green_depth,
unsigned *alpha_depth,
Vector2DOf<int> *size,
DynamicArrayOf<BYTE> *red,
DynamicArrayOf<BYTE> *green,
DynamicArrayOf<BYTE> *blue,
DynamicArrayOf<BYTE> *alpha
)
{
Check_Object(this);
Check_Pointer(filename);
//
//--------------
// Open the file
//--------------
//
FileStream targa_file(filename);
if (!targa_file.IsFileOpened())
{
size->x = size->y = 0;
*red_depth = *green_depth = *blue_depth = *alpha_depth = 0;
return;
}
//
//----------------------
// Read the targa header
//----------------------
//
TargaHeader header;
ReadTargaHeader(
&header,
&targa_file,
&size->x,
&size->y,
red_depth,
green_depth,
blue_depth,
alpha_depth
);
Verify(size->x > 0 && size->y > 0);
Verify(*red_depth == 8 && *green_depth == 8 && *blue_depth == 8);
Verify(!*alpha_depth || *alpha_depth == 8);
//
//------------------------
// Set the channel lengths
//------------------------
//
unsigned channel_size = size->x * size->y;
red->SetLength(channel_size);
green->SetLength(channel_size);
blue->SetLength(channel_size);
//
//----------------------------------------------
// If this is an alpha texture, read it that way
//----------------------------------------------
//
if (*alpha_depth > 0)
{
alpha->SetLength(channel_size);
DynamicArrayOf<TargaColorA> raw(channel_size);
ReadTargaChannels(&targa_file, &header, &raw);
for (int i=0; i<channel_size; ++i)
{
(*red)[i] = raw[i].red;
(*green)[i] = raw[i].green;
(*blue)[i] = raw[i].blue;
(*alpha)[i] = raw[i].alpha;
}
}
//
//-----------------------------
// This is not an alpha texture
//-----------------------------
//
else
{
DynamicArrayOf<TargaColor> raw(channel_size);
ReadTargaChannels(&targa_file, &header, &raw);
for (int i=0; i<channel_size; ++i)
{
(*red)[i] = raw[i].red;
(*green)[i] = raw[i].green;
(*blue)[i] = raw[i].blue;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::ReadPNG(
const char* filename,
unsigned *red_depth,
unsigned *blue_depth,
unsigned *green_depth,
unsigned *alpha_depth,
Vector2DOf<int> *size,
DynamicArrayOf<BYTE> *red,
DynamicArrayOf<BYTE> *green,
DynamicArrayOf<BYTE> *blue,
DynamicArrayOf<BYTE> *alpha
)
{
Check_Object(this);
Check_Pointer(filename);
//
//--------------
// Open the file
//--------------
//
if (!::gos_DoesFileExist(filename))
{
size->x = size->y = 0;
*red_depth = *green_depth = *blue_depth = *alpha_depth = 0;
return;
}
Image image;
image.Load((char *)filename);
size->x = image.GetWidth();
size->y = image.GetHeight();
*red_depth = 8;
*green_depth = 8;
*blue_depth = 8;
/* default mask in Image::CreateBlank has red in the most significant byte */
/* so make sure here the right mask is set */
RGBMask mask;
if(image.GetBpp()==32)
{
mask.Set(0x0000ff,0x00ff00,0xff0000);
*alpha_depth = 8;
}
else {
mask.Set(0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
*alpha_depth = 0;
}
image.MaskTo(mask);
Verify(size->x > 0 && size->y > 0);
Verify(*red_depth == 8 && *green_depth == 8 && *blue_depth == 8);
Verify(!*alpha_depth || *alpha_depth == 8);
//
//------------------------
// Set the channel lengths
//------------------------
//
unsigned channel_size = size->x * size->y;
red->SetLength(channel_size);
green->SetLength(channel_size);
blue->SetLength(channel_size);
//
//----------------------------------------------
// If this is an alpha texture, read it that way
//----------------------------------------------
//
BYTE *dat = (BYTE *)image.Lock();
if (*alpha_depth > 0)
{
alpha->SetLength(channel_size);
for (int i=0; i<channel_size; ++i)
{
(*red)[i] = *(dat+i*4+0);
(*green)[i] = *(dat+i*4+1);
(*blue)[i] = *(dat+i*4+2);
(*alpha)[i] = *(dat+i*4+3);
}
}
//
//-----------------------------
// This is not an alpha texture
//-----------------------------
//
else
{
for (int i=0; i<channel_size; ++i)
{
(*red)[i] = *(dat+i*3+0);
(*green)[i] = *(dat+i*3+1);
(*blue)[i] = *(dat+i*3+2);
}
}
image.UnLock();
}
/*******************************************************************************
/* function name: SaveAsPng
/* description:
/*******************************************************************************/
void TextureProxy::SaveAsPng(const char* filename)
{
Check_Object(this);
Check_Pointer(filename);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
Vector2DOf<int> size;
GetImageSize(&size);
Verify(size.x > 0 && size.y > 0);
//
//----------------------------
// Analyze the type of texture
//----------------------------
//
unsigned
red_depth,
green_depth,
blue_depth,
alpha_depth;
GetChannelDepth(
&red_depth,
&green_depth,
&blue_depth,
&alpha_depth
);
Verify(red_depth == 8 && green_depth == 8 && blue_depth == 8);
Verify(!alpha_depth || alpha_depth == 8);
unsigned channel_size = size.x * size.y;
/* default mask in Image::CreateBlank has red in the most significant byte */
/* so make sure here the right mask is set */
RGBMask mask;
if(alpha_depth==0)
mask.Set(0x0000ff,0x00ff00,0xff0000);
else
mask.Set(0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
Image pngImage;
pngImage.CreateBlank(size.x, size.y, ITYPE_RGB, alpha_depth?32:24, mask);
BYTE *dat=(BYTE *)pngImage.Lock();
//
//----------------------------------------------------------------------
// If this is an alpha texture, write out RGBA
//----------------------------------------------------------------------
//
DynamicArrayOf<BYTE> red;
DynamicArrayOf<BYTE> green;
DynamicArrayOf<BYTE> blue;
DynamicArrayOf<BYTE> alpha;
if (alpha_depth == 8)
{
GetChannels(&red, &green, &blue, &alpha);
Verify(red.GetLength() == channel_size);
Verify(green.GetLength() == channel_size);
Verify(blue.GetLength() == channel_size);
Verify(alpha.GetLength() == channel_size);
for (int i=0; i<channel_size; ++i)
{
*(dat+i*4+0) = red[i];
*(dat+i*4+1) = green[i];
*(dat+i*4+2) = blue[i];
*(dat+i*4+3) = alpha[i];
}
}
//
//--------------------------------------------------------------------
// This is not an alpha texture, so just write out RGB
//--------------------------------------------------------------------
//
else
{
GetChannels(&red, &green, &blue, NULL);
Verify(red.GetLength() == channel_size);
Verify(green.GetLength() == channel_size);
Verify(blue.GetLength() == channel_size);
for (int i=0; i<channel_size; ++i)
{
*(dat+i*3+0) = red[i];
*(dat+i*3+1) = green[i];
*(dat+i*3+2) = blue[i];
}
}
pngImage.UnLock();
if (::gos_FileReadOnly(filename))
{
MString str;
str = MString(filename) + " is READ-ONLY. Remove the Read-Only permission and save?";
if (IDNO == MessageBox(NULL,str,"Save PNG",MB_YESNO))
{
return;
}
::gos_FileSetReadWrite(filename);
}
pngImage.SavePng((char* )filename);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool TextureProxy:: GetFormat(Proxies::TextureProxy::FormatType* format)
{
Check_Object(this);
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void TextureProxy:: SetFormat(Proxies::TextureProxy::FormatType format)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//
//############################################################################
//###################### TextureLibrary ##########################
//############################################################################
//
TextureLibrary::ClassData*
TextureLibrary::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
TextureLibraryClassID,
"TextureLibrary",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureLibrary::TextureLibrary(
ClassData *class_data,
StateLibrary *state_library
):
GenericProxy(class_data),
stateLibrary(state_library),
activeTextureProxies(NULL)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TextureLibrary::~TextureLibrary()
{
Check_Object(this);
Verify(activeTextureProxies.IsEmpty());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
TextureLibrary::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
@@ -0,0 +1,356 @@
#pragma once
#include "Proxies.hpp"
#include "GenericProxy.hpp"
namespace Proxies {
class StateLibrary;
class TextureLibrary;
class BuildMegatexturesProcess;
class GetInfoProcess;
class ArrangeMegatexturesProcess;
//
//#########################################################################
//####################### TextureProxy ##############################
//#########################################################################
//
class TextureProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
TextureProxy(
ClassData *class_data,
TextureLibrary *library
);
TextureProxy(
const char* name,
const Stuff::Vector2DOf<int> &size,
TextureLibrary *library
);
~TextureProxy();
static Stuff::MemoryBlock
*AllocatedMemory;
public:
static TextureProxy*
MakeProxy(
const char* name,
const Stuff::Vector2DOf<int> &size,
TextureLibrary *library
)
{return new TextureProxy(name, size, library);}
void
Destroy();
void*
operator new(size_t)
{return AllocatedMemory->New();}
void
operator delete(void *where)
{AllocatedMemory->Delete(where);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual int
FindErrors(FindErrorsProcess *process);
virtual void
Copy(
CopyProcess *process,
TextureProxy *texture
);
virtual void
GetInfo(
GetInfoProcess *process
);
virtual void
BuildMegatextures(BuildMegatexturesProcess *process);
virtual void
ArrangeMegatextures(ArrangeMegatexturesProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Texture management functions
//
public:
TextureLibrary*
GetTextureLibrary()
{Check_Object(this); return libraryProxy;}
virtual bool
IsEqualTo(TextureProxy *texture);
virtual TextureProxy*
UseNextTextureProxyInLibrary();
virtual TextureProxy*
UsePreviousTextureProxyInLibrary();
enum FormatType {
AlphaTexture = 0,
KeyedTexture
};
virtual bool
GetFormat(FormatType*);
virtual void
SetFormat(FormatType);
protected:
TextureLibrary
*libraryProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Texture functions
//
public:
enum {
RedChannel,
GreenChannel,
BlueChannel,
AlphaChannel
};
//
// name functions
//
bool
GetName(Stuff::MString *name);
void
SetName(const char* name);
//
// Get the bitmap size
//
virtual void
GetImageSize(Stuff::Vector2DOf<int> *size);
//
// Get channel data
//
virtual void
GetChannelDepth(
unsigned *red_depth,
unsigned *blue_depth,
unsigned *green_depth,
unsigned *alpha_depth
);
virtual void
GetChannels(
Stuff::DynamicArrayOf<BYTE> *red,
Stuff::DynamicArrayOf<BYTE> *green,
Stuff::DynamicArrayOf<BYTE> *blue,
Stuff::DynamicArrayOf<BYTE> *alpha
);
virtual void
SetChannels(
const Stuff::DynamicArrayOf<BYTE> *red,
const Stuff::DynamicArrayOf<BYTE> *green,
const Stuff::DynamicArrayOf<BYTE> *blue,
const Stuff::DynamicArrayOf<BYTE> *alpha
);
//
// Get pixel index
//
unsigned
GetPixelIndex(const Stuff::Vector2DOf<int> &location)
{Check_Object(this); return location.y*textureSize.x + location.x;}
//
// Texture saving
//
void
SaveAsTarga(const char* filename);
void
ReadTarga(
const char* filename,
unsigned *red_depth,
unsigned *green_depth,
unsigned *blue_depth,
unsigned *alpha_depth,
Stuff::Vector2DOf<int> *size,
Stuff::DynamicArrayOf<BYTE> *red,
Stuff::DynamicArrayOf<BYTE> *green,
Stuff::DynamicArrayOf<BYTE> *blue,
Stuff::DynamicArrayOf<BYTE> *alpha
);
void
ReadPNG(
const char* filename,
unsigned *red_depth,
unsigned *green_depth,
unsigned *blue_depth,
unsigned *alpha_depth,
Stuff::Vector2DOf<int> *size,
Stuff::DynamicArrayOf<BYTE> *red,
Stuff::DynamicArrayOf<BYTE> *green,
Stuff::DynamicArrayOf<BYTE> *blue,
Stuff::DynamicArrayOf<BYTE> *alpha
);
void SaveAsPng(const char* filename);
protected:
Stuff::Vector2DOf<int>
textureSize;
Stuff::MString
textureName;
unsigned
redDepth,
greenDepth,
blueDepth,
alphaDepth;
Stuff::DynamicArrayOf<BYTE>
redChannel,
greenChannel,
blueChannel,
alphaChannel;
};
//
//#########################################################################
//#################### TextureLibrary ##########################
//#########################################################################
//
class _declspec(novtable) TextureLibrary:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
TextureLibrary(
ClassData *class_data,
StateLibrary *state_library
);
public:
~TextureLibrary();
//
// Copies the elements of the given material into this material
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual int
FindErrors(FindErrorsProcess *process);
virtual void
Copy(
CopyProcess *process,
TextureLibrary *texture
);
virtual void
GetInfo(
GetInfoProcess *process
);
virtual void
BuildMegatextures(BuildMegatexturesProcess *process);
virtual void
ArrangeMegatextures(ArrangeMegatexturesProcess *process);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Texture management functions
//
public:
StateLibrary*
GetStateLibrary()
{Check_Object(this); return stateLibrary;}
protected:
StateLibrary
*stateLibrary;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Texture functions
//
public:
//
// name functions
//
bool
GetName(Stuff::MString *name)
{return false;}
void
SetName(const char* name)
{}
//
// Gets the current number of children
//
virtual unsigned
GetTextureCount() = 0;
//
// Child creation functions
//
virtual TextureProxy*
UseNewTextureProxy() = 0;
virtual TextureProxy*
UseMatchingTextureProxy(TextureProxy *texture) = 0;
virtual TextureProxy*
UseTextureProxy(const char* texture_name) = 0;
//
// Child traversal functions
//
virtual TextureProxy*
UseFirstTextureProxy() = 0;
virtual TextureProxy*
UseLastTextureProxy() = 0;
void
AttachTextureProxy(TextureProxy *proxy)
{
Check_Object(this);
AttachReference(); activeTextureProxies.Add(proxy);
}
void
DetachTextureProxy(TextureProxy* proxy);
protected:
Stuff::ChainOf<TextureProxy*>
activeTextureProxies;
};
}
@@ -0,0 +1,410 @@
#include "ProxyHeaders.hpp"
//
//############################################################################
//########################### VertexProxy ############################
//############################################################################
//
VertexProxy::ClassData*
VertexProxy::DefaultData = NULL;
MemoryBlock*
VertexProxy::AllocatedMemory = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::InitializeClass()
{
Verify(!AllocatedMemory);
AllocatedMemory =
new MemoryBlock(
sizeof(VertexProxy),
10,
10,
"VertexProxy"
);
Register_Object(AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
VertexProxyClassID,
"VertexProxy",
GenericProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(AllocatedMemory);
delete AllocatedMemory;
AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VertexProxy::VertexProxy(
ClassData *class_data,
PolygonMeshProxy *mesh
):
GenericProxy(class_data),
polygonMeshProxy(mesh),
activeIndexProxies(NULL)
{
Check_Pointer(this);
//
//---------------------------------
// Connect to a mesh if we have one
//---------------------------------
//
Check_Object(polygonMeshProxy);
polygonMeshProxy->AttachVertexProxy(this);
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VertexProxy::VertexProxy():
GenericProxy(DefaultData),
polygonMeshProxy(NULL),
activeIndexProxies(NULL)
{
Check_Pointer(this);
hasNormal = hasColor = hasUV = false;
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
VertexProxy::~VertexProxy()
{
Check_Object(this);
Verify(activeIndexProxies.IsEmpty());
if (polygonMeshProxy)
{
Check_Object(polygonMeshProxy);
polygonMeshProxy->DetachReference();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::Destroy()
{
Check_Object(this);
Verify(referenceCount == 1);
Verify(activeIndexProxies.IsEmpty());
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
VertexProxy::IsEqualTo(
VertexProxy *vertex,
Scalar threshold
)
{
Check_Object(this);
Check_Object(vertex);
//
//-------------------------------
// We are always equal to ourself
//-------------------------------
//
if (this == vertex)
return true;
//
//---------------------
// Compare our position
//---------------------
//
Point3D our_position, their_position;
GetPosition(&our_position);
vertex->GetPosition(&their_position);
if (!Close_Enough(our_position, their_position, threshold))
return false;
//
//------------------
// Compare the color
//------------------
//
RGBAColor color, other_color;
bool them = vertex->GetColor(&other_color);
bool us = GetColor(&color);
if (them != us)
return false;
if (them && us)
{
if (!Close_Enough(color, other_color))
return false;
}
//
//-------------------
// Compare the normal
//-------------------
//
Normal3D normal, other_normal;
them = vertex->GetNormal(&other_normal);
us = GetNormal(&normal);
if (them != us)
return false;
if (them && us)
{
if (!Close_Enough(normal, other_normal))
return false;
}
//
//---------------
// Compare the UV
//---------------
//
DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > uv, other_uv;
them = vertex->GetUVs(&other_uv);
us = GetUVs(&uv);
if (them != us)
return false;
if(uv.GetLength() != other_uv.GetLength())
return false;
if (them && us)
{
for(unsigned i=0;i<uv.GetLength();i++)
{
if (!Close_Enough(uv[i].x, other_uv[i].x) || !Close_Enough(uv[i].y, other_uv[i].y))
return false;
}
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
VertexProxy::IsAllButNormalEqual(
VertexProxy *vertex,
Scalar threshold
)
{
Check_Object(this);
Check_Object(vertex);
//
//-------------------------------
// We are always equal to ourself
//-------------------------------
//
if (this == vertex)
return true;
//
//---------------------
// Compare our position
//---------------------
//
Point3D our_position, their_position;
GetPosition(&our_position);
vertex->GetPosition(&their_position);
if (!Close_Enough(our_position, their_position, threshold))
return false;
//
//------------------
// Compare the color
//------------------
//
RGBAColor color, other_color;
bool them = vertex->GetColor(&other_color);
bool us = GetColor(&color);
if (them != us)
return false;
if (them && us)
{
if (!Close_Enough(color, other_color))
return false;
}
//
//---------------
// Compare the UV
//---------------
//
DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > uv, other_uv;
them = vertex->GetUVs(&other_uv);
us = GetUVs(&uv);
if (them != us)
return false;
if(uv.GetLength() != other_uv.GetLength())
return false;
if (them && us)
{
for(unsigned i=0;i<uv.GetLength();i++)
{
if (!Close_Enough(uv[i].x, other_uv[i].x) || !Close_Enough(uv[i].y, other_uv[i].y))
return false;
}
}
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
VertexProxy::AddUniqueVertex(
Stuff::DynamicArrayOf<VertexProxy*> &vertices,
unsigned *vertex_count,
VertexProxy *new_vertex,
Scalar threshold
)
{
Check_Object(&vertices);
Check_Pointer(vertex_count);
Verify(*vertex_count <= vertices.GetLength());
Check_Object(new_vertex);
unsigned vertex;
for (vertex=0; vertex<*vertex_count; ++vertex)
{
Check_Object(vertices[vertex]);
if (vertices[vertex]->IsEqualTo(new_vertex, threshold))
break;
}
if (vertex == *vertex_count)
vertices[(*vertex_count)++] = new_vertex;
return vertex;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::DetachIndexProxy(IndexProxy* proxy)
{
Check_Object(this);
activeIndexProxies.RemovePlug(proxy);
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::GetPosition(Point3D *position)
{
Check_Object(this);
Check_Pointer(position);
*position = vertexPosition;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::SetPosition(const Point3D &position)
{
Check_Object(this);
Check_Object(&position);
vertexPosition = position;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
VertexProxy::GetColor(RGBAColor *color)
{
Check_Object(this);
Check_Pointer(color);
if (!hasColor)
return false;
Check_Object(&vertexColor);
*color = vertexColor;
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::SetColor(const RGBAColor& color)
{
Check_Object(this);
Check_Object(&color);
hasColor = true;
vertexColor = color;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
VertexProxy::GetNormal(Normal3D *normal)
{
Check_Object(this);
Check_Pointer(normal);
if (!hasNormal)
return false;
Check_Object(&vertexNormal);
*normal = vertexNormal;
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::SetNormal(const Normal3D &normal)
{
Check_Object(this);
Check_Object(&normal);
hasNormal = true;
vertexNormal = normal;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
VertexProxy::GetUVs(DynamicArrayOf<Vector2DOf<Stuff::Scalar> > *uv)
{
Check_Object(this);
Check_Pointer(uv);
if (!hasUV)
return false;
Check_Object(&vertexUVs);
*uv = vertexUVs;
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
VertexProxy::SetUVs(DynamicArrayOf<Vector2DOf<Scalar> > &uv)
{
Check_Object(this);
Check_Object(&uv);
hasUV = true;
vertexUVs = uv;
}
@@ -0,0 +1,202 @@
#pragma once
#include "Proxies.hpp"
namespace Proxies {
class IndexProxy;
class LightProxy;
struct TransformedLight {
Stuff::LinearMatrix4D
lightToLocal;
LightProxy
*lightProxy;
};
//
//#########################################################################
//######################## VertexProxy ##############################
//#########################################################################
//
class VertexProxy:
public GenericProxy
{
public:
static void
InitializeClass();
static void
TerminateClass();
static ClassData
*DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructors
//
protected:
VertexProxy(
ClassData *class_data,
PolygonMeshProxy *mesh
);
VertexProxy();
~VertexProxy();
static Stuff::MemoryBlock
*AllocatedMemory;
public:
static VertexProxy*
MakeProxy()
{return new VertexProxy();}
//
// Copies the elements of the given vertex pointer into this vertex
// pointer
//
void
Destroy();
void*
operator new(size_t)
{return AllocatedMemory->New();}
void
operator delete(void *where)
{AllocatedMemory->Delete(where);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Testing
//
public:
void
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Process support
//
public:
virtual void
BurnLights(
BurnLightsProcess *process,
Stuff::DynamicArrayOf<TransformedLight> &lights
);
virtual void
Copy(
CopyProcess *process,
VertexProxy *vertex
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vertex management functions
//
public:
//
// Copies the elements of a polygon into this polygon
//
PolygonMeshProxy*
GetPolygonMeshProxy()
{Check_Object(this); return polygonMeshProxy;}
virtual bool
IsEqualTo(
VertexProxy* vertex,
Stuff::Scalar threshold
);
virtual bool
IsAllButNormalEqual(
VertexProxy* vertex,
Stuff::Scalar threshold
);
static unsigned
AddUniqueVertex(
Stuff::DynamicArrayOf<VertexProxy*> &vertices,
unsigned *vertex_count,
VertexProxy *new_vertex,
Stuff::Scalar threshold
);
//
// Vertices don't get names
//
bool
GetName(class Stuff::MString *name)
{Check_Object(this); Check_Object(name); return false;}
void
SetName(const char* name)
{Check_Object(this); Check_Pointer(name);}
protected:
PolygonMeshProxy
*polygonMeshProxy;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vertex instance functions
//
public:
void
AttachIndexProxy(IndexProxy *proxy)
{
Check_Object(this);
AttachReference(); activeIndexProxies.Add(proxy);
}
void
DetachIndexProxy(IndexProxy* proxy);
protected:
Stuff::ChainOf<IndexProxy*>
activeIndexProxies;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Vertex functions
//
public:
//
// position functions
//
virtual void
GetPosition(Stuff::Point3D *point);
virtual void
SetPosition(const Stuff::Point3D &point);
//
// color functions
//
virtual bool
GetColor(Stuff::RGBAColor *color);
virtual void
SetColor(const Stuff::RGBAColor& color);
//
// normal functions
//
virtual bool
GetNormal(Stuff::Normal3D *normal);
virtual void
SetNormal(const Stuff::Normal3D &normal);
//
// UV functions
//
virtual bool
GetUVs(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > *vector);
virtual void
SetUVs(Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > &vector);
protected:
Stuff::Point3D
vertexPosition;
Stuff::Normal3D
vertexNormal;
Stuff::RGBAColor
vertexColor;
Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> >
vertexUVs;
bool
hasNormal,
hasColor,
hasUV;
};
}