Files
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00

1666 lines
42 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "..\munga\fileutil.h"
#include "l4gauima.h"
#include "l4app.h"
#include "..\munga\notation.h"
#include "..\munga\namelist.h"
// #define LOCAL_TEST
#if defined(LOCAL_TEST)
# define Test_Tell(n) std::cout << n << std::flush
#else
# define Test_Tell(n)
#endif
//############################################################################
// GroupAttribute
// - this is a private class used nowhere else.
// It is initialized from a .GAT notation file, after which it
// holds a list of attribute group names with associated color and
// attribute fields. It may then be searched to find the values for
// that attribute group.
//############################################################################
class GroupAttribute SIGNATURED
{
public:
enum
{
nameLength=64
};
int color;
int attribute;
char name[nameLength];
GroupAttribute
*next;
GroupAttribute(const char *new_name, int new_color, int new_attrib);
~GroupAttribute()
{}
Logical
TestInstance() const
{ return True; }
static Logical
Initialize(const char *gat_file_name);
static void
Terminate();
static Logical
Search(const char *name, int *color, int *attribute);
protected:
static
GroupAttribute
*head;
};
GroupAttribute
*GroupAttribute::head;
GroupAttribute::GroupAttribute(
const char *new_name,
int new_color,
int new_attrib
)
{
Test_Tell(
"GroupAttribute::GroupAttribute(" << new_name <<
", " << new_color <<
", " << new_attrib <<
")\n"
);
Check_Pointer(this);
Check_Pointer(new_name);
name[0] = '\0'; // safety check
Str_Copy(name, new_name, nameLength-1);
name[nameLength-1] = '\0';
color = new_color;
attribute = new_attrib;
next = head;
head = this;
Check_Fpu();
}
Logical
GroupAttribute::Initialize(const char *gat_filename)
{
Test_Tell("GroupAttribute::Initialize(" << gat_filename << ")\n");
Check_Pointer(gat_filename);
Logical
result = False;
//-------------------------------------------------------------
// Open the associated .GAT file
//-------------------------------------------------------------
NotationFile
*gat_file = new NotationFile(gat_filename);
Check(gat_file);
Register_Object(gat_file);
//-------------------------------------------------------------
// Create group, attribute, color name lists
//-------------------------------------------------------------
NameList
*color_namelist = gat_file->MakeEntryList("colors");
if (color_namelist == NULL)
{
DEBUG_STREAM << gat_filename << " has no 'colors' page!" << std::endl;
}
NameList
*attribute_namelist = gat_file->MakeEntryList("attributes");
if (attribute_namelist == NULL)
{
DEBUG_STREAM << gat_filename << " has no 'attributes' page!" << std::endl;
}
NameList
*group_namelist = gat_file->MakeEntryList("groups");
if (group_namelist == NULL)
{
DEBUG_STREAM << gat_filename << " has no 'groups' page!" << std::endl;
}
if (
(attribute_namelist != NULL) &&
(color_namelist != NULL) &&
(group_namelist != NULL)
)
{
//-------------------------------------------------------------
// Register the name lists
//-------------------------------------------------------------
Register_Object(color_namelist);
Register_Object(attribute_namelist);
Register_Object(group_namelist);
//-------------------------------------------------------------
// Clear the chain header
//-------------------------------------------------------------
head = NULL;
//-------------------------------------------------------------
// For all group names, build a GroupAttribute object
//-------------------------------------------------------------
NameList::Entry
*group_entry,
*color_entry,
*attribute_entry;
int
i,
new_attribute,
new_color;
Logical
found;
for (
group_entry = group_namelist->GetFirstEntry();
group_entry != NULL;
group_entry = group_entry->GetNextEntry()
)
{
Check(group_entry);
char
buffer[256];
char
*dest,
*text = group_entry->GetChar();
new_attribute = 0;
new_color = 0;
if (text == NULL)
{
DEBUG_STREAM << text << " is an empty .GAT group!" << std::endl;
}
else
{
//-------------------------------------------------------------
// Skip white space
//-------------------------------------------------------------
while (*text != '\0')
{
while (isspace(*text))
{
++text;
}
//-------------------------------------------------------------
// Parse out one name
//-------------------------------------------------------------
for (
i=0,dest=buffer;
i<(sizeof(buffer)-1);
++i,++dest,++text
)
{
if (!isalnum(*text))
{
break;
}
*dest = *text;
}
*dest = '\0';
Test_Tell("attribute item= <" << buffer << ">\n");
//-------------------------------------------------------------
// Search color list for name
//-------------------------------------------------------------
found = False;
for (
color_entry = color_namelist->GetFirstEntry();
color_entry != NULL;
color_entry = color_entry->GetNextEntry()
)
{
Check(color_entry);
if (strcmp(color_entry->GetName(), buffer) == 0)
{
Check_Pointer(color_entry->GetData());
new_color = color_entry->GetAtoi();
Test_Tell("color=" << new_color << "\n");
found = True;
break;
}
}
if (! found)
{
//----------------------------------------------------------
// Search attribute list for name
//----------------------------------------------------------
found = False;
for (
attribute_entry =attribute_namelist->GetFirstEntry();
attribute_entry != NULL;
attribute_entry = attribute_entry->GetNextEntry()
)
{
Check(attribute_entry);
if (strcmp(attribute_entry->GetName(), buffer) == 0)
{
Check_Pointer(attribute_entry->GetData());
new_attribute |= attribute_entry->GetAtoi();
Test_Tell(
"attribute=" << std::hex << new_attribute << std::dec << ">\n"
);
found = True;
break;
}
}
if (! found)
{
DEBUG_STREAM <<
"Attribute '" << buffer << "' not found!" << std::endl;
}
}
}
}
Check(group_entry);
Check_Pointer(group_entry->GetName());
# if DEBUG_LEVEL == 0
new GroupAttribute(
group_entry->GetName(),
new_color,
new_attribute
);
# else
GroupAttribute
*group_attribute =
new GroupAttribute(
group_entry->GetName(),
new_color,
new_attribute
);
Check(group_attribute);
Register_Object(group_attribute);
Test_Tell("object created\n");
# endif
}
//-------------------------------------------------------------
// Release the name lists
//-------------------------------------------------------------
Test_Tell("loop finished, deleting namelists\n");
Check(color_namelist);
Unregister_Object(color_namelist);
delete color_namelist;
Check(attribute_namelist);
Unregister_Object(attribute_namelist);
delete attribute_namelist;
Check(group_namelist);
Unregister_Object(group_namelist);
delete group_namelist;
result = True;
}
//-------------------------------------------------------------
// Release the notation file
//-------------------------------------------------------------
Test_Tell("deleting .GAT notation file\n");
Check(gat_file);
Unregister_Object(gat_file);
delete gat_file;
Test_Tell("returning " << result <<"\n");
Check_Fpu();
return result;
}
void
GroupAttribute::Terminate()
{
Test_Tell("GroupAttribute::Terminate\n");
GroupAttribute
*group_attribute,
*next;
for(
group_attribute= head;
group_attribute != NULL;
group_attribute = next
)
{
Check(group_attribute);
next = group_attribute->next;
Unregister_Object(group_attribute);
delete group_attribute;
}
head = NULL;
Test_Tell("Termination completed\n");
Check_Fpu();
}
Logical
GroupAttribute::Search(const char *name, int *color_dest, int *attrib_dest)
{
Test_Tell("GroupAttribute::Search("<< name <<")\n");
GroupAttribute
*group_attribute;
for(
group_attribute= head;
group_attribute != NULL;
group_attribute = group_attribute->next
)
{
Check(group_attribute);
if (
strncmp(
name,
group_attribute->name,
GroupAttribute::nameLength
) == 0
)
{
Test_Tell("Found!\n");
*color_dest = group_attribute->color;
*attrib_dest = group_attribute->attribute;
Check_Fpu();
return True;
}
}
Check_Fpu();
return False;
}
//############################################################################
// L4GaugeImage
//############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
L4GaugeImage *
L4GaugeImage::Make(const char */*file_name*/)
{
return NULL; // Gauge images come exclusively from resources
}
L4GaugeImage *
L4GaugeImage::Make(ResourceDescription::ResourceID new_resource_id)
{
Check(application);
Check(application->GetResourceFile());
L4GaugeImage
*image = NULL;
//-------------------------------------------
// Attempt to find the specified resource
//-------------------------------------------
ResourceDescription
*stream_resource_description =
application->GetResourceFile()->SearchList(
new_resource_id,
ResourceDescription::GaugeImageStreamResourceType
);
if (stream_resource_description == NULL)
{
Tell(
"L4GaugeImage::Make: resource ID '" << new_resource_id <<
"' does not exist\n"
);
}
else
{
//-------------------------------------------
// Found it, open a DynamicMemoryStream
//-------------------------------------------
Check(stream_resource_description);
stream_resource_description->Lock();
MemoryStream
memory_stream(
stream_resource_description->resourceAddress,
stream_resource_description->resourceSize
);
if (stream_resource_description->resourceAddress == NULL)
{
Tell("L4GaugeImage::Make: couldn't open stream\n");
}
else
{
//-------------------------------------------
// Create the object
//-------------------------------------------
image = new L4GaugeImage(&memory_stream);
}
stream_resource_description->Unlock();
}
Check_Fpu();
return image;
}
L4GaugeImage::L4GaugeImage(MemoryStream *mem_stream)
{
Test_Tell("L4GaugeImage::L4GaugeImage\n");
Check_Pointer(this);
Check(mem_stream);
int
i;
//-------------------------------------------------------------
// Read the number of vertices
//-------------------------------------------------------------
MemoryStream_Read(mem_stream, &vertexCount);
Verify(vertexCount > 0);
//-------------------------------------------------------------
// Allocate the vertex array
//-------------------------------------------------------------
vertexArray = new Point3D[vertexCount];
Check_Pointer(vertexArray);
Register_Pointer(vertexArray);
//-------------------------------------------------------------
// Read in the vertex values
//-------------------------------------------------------------
for(i=0; i<vertexCount; ++i)
{
MemoryStream_Read(mem_stream, &vertexArray[i]);
}
//-------------------------------------------------------------
// Read the number of LOD's from the stream
//-------------------------------------------------------------
MemoryStream_Read(mem_stream, &LODCount);
Verify(LODCount > 0);
//-------------------------------------------------------------
// Allocate the LOD scales
//-------------------------------------------------------------
LODScales = new Scalar[LODCount];
Check_Pointer(LODScales);
Register_Pointer(LODScales);
//-------------------------------------------------------------
// Read the LOD scales
//-------------------------------------------------------------
for(i=0; i<LODCount; ++i)
{
MemoryStream_Read(mem_stream, &LODScales[i]);
}
//-------------------------------------------------------------
// Allocate the LOD lists
//-------------------------------------------------------------
LODList = new L4GaugeImageList*[LODCount];
Check_Pointer(LODList);
Register_Pointer(LODList);
//-------------------------------------------------------------
// Read the LOD lists
//-------------------------------------------------------------
for(i=0; i<LODCount; ++i)
{
LODList[i] = new L4GaugeImageList(mem_stream);
Check(LODList[i]);
Register_Object(LODList[i]);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4GaugeImage::~L4GaugeImage()
{
Test_Tell("L4GaugeImage::~L4GaugeImage\n");
Check(this);
int
i;
//-------------------------------------------------------------
// Delete the vertices
//-------------------------------------------------------------
Check_Pointer(vertexArray);
Unregister_Pointer(vertexArray);
delete[] vertexArray;
//-------------------------------------------------------------
// Delete the LOD scales
//-------------------------------------------------------------
Check_Pointer(LODScales);
Unregister_Pointer(LODScales);
delete[] LODScales;
//-------------------------------------------------------------
// Delete the LOD list items
//-------------------------------------------------------------
Check_Pointer(LODList);
for(i=0; i<LODCount; ++i)
{
Check(LODList[i]);
Unregister_Object(LODList[i]);
delete LODList[i];
}
//-------------------------------------------------------------
// Delete the LOD list
//-------------------------------------------------------------
Unregister_Pointer(LODList);
delete[] LODList;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
L4GaugeImage::CreateL4GaugeImageStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
ResourceDescription::ResourceID
res_id = ResourceDescription::NullResourceID;
//----------------------------------------------------------------------
// Check to see if the model has a gauge image specified...
//----------------------------------------------------------------------
const char *gauge_filename;
if (model_file->GetEntry("gauge", "image", &gauge_filename) != 0)
{
//-------------------------------------------------------------
// It does, attempt to open the given notation file
//-------------------------------------------------------------
Tell("Opening gauge image " << gauge_filename << "\n");
char *gim_filename =
MakePathedFilename(directories->gaugeDirectory, gauge_filename);
Register_Pointer(gim_filename);
NotationFile
*gim_file = new NotationFile(gim_filename);
Check(gim_file);
Register_Object(gim_file);
//--------------------------------------------------------
// Search for the name of the .GAT file
//--------------------------------------------------------
const char
*gat_entry;
if (gim_file->GetEntry("object", "gatfile", &gat_entry) == 0)
{
DEBUG_STREAM << "Missing .gat specification!" << std::endl;
}
else
{
//-------------------------------------------------------------
// Create the GroupAttribute data
//-------------------------------------------------------------
char *gat_filename =
MakePathedFilename(directories->gaugeDirectory, gat_entry);
Register_Pointer(gat_filename);
if (GroupAttribute::Initialize(gat_filename))
{
//-------------------------------------------------------------
// Create a dynamic memory stream, write out the data
// (note: the call to L4GaugeImage::DynamicMemoryStreamWrite()
// internally calls the dynamic stream writes for all of the
// 'owned' sub-parts as well)
//-------------------------------------------------------------
DynamicMemoryStream
*gim_stream = new DynamicMemoryStream();
Check(gim_stream);
Register_Object(gim_stream);
if (
L4GaugeImage::MemoryStreamWrite(
gim_stream,
gim_file
) == True
)
{
//-------------------------------------------------------------
// Create the resource description, assign an ID
//-------------------------------------------------------------
ResourceDescription
*res_desc_stream =
resource_file->ResourceFile::AddResourceMemoryStream(
model_name,
ResourceDescription::GaugeImageStreamResourceType,
1,
ResourceDescription::Preload,
gim_stream
);
Check(res_desc_stream);
res_id = res_desc_stream->resourceID;
}
//-------------------------------------------------------------
// Release the GroupAttribute data
//-------------------------------------------------------------
GroupAttribute::Terminate();
Check(gim_stream);
Unregister_Object(gim_stream);
delete gim_stream;
}
Check_Pointer(gat_filename);
Unregister_Pointer(gat_filename);
delete gat_filename;
}
//-------------------------------------------------------------
// Release variables
//-------------------------------------------------------------
Check(gim_file);
Unregister_Object(gim_file);
delete gim_file;
Check_Pointer(gim_filename);
Unregister_Pointer(gim_filename);
delete gim_filename;
Tell("Closed gauge image\n" << std::flush);
}
//-------------------------------------------------------------
// Return the new ResourceID
//-------------------------------------------------------------
Test_Tell("res_id = " << res_id << "\n");
Check_Fpu();
return res_id;
}
Logical
L4GaugeImage::MemoryStreamWrite(
MemoryStream *mem_stream,
NotationFile *gim_file
)
{
Test_Tell(" L4GaugeImage::MemoryStreamWrite(" << mem_stream <<
", " << gim_file <<
")\n"
);
Check(mem_stream);
Check(gim_file);
int
i;
//-------------------------------------------------------------
// 'result' is set to False if an error occurs.
//-------------------------------------------------------------
Logical
result = True;
//-------------------------------------------------------------
// Write the vertices
//-------------------------------------------------------------
NameList
*vertex_list = gim_file->MakeEntryList("vertices");
if (vertex_list == NULL)
{
DEBUG_STREAM << "No 'vertices' page in the .GIM file!" << std::endl;
result = False;
}
else
{
Check(vertex_list);
Register_Object(vertex_list);
//-------------------------------------------------------------
// Get the number of vertices
//-------------------------------------------------------------
int
vertex_count = vertex_list->EntryCount();
Test_Tell("vertex_count = " << vertex_count << "\n");
if (vertex_count <= 0)
{
DEBUG_STREAM <<
"The 'vertices' page in the .GIM file has no entries!" <<std::endl;
result = False;
}
else
{
//-------------------------------------------------------------
// Write the number of vertices to the stream
//-------------------------------------------------------------
MemoryStream_Write(mem_stream, &vertex_count);
//-------------------------------------------------------------
// Write the vertices
//-------------------------------------------------------------
Point3D
point_3d;
NameList::Entry
*vertex_entry = vertex_list->GetFirstEntry();
for (int i=0; i<vertex_count; ++i)
{
Verify(vertex_entry != NULL);
Convert_From_Ascii(vertex_entry->GetChar(), &point_3d);
Test_Tell(" " << point_3d << "\n");
MemoryStream_Write(mem_stream, &point_3d);
vertex_entry = vertex_entry->GetNextEntry();
}
}
//-------------------------------------------------------------
// Delete the vertex list
//-------------------------------------------------------------
Check(vertex_list);
Unregister_Object(vertex_list);
delete vertex_list;
}
//-------------------------------------------------------------
// Write the levels of detail
//-------------------------------------------------------------
if (result == True)
{
NameList
*lod_namelist = gim_file->MakeEntryList("lods");
if (lod_namelist == NULL)
{
DEBUG_STREAM << "No 'lods' page in the .GIM file!" << std::endl;
result = False;
}
else
{
Check(lod_namelist);
Register_Object(lod_namelist);
//-------------------------------------------------------------
// Get the number of LOD's
//-------------------------------------------------------------
int
lod_count = lod_namelist->EntryCount();
Test_Tell("lod_count = " << lod_count << "\n");
if (lod_count <= 0)
{
DEBUG_STREAM <<
"The 'lod' page in the .GIM file has no entries!" << std::endl;
result = False;
}
else
{
//-------------------------------------------------------------
// Write the number of LOD's to the stream
//-------------------------------------------------------------
MemoryStream_Write(mem_stream, &lod_count);
//-------------------------------------------------------------
// Write the LOD scales
//-------------------------------------------------------------
NameList::Entry
*scale_entry;
Scalar
scale;
const char
*text;
scale_entry = lod_namelist->GetFirstEntry();
for (i=0; i<lod_count; ++i)
{
Verify(scale_entry != NULL);
text = scale_entry->GetChar();
if (text == NULL)
{
DEBUG_STREAM << "Missing scale value!" << std::endl;
result = False;
break;
}
scale = (Scalar) atof(text);
Test_Tell(" " << scale << "\n");
MemoryStream_Write(mem_stream, &scale);
scale_entry = scale_entry->GetNextEntry();
}
//-------------------------------------------------------------
// Write the LOD lists
//-------------------------------------------------------------
scale_entry = lod_namelist->GetFirstEntry();
for (i=0; i<lod_count; ++i)
{
Verify(scale_entry != NULL);
result = L4GaugeImageList::MemoryStreamWrite(
mem_stream,
gim_file,
scale_entry->GetName()
);
if (result == False)
{
break;
}
scale_entry = scale_entry->GetNextEntry();
}
}
}
//-------------------------------------------------------------
// Delete the LOD list
//-------------------------------------------------------------
Check(lod_namelist);
Unregister_Object(lod_namelist);
delete lod_namelist;
}
Check_Fpu();
return result;
}
void
L4GaugeImage::Draw(
Scalar LOD_value, // smaller = more detail (1.0 = 'normal')
Scalar scale_value, // metersPerPixel
GraphicsView *graphics_view,
int default_color,
AffineMatrix &localToView,
int boxed_color
)
{
Test_Tell(
"L4GaugeImage::Draw(" << scale_value <<
", " << graphics_view <<
", " << default_color <<
", " << localToView <<
", " << boxed_color <<
")\n"
);
Check(this);
Check(graphics_view);
// localToView allowed to be NULL
Check_Pointer(LODScales);
Check_Pointer(LODList);
# define VERTEX_ALLOTMENT 100 // HACK - I'm guessing this is big enough.
Verify(vertexCount <= VERTEX_ALLOTMENT);
static
Point3D
local_vertex_array[VERTEX_ALLOTMENT];
static
Logical
local_flag_array[VERTEX_ALLOTMENT];
int
lod_index;
if (localToView == NULL)
{
return;
}
//-------------------------------------------------------------
// Find LOD index
//-------------------------------------------------------------
for(lod_index=0; lod_index<LODCount; ++lod_index)
{
if (LOD_value <= LODScales[lod_index])
{
break;
}
}
//-------------------------------------------------------------
// Continue if the index is within range
//-------------------------------------------------------------
if (lod_index < LODCount)
{
//-------------------------------------------------------------
// Clear transformed vertex flag array
//-------------------------------------------------------------
Logical
*flag_pointer = &local_flag_array[0];
int
i;
for(i=0; i<vertexCount; ++i)
{
*flag_pointer++ = False;
}
//-------------------------------------------------------------
// Draw LODList item
//-------------------------------------------------------------
Check(LODList[lod_index]);
LODList[lod_index]->Draw(
graphics_view,
default_color,
localToView,
vertexArray,
local_vertex_array,
local_flag_array,
scale_value,
boxed_color
);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Instance
//
Logical
L4GaugeImage::TestInstance() const
{
return True;
}
//############################################################################
// L4GaugeImageList
//############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
L4GaugeImageList::L4GaugeImageList(MemoryStream *mem_stream)
{
Test_Tell("L4GaugeImageList::L4GaugeImageList\n");
Check_Pointer(this);
Check(mem_stream);
int
i;
//-------------------------------------------------------------
// Read the number of primitives from the stream
//-------------------------------------------------------------
MemoryStream_Read(mem_stream, &primitiveCount);
Verify(primitiveCount > 0);
//-------------------------------------------------------------
// Allocate the primitive list
//-------------------------------------------------------------
primitiveList = new L4GaugeImagePrimitive*[primitiveCount];
Check_Pointer(primitiveList);
Register_Pointer(primitiveList);
//-------------------------------------------------------------
// Read the primitives
//-------------------------------------------------------------
for(i=0; i<primitiveCount; ++i)
{
primitiveList[i] = new L4GaugeImagePrimitive(mem_stream);
Check(primitiveList[i]);
Register_Object(primitiveList[i]);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4GaugeImageList::~L4GaugeImageList()
{
Test_Tell("L4GaugeImageList::~L4GaugeImageList\n");
Check(this);
Check_Pointer(primitiveList);
int
i;
for(i=0; i<primitiveCount; ++i)
{
Check(primitiveList[i]);
Unregister_Object(primitiveList[i]);
delete primitiveList[i];
}
Unregister_Pointer(primitiveList);
delete[] primitiveList;
Check_Fpu();
}
Logical
L4GaugeImageList::MemoryStreamWrite(
MemoryStream *mem_stream,
NotationFile *gim_file,
const char *page_name
)
{
Test_Tell(" L4GaugeImageList::MemoryStreamWrite(" << mem_stream <<
", " << gim_file <<
", " << page_name <<
")\n"
);
Check(mem_stream);
Check(gim_file);
int
i;
Logical
result = True;
NameList
*primitive_list = gim_file->MakeEntryList(page_name);
if (primitive_list == NULL)
{
DEBUG_STREAM << "Can't find the '" << page_name << "' page in the .GIM file!"
<< std::endl;
result = False;
}
else
{
Check(primitive_list);
Register_Object(primitive_list);
//-------------------------------------------------------------
// Get the number of primitives
//-------------------------------------------------------------
int
primitive_count = primitive_list->EntryCount();
Test_Tell(" primitive_count = " << primitive_count << "\n");
if (primitive_count <= 0)
{
DEBUG_STREAM << "The '"<<page_name<<"' page in the .GIM file has no entries!"
<< std::endl;
result = False;
}
else
{
//-------------------------------------------------------------
// Write the number of primitives to the stream
//-------------------------------------------------------------
MemoryStream_Write(mem_stream, &primitive_count);
//-------------------------------------------------------------
// Write the primitives
//-------------------------------------------------------------
NameList::Entry
*primitive_entry = primitive_list->GetFirstEntry();
for (i=0; i<primitive_count; ++i)
{
Verify(primitive_entry != NULL);
result = L4GaugeImagePrimitive::MemoryStreamWrite(
mem_stream,
primitive_entry->GetName(),
primitive_entry->GetChar()
);
if (result == False)
{
break;
}
primitive_entry = primitive_entry->GetNextEntry();
}
}
//-------------------------------------------------------------
// Delete the primitive list
//-------------------------------------------------------------
Check(primitive_list);
Unregister_Object(primitive_list);
delete primitive_list;
}
Check_Fpu();
return result;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Support
//
Logical
L4GaugeImageList::TestInstance() const
{
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
L4GaugeImageList::Draw(
GraphicsView *graphics_view,
int default_color,
AffineMatrix &localToView,
Point3D *untransformed_vertex_array,
Point3D *transformed_vertex_array,
Logical *transformed_flag_array,
Scalar scale_factor,
int boxed_color
)
{
Test_Tell(
"L4GaugeImageList::Draw(" << graphics_view <<
", " << default_color <<
", " << localToView <<
", " << untransformed_vertex_array <<
", " << transformed_vertex_array <<
", " << transformed_flag_array <<
", " << scale_factor <<
", " << boxed_color <<
")\n"
);
Check(this);
Check(graphics_view);
Check(&localToView);
Check_Pointer(untransformed_vertex_array);
Check_Pointer(transformed_vertex_array);
Check_Pointer(transformed_flag_array);
Check_Pointer(primitiveList);
int
i;
L4GaugeImagePrimitive
**array_pointer = primitiveList;
if (boxed_color != 0)
{
//--------------------------------------------------------
// Initialize bounding box
//--------------------------------------------------------
Rectangle2D
bounds(9999,9999,-9999,-9999);
//--------------------------------------------------------
// Draw primitives, collect bounding data
//--------------------------------------------------------
for(i=0; i<primitiveCount; ++i)
{
Test_Tell("List #" << i << " of " << primitiveCount << "\n");
Check(*array_pointer);
(*array_pointer++)->Draw(
graphics_view,
default_color,
localToView,
untransformed_vertex_array,
transformed_vertex_array,
transformed_flag_array,
scale_factor,
&bounds
);
}
//--------------------------------------------------------
// Draw the bounding box
//--------------------------------------------------------
graphics_view->SetColor(boxed_color);
graphics_view->MoveToAbsolute(
bounds.bottomLeft.x-4,
bounds.bottomLeft.y-4
);
graphics_view->DrawRectangleToAbsolute(
bounds.topRight.x+4,
bounds.topRight.y+4
);
}
else
{
//--------------------------------------------------------
// Just draw it
//--------------------------------------------------------
for(i=0; i<primitiveCount; ++i)
{
Test_Tell("List #" << i << " of " << primitiveCount << "\n");
Check(*array_pointer);
(*array_pointer++)->Draw(
graphics_view,
default_color,
localToView,
untransformed_vertex_array,
transformed_vertex_array,
transformed_flag_array,
scale_factor,
NULL
);
}
}
Check_Fpu();
}
//############################################################################
// L4GaugeImagePrimitive
//############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
L4GaugeImagePrimitive::L4GaugeImagePrimitive(MemoryStream *mem_stream)
{
Test_Tell("L4GaugeImagePrimitive::L4GaugeImagePrimitive\n");
Check_Pointer(this);
Check(mem_stream);
int
i,
n;
//--------------------------------------------------------------
// Read the primitive type ID, use the input stream accordingly
//--------------------------------------------------------------
MemoryStream_Read(mem_stream, &n);
type = (primitiveType) n;
switch(type)
{
case primitiveVector:
Test_Tell(" primitiveVector\n");
//--------------------------------------------------------
// Read the attribute and color
//--------------------------------------------------------
MemoryStream_Read(mem_stream, &color);
MemoryStream_Read(mem_stream, &attributes);
Test_Tell(" color = " << color << "\n");
Test_Tell(" attributes = " << std::hex << attributes << std::dec << "\n");
//--------------------------------------------------------
// Read the vertex index count
//--------------------------------------------------------
MemoryStream_Read(mem_stream, &data.vector.indexCount);
Test_Tell(" indexCount = " << data.vector.indexCount << "\n");
Verify(data.vector.indexCount > 0);
//--------------------------------------------------------
// Allocate the index table
//--------------------------------------------------------
data.vector.indexList = new int[data.vector.indexCount];
Check_Pointer(data.vector.indexList);
Register_Pointer(data.vector.indexList);
//--------------------------------------------------------
// Read the indices
//--------------------------------------------------------
for(i=0; i<data.vector.indexCount; ++i)
{
MemoryStream_Read(mem_stream, &data.vector.indexList[i]);
Test_Tell(" " << data.vector.indexList[i] << "\n");
}
break;
default:
Warn(
"L4GaugeImagePrimitive::L4GaugeImagePrimitive: Evil type_id!");
break;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4GaugeImagePrimitive::~L4GaugeImagePrimitive()
{
Test_Tell("L4GaugeImagePrimitive destructor\n");
Check(this);
switch(type)
{
case primitiveVector:
Check_Pointer(data.vector.indexList);
Unregister_Pointer(data.vector.indexList);
delete[] data.vector.indexList;
break;
default:
Warn("L4GaugeImagePrimitive::~L4GaugeImagePrimitive: Evil type_id!");
break;
}
Check_Fpu();
}
Logical
L4GaugeImagePrimitive::MemoryStreamWrite(
MemoryStream *mem_stream,
const char *type_name,
const char *data
)
{
Test_Tell("L4GaugeImagePrimitive::MemoryStreamWrite(" <<mem_stream<<
", " << type_name <<
", " << data <<
")\n"
);
Check(mem_stream);
Check_Pointer(type_name);
Check_Pointer(data);
# define MAX_INDICES 64
int
i,
type_number,
attribute_value = 0,
color_value = 0,
index[MAX_INDICES],
index_count = 0;
Logical
result = True;
//--------------------------------------------------------
// LINELIST primitive
//--------------------------------------------------------
if (stricmp(type_name, "linelist") == 0)
{
Test_Tell(" LINELIST\n");
//--------------------------------------------------------
// Write the primitive type ID
//--------------------------------------------------------
type_number = L4GaugeImagePrimitive::primitiveVector;
MemoryStream_Write(mem_stream, &type_number);
//--------------------------------------------------------
// Parse vertices (which start with 'v')
// and parse attributes (which start with 'a')
//--------------------------------------------------------
const char
*scan = data;
# if (DEBUG_LEVEL > 0)
int
check_length = strlen(data)+1;
# endif
while(*scan != '\0')
{
Verify((scan-data) < check_length);
//--------------------------------------------------------
// Skip white space
//--------------------------------------------------------
while (isspace(*scan))
{
++scan;
}
//--------------------------------------------------------
// Parse non-space string
//--------------------------------------------------------
if (*scan == 'v')
{
int
n;
//--------------------------------------------------------
// Convert to value, save in array
//--------------------------------------------------------
++scan; // ignore 'v'
for(n=0; isdigit(*scan); ++scan)
{
n = (n*10) + (*scan - '0');
}
Test_Tell(" " << n << "\n");
if (index_count < MAX_INDICES)
{
index[index_count++] = n;
}
}
else if (*scan == 'a')
{
char
buffer[64],
*dest;
//--------------------------------------------------------
// Collect the name
//--------------------------------------------------------
for(
i=0, dest=buffer;
i<(sizeof(buffer)-1);
++i,++scan,++dest
)
{
if (isspace(*scan))
{
break;
}
if (*scan == '\0')
{
break;
}
*dest = *scan;
}
*dest = '\0';
//--------------------------------------------------------
// Search for the name
//--------------------------------------------------------
if (
GroupAttribute::Search(
buffer,
&color_value,
&attribute_value
) == False
)
{
DEBUG_STREAM << "Couldn't find attribute group '" <<
buffer << "'!" << std::endl;
}
}
}
//--------------------------------------------------------
// Write the attributes
//--------------------------------------------------------
Test_Tell(" color=" << color_value << "\n");
MemoryStream_Write(mem_stream, &color_value);
Test_Tell(" attribute=" << attribute_value << "\n");
MemoryStream_Write(mem_stream, &attribute_value);
//--------------------------------------------------------
// Write the vertex index count
//--------------------------------------------------------
if (index_count == 0)
{
DEBUG_STREAM << "No vertex indices in primitive!" << std::endl;
result = False;
}
else
{
Test_Tell(" index_count=" << index_count << "\n");
MemoryStream_Write(mem_stream, &index_count);
//--------------------------------------------------------
// Write the indices
//--------------------------------------------------------
for(i=0; i < index_count; ++i)
{
MemoryStream_Write(mem_stream, &index[i]);
}
}
}
else
{
DEBUG_STREAM << "Unsupported primitive ("<< type_name << ") in .GIM file!"
<< std::endl;
result = False;
}
Check_Fpu();
return result;
}
//============================================================================
// TestInstance
//============================================================================
Logical
L4GaugeImagePrimitive::TestInstance() const
{
return True;
}
//============================================================================
// Draw
//============================================================================
void
L4GaugeImagePrimitive::Draw(
GraphicsView *graphics_view,
int default_color,
AffineMatrix &localToView,
Point3D *untransformed_vertex_array,
Point3D *transformed_vertex_array,
Logical *transformed_flag_array,
Scalar scale_factor,
Rectangle2D *bounds
)
{
Test_Tell(
"L4GaugeImagePrimitive::Draw(" << graphics_view <<
", " << default_color <<
", " << localToView <<
", " << untransformed_vertex_array <<
", " << transformed_vertex_array <<
", " << transformed_flag_array <<
", " << scale_factor <<
", " << bounds <<
")\n"
);
Check(this);
Check(graphics_view);
Check(&localToView);
Check_Pointer(untransformed_vertex_array);
Check_Pointer(transformed_vertex_array);
Check_Pointer(transformed_flag_array);
//-----------------------------------------------
// Draw primitive
//-----------------------------------------------
switch(type)
{
case primitiveVector:
if (data.vector.indexCount > 1)
{
//-----------------------------------------------
// Set color
//-----------------------------------------------
if (color != 0)
{
default_color = color;
}
graphics_view->SetColor(default_color);
int
i,
*index_pointer(data.vector.indexList),
index;
Point3D
*dest;
//-----------------------------------------------
// Move to starting point
//-----------------------------------------------
index = *index_pointer++;
dest = &transformed_vertex_array[index];
TransformVertex(
localToView,
untransformed_vertex_array[index],
dest,
transformed_flag_array[index],
scale_factor,
bounds
);
Test_Tell("Start at " << index << "=" << *dest << "\n");
graphics_view->MoveToAbsolute((int)dest->x,(int)dest->z);
//-----------------------------------------------
// Draw subsequent lines
//-----------------------------------------------
for(i=data.vector.indexCount-1; i>0; --i)
{
index = *index_pointer++;
dest = &transformed_vertex_array[index];
TransformVertex(
localToView,
untransformed_vertex_array[index],
dest,
transformed_flag_array[index],
scale_factor,
bounds
);
Test_Tell("Draw to " << index << "=" << *dest << "\n");
graphics_view->DrawLineToAbsolute((int)(dest->x),(int)(dest->z));
}
}
break;
default:
Warn("L4GaugeImagePrimitive::Draw: Evil type_id!");
break;
}
Check_Fpu();
}
void
L4GaugeImagePrimitive::TransformVertex(
AffineMatrix &local_to_view,
Point3D &untransformed_vertex,
Point3D *transformed_vertex,
Logical &transformed_flag,
Scalar scale_factor,
Rectangle2D *bounds
)
{
Check(this);
Check_Pointer(transformed_vertex);
//-----------------------------------------
// Transform only if not already done
//-----------------------------------------
if (! transformed_flag)
{
if (attributes & attributeUnscaled)
{
//-----------------------------------------
// Unscaled: pre-multiply by scaling factor
//-----------------------------------------
Point3D
temp;
temp = untransformed_vertex;
temp *= scale_factor;
Check_Fpu();
transformed_vertex->Multiply(
temp,
local_to_view
);
Check_Fpu();
}
else
{
//-----------------------------------------
// Normally scaled: transform the vertex
//-----------------------------------------
transformed_vertex->Multiply(
untransformed_vertex,
local_to_view
);
Check_Fpu();
}
//-----------------------------------------
// Round, and fix 'y' sign
//-----------------------------------------
transformed_vertex->x += .5;
transformed_vertex->z = -transformed_vertex->z + .5;
//-----------------------------------------------
// Set the 'transformed' flag
//-----------------------------------------------
transformed_flag = True;
}
//-----------------------------------------------
// Accumulate bounds
//-----------------------------------------------
if (bounds != NULL)
{
if (transformed_vertex->x < bounds->bottomLeft.x)
{
bounds->bottomLeft.x = transformed_vertex->x;
}
if (transformed_vertex->x > bounds->topRight.x)
{
bounds->topRight.x = transformed_vertex->x;
}
if (transformed_vertex->z < bounds->bottomLeft.y)
{
bounds->bottomLeft.y = transformed_vertex->z;
}
if (transformed_vertex->z > bounds->topRight.y)
{
bounds->topRight.y = transformed_vertex->z;
}
}
Check_Fpu();
}