Initial revision.

This commit is contained in:
curt
2002-09-13 20:29:04 +00:00
parent 6d79582890
commit 01113e82f3
68 changed files with 16414 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
includedir = @includedir@/sky
lib_LIBRARIES = libsgcloud3d.a
include_HEADERS = \
SkySceneLoader.hpp \
SkyUtil.hpp
libsgcloud3d_a_SOURCES = \
vec3fv.cpp \
mat16fv.cpp \
tri.cpp \
plane.cpp \
camera.cpp \
camutils.cpp \
minmaxbox.cpp \
SkyMinMaxBox.cpp \
SkyLight.cpp \
SkyMaterial.cpp \
SkyTextureManager.cpp \
SkyTextureState.cpp \
SkyDynamicTextureManager.cpp \
SkyRenderableInstanceCloud.cpp \
SkyRenderableInstanceGroup.cpp \
SkyCloud.cpp \
SkyArchive.cpp \
SkyUtil.cpp \
SkyContext.cpp \
SkySceneManager.cpp \
SkySceneLoader.cpp

View File

@@ -0,0 +1,19 @@
//============================================================================
// File : SkyAABBTree.hpp
//
// Author : Wesley Hunt
//
// Content : axis-aligned bounding box tree
//
//============================================================================
#ifndef __SKYAABBTREE_HPP__
#define __SKYAABBTREE_HPP__
#include "SkyBVTree.hpp"
#include "SkyBVTreeSplitter.hpp"
template <class object>
class SkyAABBTree : public SkyBVTree<object, SkyMinMaxBox, SkyAABBTreeSplitter<object> >
{};
#endif //__SKYAABBTREE_HPP__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
//------------------------------------------------------------------------------
// File : SkyArchive.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyArchive.hpp
*
* A hierarchical archive Class for storing data.
*/
#ifndef __SKYARCHIVE_HPP__
#define __SKYARCHIVE_HPP__
#pragma warning( disable : 4786 )
#include "vec2f.hpp"
#include "vec3f.hpp"
#include "vec4f.hpp"
#include "SkyUtil.hpp"
#include <map> // for std::multimap
//! Types supported by the archive system
enum SkyArchiveTypeCode
{
BOOL_TYPE,
INT8_TYPE,
INT16_TYPE,
INT32_TYPE,
UINT8_TYPE,
UINT16_TYPE,
UINT32_TYPE,
FLOAT32_TYPE,
FLOAT64_TYPE,
STRING_TYPE,
VEC2F_TYPE,
VEC3F_TYPE,
VEC4F_TYPE,
ARCHIVE_TYPE,
ANY_TYPE,
NULL_TYPE
};
struct SkyArchiveEntry;
struct StringLessFunctor
{
bool operator() (const char* p1, const char* p2) const
{
return ::strcmp( p1, p2) < 0;
}
};
//============================================================================
//
// Class : SkyArchive
//
//! A simple hierarchical archive file useful for loading and saving data.
//
/*! SkyArchive bundles information so that an application can store,
manipulate, and retrieve data in a storage-independent manner. Information
stored in an SkyArchive file can be modified without breaking
compatibility with the code that retrieves the data. In essence, it can be
thought of as a very basic database mechanism.
A SkyArchive is simply a container. The class defines methods that allow
you to put information in a SkyArchive, determine the information in a
SkyArchive, and retrieve information from a SkyArchive. It's important
to note that the SkyArchive is a recursive storage mechanism; a
SkyArchive itself can hold one or more other SkyArchives.
Data are added to an archive in fields. The datum in a field is associated
with a name, number of bytes, and a type code. The name can be anything you
choose and is not required to be unique. The number of bytes must be accurate.
The type code must be one of the SkyArchiveTypeCode enums. Several of the Add
functions have been specialized for the common base types. It isn't necessary
to provide the number of bytes when using the specialized functions, since it can be
inferred from the type code.
The functions that retrieve fields from an archive are similar to the ones
that add data, only their roles are reversed. As with the Add functions,
there are several specialized functions for the common base types while
custom information can be retrieved using the generic FindData function.
Querying the contents of an archive is provided through the GetInfo
functions. These functions are important as they allow you to write
code that can intelligently determine how to retrieve information at
run-time: you no longer have to hardcode the order in which you retrieve
data from your files.
archive data fields are held in using an STL multimap. The multimap key
is a QString (field name) and the data is held in a SkyArchiveEntry
structure (see SkyArchive.cpp for details of this structure).
The fields are stored in alphabetical order based on the key names.
*/
class SkyArchive
{
public:
//=========================================================================
// Creation & Destruction
//=========================================================================
// Empty archive: no name, no data fields.
SkyArchive();
// Creates a named archive with no data fields.
SkyArchive( const char* pName);
// Deep copy the contents of one archive to another.
SkyArchive( const SkyArchive& src);
// Deep copy the contents of one archive to another.
SkyArchive& operator=( const SkyArchive& src);
~SkyArchive();
//=========================================================================
// Basic SkyArchive Information
//=========================================================================
// Returns true if the archive contains no data fields.
bool IsEmpty() const;
//! Returns the archive's name.
const char* GetName() const { return _pName; };
//=========================================================================
// Adding Content to SkyArchive
//=========================================================================
// Adds a new datafield to the archive.
SKYRESULT AddData(const char* pName,
SkyArchiveTypeCode eType,
const void* pData,
unsigned int iNumBytes,
unsigned int iNumItems = 1);
SKYRESULT AddBool( const char* pName, bool aBool);
SKYRESULT AddInt8( const char* pName, char anInt8);
SKYRESULT AddInt16( const char* pName, short anInt16);
SKYRESULT AddInt32( const char* pName, int anInt32);
SKYRESULT AddUInt8( const char* pName, unsigned char anUInt8);
SKYRESULT AddUInt16( const char* pName, unsigned short anUInt16);
SKYRESULT AddUInt32( const char* pName, unsigned int anUInt32);
SKYRESULT AddFloat32( const char* pName, float aFloat32);
SKYRESULT AddFloat64( const char* pName, double aFloat64);
SKYRESULT AddString( const char* pName, const char* pString);
SKYRESULT AddArchive( const SkyArchive& anArchive);
// Vector types (MJH:: only supports float versions for now!!!)
SKYRESULT AddVec2f( const char* pName, const Vec2f& aPoint2f);
SKYRESULT AddVec3f( const char* pName, const Vec3f& aPoint3f);
SKYRESULT AddVec4f( const char* pName, const Vec4f& aPoint4f);
//=========================================================================
// Retrieving Content from SkyArchive
//=========================================================================
// Retrieves the specified datafield the archive, if it exists.
SKYRESULT FindData( const char* pName,
SkyArchiveTypeCode eType,
void** const pData,
unsigned int* pNumBytes,
unsigned int index = 0) const;
SKYRESULT FindBool( const char* pName, bool* pBool, unsigned int index = 0) const;
SKYRESULT FindInt8( const char* pName, char* pInt8, unsigned int index = 0) const;
SKYRESULT FindInt16( const char* pName, short* pInt16, unsigned int index = 0) const;
SKYRESULT FindInt32( const char* pName, int* pInt32, unsigned int index = 0) const;
SKYRESULT FindUInt8( const char* pName, unsigned char* pUInt8, unsigned int index = 0) const;
SKYRESULT FindUInt16( const char* pName, unsigned short* pUInt16, unsigned int index = 0) const;
SKYRESULT FindUInt32( const char* pName, unsigned int* pUInt32, unsigned int index = 0) const;
SKYRESULT FindFloat32(const char* pName, float* pFloat32, unsigned int index = 0) const;
SKYRESULT FindFloat64(const char* pName, double* pFloat64, unsigned int index = 0) const;
SKYRESULT FindString( const char* pName, char** const pString, unsigned int index = 0) const;
SKYRESULT FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index = 0) const;
SKYRESULT FindVec2f( const char* pName, Vec2f* pVec2f, unsigned int index = 0) const;
SKYRESULT FindVec3f( const char* pName, Vec3f* pVec3f, unsigned int index = 0) const;
SKYRESULT FindVec4f( const char* pName, Vec4f* pVec4f, unsigned int index = 0) const;
SKYRESULT AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index = 0) const;
//=========================================================================
// Querying Contents of SkyArchive
//=========================================================================
// Computes the number of fields that contain the given name and type.
SKYRESULT GetInfo(const char* pName,
SkyArchiveTypeCode eType,
unsigned int* pNumFound = NULL) const;
// Returns information about the key at the specified index.
SKYRESULT GetInfo(unsigned int iNameIndex,
char** pNameFound,
SkyArchiveTypeCode* pTypeCode,
unsigned int* pNumFound);
// Computes the number of unique key names in _dataTableable.
unsigned int GetNumUniqueNames() const;
// Remove the contents of the SkyArchive.
SKYRESULT MakeEmpty();
// Loads the contents from a file.
SKYRESULT Load(const char* pFileName);
// Commits the contents of a SkyArchive to file storage.
SKYRESULT Save(const char* pFileName) const;
private:
char* _pName; // this archive's name
//=========================================================================
// Data storage
//=========================================================================
typedef std::multimap<char*, SkyArchiveEntry*, StringLessFunctor> SkyArchiveMMap;
typedef SkyArchiveMMap::const_iterator SkyMMapConstIter;
typedef SkyArchiveMMap::iterator SkyMMapIter;
SkyArchiveMMap _dataTable; // this is where the data reside.
// Performs a deep-copy of one archive's archive_mmap_t to another.
void _CopyDataTable( const SkyArchiveMMap& src);
// Locates an archive entry in _dataTable
const SkyArchiveEntry* _FindEntry( const char* pName,
unsigned int index,
SkyArchiveTypeCode eType) const;
// Saves the archive to a file stream.
SKYRESULT _Save(FILE* pDestFile) const;
// Initializes the archive from a file stream.
SKYRESULT _Load(FILE* pSrcFile);
};
#endif //__SKYARCHIVE_HPP__

View File

@@ -0,0 +1,297 @@
//------------------------------------------------------------------------------
// File : SkyBVTree.hpp
//------------------------------------------------------------------------------
// Empyrean / SkyWorks : Copyright 2002 Mark J. Harris
//------------------------------------------------------------------------------
/**
* @file SkyBVTree.hpp
*
* This source was written by Wesley Hunt. Many thanks to him for providing it.
*/
//-----------------------------------------------------------------------------
// SkyBVTree.hpp
//
// Author: Wesley Hunt (hunt@cs.unc.edu)
// Date: 2000/12/19
//-----------------------------------------------------------------------------
// Overview
// --------
// declare an SkyBVTree with whatever object type and bounding volume type you
// want. The hard part is to pass in a NodeSplitter class that determines how
// to split a node up. See below for a description of its requirements.
// Finally, use that tree like so:
// * BeginTree()
// * AddObject(Object, ObjectBV)
// * ...
// * EndTree()
// < Do whatever you want with GetRoot() >
// < Use GetLeftChild() and GetRightChild() to traverse the nodes >
//
// The class hierarchy is designed for a flexible, simple public interface.
// This pushes some extra complexity into the class hierarchy, but there are two
// main advantages to the final approach:
// 1. There are no interface requirements for the Object and BoundingVolume
// template parameters. This means you don't have to modify your existing
// class interfaces to use them with the tree.
// 2. All the dependent logic for dealing with the bounding volumes is pushed
// into the NodeSplitter class. So there is one centralized location for
// adapting your bounding volume classes to work with the tree. See the
// description of the NodeSplitter template requirements for more details.
//
// Class Descriptions
// ------------------
//
// SkyBaseBVTree
// -------------
// declares the node class that the tree holds. It exposes
// the public functions of the nodes and defines protected accessors that
// the derived tree class can use to manipulate nodes and build the tree.
//
// Node
// ----
// This is the class that gives access to the tree. You can access each
// object and bounding volume owned by a node, along with that node's
// children.
//
// NodeObject
// ----------------
// An aggregation of an object and its associated bounding volume.
// Each node in the tree essentially owns an array of NodeObjects. This
// array is passed to the NodeSplitter class to allow it to examine a
// node's contained objects before making a decision on how to split the
// node up.
//
// SkyBVTree
// ---------
// The main tree class. To use it, supply and object type, a bounding volume
// type, and a NodeSplitter class that is used to split the nodes up during
// tree construction.
//
// Template class requirements
// ---------------------------
//
// Object
// ------
// None
//
// BoundingVolume
// --------------
// None
//
// NodeSplitter
// ------------
// This is the user-supplied class that decides how to split a node during
// tree construction. It is given an array of NodeObjects that the node owns and
// is responsible for determining the node's bounding volume as well as how to
// split the node up into left and right children.
// The required API is as follows:
//
// * a constructor that takes an array of NodeObject and an unsigned int giving
// the size of the array. These are the objects owned by the node to be split.
// * a method GetNodeBV() that returns the BoundingVolume of the node.
// Typically this is the union of the bounding volumes of the objects owned
// by the node.
// * A unary function operator used to partition the objects in the node. The
// operator must take a single NodeObject as a parameter and return as
// a bool whether to place the NodeObject in the left or right child.
// Basically, it should be compatible with std::partition using NodeObjects.
// * A binary function operator used to sort the objects. If a partition fails,
// the nodes are then sorted based on this function and half are sent to each child.
// This operator must define a total ordering of the NodeObjects.
// Basically, it should be compatible with std::sort using NodeObjects.
//
// Example:
// struct NodeSplitter
// {
// NodeSplitter(const NodeObject* objs, unsigned int numObjs);
// BoundingVolume& GetNodeBV() const;
// // Partition predicate
// bool operator()(const NodeObject& obj) const;
// // Sort predicate
// bool operator()(const NodeObject& obj1, const NodeObject& obj2) const;
// };
//
//-----------------------------------------------------------------------------
#ifndef __SKYBVTREE_HPP__
#define __SKYBVTREE_HPP__
#include <algorithm>
#include <vector>
//-----------------------------------------------------------------------------
// SkyBaseBVTree<Object, BoundingVolume>
//-----------------------------------------------------------------------------
// See header description for details.
//-----------------------------------------------------------------------------
template <class Object, class BoundingVolume>
class SkyBaseBVTree
{
public:
typedef BoundingVolume BV;
class NodeObject;
public:
class Node
{
friend class SkyBaseBVTree<Object, BoundingVolume>;
public:
Node() : _pObjs(NULL), _iNumObjs(0) {}
Node(NodeObject* pObjs, unsigned int iNumObjs) : _pObjs(pObjs), _iNumObjs(iNumObjs) {}
// Public interface
const Object& GetObj(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetObj(); }
const BV& GetBV(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetBV(); }
unsigned int GetNumObjs() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs; }
const BV& GetNodeBV() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _volume; }
const Node* GetLeftChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+1; }
const Node* GetRightChild() const { assert(_iNumObjs != 0 && _pObjs != NULL); return this+(GetLeftChild()->GetNumObjs()<<1); }
bool IsLeaf() const { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs == 1; }
private:
// List of Objects owned by the node
NodeObject *_pObjs;
unsigned int _iNumObjs;
BV _volume;
};
public:
class NodeObject
{
public:
NodeObject(const Object& o, const BV& v) : _obj(o), _volume(v) {}
const Object& GetObj() const { return _obj; }
const BV& GetBV() const { return _volume; }
private:
Object _obj;
BV _volume;
};
protected:
// Give non-const access to the node for descendant classes to build the tree
BV& GetNodeBV(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_volume; }
Node* GetLeftChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+1; }
Node* GetRightChild(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+(GetLeftChild(pNode)->GetNumObjs()<<1); }
NodeObject* GetObjs(Node* pNode) { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_pObjs; }
// Links a node's children by assigning the given number of objects to each child
// assumes the node has already had it's objects partitioned
void LinkNodeChildren(Node* pNode, unsigned int iLeftNumObjs)
{
assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL);
GetLeftChild(pNode)->_pObjs = pNode->_pObjs;
GetLeftChild(pNode)->_iNumObjs = iLeftNumObjs;
GetRightChild(pNode)->_pObjs = pNode->_pObjs + iLeftNumObjs;
GetRightChild(pNode)->_iNumObjs = pNode->_iNumObjs - iLeftNumObjs;
}
};
//------------------------------------------------------------------------------
// Function : ClearVector
// Description :
//------------------------------------------------------------------------------
/**
* @fn ClearVector(std::vector<T>& vec)
* @brief This utility function uses the std::vector::swap trick to free the memory of a vector
*
* This is necessary since clear() doesn't actually free anything.
*/
template<class T>
void ClearVector(std::vector<T>& vec)
{
std::vector<T>().swap(vec);
}
//-----------------------------------------------------------------------------
// SkyBVTree<Object, BoundingVolume, NodeSplitter>
//-----------------------------------------------------------------------------
// See header description for details.
//-----------------------------------------------------------------------------
template <class Object, class BoundingVolume, class NodeSplitter>
class SkyBVTree : public SkyBaseBVTree<Object, BoundingVolume>
{
public:
typedef SkyBaseBVTree<Object, BoundingVolume> BaseTree;
typedef BaseTree::BV BV;
typedef BaseTree::NodeObject NodeObject;
typedef BaseTree::Node Node;
void Clear()
{
BeginTree();
}
void BeginTree(unsigned int iNumObjs = 0)
{
ClearVector(_objList);
ClearVector(_nodes);
if (iNumObjs > 0) _objList.reserve(iNumObjs);
}
void AddObject(const Object &obj, const BV& volume)
{
_objList.push_back(NodeObject(obj, volume));
}
void EndTree()
{
if (_objList.size() == 0) return;
// Initialize the root node with all the objects
_nodes.push_back(Node(&_objList[0], _objList.size()));
// create room for the other nodes. They are initialized in BuildTree().
_nodes.reserve(_objList.size()*2-1);
_nodes.resize(_objList.size()*2-1);
BuildTree(&_nodes[0]);
}
const Node *GetRoot() const { return _nodes.empty() ? NULL : &_nodes[0]; }
// Memory usage info
unsigned int CalcMemUsage() const
{
unsigned int usage = 0;
usage += sizeof(*this);
usage += _objList.capacity() * sizeof(_objList[0]);
usage += _nodes.capacity() * sizeof(_nodes[0]);
return usage;
}
public:
private:
// Does the real work
void BuildTree(Node *pCurNode)
{
int iLeftNumObjs;
{
// Initialize the node splitter with the current node
NodeSplitter splitter(GetObjs(pCurNode), pCurNode->GetNumObjs());
// set the node's bounding volume using the splitter
GetNodeBV(pCurNode) = splitter.GetNodeBV();
// When a node has one object we can stop
if (pCurNode->GetNumObjs() == 1) return;
// Try and partition the objects
iLeftNumObjs = std::partition(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter) - GetObjs(pCurNode);
if ((iLeftNumObjs == 0) || (iLeftNumObjs == pCurNode->GetNumObjs()))
{
// Partition failed. Sort and split again to force a complete tree
std::sort(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter);
iLeftNumObjs = pCurNode->GetNumObjs() / 2;
}
}
LinkNodeChildren(pCurNode, iLeftNumObjs);
BuildTree(GetLeftChild(pCurNode));
BuildTree(GetRightChild(pCurNode));
}
std::vector<Node> _nodes;
std::vector<NodeObject> _objList;
};
#endif //__SKYBVTREE_HPP__

View File

@@ -0,0 +1,242 @@
//============================================================================
// File : SkyBVTreeSplitter.hpp
//
// Author : Wesley Hunt
//
// Content : NodeSplitter classes for SkyBVTrees using SkyBoundingBox or
// SkyBoundingSphere (not implemented).
//
//============================================================================
#ifndef __SKYBVTREESPLITTER_HPP__
#define __SKYBVTREESPLITTER_HPP__
//----------------------------------------------------------------------------
//-- Includes ----------------------------------------------------------------
//----------------------------------------------------------------------------
#include "SkyBVTree.hpp"
#include "SkyMinMaxBox.hpp"
//#include <Mlx/MlxBoundingSphere.hpp>
//#if _MSC_VER == 1200
//#include <Auxlib/AuxCompileTimeChecker.hpp>
//#endif
//----------------------------------------------------------------------------
//-- Forward Declarations ----------------------------------------------------
//----------------------------------------------------------------------------
// A strategy for splitting nodes compatible with bounding boxes and spheres.
template<class Object> class SkyBoundingBoxSplitter;
// SkyBVTree compatible node splitters implemented using the above strategy.
template<class Object> class SkyAABBTreeSplitter;
//template<class Object> class SkySphereTreeSplitter;
//----------------------------------------------------------------------------
//-- Defines, Constants, Enumerated Types ------------------------------------
//----------------------------------------------------------------------------
const float rLongObjectPercentageTolerance = 0.75f;
//----------------------------------------------------------------------------
// SkyBoundingBoxSplitter
//----------------------------------------------------------------------------
// This class defines a NodeSplitter strategy that has the functionality
// required by SkyBVTree's NodeSplitter template class. Can be used with
// SkyMinMaxBox and SkyBoundingSphere.
//
// It defines a two-tiered split strategy:
//
// * First it tries to separate large objects from any smaller objects.
// * If there are no large objects, it splits along the midpoint of the longest
// axis defined by the objects.
// * Finally, if all else fails, it defines a total ordering along the longest
// axis based on the center of each node.
//----------------------------------------------------------------------------
template<class Object>
class SkyBoundingBoxSplitter
{
public:
typedef SkyBaseBVTree<Object, SkyMinMaxBox>::NodeObject NodeObjectBox;
//typedef SkyBaseBVTree<Object, SkyBoundingSphere>::NodeObject NodeObjectSphere;
#if _MSC_VER == 1200
// !!! WRH HACK MSVC++6 SP5 Workaround.
// VC6 can't disambiguate this constructor because it doesn't consider the two
// NodeObject templates to be different classes for the purposes of
// overloading. It won't recognize that the second template parameters are
// different. Forcing them to be explicit template specializations fixes
// the problem.
template<class BV>
SkyBoundingBoxSplitter(const SkyBaseBVTree<Object, BV>::NodeObject*, unsigned int)
{
//AUX_STATIC_CHECK(false, VisualC_6_WorkAround); ???
}
template<>
#endif
SkyBoundingBoxSplitter(const NodeObjectBox* pObjs, unsigned int iNumObjs)
{
for (unsigned int i = 0; i < iNumObjs; ++i)
{
_nodeBBox.Union(pObjs[i].GetBV());
}
Init(pObjs, iNumObjs);
}
/*#if _MSC_VER == 1200
template<>
#endif
SkyBoundingBoxSplitter(const NodeObjectSphere* objs,
#ifdef _PLATFORM_XBOX
Int32
#else
UInt32
#endif
numObjs)
{
for (int i=0; i<numObjs; ++i)
{
SkyMinMaxBox box;
box.AddPoint(objs[i].GetBV().GetCenter());
box.Bloat(objs[i].GetBV().GetRadius());
_nodeBBox.Union(box);
}
Init(objs, numObjs);
}*/
template<class nodeObj>
bool SplitLeft(const nodeObj& obj) const
{
if (_bIsolateLongObjects)
return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength;
else
return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue;
}
template<class nodeObj>
bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const
{
return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV());
}
const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; }
private:
template<class nodeObj>
void Init(const nodeObj* pObjs, unsigned int iNumObjs)
{
_iSplitAxis = FindSplitAxis(_nodeBBox);
_rSplitValue = FindSplitValue(_nodeBBox, _iSplitAxis);
_rMaxObjectLength = GetSplitAxisLength(_nodeBBox) * rLongObjectPercentageTolerance;
_bIsolateLongObjects = false;
for (unsigned int i = 0; i < iNumObjs; ++i)
{
if (GetSplitAxisLength(pObjs[i].GetBV()) > _rMaxObjectLength)
{
_bIsolateLongObjects = true;
break;
}
}
}
int FindSplitAxis(const SkyMinMaxBox& bbox)
{
int iAxis = 0, i;
Vec3f vecExt = bbox.GetMax() - bbox.GetMin();
for (i = 1; i < 3; ++i) if (vecExt[i] > vecExt[iAxis]) iAxis = i;
return iAxis;
}
float FindSplitValue(const SkyMinMaxBox& bbox, int iSplitAxis)
{
return (bbox.GetMin()[iSplitAxis] + bbox.GetMax()[iSplitAxis])*0.5f;
}
/*float GetSplitAxisLength(const SkyBoundingSphere& sphere) const
{
return 2.f*sphere.GetRadius();
}*/
float GetSplitAxisLength(const SkyMinMaxBox& bbox) const
{
return bbox.GetMax()[_iSplitAxis] - bbox.GetMin()[_iSplitAxis];
}
float GetSplitAxisCenter(const SkyMinMaxBox& bbox) const
{
return (bbox.GetMin()[_iSplitAxis] + bbox.GetMax()[_iSplitAxis]) * 0.5f;
}
/*float GetSplitAxisCenter(const SkyBoundingSphere& sphere) const
{
return sphere.GetCenter()[SplitAxis];
}*/
int _iSplitAxis;
float _rSplitValue;
bool _bIsolateLongObjects;
float _rMaxObjectLength;
SkyMinMaxBox _nodeBBox;
};
//----------------------------------------------------------------------------
// SkyAABBTreeSplitter
//----------------------------------------------------------------------------
// A NodeSplitter that is compatible with SkyBVTree for SkyMinMaxBox.
// Implemented using the SkyBoundingBoxSplitter strategy.
//----------------------------------------------------------------------------
template<class Object>
class SkyAABBTreeSplitter
{
public:
typedef SkyMinMaxBox BV;
typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
SkyAABBTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) {}
const BV& GetNodeBV() const { return _splitter.GetNodeBBox(); }
bool operator()(const NodeObject& obj) const
{
return _splitter.SplitLeft(obj);
}
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
{
return _splitter.LessThan(obj1, obj2);
}
private:
SkyBoundingBoxSplitter<Object> _splitter;
};
//----------------------------------------------------------------------------
// SkySphereTreeSplitter
//----------------------------------------------------------------------------
// A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere.
// Implemented using the SkyBoundingBoxSplitter strategy.
//----------------------------------------------------------------------------
/*template<class Object>
class SkySphereTreeSplitter
{
public:
typedef SkyBoundingSphere BV;
typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
MlxSphereTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs)
{
_nodeBV = pObjs[0].GetBV();
for (unsigned int i = 1; i < iNumObjs; ++i) _nodeBV.Union(pObjs[i].GetBV());
}
const BV& GetNodeBV() const { return _nodeBV; }
bool operator()(const NodeObject& obj) const
{
return _splitter.SplitLeft(obj);
}
bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
{
return _splitter.LessThan(obj1, obj2);
}
private:
BV _nodeBV;
SkyBoundingBoxSplitter<Object> _splitter;
};*/
#endif //__SKYBVTREESPLITTER_HPP__

View File

@@ -0,0 +1,151 @@
//------------------------------------------------------------------------------
// File : SkyBoundingVolume.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyBoundingVolume.hpp
*
* Base class interface definition for a bounding volume.
*/
#ifndef __SKYBOUNDINGVOLUME_HPP__
#define __SKYBOUNDINGVOLUME_HPP__
#include <vec3f.hpp>
#include <mat44.hpp>
// forward to reduce unnecessary dependencies
class Camera;
//------------------------------------------------------------------------------
/**
* @class SkyBoundingVolume
* @brief An abstract base class for bounding volumes (AABB,OBB,Sphere,etc.)
*
* This base class maintains a center and a radius, so it is effectively a bounding
* sphere. Derived classes may represent other types of bounding volumes, but they
* should be sure to update the radius and center, because some objects will treat
* all bounding volumes as spheres.
*
*/
class SkyBoundingVolume
{
public:
//! Constructor
SkyBoundingVolume() : _vecCenter(0, 0, 0), _rRadius(0) {}
//! Destructor
virtual ~SkyBoundingVolume() {}
//------------------------------------------------------------------------------
// Function : SetCenter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SetCenter(const Vec3f &center)
* @brief Sets the center of the bounding volume.
*/
virtual void SetCenter(const Vec3f &center) { _vecCenter = center; }
//------------------------------------------------------------------------------
// Function : SetRadius
// Description :
//------------------------------------------------------------------------------
/**
* @fn SetRadius(float radius)
* @brief Sets the radius of the bounding volume.
*/
virtual void SetRadius(float radius) { _rRadius = radius; }
//------------------------------------------------------------------------------
// Function : Vec3f& GetCenter
// Description :
//------------------------------------------------------------------------------
/**
* @fn Vec3f& GetCenter() const
* @brief Returns the center of the bounding volume.
*/
virtual const Vec3f& GetCenter() const { return _vecCenter; }
//------------------------------------------------------------------------------
// Function : GetRadius
// Description :
//------------------------------------------------------------------------------
/**
* @fn GetRadius() const
* @brief Returns the radius ofthe bounding volume.
*/
virtual float GetRadius() const { return _rRadius; }
//------------------------------------------------------------------------------
// Function : ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn ViewFrustumCull( const Camera &cam, const Mat44f &mat )
* @brief Cull a bounding volume.
*
* Returns false if the bounding volume is entirely outside the camera's frustum,
* true otherwise.
*/
virtual bool ViewFrustumCull( const Camera &cam, const Mat44f &mat ) = 0;
//------------------------------------------------------------------------------
// Function : AddPoint
// Description :
//------------------------------------------------------------------------------
/*
* @fn AddPoint( const Vec3f &pt )
* @brief Add a point to a bounding volume.
*
* One way to create a bounding volume is to add points. What should/could happen
* is that the BV will store an object space BV and then when a call to SetPosition
* is called, the stored values will be transformed and stored separately, so that
* the original values always exist.
*
*/
//virtual void AddPoint( const Vec3f &point ) = 0;
//------------------------------------------------------------------------------
// Function : AddPoint
// Description :
//------------------------------------------------------------------------------
/*
* @fn AddPoint( float x, float y, float z )
* @brief Add a point to a bounding volume.
*
* @see AddPoint(const Vec3f &pt)
*/
//virtual void AddPoint( float x, float y, float z ) = 0;
//------------------------------------------------------------------------------
// Function : Clear
// Description :
//------------------------------------------------------------------------------
/*
* @fn Clear()
* @brief Clear all data from the bounding volume.
*/
//virtual void Clear() = 0;
protected:
Vec3f _vecCenter;
float _rRadius;
};
#endif //__SKYBOUNDINGVOLUME_HPP__

View File

@@ -0,0 +1,966 @@
//------------------------------------------------------------------------------
// File : SkyCloud.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyCloud.cpp
*
* Implementation of class SkyCloud.
*/
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
//#include "glvu.hpp"
#include "SkyCloud.hpp"
#include "SkyRenderableInstance.hpp"
#include "SkyContext.hpp"
#include "SkyMaterial.hpp"
#include "SkyLight.hpp"
#include "SkyTextureManager.hpp"
#include "SkySceneManager.hpp"
#include <algorithm>
//! The version used for cloud archive files.
#define CLOUD_ARCHIVE_VERSION 0.1f
//------------------------------------------------------------------------------
// Static initialization
//------------------------------------------------------------------------------
SkyMaterial* SkyCloud::s_pMaterial = NULL;
SkyMaterial* SkyCloud::s_pShadeMaterial = NULL;
unsigned int SkyCloud::s_iShadeResolution = 32;
float SkyCloud::s_rAlbedo = 0.9f;
float SkyCloud::s_rExtinction = 80.0f;
float SkyCloud::s_rTransparency = exp(-s_rExtinction);
float SkyCloud::s_rScatterFactor = s_rAlbedo * s_rExtinction * SKY_INV_4PI;
float SkyCloud::s_rSortAngleErrorTolerance = 0.8f;
float SkyCloud::s_rSortSquareDistanceTolerance = 100;
//------------------------------------------------------------------------------
// Function : SkyCloud::SkyCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::SkyCloud()
* @brief Constructor.
*/
SkyCloud::SkyCloud()
: SkyRenderable(),
_bUsePhaseFunction(true),
_vecLastSortViewDir(Vec3f::ZERO),
_vecLastSortCamPos(Vec3f::ZERO)
{
if (!s_pShadeMaterial)
{
s_pShadeMaterial = new SkyMaterial;
s_pShadeMaterial->SetAmbient(Vec4f(0.1f, 0.1f, 0.1f, 1));
s_pShadeMaterial->EnableDepthTest(false);
s_pShadeMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
s_pShadeMaterial->EnableBlending(true);
s_pShadeMaterial->SetAlphaFunc(GL_GREATER);
s_pShadeMaterial->SetAlphaRef(0);
s_pShadeMaterial->EnableAlphaTest(true);
s_pShadeMaterial->SetColorMaterialMode(GL_DIFFUSE);
s_pShadeMaterial->EnableColorMaterial(true);
s_pShadeMaterial->EnableLighting(false);
s_pShadeMaterial->SetTextureApplicationMode(GL_MODULATE);
}
if (!s_pMaterial)
{
s_pMaterial = new SkyMaterial;
s_pMaterial->SetAmbient(Vec4f(0.3f, 0.3f, 0.3f, 1));
s_pMaterial->SetDepthMask(false);
s_pMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
s_pMaterial->EnableBlending(true);
s_pMaterial->SetAlphaFunc(GL_GREATER);
s_pMaterial->SetAlphaRef(0);
s_pMaterial->EnableAlphaTest(true);
s_pMaterial->SetColorMaterialMode(GL_DIFFUSE);
s_pMaterial->EnableColorMaterial(true);
s_pMaterial->EnableLighting(false);
s_pMaterial->SetTextureApplicationMode(GL_MODULATE);
_CreateSplatTexture(32); // will assign the texture to both static materials
}
}
//------------------------------------------------------------------------------
// Function : SkyCloud::~SkyCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::~SkyCloud()
* @brief Destructor.
*/
SkyCloud::~SkyCloud()
{
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Update
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Update(const Camera &cam, SkyRenderableInstance* pInstance)
* @brief Currently does nothing.
*/
SKYRESULT SkyCloud::Update(const Camera &cam, SkyRenderableInstance* pInstance)
{
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : DrawQuad
// Description :
//------------------------------------------------------------------------------
/**
* @fn DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
* @brief Draw a quad.
*/
inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
{
glColor4fv(&(color.x));
Vec3f left = pos; left -= y;
Vec3f right = left; right += x;
left -= x;
glTexCoord2f(0, 0); glVertex3fv(&(left.x));
glTexCoord2f(1, 0); glVertex3fv(&(right.x));
left += y; left += y;
right += y; right += y;
glTexCoord2f(1, 1); glVertex3fv(&(right.x));
glTexCoord2f(0, 1); glVertex3fv(&(left.x));
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Display(const Camera &camera, SkyRenderableInstance *pInstance)
* @brief Renders the cloud.
*
* The cloud is rendered by splatting the particles from back to front with respect
* to @a camera. Since instances of clouds each have their own particles, which
* are pre-transformed into world space, @a pInstance is not used.
*
* An alternative method is to store the particles untransformed, and transform the
* camera and light into cloud space for rendering. This is more complicated,
* and not as straightforward. Since I have to store the particles with each instance
* anyway, I decided to pre-transform them instead.
*/
SKYRESULT SkyCloud::Display(const Camera &camera, SkyRenderableInstance *pInstance)
{
// copy the current camera
Camera cam(camera);
// This cosine computation, along with the if() below, are an optimization. The goal
// is to avoid sorting when it will make no visual difference. This will be true when the
// cloud particles are almost sorted for the current viewpoint. This is the case most of the
// time, since the viewpoint does not move very far in a single frame. Each time we sort,
// we cache the current view direction. Then, each time the cloud is displayed, if the
// current view direction is very close to the current view direction (dot product is nearly 1)
// then we do not resort the particles.
float rCosAngleSinceLastSort =
_vecLastSortViewDir * cam.ViewDir(); // dot product
float rSquareDistanceSinceLastSort =
(cam.Orig - _vecLastSortCamPos).LengthSqr();
if (rCosAngleSinceLastSort < s_rSortAngleErrorTolerance ||
rSquareDistanceSinceLastSort > s_rSortSquareDistanceTolerance)
{
// compute the sort position for particles.
// don't just use the camera position -- if it is too far away from the cloud, then
// precision limitations may cause the STL sort to hang. Instead, put the sort position
// just outside the bounding sphere of the cloud in the direction of the camera.
Vec3f vecSortPos = -cam.ViewDir();
vecSortPos *= (1.1 * _boundingBox.GetRadius());
// sort the particles from back to front wrt the camera position.
_SortParticles(cam.ViewDir(), vecSortPos, SKY_CLOUD_SORT_TOWARD);
//_vecLastSortViewDir = GLVU::GetCurrent()->GetCurrentCam()->ViewDir();
//_vecLastSortCamPos = GLVU::GetCurrent()->GetCurrentCam()->Orig;
_vecLastSortViewDir = cam.ViewDir();
_vecLastSortCamPos = cam.Orig;
}
// set the material state / properties that clouds use for rendering:
// Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
// Enables alpha test to discard completely transparent fragments.
// Disables depth test.
// Enables texturing, with modulation, and the texture set to the shared splat texture.
s_pMaterial->Activate();
Vec4f color;
Vec3f eyeDir;
// Draw the particles using immediate mode.
glBegin(GL_QUADS);
int i = 0;
for (ParticleIterator iter = _particles.begin(); iter != _particles.end(); iter++)
{
i++;
SkyCloudParticle *p = *iter;
// Start with ambient light
color = p->GetBaseColor();
if (_bUsePhaseFunction) // use the phase function for anisotropic scattering.
{
eyeDir = cam.Orig;
eyeDir -= p->GetPosition();
eyeDir.Normalize();
float pf;
// add the color contribution to this particle from each light source, modulated by
// the phase function. See _PhaseFunction() documentation for details.
for (int i = 0; i < p->GetNumLitColors(); i++)
{
pf = _PhaseFunction(_lightDirections[i], eyeDir);
// expand this to avoid temporary vector creation in the inner loop
color.x += p->GetLitColor(i).x * pf;
color.y += p->GetLitColor(i).y * pf;
color.z += p->GetLitColor(i).z * pf;
}
}
else // just use isotropic scattering instead.
{
for (int i = 0; i < (*iter)->GetNumLitColors(); ++i)
{
color += p->GetLitColor(i);
}
}
// Set the transparency independently of the colors
color.w = 1 - s_rTransparency;
// draw the particle as a textured billboard.
DrawQuad((*iter)->GetPosition(), cam.X * p->GetRadius(), cam.Y * p->GetRadius(), color);
}
glEnd();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::DisplaySplit
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::DisplaySplit(const Camera &camera, const Vec3f &vecSplitPoint, bool bBackHalf, SkyRenderableInstance *pInstance)
* @brief The same as Display(), except it displays only the particles in front of or behind the split point.
*
* This is used to render clouds into two impostor images for displaying clouds that contain objects.
*
* @see SkyRenderableInstanceCloud
*/
SKYRESULT SkyCloud::DisplaySplit(const Camera &camera,
const Vec3f &vecSplitPoint,
bool bBackHalf,
SkyRenderableInstance *pInstance /* = NULL */)
{
// copy the current camera
Camera cam(camera);
Vec3f vecCloudSpaceSplit = vecSplitPoint;
if (bBackHalf) // only sort when rendering the back half. Reuse sort for front half.
{
// compute the sort position for particles.
// don't just use the camera position -- if it is too far away from the cloud, then
// precision limitations may cause the STL sort to hang. Instead, put the sort position
// just outside the bounding sphere of the cloud in the direction of the camera.
_vecSortPos = -cam.ViewDir();
_vecSortPos *= (1.1 * _boundingBox.GetRadius());
// sort the particles from back to front wrt the camera position.
_SortParticles(cam.ViewDir(), _vecSortPos, SKY_CLOUD_SORT_TOWARD);
// we can't use the view direction optimization when the cloud is split, or we get a lot
// of popping of objects in and out of cloud cover. For consistency, though, we need to update
// the cached sort direction, since we just sorted the particles.
///_vecLastSortViewDir = GLVU::GetCurrent()->GetCurrentCam()->ViewDir();
// compute the split distance.
vecCloudSpaceSplit -= _vecSortPos;
_rSplitDistance = vecCloudSpaceSplit * cam.ViewDir();
}
// set the material state / properties that clouds use for rendering:
// Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
// Enables alpha test to discard completely transparent fragments.
// Disables depth test.
// Enables texturing, with modulation, and the texture set to the shared splat texture.
s_pMaterial->Activate();
Vec4f color;
Vec3f eyeDir;
// Draw the particles using immediate mode.
glBegin(GL_QUADS);
// if bBackHalf is false, then we just continue where we left off. If it is true, we
// reset the iterator to the beginning of the sorted list.
static ParticleIterator iter;
if (bBackHalf)
iter = _particles.begin();
// iterate over the particles and render them.
for (; iter != _particles.end(); ++iter)
{
SkyCloudParticle *p = *iter;
if (bBackHalf && (p->GetSquareSortDistance() < _rSplitDistance))
break;
// Start with ambient light
color = p->GetBaseColor();
if (_bUsePhaseFunction) // use the phase function for anisotropic scattering.
{
eyeDir = cam.Orig;
eyeDir -= p->GetPosition();
eyeDir.Normalize();
float pf;
// add the color contribution to this particle from each light source, modulated by
// the phase function. See _PhaseFunction() documentation for details.
for (int i = 0; i < p->GetNumLitColors(); i++)
{
pf = _PhaseFunction(_lightDirections[i], eyeDir);
// expand this to avoid temporary vector creation in the inner loop
color.x += p->GetLitColor(i).x * pf;
color.y += p->GetLitColor(i).y * pf;
color.z += p->GetLitColor(i).z * pf;
}
}
else // just use isotropic scattering instead.
{
for (int i = 0; i < p->GetNumLitColors(); ++i)
{
color += p->GetLitColor(i);
}
}
// set the transparency independently of the colors.
color.w = 1 - s_rTransparency;
// draw the particle as a textured billboard.
DrawQuad((*iter)->GetPosition(), cam.X * p->GetRadius(), cam.Y * p->GetRadius(), color);
}
glEnd();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Illuminate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Illuminate(SkyLight *pLight, SkyRenderableInstance* pInstance, bool bReset)
* @brief Compute the illumination of the cloud by the lightsource @a pLight
*
* This method uses graphics hardware to compute multiple forward scattering at each cloud
* in the cloud of light from the directional light source @a pLight. The algorithm works
* by successively subtracting "light" from an initially white (fully lit) frame buffer by
* using hardware blending and read back. The method stores the illumination from each light
* source passed to it separately at each particle, unless @a bReset is true, in which case
* the lists of illumination in the particles are reset before the lighting is computed.
*
*/
SKYRESULT SkyCloud::Illuminate(SkyLight *pLight, SkyRenderableInstance* pInstance, bool bReset)
{
int iOldVP[4];
glGetIntegerv(GL_VIEWPORT, iOldVP);
glViewport(0, 0, s_iShadeResolution, s_iShadeResolution);
Vec3f vecDir(pLight->GetDirection());
// if this is the first pass through the lights, reset will be true, and the cached light
// directions should be updated. Light directions are cached in cloud space to accelerate
// computation of the phase function, which depends on light direction and view direction.
if (bReset)
_lightDirections.clear();
_lightDirections.push_back(vecDir); // cache the (unit-length) light direction
// compute the light/sort position for particles from the light direction.
// don't just use the camera position -- if it is too far away from the cloud, then
// precision limitations may cause the STL sort to hang. Instead, put the sort position
// just outside the bounding sphere of the cloud in the direction of the camera.
Vec3f vecLightPos(vecDir);
vecLightPos *= (1.1*_boundingBox.GetRadius());
vecLightPos += _boundingBox.GetCenter();
// Set up a camera to look at the cloud from the light position. Since the sun is an infinite
// light source, this camera will use an orthographic projection tightly fit to the bounding
// sphere of the cloud.
Camera cam;
// Avoid degenerate camera bases.
Vec3f vecUp(0, 1, 0);
if (fabs(vecDir * vecUp) - 1 < 1e-6) // check that the view and up directions are not parallel.
vecUp.Set(1, 0, 0);
cam.LookAt(vecLightPos, _boundingBox.GetCenter(), vecUp);
// sort the particles away from the light source.
_SortParticles(cam.ViewDir(), vecLightPos, SKY_CLOUD_SORT_AWAY);
// projected dist to cntr along viewdir
float DistToCntr = (_boundingBox.GetCenter() - vecLightPos) * cam.ViewDir();
// calc tight-fitting near and far distances for the orthographic frustum
float rNearDist = DistToCntr - _boundingBox.GetRadius();
float rFarDist = DistToCntr + _boundingBox.GetRadius();
// set the modelview matrix from this camera.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
float M[16];
cam.GetModelviewMatrix(M);
glLoadMatrixf(M);
// switch to parallel projection
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(-_boundingBox.GetRadius(), _boundingBox.GetRadius(),
-_boundingBox.GetRadius(), _boundingBox.GetRadius(),
rNearDist, rFarDist);
// set the material state / properties that clouds use for shading:
// Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
// Enables alpha test to discard completely transparent fragments.
// Disables depth test.
// Enables texturing, with modulation, and the texture set to the shared splat texture.
s_pShadeMaterial->Activate();
// these are used for projecting the particle position to determine where to read pixels.
double MM[16], PM[16];
int VP[4] = { 0, 0, s_iShadeResolution, s_iShadeResolution };
glGetDoublev(GL_MODELVIEW_MATRIX, MM);
glGetDoublev(GL_PROJECTION_MATRIX, PM);
// initialize back buffer to all white -- modulation darkens areas where cloud particles
// absorb light, and lightens it where they scatter light in the forward direction.
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float rPixelsPerLength = s_iShadeResolution / (2 * _boundingBox.GetRadius());
// the solid angle over which we will sample forward-scattered light.
float rSolidAngle = 0.09;
int i = 0;
int iNumFailed = 0;
for (ParticleIterator iter = _particles.begin(); iter != _particles.end(); ++iter, ++i)
{
Vec3f vecParticlePos = (*iter)->GetPosition();
Vec3f vecOffset(vecLightPos);
vecOffset -= vecParticlePos;
// compute the pixel area to read back in order to integrate the illumination of the particle
// over a constant solid angle.
float rDistance = fabs(cam.ViewDir() * vecOffset) - rNearDist;
float rArea = rSolidAngle * rDistance * rDistance;
int iPixelDim = sqrt(rArea) * rPixelsPerLength;
int iNumPixels = iPixelDim * iPixelDim;
if (iNumPixels < 1)
{
iNumPixels = 1;
iPixelDim = 1;
}
// the scale factor to convert the read back pixel colors to an average illumination of the area.
float rColorScaleFactor = rSolidAngle / (iNumPixels * 255.0f);
unsigned char *c = new unsigned char[4 * iNumPixels];
Vec3d vecWinPos;
// find the position in the buffer to which the particle position projects.
if (!gluProject(vecParticlePos.x, vecParticlePos.y, vecParticlePos.z,
MM, PM, VP,
&(vecWinPos.x), &(vecWinPos.y), &(vecWinPos.z)))
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"Error: SkyCloud::Illuminate(): failed to project particle position.");
}
// offset the projected window position by half the size of the readback region.
vecWinPos.x -= 0.5 * iPixelDim;
if (vecWinPos.x < 0) vecWinPos.x = 0;
vecWinPos.y -= 0.5 * iPixelDim;
if (vecWinPos.y < 0) vecWinPos.y = 0;
// read back illumination of this particle from the buffer.
glReadBuffer(GL_BACK);
glReadPixels(vecWinPos.x, vecWinPos.y, iPixelDim, iPixelDim, GL_RGBA, GL_UNSIGNED_BYTE, c);
// scattering coefficient vector.
Vec4f vecScatter(s_rScatterFactor, s_rScatterFactor, s_rScatterFactor, 1);
// add up the read back pixels (only need one component -- its grayscale)
int iSum = 0;
for (int k = 0; k < 4 * iNumPixels; k+=4)
iSum += c[k];
delete [] c;
// compute the amount of light scattered to this particle by particles closer to the light.
// this is the illumination over the solid angle that we measured (using glReadPixels) times
// the scattering coefficient (vecScatter);
Vec4f vecScatteredAmount(iSum * rColorScaleFactor,
iSum * rColorScaleFactor,
iSum * rColorScaleFactor,
1 - s_rTransparency);
vecScatteredAmount &= vecScatter;
// the color of th particle (iter) contributed by this light source (pLight) is the
// scattered light from the part of the cloud closer to the light, times the diffuse color
// of the light source. The alpha is 1 - the uniform transparency of all particles (modulated
// by the splat texture).
Vec4f vecColor = vecScatteredAmount;
vecColor &= pLight->GetDiffuse();
vecColor.w = 1 - s_rTransparency;
// add this color to the list of lit colors for the particle. The contribution from each light
// is kept separate because the phase function we apply at runtime depends on the light vector
// for each light source separately. This view-dependent effect is impossible without knowing
// the amount of light contributed for each light. This, of course, assumes the clouds will
// be lit by a reasonably small number of lights (The sun plus some simulation of light reflected
// from the sky and / or ground.) This technique works very well for simulating anisotropic
// illumination by skylight.
if (bReset)
{
(*iter)->SetBaseColor(s_pMaterial->GetAmbient());
(*iter)->ClearLitColors();
(*iter)->AddLitColor(vecColor);
}
else
{
(*iter)->AddLitColor(vecColor);
}
// the following computation (scaling of the scattered amount by the phase function) is done
// after the lit color is stored so we don't add the scattering to this particle twice.
vecScatteredAmount *= 1.5; // rayleigh scattering phase function for angle of zero or 180 = 1.5!
// clamp the color
if (vecScatteredAmount.x > 1) vecScatteredAmount.x = 1;
if (vecScatteredAmount.y > 1) vecScatteredAmount.y = 1;
if (vecScatteredAmount.z > 1) vecScatteredAmount.z = 1;
vecScatteredAmount.w = 1 - s_rTransparency;
vecScatteredAmount.x = 0.50; vecScatteredAmount.y = 0.60; vecScatteredAmount.z = 0.70;
// Draw the particle as a texture billboard. Use the scattered light amount as the color to
// simulate forward scattering of light by this particle.
glBegin(GL_QUADS);
DrawQuad(vecParticlePos, cam.X * (*iter)->GetRadius(), cam.Y * (*iter)->GetRadius(), vecScatteredAmount);
glEnd();
//glutSwapBuffers(); // Uncomment this swap buffers to visualize cloud illumination computation.
}
// Note: here we could optionally store the current back buffer as a shadow image
// to be projected from the light position onto the scene. This way we can have clouds shadow
// the environment.
// restore matrix stack and viewport.
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::CopyBoundingVolume
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::CopyBoundingVolume() const
* @brief Returns a new copy of the SkyMinMaxBox for this cloud.
*/
SkyMinMaxBox* SkyCloud::CopyBoundingVolume() const
{
SkyMinMaxBox *pBox = new SkyMinMaxBox();
pBox->SetMax(_boundingBox.GetMax());
pBox->SetMin(_boundingBox.GetMin());
return pBox;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Load
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Load(const SkyArchive &archive, float rScale, bool bLocal)
* @brief Loads the cloud data from @a archive.
*
* If @a rScale does not equal 1.0, then the cloud is scaled by an amount rScale.
*/
SKYRESULT SkyCloud::Load(const SkyArchive &archive,
float rScale /* = 1.0f */,
bool bLocal /* = false */)
{
unsigned int iNumParticles;
Vec3f vecCenter = Vec3f::ZERO;
//Vec3f vecCenter;
//float rRadius;
//archive.FindVec3f("CldCenter", &vecCenter);
//archive.FindFloat32("CldRadius", &rRadius);
//_boundingBox.SetMin(vecCenter - Vec3f(rRadius, rRadius, rRadius));
//_boundingBox.SetMax(vecCenter + Vec3f(rRadius, rRadius, rRadius));
archive.FindUInt32("CldNumParticles", &iNumParticles);
if (!bLocal)
archive.FindVec3f("CldCenter", &vecCenter);
Vec3f *pParticlePositions = new Vec3f[iNumParticles];
float *pParticleRadii = new float[iNumParticles];
Vec4f *pParticleColors = new Vec4f[iNumParticles];
unsigned int iNumBytes;
archive.FindData("CldParticlePositions", ANY_TYPE, (void**const)&pParticlePositions, &iNumBytes);
archive.FindData("CldParticleRadii", ANY_TYPE, (void**const)&pParticleRadii, &iNumBytes);
archive.FindData("CldParticleColors", ANY_TYPE, (void**const)&pParticleColors, &iNumBytes);
for (unsigned int i = 0; i < iNumParticles; ++i)
{
SkyCloudParticle *pParticle = new SkyCloudParticle((pParticlePositions[i] + vecCenter) * rScale,
pParticleRadii[i] * rScale,
pParticleColors[i]);
_boundingBox.AddPoint(pParticle->GetPosition());
_particles.push_back(pParticle);
}
// this is just a bad hack to align cloud field from skyworks with local horizon at KSFO
// we need to develop out own scheme for loading and positioning clouds
Mat33f rot_mat;
Vec3f moveit;
//moveit.Set( -10000.0, 1500.0, 1500.0 );
moveit.Set( 0.0, 0.0, 1050.0 );
rot_mat.Set( 1, 0, 0,
0, 0, -1,
0, 1, 0);
// flip the y and z axis
Rotate( rot_mat );
// adjust for lon af KSFO -122.357
rot_mat.Set( -0.5352f, 0.8447f, 0.0f,
-0.8447f, -0.5352f, 0.0f,
-0.0f, 0.0f, 1.0f);
Rotate( rot_mat );
// and about x for latitude 37.6135
rot_mat.Set( 1.0f, 0.0, 0.0f,
0.0f, 0.7921f, -0.6103f,
0.0f, 0.6103f, 0.7921f);
Rotate( rot_mat );
Translate( moveit );
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Save
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Save(SkyArchive &archive) const
* @brief Saves the cloud data to @a archive.
*
* @todo <WRITE EXTENDED SkyCloud::Save FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyCloud::Save(SkyArchive &archive) const
{
SkyArchive myArchive("Cloud");
//myArchive.AddVec3f("CldCenter", _center);
//myArchive.AddFloat32("CldRadius", _boundingBox.GetRadius());
myArchive.AddUInt32("CldNumParticles", _particles.size());
// make temp arrays
Vec3f *pParticlePositions = new Vec3f[_particles.size()];
float *pParticleRadii = new float[_particles.size()];
Vec4f *pParticleColors = new Vec4f[_particles.size()];
unsigned int i = 0;
for (ParticleConstIterator iter = _particles.begin(); iter != _particles.end(); ++iter, ++i)
{
pParticlePositions[i] = (*iter)->GetPosition(); // position around origin
pParticleRadii[i] = (*iter)->GetRadius();
pParticleColors[i] = (*iter)->GetBaseColor();
}
myArchive.AddData("CldParticlePositions",
ANY_TYPE,
pParticlePositions,
sizeof(Vec3f),
_particles.size());
myArchive.AddData("CldParticleRadii",
ANY_TYPE,
pParticleRadii,
sizeof(float),
_particles.size());
myArchive.AddData("CldParticleColors",
ANY_TYPE,
pParticleColors,
sizeof(Vec3f),
_particles.size());
archive.AddArchive(myArchive);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Rotate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Rotate(const Mat33f& rot)
* @brief @todo <WRITE BRIEF SkyCloud::Rotate DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyCloud::Rotate FUNCTION DOCUMENTATION>
*/
void SkyCloud::Rotate(const Mat33f& rot)
{
_boundingBox.Clear();
for (int i = 0; i < _particles.size(); ++i)
{
_particles[i]->SetPosition(rot * _particles[i]->GetPosition());
_boundingBox.AddPoint(_particles[i]->GetPosition());
}
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Translate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Translate(const Vec3f& trans)
* @brief @todo <WRITE BRIEF SkyCloud::Translate DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyCloud::Translate FUNCTION DOCUMENTATION>
*/
void SkyCloud::Translate(const Vec3f& trans)
{
for (int i = 0; i < _particles.size(); ++i)
{
_particles[i]->SetPosition(_particles[i]->GetPosition() + trans);
}
_boundingBox.SetMax(_boundingBox.GetMax() + trans);
_boundingBox.SetMin(_boundingBox.GetMin() + trans);
}
//------------------------------------------------------------------------------
// Function : SkyCloud::Scale
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::Scale(const float scale)
* @brief @todo <WRITE BRIEF SkyCloud::Scale DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyCloud::Scale FUNCTION DOCUMENTATION>
*/
void SkyCloud::Scale(const float scale)
{
_boundingBox.Clear();
for (int i = 0; i < _particles.size(); ++i)
{
_particles[i]->SetPosition(_particles[i]->GetPosition() * scale);
_boundingBox.AddPoint(_particles[i]->GetPosition());
}
}
//------------------------------------------------------------------------------
// Function : SkyCloud::_SortParticles
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::_SortParticles(const Vec3f& vecViewDir, const Vec3f& sortPoint, SortDirection dir)
* @brief Sorts the cloud particles in the direction specified by @a dir.
*
* @vecSortPoint is assumed to already be transformed into the basis space of the cloud.
*/
void SkyCloud::_SortParticles(const Vec3f& vecViewDir,
const Vec3f& vecSortPoint,
SortDirection dir)
{
Vec3f partPos;
for (int i = 0; i < _particles.size(); ++i)
{
partPos = _particles[i]->GetPosition();
partPos -= vecSortPoint;
_particles[i]->SetSquareSortDistance(partPos * vecViewDir);//partPos.LengthSqr());
}
switch (dir)
{
case SKY_CLOUD_SORT_TOWARD:
std::sort(_particles.begin(), _particles.end(), _towardComparator);
break;
case SKY_CLOUD_SORT_AWAY:
std::sort(_particles.begin(), _particles.end(), _awayComparator);
break;
default:
break;
}
}
//------------------------------------------------------------------------------
// Function : EvalHermite
// Description :
//------------------------------------------------------------------------------
/**
* EvalHermite(float pA, float pB, float vA, float vB, float u)
* @brief Evaluates Hermite basis functions for the specified coefficients.
*/
inline float EvalHermite(float pA, float pB, float vA, float vB, float u)
{
float u2=(u*u), u3=u2*u;
float B0 = 2*u3 - 3*u2 + 1;
float B1 = -2*u3 + 3*u2;
float B2 = u3 - 2*u2 + u;
float B3 = u3 - u;
return( B0*pA + B1*pB + B2*vA + B3*vB );
}
// NORMALIZED GAUSSIAN INTENSITY MAP (N must be a power of 2)
//------------------------------------------------------------------------------
// Function : CreateGaussianMap
// Description :
//------------------------------------------------------------------------------
/**
* CreateGaussianMap(int N)
*
* Creates a 2D gaussian image using a hermite surface.
*/
unsigned char* CreateGaussianMap(int N)
{
float *M = new float[2*N*N];
unsigned char *B = new unsigned char[4*N*N];
float X,Y,Y2,Dist;
float Incr = 2.0f/N;
int i=0;
int j = 0;
Y = -1.0f;
for (int y=0; y<N; y++, Y+=Incr)
{
Y2=Y*Y;
X = -1.0f;
for (int x=0; x<N; x++, X+=Incr, i+=2, j+=4)
{
Dist = (float)sqrt(X*X+Y2);
if (Dist>1) Dist=1;
M[i+1] = M[i] = EvalHermite(0.4f,0,0,0,Dist);// * (1 - noise);
B[j+3] = B[j+2] = B[j+1] = B[j] = (unsigned char)(M[i] * 255);
}
}
SAFE_DELETE_ARRAY(M);
return(B);
}
//------------------------------------------------------------------------------
// Function : SkyCloud::_CreateSplatTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::_CreateSplatTexture(unsigned int iResolution)
* @brief Creates the texture map used for cloud particles.
*/
void SkyCloud::_CreateSplatTexture(unsigned int iResolution)
{
unsigned char *splatTexture = CreateGaussianMap(iResolution);
SkyTexture texture;
TextureManager::InstancePtr()->Create2DTextureObject(texture, iResolution, iResolution,
GL_RGBA, splatTexture);
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, texture);
s_pShadeMaterial->SetTexture(0, GL_TEXTURE_2D, texture);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_pMaterial->EnableTexture(0, true);
s_pShadeMaterial->EnableTexture(0, true);
SAFE_DELETE_ARRAY(splatTexture);
}
//------------------------------------------------------------------------------
// Function : SkyCloud::_PhaseFunction
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloud::_PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir)
* @brief Computes the phase (scattering) function of the given light and view directions.
*
* A phase function is a transfer function that determines, for any angle between incident
* and outgoing directions, how much of the incident light intensity will be
* scattered in the outgoing direction. For example, scattering by very small
* particles such as those found in clear air, can be approximated using <i>Rayleigh
* scattering</i>. The phase function for Rayleigh scattering is
* p(q) = 0.75*(1 + cos<sup>2</sup>(q)), where q is the angle between incident
* and scattered directions. Scattering by larger particles is more complicated.
* It is described by Mie scattering theory. Cloud particles are more in the regime
* of Mie scattering than Rayleigh scattering. However, we obtain good visual
* results by using the simpler Rayleigh scattering phase function as an approximation.
*/
float SkyCloud::_PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir)
{
float rCosAlpha = vecLightDir * vecViewDir;
return .75f * (1 + rCosAlpha * rCosAlpha); // rayleigh scattering = (3/4) * (1+cos^2(alpha))

View File

@@ -0,0 +1,175 @@
//------------------------------------------------------------------------------
// File : SkyCloud.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyCloud.hpp
*
* Interface definition for class SkyCloud.
*/
#ifndef __SKYCLOUD_HPP__
#define __SKYCLOUD_HPP__
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
#include "SkyCloudParticle.hpp"
#include "SkyRenderable.hpp"
#include "SkyMinMaxBox.hpp"
#include "camera.hpp"
#include "SkyArchive.hpp"
#include "mat33.hpp"
class SkyMaterial;
class SkyLight;
class SkyRenderableInstance;
//------------------------------------------------------------------------------
/**
* @class SkyCloud
* @brief A renderable that represents a volumetric cloud.
*
* A SkyCloud is made up of particles, and is rendered using particle splatting.
* SkyCloud is intended to represent realisticly illuminated volumetric clouds
* through which the viewer and / or other objects can realistically pass.
*
* Realistic illumination is performed by the Illuminate() method, which uses a
* graphics hardware algorithm to precompute and store multiple forward scattering
* of light by each particle in the cloud. Clouds may be illuminated by multiple
* light sources. The light from each source is precomputed and stored at each
* particle. Each light's contribution is stored separately so that we can
* compute view-dependent (anisotropic) scattering at run-time. This gives realistic
* effects such as the "silver lining" that you see on a thick cloud when it crosses
* in front of the sun.
*
* At run-time, the cloud is rendered by drawing each particle as a view-oriented
* textured billboard (splat), with lighting computed from the precomputed illumination
* as follows: for each light source <i>l</i>, compute the scattering function (See _PhaseFunction())
* based on the view direction and the direction from the particle to the viewer. This
* scattering function modulates the lighting contribution of <i>l</i>. The modulated
* contributions are then added and used to modulate the color of the particle. The result
* is view-dependent scattering.
*
* If the phase (scattering) function is not enabled (see IsPhaseFunctionEnabled()), then the
* contributions of the light sources are simply added.
*
* @see SkyRenderableInstanceCloud, SkyCloudParticle, SkySceneManager
*/
class SkyCloud : public SkyRenderable
{
public:
SkyCloud();
virtual ~SkyCloud();
virtual SKYRESULT Update(const Camera &cam, SkyRenderableInstance* pInstance = NULL);
virtual SKYRESULT Display(const Camera &camera, SkyRenderableInstance *pInstance = NULL);
SKYRESULT DisplaySplit(const Camera &camera,
const Vec3f &vecSplitPoint,
bool bBackHalf,
SkyRenderableInstance *pInstance = NULL);
SKYRESULT Illuminate( SkyLight *pLight,
SkyRenderableInstance* pInstance,
bool bReset = false);
virtual SkyMinMaxBox* CopyBoundingVolume() const;
//! Enables the use of a scattering function for anisotropic light scattering.
void EnablePhaseFunction(bool bEnable) { _bUsePhaseFunction = bEnable; }
//! Returns true if the use of a scattering function is enabled.
bool IsPhaseFunctionEnabled() const { return _bUsePhaseFunction; }
SKYRESULT Save(SkyArchive &archive) const;
SKYRESULT Load(const SkyArchive &archive, float rScale = 1.0f, bool bLocal = false);
void Rotate(const Mat33f& rot);
void Translate(const Vec3f& trans);
void Scale(const float scale);
protected: // methods
enum SortDirection
{
SKY_CLOUD_SORT_TOWARD,
SKY_CLOUD_SORT_AWAY
};
void _SortParticles( const Vec3f& vecViewDir,
const Vec3f& vecSortPoint,
SortDirection dir);
void _CreateSplatTexture( unsigned int iResolution);
float _PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir);
protected: // datatypes
typedef std::vector<SkyCloudParticle*> ParticleArray;
typedef ParticleArray::iterator ParticleIterator;
typedef ParticleArray::const_iterator ParticleConstIterator;
typedef std::vector<Vec3f> DirectionArray;
typedef DirectionArray::iterator DirectionIterator;
class ParticleAwayComparator
{
public:
bool operator()(SkyCloudParticle* pA, SkyCloudParticle *pB)
{
return ((*pA) < (*pB));
}
};
class ParticleTowardComparator
{
public:
bool operator()(SkyCloudParticle* pA, SkyCloudParticle *pB)
{
return ((*pA) > (*pB));
}
};
protected: // data
ParticleArray _particles; // cloud particles
// particle sorting functors for STL sort.
ParticleTowardComparator _towardComparator;
ParticleAwayComparator _awayComparator;
DirectionArray _lightDirections; // light directions in cloud space (cached)
SkyMinMaxBox _boundingBox; // bounds
bool _bUsePhaseFunction;
Vec3f _vecLastSortViewDir;
Vec3f _vecLastSortCamPos;
Vec3f _vecSortPos;
float _rSplitDistance;
static SkyMaterial *s_pMaterial; // shared material for clouds.
static SkyMaterial *s_pShadeMaterial;// shared material for illumination pass.
static unsigned int s_iShadeResolution; // the resolution of the viewport used for shading
static float s_rAlbedo; // the cloud albedo
static float s_rExtinction; // the extinction of the clouds
static float s_rTransparency; // the transparency of the clouds
static float s_rScatterFactor; // How much the clouds scatter
static float s_rSortAngleErrorTolerance; // how far the view must turn to cause a resort.
static float s_rSortSquareDistanceTolerance; // how far the view must move to cause a resort.
};
#endif //__SKYCLOUD_HPP__

View File

@@ -0,0 +1,175 @@
//------------------------------------------------------------------------------
// File : SkyCloudParticle.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyCloudParticle.hpp
*
* Definition of a simple cloud particle class.
*/
#ifndef __SKYCLOUDPARTICLE_HPP__
#define __SKYCLOUDPARTICLE_HPP__
#include "vec3f.hpp"
#include "vec4f.hpp"
#include <vector>
//------------------------------------------------------------------------------
/**
* @class SkyCloudParticle
* @brief A class for particles that make up a cloud.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyCloudParticle
{
public:
inline SkyCloudParticle();
inline SkyCloudParticle(const Vec3f& pos,
float rRadius,
const Vec4f& baseColor,
float rTransparency = 0);
inline ~SkyCloudParticle();
//! Returns the radius of the particle.
float GetRadius() const { return _rRadius; }
//! Returns the transparency of the particle.
float GetTransparency() const { return _rTransparency; }
//! Returns the position of the particle.
const Vec3f& GetPosition() const { return _vecPosition; }
//! Returns the base color of the particle. This is often used for ambient color.
const Vec4f& GetBaseColor() const { return _vecBaseColor; }
//! Returns the number of light contributions to this particle's color.
unsigned int GetNumLitColors() const { return _vecLitColors.size(); }
//! Returns the light contribution to the color of this particle from light @a index.
inline const Vec4f& GetLitColor(unsigned int index) const;
//! Returns the square distance from the sort position used for the operator< in sorts / splits.
float GetSquareSortDistance() const { return _rSquareSortDistance; }
//! Sets the radius of the particle.
void SetRadius(float rad) { _rRadius = rad; }
//! Returns the transparency of the particle.
void SetTransparency(float trans) { _rTransparency = trans; }
//! Sets the position of the particle.
void SetPosition(const Vec3f& pos) { _vecPosition = pos; }
//! Sets the base color of the particle. This is often used for ambient color.
void SetBaseColor(const Vec4f& col) { _vecBaseColor = col; }
//! Sets the light contribution to the color of this particle from light @a index.
void AddLitColor(const Vec4f& col) { _vecLitColors.push_back(col); }
//! Clears the list of light contributions.
void ClearLitColors() { _vecLitColors.clear(); }
//! Sets the square distance from the sort position used for the operator< in sorts.
void SetSquareSortDistance(float rSquareDistance) { _rSquareSortDistance = rSquareDistance; }
//! This operator is used to sort particle arrays from nearest to farthes.
bool operator<(const SkyCloudParticle& p) const
{
return (_rSquareSortDistance < p._rSquareSortDistance);
}
//! This operator is used to sort particle arrays from farthest to nearest.
bool operator>(const SkyCloudParticle& p) const
{
return (_rSquareSortDistance > p._rSquareSortDistance);
}
protected:
float _rRadius;
float _rTransparency;
Vec3f _vecPosition;
Vec4f _vecBaseColor;
std::vector<Vec4f> _vecLitColors;
Vec3f _vecEye;
// for sorting particles during shading
float _rSquareSortDistance;
};
//------------------------------------------------------------------------------
// Function : SkyCloudParticle::SkyCloudParticle
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloudParticle::SkyCloudParticle()
* @brief Default constructor.
*/
inline SkyCloudParticle::SkyCloudParticle()
: _rRadius(0),
_rTransparency(0),
_vecPosition(0, 0, 0),
_vecBaseColor(0, 0, 0, 1),
_vecEye(0, 0, 0),
_rSquareSortDistance(0)
{
_vecLitColors.clear();
}
//------------------------------------------------------------------------------
// Function : SkyCloudParticle::SkyCloudParticle
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloudParticle::SkyCloudParticle(const Vec3f& pos, float rRadius, const Vec4f& baseColor, float rTransparency)
* @brief Constructor.
*/
inline SkyCloudParticle::SkyCloudParticle(const Vec3f& pos,
float rRadius,
const Vec4f& baseColor,
float rTransparency /* = 0 */)
: _rRadius(rRadius),
_rTransparency(rTransparency),
_vecPosition(pos),
_vecBaseColor(baseColor),
_vecEye(0, 0, 0),
_rSquareSortDistance(0)
{
_vecLitColors.clear();
}
//------------------------------------------------------------------------------
// Function : SkyCloudParticle::~SkyCloudParticle
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyCloudParticle::~SkyCloudParticle()
* @brief Destructor.
*/
inline SkyCloudParticle::~SkyCloudParticle()
{
_vecLitColors.clear();
}
//------------------------------------------------------------------------------
// Function : Vec4f& SkyCloudParticle::GetLitColor
// Description :
//------------------------------------------------------------------------------
/**
* @fn Vec4f& SkyCloudParticle::GetLitColor(unsigned int index) const
* @brief Returns the lit color specified by index.
*
* If the index is out of range, returns a zero vector.
*/
inline const Vec4f& SkyCloudParticle::GetLitColor(unsigned int index) const
{
if (index <= _vecLitColors.size())
return _vecLitColors[index];
else
return Vec4f::ZERO;
}
#endif //__SKYCLOUDPARTICLE_HPP__

View File

@@ -0,0 +1,283 @@
//------------------------------------------------------------------------------
// File : SkyContext.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyContext.cpp
*
* Graphics Context Interface. Initializes GL extensions, etc.
*/
#include <GL/glut.h>
#include <GL/glx.h>
//#include "extgl.h"
#include "SkyContext.hpp"
#include "SkyUtil.hpp"
#include "SkyMaterial.hpp"
#include "SkyTextureState.hpp"
//------------------------------------------------------------------------------
// Function : SkyContext::SkyContext
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::SkyContext()
* @brief Constructor.
*
*/
SkyContext::SkyContext()
{
_iWidth = glutGet(GLUT_WINDOW_WIDTH);
_iHeight = glutGet(GLUT_WINDOW_HEIGHT);
// materials and structure classes
AddCurrentGLContext();
// Initialize all the extensions and load the functions - JW (file is extgl.c)
#ifdef _WIN32
glInitialize();
InitializeExtension("GL_ARB_multitexture");
#endif
}
//------------------------------------------------------------------------------
// Function : SkyContext::~SkyContext
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::~SkyContext()
* @brief Destructor.
*/
SkyContext::~SkyContext()
{
// delete map of materials
for (ContextMaterialIterator cmi = _currentMaterials.begin(); cmi != _currentMaterials.end(); ++cmi)
{
SAFE_DELETE(cmi->second);
}
_currentMaterials.clear();
}
//------------------------------------------------------------------------------
// Function : SkyContext::ProcessReshapeEvent
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::ProcessReshapeEvent(int iWidth, int iHeight)
* @brief Handles window resize events, and notifies all context listeners of the event.
*/
SKYRESULT SkyContext::ProcessReshapeEvent(int iWidth, int iHeight)
{
_iWidth = iWidth;
_iHeight = iHeight;
return _SendMessage(SKYCONTEXT_MESSAGE_RESHAPE);
}
//------------------------------------------------------------------------------
// Function : SkyContext::InitializeExtensions
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::InitializeExtensions(const char *pExtensionNames)
* @brief Initializes GL extension specified by @a pExtensionNames.
*/
SKYRESULT SkyContext::InitializeExtension(const char *pExtensionName)
{ /***
if (!QueryExtension(pExtensionName)) // see query search function defined in extgl.c
{
SkyTrace(
"ERROR: SkyContext::InitializeExtenstions: The following extensions are unsupported: %s\n",
pExtensionName);
return SKYRESULT_FAIL;
} **/
//set this false to catch all the extensions until we come up with a linux version
return SKYRESULT_FAIL;
}
//------------------------------------------------------------------------------
// Function : SkyContext::GetCurrentMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::GetCurrentMaterial()
* @brief Returns the current cached material state that is active in this OpenGL context.
*
* @todo <WRITE EXTENDED SkyContext::GetCurrentMaterial FUNCTION DOCUMENTATION>
*/
SkyMaterial* SkyContext::GetCurrentMaterial()
{
ContextMaterialIterator cmi = _currentMaterials.find(glXGetCurrentContext());
if (_currentMaterials.end() != cmi)
return cmi->second;
else
{
SkyTrace("SkyContext::GetCurrentMaterial(): Invalid context.");
return NULL;
}
}
//------------------------------------------------------------------------------
// Function : SkyContext::GetCurrentTextureState
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::GetCurrentTextureState()
* @brief Returns the current cached texture state that is active in this OpenGL context.
*
* @todo <WRITE EXTENDED SkyContext::GetCurrentTextureState FUNCTION DOCUMENTATION>
*/
SkyTextureState* SkyContext::GetCurrentTextureState()
{
ContextTextureStateIterator ctsi = _currentTextureState.find(glXGetCurrentContext());
if (_currentTextureState.end() != ctsi)
return ctsi->second;
else
{
SkyTrace("SkyContext::GetCurrentTextureState(): Invalid context.");
return NULL;
}
}
//------------------------------------------------------------------------------
// Function : SkyContext::AddCurrentGLContext
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::AddCurrentGLContext()
* @brief @todo <WRITE BRIEF SkyContext::AddCurrentGLContext DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyContext::AddCurrentGLContext FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyContext::AddCurrentGLContext()
{
SkyMaterial *pCurrentMaterial = new SkyMaterial;
_currentMaterials.insert(std::make_pair(glXGetCurrentContext(), pCurrentMaterial));
SkyTextureState *pCurrentTS = new SkyTextureState;
_currentTextureState.insert(std::make_pair(glXGetCurrentContext() , pCurrentTS));
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyContext::Register
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::Register(Listener* pListener, int priority)
* @brief Register with the messaging system to handle notification of mode changes
*/
SKYRESULT SkyContext::Register(Listener* pListener, int priority)
{
std::list<ListenerPair>::iterator iter =
std::find_if(_listeners.begin(), _listeners.end(), _ListenerPred(pListener));
if (iter == _listeners.end())
{
// insert the listener, sorted by priority
for (iter=_listeners.begin(); iter != _listeners.end(); ++iter)
{
if (priority <= iter->first)
{
_listeners.insert(iter, ListenerPair(priority, pListener));
break;
}
}
if (iter == _listeners.end())
{
_listeners.push_back(ListenerPair(priority, pListener));
}
// Send a message to the pListener if we are already active so it
// can intialize itself
//FAIL_RETURN(pListener->GraphicsReshapeEvent());
}
else
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyContext: Listener is already registered");
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyContext::UnRegister
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyContext::UnRegister(Listener *pListener)
* @brief UnRegister with the messaging system.
*/
SKYRESULT SkyContext::UnRegister(Listener *pListener)
{
std::list<ListenerPair>::iterator iter =
std::find_if(_listeners.begin(), _listeners.end(), _ListenerPred(pListener));
if (iter == _listeners.end())
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyContext: Listener is not registered");
}
else
{
_listeners.erase(iter);
}
return SKYRESULT_OK;
}
/**
* @fn SkyContext::_SendMessage(SkyMessageType msg)
* @brief Messaging system to handle notification of mode changes
*/
SKYRESULT SkyContext::_SendMessage(SkyMessageType msg)
{
if (_listeners.size() == 0) return SKYRESULT_OK;
bool failure = false;
SKYRESULT res, failureCode = SKYRESULT_OK;
std::list<ListenerPair>::iterator iter;
SKYRESULT (Listener::*fnPtr)() = NULL;
// Make a pointer to the appropriate method
switch (msg)
{
case SKYCONTEXT_MESSAGE_RESHAPE: fnPtr = &Listener::GraphicsReshapeEvent; break;
}
// Notify all listeners of the messag. catch failures, but still call everyone else.
// !!! WRH HORRIBLE HACK must cache the current "end" because these functions could register new listeners
std::list<ListenerPair>::iterator endIter = _listeners.end();
endIter--;
iter = _listeners.begin();
do
{
if ( SKYFAILED( res = (iter->second->*fnPtr)() ) )
{
failureCode = res;
SkyTrace("SkyContext: SendMessage failed");
}
if (iter == endIter) break;
iter++;
} while (true);
FAIL_RETURN(failureCode);
return SKYRESULT_OK;
}

View File

@@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
// File : SkyContext.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyContext.hpp
*
* Graphics Context Interface. Initializes GL extensions, etc.
*/
#ifndef __SKYCONTEXT_HPP__
#define __SKYCONTEXT_HPP__
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
#include "SkySingleton.hpp"
#ifdef _WIN32
#include "extgl.h"
#endif
#include <list>
#include <map>
#include <algorithm>
// ifdef to replace windows stuff for handles-JW
typedef void *HANDLE;
typedef HANDLE *PHANDLE;
#define DECLARE_HANDLE(n) typedef HANDLE n
DECLARE_HANDLE(HGLRC);
// end of ifdef
class SkyContext;
class SkyMaterial;
class SkyTextureState;
//! Graphics Context Singleton declaration.
/*! The Context must be created by calling GraphicsContext::Instantiate(). */
typedef SkySingleton<SkyContext> GraphicsContext;
//------------------------------------------------------------------------------
/**
* @class SkyContext
* @brief A manager / proxy for the state of OpenGL contexts.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyContext
{
public: // datatypes
//------------------------------------------------------------------------------
/**
* @class Listener
* @brief Inherit this class and overide its methods to be notified of context events.
*/
class Listener
{
public:
//! Handle a change in the dimensions of the graphics window.
virtual SKYRESULT GraphicsReshapeEvent() { return SKYRESULT_OK; }
};
/**
* @enum SkyMessageType messages that the context can generate for it's listeners.
*/
enum SkyMessageType
{
SKYCONTEXT_MESSAGE_RESHAPE,
SKYCONTEXT_MESSAGE_COUNT
};
public: // methods
SKYRESULT ProcessReshapeEvent(int iWidth, int iHeight);
SKYRESULT InitializeExtension(const char *pExtensionName);
//! Returns the current dimensions of the window.
void GetWindowSize(int &iWidth, int &iHeight) { iWidth = _iWidth; iHeight = _iHeight; }
SkyMaterial* GetCurrentMaterial();
SkyTextureState* GetCurrentTextureState();
SKYRESULT AddCurrentGLContext();
//------------------------------------------------------------------------------
// Register with the messaging system to handle notification of mode changes
//------------------------------------------------------------------------------
SKYRESULT Register(Listener *pListener, int priority = 0);
SKYRESULT UnRegister(Listener *pLlistener);
protected: // methods
SkyContext();
~SkyContext();
protected: // data
int _iWidth;
int _iHeight;
typedef std::map<HGLRC, SkyMaterial*> ContextMaterialMap;
typedef ContextMaterialMap::iterator ContextMaterialIterator;
typedef std::map<HGLRC, SkyTextureState*> ContextTextureStateMap;
typedef ContextTextureStateMap::iterator ContextTextureStateIterator;
ContextMaterialMap _currentMaterials;
ContextTextureStateMap _currentTextureState;
//------------------------------------------------------------------------------
// Messaging system to handle notification of mode changes
//------------------------------------------------------------------------------
typedef std::pair<int, Listener*> ListenerPair;
class _ListenerPred
{
public:
_ListenerPred(const Listener* l) { _l = l; }
bool operator()(const ListenerPair& pair) { return pair.second == _l; }
protected:
const Listener *_l;
};
SKYRESULT _SendMessage(SkyMessageType msg);
std::list<ListenerPair> _listeners;
};
#endif //__SKYCONTEXT_HPP__

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
// File : SkyControlled.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyControlled.hpp
*
* Interface definition for controlled objects.
*/
#ifndef __SKYCONTROLLED_HPP__
#define __SKYCONTROLLED_HPP__
//#include "BHXController.hpp"
template<typename ControlStateType> class SkyController;
//------------------------------------------------------------------------------
/**
* @class SkyControlled
* @brief A base class defining an interface for controlled objects.
*
* This class abstracts the control of objects into a simple interface that a
* class may inherit that allows it to be controlled by SkyController objects.
* A class simply inherits from SkyControlled, which forces the class to implement
* the method UpdateStateFromControls(). This method usually uses the SkyController
* object passed to SetController() to query the input state via
* SkyController::GetControlState().
*
* @see SkyController
*/
template<typename ControlStateType>
class SkyControlled
{
public:
//! Constructor.
SkyControlled() { _pController = NULL; }
//! Destructor
virtual ~SkyControlled() { _pController = NULL; }
//! Sets the controller which will control this controlled object.
void SetController(SkyController<ControlStateType> *pController) { _pController = pController; }
//! Updates the state of the controlled object based on the controls (received from the controller).
virtual SKYRESULT UpdateStateFromControls(SKYTIME timeStep) = 0;
protected:
SkyController<ControlStateType> *_pController;
ControlStateType _controlState;
};
#endif //__SKYCONTROLLED_HPP__

View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
// File : SkyController.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyController.hpp
*
* Abstract base class for game object controllers.
*/
#ifndef __SKYCONTROLLER_HPP__
#define __SKYCONTROLLER_HPP__
#include "SkyUtil.hpp"
//------------------------------------------------------------------------------
/**
* @class SkyController
* @brief A class that defines an interface for translating general control input into game object control.
*
* This class abstracts game object control from specific control input, such
* as via user interface devices or via artificial intelligence. Subclasses of
* this class implement the method GetControlState() so that objects controlled
* by an instance of a SkyController can query the control state that determines
* their actions. The object need not know whether it is controlled by a human
* or the computer since either controller provides it the same interface.
*
* @see SkyControlled
*/
template <typename ControlStateType>
class SkyController
{
public:
//! Constructor.
SkyController() {}
//! Destructor.
virtual ~SkyController() {}
//! Fills out the control state structure passed in with the current state of controls.
virtual SKYRESULT GetControlState(ControlStateType &controlState) = 0;
};
#endif //__SKYCONTROLLER_HPP__

View File

@@ -0,0 +1,278 @@
//------------------------------------------------------------------------------
// File : SkyDynamicTextureManager.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyDynamicTextureManager.cpp
*
* Implementation of a repository for check out and check in of dynamic textures.
*/
#pragma warning( disable : 4786 )
#include "SkyDynamicTextureManager.hpp"
#include "SkyTexture.hpp"
#include "SkyContext.hpp"
#pragma warning( disable : 4786 )
//! Set this to 1 to print lots of dynamic texture usage messages.
#define SKYDYNTEXTURE_VERBOSE 0
//! The maximum number of textures of each resolution to allow in the checked in pool.
#define SKYDYNTEXTURE_TEXCACHE_LIMIT 32
//------------------------------------------------------------------------------
// Function : SkyDynamicTextureManager::SkyDynamicTextureManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyDynamicTextureManager::SkyDynamicTextureManager()
* @brief Constructor.
*/
SkyDynamicTextureManager::SkyDynamicTextureManager()
#ifdef SKYDYNTEXTURE_VERBOSE
: _iNumTextureBytesUsed(0),
_iNumTextureBytesCheckedIn(0),
_iNumTextureBytesCheckedOut(0)
#endif
{
for (int i = 0; i < 11; ++i)
for (int j = 0; j < 11; ++j)
_iAvailableSizeCounts[i][j] = 0;
}
//------------------------------------------------------------------------------
// Function : SkyDynamicTextureManager::~SkyDynamicTextureManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyDynamicTextureManager::~SkyDynamicTextureManager()
* @brief Destructor.
*/
SkyDynamicTextureManager::~SkyDynamicTextureManager()
{
for ( TextureSet::iterator subset = _availableTexturePool.begin();
subset != _availableTexturePool.end();
++subset )
{ // iterate over texture subsets.
for ( TextureSubset::iterator texture = (*subset).second->begin();
texture != (*subset).second->end();
++texture )
{
texture->second->Destroy();
delete texture->second;
}
subset->second->clear();
}
_availableTexturePool.clear();
for ( TextureSubset::iterator texture = _checkedOutTexturePool.begin();
texture != _checkedOutTexturePool.end();
++texture )
{
texture->second->Destroy();
delete texture->second;
}
_checkedOutTexturePool.clear();
}
//------------------------------------------------------------------------------
// Function : SkyDynamicTextureManager::CheckOutTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyDynamicTextureManager::CheckOutTexture(unsigned int iWidth, unsigned int iHeight)
* @brief Returns a texture from the available pool, creating a new one if necessary.
*
* Thi texture returned by this method is checked out: it will be maintained in a
* checked out pool until it is checked in with CheckInTexture(). The texture is owned
* by the SkyDynamicTextureManager -- it should not be deleted by another object. Checked out
* textures can be modified (copied, or rendered to, etc.), but should not be reallocated
* or resized. All checked out textures will be deleted when the SkyDynamicTextureManager
* is destroyed, so this manager should be destroyed only after rendering ceases.
*/
SkyTexture* SkyDynamicTextureManager::CheckOutTexture(unsigned int iWidth,
unsigned int iHeight)
{
int iWidthLog, iHeightLog;
iWidthLog = SkyGetLogBaseTwo(iWidth);
iHeightLog = SkyGetLogBaseTwo(iHeight);
// first see if a texture of this resolution is available:
// find the subset of textures with width = iWidth, if it exists.
TextureSet::iterator subset = _availableTexturePool.find(iWidth);
if (subset != _availableTexturePool.end())
{ // found the iWidth subset
// now find a texture with height = iHeight:
TextureSubset::iterator texture = (*subset).second->find(iHeight);
if (texture != (*subset).second->end())
{ // found one!
// extract the texture
SkyTexture *pTexture = (*texture).second;
(*texture).second = NULL;
// first remove it from this set.
(*subset).second->erase(texture);
// now add it to the checked out texture set.
_checkedOutTexturePool.insert(TextureSubset::value_type(pTexture->GetID(), pTexture));
// update checked out/in amount.
#if SKYDYNTEXTURE_VERBOSE
_iNumTextureBytesCheckedIn -= iWidth * iHeight * 4;
_iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
printf("CHECKOUT: %d x %d\n", iWidth, iHeight);
#endif
_iAvailableSizeCounts[iWidthLog][iHeightLog]--;
// we're now free to give this texture to the user
return pTexture;
}
else
{ // we didn't find an iWidth x iHeight texture, although the iWidth subset exists
// create a new texture of the appropriate dimensions and return it.
SkyTexture *pNewTexture = CreateDynamicTexture(iWidth, iHeight);
_checkedOutTexturePool.insert(TextureSubset::value_type(pNewTexture->GetID(),
pNewTexture));
#if SKYDYNTEXTURE_VERBOSE
_iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
#endif
return pNewTexture;
}
}
else
{ // we don't yet have a subset for iWidth textures. Create one.
TextureSubset *pSubset = new TextureSubset;
_availableTexturePool.insert(TextureSet::value_type(iWidth, pSubset));
// now create a new texture of the appropriate dimensions and return it.
SkyTexture *pNewTexture = CreateDynamicTexture(iWidth, iHeight);
_checkedOutTexturePool.insert(TextureSubset::value_type(pNewTexture->GetID(), pNewTexture));
#if SKYDYNTEXTURE_VERBOSE
_iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
#endif
return pNewTexture;
}
}
//------------------------------------------------------------------------------
// Function : SkyDynamicTextureManager::CheckInTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
* @brief Returns a checked-out texture to the available pool.
*
* This method removes the checked out texture from the checked out pool if it is
* checked out, and then checks it in to the available pool.
*/
void SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
{
// first see if the texture is in the checked out pool.
TextureSubset::iterator coTexture = _checkedOutTexturePool.find(pTexture->GetID());
if (coTexture != _checkedOutTexturePool.end())
{ // if it is there, remove it.
_checkedOutTexturePool.erase(coTexture);
_iNumTextureBytesCheckedOut -= pTexture->GetWidth() * pTexture->GetHeight() * 4;
}
// Don't cache too many unused textures.
int iWidthLog, iHeightLog;
iWidthLog = SkyGetLogBaseTwo(pTexture->GetWidth());
iHeightLog = SkyGetLogBaseTwo(pTexture->GetHeight());
if (_iAvailableSizeCounts[iWidthLog][iHeightLog] >= SKYDYNTEXTURE_TEXCACHE_LIMIT)
{
#if SKYDYNTEXTURE_VERBOSE
_iNumTextureBytesUsed -= pTexture->GetWidth() * pTexture->GetHeight() * 4;
printf("%dx%d texture DESTROYED.\n\t Total memory used: %d bytes.\n",
pTexture->GetWidth(), pTexture->GetHeight(), _iNumTextureBytesUsed);
#endif
pTexture->Destroy();
SAFE_DELETE(pTexture);
return;
}
// now check the texture into the available pool.
// find the width subset:
TextureSet::iterator subset = _availableTexturePool.find(pTexture->GetWidth());
if (subset != _availableTexturePool.end())
{ // the subset exists. Add the texture to it
(*subset).second->insert(TextureSubset::value_type(pTexture->GetHeight(), pTexture));
_iNumTextureBytesCheckedIn += pTexture->GetWidth() * pTexture->GetHeight() * 4;
_iAvailableSizeCounts[iWidthLog][iHeightLog]++;
}
else
{ // subset not found. Create it.
TextureSubset *pSubset = new TextureSubset;
// insert the texture.
pSubset->insert(TextureSubset::value_type(pTexture->GetHeight(), pTexture));
// insert the subset into the available pool
_availableTexturePool.insert(TextureSet::value_type(pTexture->GetWidth(), pSubset));
#if SKYDYNTEXTURE_VERBOSE
_iNumTextureBytesCheckedIn += pTexture->GetWidth() * pTexture->GetHeight() * 4;
_iAvailableSizeCounts[iWidthLog][iHeightLog]++;
#endif
}
pTexture = NULL;
}
//------------------------------------------------------------------------------
// Function : SkyDynamicTextureManager::CreateDynamicTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
* @brief Allocate a new dynamic texture object of the given resolution.
*
* This method is used by CheckOutTexture() when it can't find an available texture of
* the requested resolution. It can also be called externally, but will result in an
* unmanaged texture unless the new texture is subsequently checked in using CheckInTexture().
*/
SkyTexture* SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
{
unsigned int iID;
glGenTextures(1, &iID);
SkyTexture *pNewTexture = new SkyTexture(iWidth, iHeight, iID);
glBindTexture(GL_TEXTURE_2D, pNewTexture->GetID());
// set default filtering.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// create an empty buffer
unsigned char *pData = new unsigned char[iWidth * iHeight * 4];
// allocate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData );
delete [] pData;
// update the used texture bytes...
_iNumTextureBytesUsed += iWidth * iHeight * 4;
#if SKYDYNTEXTURE_VERBOSE
printf("New %dx%d texture created.\n\t Total memory used: %d bytes\n", iWidth, iHeight, _iNumTextureBytesUsed);
printf("\tTotal memory checked in: %d\n", _iNumTextureBytesCheckedIn);
printf("\tTotal memory checked out: %d\n", _iNumTextureBytesCheckedOut);
#endif
return pNewTexture;
}

View File

@@ -0,0 +1,80 @@
//------------------------------------------------------------------------------
// File : SkyDynamicTextureManager.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyDynamicTextureManager.hpp
*
* Interface definition of a repository for check out and check in of dynamic textures.
*/
#ifndef __SKYDYNAMICTEXTUREMANAGER_HPP__
#define __SKYDYNAMICTEXTUREMANAGER_HPP__
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
#include <map>
#include <GL/glut.h>
#include "SkyUtil.hpp"
#include "SkySingleton.hpp"
using namespace std;
class SkyTexture;
class SkyDynamicTextureManager;
//! Dynamic Texture Manager Singleton declaration.
/*! The DynamicTextureManager must be created by calling DynamicTextureManager::Instantiate(). */
typedef SkySingleton<SkyDynamicTextureManager> DynamicTextureManager;
//------------------------------------------------------------------------------
/**
* @class SkyDynamicTextureManager
* @brief A repository that allows check-out and check-in from a pool of dynamic textures.
*
* When an object needs a dynamic texture, it checks it out using CheckOutTexture(), passing
* the resolution of the texture it needs. When the object is done with the texture, it
* calls CheckInTexture(). New dynamic textures can be allocated by calling CreateDynamicTexture,
* but these textures will be unmanaged.
*/
class SkyDynamicTextureManager
{
public:
SkyTexture* CheckOutTexture(unsigned int iWidth, unsigned int iHeight);
void CheckInTexture(SkyTexture* pTexture);
SkyTexture* CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight);
protected: // methods
SkyDynamicTextureManager(); // these are protected because it is a singleton.
~SkyDynamicTextureManager();
protected: // datatypes
typedef multimap<unsigned int, SkyTexture*> TextureSubset;
typedef multimap<unsigned int, TextureSubset*> TextureSet;
protected: // data
TextureSet _availableTexturePool;
TextureSubset _checkedOutTexturePool;
unsigned int _iAvailableSizeCounts[11][11];
unsigned int _iNumTextureBytesUsed;
unsigned int _iNumTextureBytesCheckedOut;
unsigned int _iNumTextureBytesCheckedIn;
};
#endif //__SKYDYNAMICTEXTUREMANAGER_HPP__

View File

@@ -0,0 +1,221 @@
//------------------------------------------------------------------------------
// File : SkyLight.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyLight.cpp
*
* Implementation of a class that maintains the state and operation of a light.
*/
#pragma warning( disable : 4786)
#include "SkyLight.hpp"
#include "SkyMaterial.hpp"
#include "mat44.hpp"
#include <GL/glut.h>
SkyMaterial* SkyLight::s_pMaterial = NULL;
//------------------------------------------------------------------------------
// Function : SkyLight::SkyLight
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyLight::SkyLight(SkyLightType eType)
* @brief @todo <WRITE BRIEF SkyLight::SkyLight DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyLight::SkyLight FUNCTION DOCUMENTATION>
*/
SkyLight::SkyLight(SkyLightType eType)
: _bEnabled(true),
_bDirty(true),
_iLastGLID(-1),
_eType(eType),
_vecPosition(0, 0, 1, 1),
_vecDirection(0, 0, -1, 0),
_vecDiffuse(1, 1, 1, 1),
_vecAmbient(0, 0, 0, 0),
_vecSpecular(1, 1, 1, 1),
_vecAttenuation(1, 0, 0),
_rSpotExponent(0),
_rSpotCutoff(180)
{
if (!s_pMaterial)
{
s_pMaterial = new SkyMaterial;
s_pMaterial->SetColorMaterialMode(GL_DIFFUSE);
s_pMaterial->EnableColorMaterial(true);
s_pMaterial->EnableLighting(false);
}
}
//------------------------------------------------------------------------------
// Function : SkyLight::~SkyLight
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyLight::~SkyLight()
* @brief @todo <WRITE BRIEF SkyLight::~SkyLight DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyLight::~SkyLight FUNCTION DOCUMENTATION>
*/
SkyLight::~SkyLight()
{
}
//------------------------------------------------------------------------------
// Function : SkyLight::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyLight::Display() const
* @brief Displays a wireframe representation of the light.
*
* This is useful for debugging.
*/
void SkyLight::Display() const
{
s_pMaterial->Activate();
//if (_bEnabled)
//glColor3fv(&(_vecDiffuse.x));
//else
glColor3f(0, 0, 0);
switch(_eType)
{
case SKY_LIGHT_POINT:
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glTranslatef(_vecPosition.x, _vecPosition.y, _vecPosition.z);
glutWireSphere(4, 8, 8);
}
glPopMatrix();
break;
case SKY_LIGHT_DIRECTIONAL:
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
Mat44f mat;
Vec3f vecPos(_vecPosition.x, _vecPosition.y, _vecPosition.z);
Vec3f vecDir(_vecDirection.x, _vecDirection.y, _vecDirection.z);
Vec3f vecUp(0, 1, 0);
if (fabs(vecDir * vecUp) - 1 < 1e-6) // check that the view and up directions are not parallel.
vecUp.Set(1, 0, 0);
mat.invLookAt(vecPos, vecPos + 10 * vecDir, vecUp);
glPushMatrix();
{
glTranslatef(-50 * vecDir.x, -50 * vecDir.y, -50 * vecDir.z);
glMultMatrixf(mat);
glutWireCone(10, 10, 4, 1);
}
glPopMatrix();
glMultMatrixf(mat);
GLUquadric *pQuadric = gluNewQuadric();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gluCylinder(pQuadric, 4, 4, 50, 4, 4);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glPopMatrix();
}
break;
case SKY_LIGHT_SPOT:
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
Mat44f mat;
Vec3f vecUp = Vec3f(0, 1, 0);
Vec3f vecPos(_vecPosition.x, _vecPosition.y, _vecPosition.z);
Vec3f vecDir(_vecDirection.x, _vecDirection.y, _vecDirection.z);
if (_vecDirection == vecUp)
vecUp.Set(1, 0, 0);
mat.invLookAt(vecPos + 50 * vecDir, vecPos + 51 * vecDir, vecUp);
glMultMatrixf(mat);
float rAlpha= acos(pow(10, (-12 / _rSpotExponent)));
//glutWireCone(50 * tan(SKYDEGREESTORADS * rAlpha), 50, 16, 8);
glutWireCone(50 * tan(SKYDEGREESTORADS * _rSpotCutoff), 50, 16, 8);
}
glPopMatrix();
}
break;
default:
break;
}
}
//------------------------------------------------------------------------------
// Function : SkyLight::Activate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyLight::Activate(int iLightID)
* @brief @todo <WRITE BRIEF SkyLight::Activate DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyLight::Activate FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyLight::Activate(int iLightID)
{
glPushMatrix();
// set the position every frame
if (SKY_LIGHT_DIRECTIONAL != _eType)
glLightfv(GL_LIGHT0 + iLightID, GL_POSITION, &(_vecPosition.x));
else
glLightfv(GL_LIGHT0 + iLightID, GL_POSITION, &(_vecDirection.x));
if (SKY_LIGHT_SPOT == _eType)
glLightfv(GL_LIGHT0 + iLightID, GL_SPOT_DIRECTION, &(_vecDirection.x));
// set other light properties only when they change.
if (_bDirty || iLightID != _iLastGLID)
{
glLightfv(GL_LIGHT0 + iLightID, GL_DIFFUSE, &(_vecDiffuse.x));
glLightfv(GL_LIGHT0 + iLightID, GL_AMBIENT, &(_vecAmbient.x));
glLightfv(GL_LIGHT0 + iLightID, GL_SPECULAR, &(_vecSpecular.x));
glLightf(GL_LIGHT0 + iLightID, GL_CONSTANT_ATTENUATION, _vecAttenuation.x);
glLightf(GL_LIGHT0 + iLightID, GL_LINEAR_ATTENUATION, _vecAttenuation.y);
glLightf(GL_LIGHT0 + iLightID, GL_QUADRATIC_ATTENUATION, _vecAttenuation.z);
if (SKY_LIGHT_SPOT == _eType)
{
glLightf(GL_LIGHT0 + iLightID, GL_SPOT_CUTOFF, _rSpotCutoff);
glLightf(GL_LIGHT0 + iLightID, GL_SPOT_EXPONENT, _rSpotExponent);
}
else
{
glLightf(GL_LIGHT0 + iLightID, GL_SPOT_CUTOFF, 180);
glLightf(GL_LIGHT0 + iLightID, GL_SPOT_EXPONENT, 0);
}
if (_bEnabled)
glEnable(GL_LIGHT0 + iLightID);
else
{
glDisable(GL_LIGHT0 + iLightID);
}
_iLastGLID = iLightID;
_bDirty = false;
}
glPopMatrix();
return SKYRESULT_OK;
}

View File

@@ -0,0 +1,97 @@
//------------------------------------------------------------------------------
// File : SkyLight.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyLight.hpp
*
* Definition of a class that maintains the state and operation of a light.
*/
#ifndef __SKYLIGHT_HPP__
#define __SKYLIGHT_HPP__
#include "vec3f.hpp"
#include "vec4f.hpp"
#include "SkyUtil.hpp"
class SkyMaterial;
class SkyLight
{
public: // types
enum SkyLightType
{
SKY_LIGHT_POINT,
SKY_LIGHT_DIRECTIONAL,
SKY_LIGHT_SPOT,
SKY_LIGHT_NUM_TYPES
};
public: // methods
SkyLight(SkyLightType eType);
virtual ~SkyLight();
// for visualization of light positions / directions.
void Display() const;
bool GetEnabled() const { return _bEnabled; }
SkyLightType GetType() const { return _eType; }
const float* GetPosition() const { return _vecPosition; }
const float* GetDirection() const { return _vecDirection; }
const float* GetDiffuse() const { return _vecDiffuse; }
const float* GetAmbient() const { return _vecAmbient; }
const float* GetSpecular() const { return _vecSpecular; }
const float* GetAttenuation() const { return _vecAttenuation; }
float GetSpotExponent() const { return _rSpotExponent; }
float GetSpotCutoff() const { return _rSpotCutoff; }
void Enable(bool bEnable) { _bEnabled = bEnable; _bDirty = true; }
void SetType(const SkyLightType& t) { _eType = t; _bDirty = true; }
void SetPosition(const float pos[3])
{ _vecPosition.Set(pos[0], pos[1], pos[2], (_eType != SKY_LIGHT_DIRECTIONAL)); _bDirty = true; }
void SetDirection(const float dir[3]) { _vecDirection.Set(dir[0], dir[1], dir[2], 0); _bDirty = true; }
void SetDiffuse(const float color[4]) { _vecDiffuse.Set(color); _bDirty = true; }
void SetAmbient(const float color[4]) { _vecAmbient.Set(color); _bDirty = true; }
void SetSpecular(const float color[4]){ _vecSpecular.Set(color); _bDirty = true; }
void SetAttenuation(float rConstant, float rLinear, float rQuadratic)
{ _vecAttenuation.Set(rConstant, rLinear, rQuadratic); _bDirty = true; }
void SetSpotExponent(float rExp) { _rSpotExponent = rExp; _bDirty = true; }
void SetSpotCutoff(float rCutoff) { _rSpotCutoff = rCutoff; _bDirty = true; }
SKYRESULT Activate(int iLightID);
protected: // data
bool _bEnabled;
bool _bDirty;
int _iLastGLID;
SkyLightType _eType;
Vec4f _vecPosition;
Vec4f _vecDirection;
Vec4f _vecDiffuse;
Vec4f _vecAmbient;
Vec4f _vecSpecular;
Vec3f _vecAttenuation; // constant, linear, and quadratic attenuation factors.
float _rSpotExponent;
float _rSpotCutoff;
static SkyMaterial *s_pMaterial; // used for rendering the lights during debugging
};
#endif //__SKYLIGHT_HPP__

View File

@@ -0,0 +1,322 @@
//------------------------------------------------------------------------------
// File : SkyMaterial.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyMaterial.cpp
*
* Implementation of class SkyMaterial, a meterial property object.
*/
#include "SkyMaterial.hpp"
#include "SkyContext.hpp"
//------------------------------------------------------------------------------
// Function : SkyMaterial::SkyMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMaterial::SkyMaterial()
* @brief Constructor.
*/
SkyMaterial::SkyMaterial()
: _iMaterialID(-1),
_vecDiffuse(Vec4f::ZERO),
_vecSpecular(Vec4f::ZERO),
_vecAmbient(Vec4f::ZERO),
_vecEmissive(Vec4f::ZERO),
_rSpecularPower(0),
_bLighting(true),
_eColorMaterialFace(GL_FRONT_AND_BACK),
_eColorMaterialMode(GL_AMBIENT_AND_DIFFUSE),
_bColorMaterial(false),
_vecFogColor(Vec4f::ZERO),
_eFogMode(GL_EXP),
_bFog(false),
_eDepthFunc(GL_LESS),
_bDepthMask(true),
_bDepthTest(true),
_eAlphaFunc(GL_ALWAYS),
_rAlphaRef(0),
_bAlphaTest(false),
_eBlendSrcFactor(GL_ONE),
_eBlendDstFactor(GL_ZERO),
_bBlending(false),
_bFaceCulling(false),
_eFaceCullingMode(GL_BACK),
_eTextureEnvMode(GL_MODULATE)
{
_rFogParams[SKY_FOG_DENSITY] = 1;
_rFogParams[SKY_FOG_START] = 0;
_rFogParams[SKY_FOG_END] = 1;
}
//------------------------------------------------------------------------------
// Function : SkyMaterial::~SkyMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMaterial::~SkyMaterial()
* @brief Destructor.
*/
SkyMaterial::~SkyMaterial()
{
}
//------------------------------------------------------------------------------
// Function : SkyMaterial::SetFogParameter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMaterial::SetFogParameter(GLenum eParameter, float rValue)
*/
SKYRESULT SkyMaterial::SetFogParameter(GLenum eParameter, float rValue)
{
switch (eParameter)
{
case GL_FOG_DENSITY:
_rFogParams[SKY_FOG_DENSITY] = rValue;
break;
case GL_FOG_START:
_rFogParams[SKY_FOG_START] = rValue;
break;
case GL_FOG_END:
_rFogParams[SKY_FOG_END] = rValue;
break;
default:
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyMaterial::SetFogParameter(): Invalid parameter.");
break;
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyMaterial::GetFogParameter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMaterial::GetFogParameter(GLenum eParameter) const
*/
float SkyMaterial::GetFogParameter(GLenum eParameter) const
{
switch (eParameter)
{
case GL_FOG_DENSITY:
return _rFogParams[SKY_FOG_DENSITY];
break;
case GL_FOG_START:
return _rFogParams[SKY_FOG_START];
break;
case GL_FOG_END:
return _rFogParams[SKY_FOG_END];
break;
default:
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyMaterial::GetFogParameter(): Invalid parameter.");
break;
}
return -1;
}
//------------------------------------------------------------------------------
// Function : SkyMaterial::Activate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMaterial::Activate()
* @brief @todo <WRITE BRIEF SkyMaterial::SetMaterialPropertiesForDisplay DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyMaterial::SetMaterialPropertiesForDisplay FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyMaterial::Activate()
{
// Update the cached current material, and only pass values that have changed to the GL.
SkyMaterial *pCurrentMaterial = GraphicsContext::InstancePtr()->GetCurrentMaterial();
assert(NULL != pCurrentMaterial);
// basic material properties
if (pCurrentMaterial->GetDiffuse() != GetDiffuse())
{
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &(GetDiffuse().x));
pCurrentMaterial->SetDiffuse(GetDiffuse());
}
if (pCurrentMaterial->GetSpecular() != GetSpecular())
{
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &(GetSpecular().x));
pCurrentMaterial->SetSpecular(GetSpecular());
}
if (pCurrentMaterial->GetAmbient() != GetAmbient())
{
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &(GetAmbient().x));
pCurrentMaterial->SetAmbient(GetAmbient());
}
if (pCurrentMaterial->GetEmissive() != GetEmissive())
{
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &(GetEmissive().x));
pCurrentMaterial->SetEmissive(GetEmissive());
}
if (pCurrentMaterial->GetSpecularPower() != GetSpecularPower())
{
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, GetSpecularPower());
pCurrentMaterial->SetSpecularPower(GetSpecularPower());
}
// lighting
if (pCurrentMaterial->IsLightingEnabled() != IsLightingEnabled())
{
if (IsLightingEnabled())
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
pCurrentMaterial->EnableLighting(IsLightingEnabled());
}
// color material (which material property tracks color calls)
if (pCurrentMaterial->GetColorMaterialFace() != GetColorMaterialFace() ||
pCurrentMaterial->GetColorMaterialMode() != GetColorMaterialMode())
{
glColorMaterial(GetColorMaterialFace(), GetColorMaterialMode());
pCurrentMaterial->SetColorMaterialFace(GetColorMaterialFace());
pCurrentMaterial->SetColorMaterialMode(GetColorMaterialMode());
}
if (pCurrentMaterial->IsColorMaterialEnabled() != IsColorMaterialEnabled())
{
if (IsColorMaterialEnabled())
glEnable(GL_COLOR_MATERIAL);
else
glDisable(GL_COLOR_MATERIAL);
pCurrentMaterial->EnableColorMaterial(IsColorMaterialEnabled());
}
// fog
if (pCurrentMaterial->GetFogMode() != GetFogMode())
{
glFogf(GL_FOG_MODE, GetFogMode());
pCurrentMaterial->SetFogMode(GetFogMode());
}
if (pCurrentMaterial->GetFogColor() != GetFogColor())
{
glFogfv(GL_FOG_COLOR, GetFogColor());
pCurrentMaterial->SetFogColor(GetFogColor());
}
if (pCurrentMaterial->GetFogParameter(GL_FOG_DENSITY) != GetFogParameter(GL_FOG_DENSITY))
{
glFogf(GL_FOG_DENSITY, GetFogParameter(GL_FOG_DENSITY));
pCurrentMaterial->SetFogParameter(GL_FOG_DENSITY, GetFogParameter(GL_FOG_DENSITY));
}
if (pCurrentMaterial->GetFogParameter(GL_FOG_START) != GetFogParameter(GL_FOG_START))
{
glFogf(GL_FOG_START, GetFogParameter(GL_FOG_START));
pCurrentMaterial->SetFogParameter(GL_FOG_START, GetFogParameter(GL_FOG_START));
}
if (pCurrentMaterial->GetFogParameter(GL_FOG_END) != GetFogParameter(GL_FOG_END))
{
glFogf(GL_FOG_END, GetFogParameter(GL_FOG_END));
pCurrentMaterial->SetFogParameter(GL_FOG_END, GetFogParameter(GL_FOG_END));
}
if (pCurrentMaterial->IsFogEnabled() != IsFogEnabled())
{
if (IsFogEnabled())
glEnable(GL_FOG);
else
glDisable(GL_FOG);
pCurrentMaterial->EnableFog(IsFogEnabled());
}
// depth test
if (pCurrentMaterial->GetDepthFunc() != GetDepthFunc())
{
glDepthFunc(GetDepthFunc());
pCurrentMaterial->SetDepthFunc(GetDepthFunc());
}
if (pCurrentMaterial->GetDepthMask() != GetDepthMask())
{
glDepthMask(GetDepthMask());
pCurrentMaterial->SetDepthMask(GetDepthMask());
}
if (pCurrentMaterial->IsDepthTestEnabled() != IsDepthTestEnabled())
{
if (IsDepthTestEnabled())
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
pCurrentMaterial->EnableDepthTest(IsDepthTestEnabled());
}
// alpha test
if (pCurrentMaterial->GetAlphaFunc() != GetAlphaFunc() ||
pCurrentMaterial->GetAlphaRef() != GetAlphaRef())
{
glAlphaFunc(GetAlphaFunc(), GetAlphaRef());
pCurrentMaterial->SetAlphaFunc(GetAlphaFunc());
pCurrentMaterial->SetAlphaRef(GetAlphaRef());
}
if (pCurrentMaterial->IsAlphaTestEnabled() != IsAlphaTestEnabled())
{
if (IsAlphaTestEnabled())
glEnable(GL_ALPHA_TEST);
else
glDisable(GL_ALPHA_TEST);
pCurrentMaterial->EnableAlphaTest(IsAlphaTestEnabled());
}
// blending
if (pCurrentMaterial->GetBlendingSourceFactor() != GetBlendingSourceFactor() ||
pCurrentMaterial->GetBlendingDestFactor() != GetBlendingDestFactor())
{
glBlendFunc(GetBlendingSourceFactor(), GetBlendingDestFactor());
pCurrentMaterial->SetBlendFunc(GetBlendingSourceFactor(), GetBlendingDestFactor());
}
if (pCurrentMaterial->IsBlendingEnabled() != IsBlendingEnabled())
{
if (IsBlendingEnabled())
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
pCurrentMaterial->EnableBlending(IsBlendingEnabled());
}
if (pCurrentMaterial->GetFaceCullingMode() != GetFaceCullingMode())
{
glCullFace(GetFaceCullingMode());
pCurrentMaterial->SetFaceCullingMode(GetFaceCullingMode());
}
if (pCurrentMaterial->IsFaceCullingEnabled() != IsFaceCullingEnabled())
{
if (IsFaceCullingEnabled())
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
pCurrentMaterial->EnableFaceCulling(IsFaceCullingEnabled());
}
// texturing
FAIL_RETURN(_textureState.Activate());
if (pCurrentMaterial->GetTextureApplicationMode() != GetTextureApplicationMode())
{
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GetTextureApplicationMode());
pCurrentMaterial->SetTextureApplicationMode(GetTextureApplicationMode());
}
return SKYRESULT_OK;
}

View File

@@ -0,0 +1,268 @@
//------------------------------------------------------------------------------
// File : SkyMaterial.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyMaterial.hpp
*
* Interface definition for class SkyMaterial, a meterial property object.
*/
#ifndef __SKYMATERIAL_HPP__
#define __SKYMATERIAL_HPP__
#pragma warning( disable : 4786)
#include "vec4f.hpp"
#include "SkyUtil.hpp"
#include "SkyTextureManager.hpp"
#include "SkyTextureState.hpp"
#include <GL/glut.h>
// forward
class SkyRenderable;
//------------------------------------------------------------------------------
/**
* @class SkyMaterial
* @brief A class for organizing and caching material state.
*
* This class handles setting and querying material state. By calling the Activate()
* method, the material's state can be made current in OpenGL. The material will not
* set states that are currently active in the current OpenGL context.
*/
class SkyMaterial
{
public:
SkyMaterial();
~SkyMaterial();
SKYRESULT Activate();
// Getters for basic material properties
//! Returns the material identifier.
int GetMaterialID() const { return _iMaterialID; }
//! Returns the material diffuse color.
const Vec4f& GetDiffuse() const { return _vecDiffuse; }
//! Returns the material specular color.
const Vec4f& GetSpecular() const { return _vecSpecular; }
//! Returns the material ambient color.
const Vec4f& GetAmbient() const { return _vecAmbient; }
//! Returns the material emissive color.
const Vec4f& GetEmissive() const { return _vecEmissive; }
//! Returns the material specular power (shininess).
const float GetSpecularPower() const { return _rSpecularPower; }
// lighting
//! Returns true if lighting is enabled for this material.
bool IsLightingEnabled() const { return _bLighting; }
// color material (which material property tracks color calls)
//! Returns the face for which color material tracking is enabled.
GLenum GetColorMaterialFace() const { return _eColorMaterialFace; }
//! Returns the color material tracking mode.
GLenum GetColorMaterialMode() const { return _eColorMaterialMode; }
//! Returns true if color material tracking is enabled.
bool IsColorMaterialEnabled() const { return _bColorMaterial; }
//! Returns the fog density or start / end distance.
float GetFogParameter(GLenum eParameter) const;
//! Returns the fog mode (exponential, linear, etc.)
GLenum GetFogMode() const { return _eFogMode; }
//! Returns the fog color.
const Vec4f& GetFogColor() const { return _vecFogColor; }
//! Returns true if fog is enabled for this material.
bool IsFogEnabled() const { return _bFog; }
// texturing
//! Returns the active texture target for texture unit @a iTextureUnit.
GLenum GetActiveTarget(unsigned int iTextureUnit) const
{ return _textureState.GetActiveTarget(iTextureUnit); }
//! Returns the bound texture ID for texture unit @a iTextureUnit.
unsigned int GetTextureID(unsigned int iTextureUnit) const
{ return _textureState.GetTextureID(iTextureUnit); }
//! Returns true if texturing is enabled for texture unit @a iTextureUnit.
bool IsTextureEnabled(unsigned int iTextureUnit) const
{ return _textureState.IsTextureEnabled(iTextureUnit); }
//! Returns the value of the texture parameter @a eParameter for texture unit @a iTextureUnit.
GLenum GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const
{ return _textureState.GetTextureParameter(iTextureUnit, eParameter); }
//! Returns the texture application mode of the texture environment.
GLenum GetTextureApplicationMode() const { return _eTextureEnvMode; }
//! Returns a reference to the texture state object owned by this materal.
SkyTextureState& GetTextureState() { return _textureState; }
// depth test
//! Returns true if depth testing is enabled for this material.
bool IsDepthTestEnabled() const { return _bDepthTest; }
//! Returns the depth test function for this material.
GLenum GetDepthFunc() const { return _eDepthFunc; }
//! Returns true if depth writes are enabled for this material, false if not.
bool GetDepthMask() const { return _bDepthMask; }
// alpha test
//! Returns true if alpha testing is enabled for this material.
bool IsAlphaTestEnabled() const { return _bAlphaTest; }
//! Returns the alpha test function for this material.
GLenum GetAlphaFunc() const { return _eAlphaFunc; }
//! Returns the reference value for alpha comparison.
float GetAlphaRef() const { return _rAlphaRef; }
// blending
//! Returns true if blending is enabled for this material.
bool IsBlendingEnabled() const { return _bBlending; }
//! Returns the source blending factor for this material.
GLenum GetBlendingSourceFactor() const { return _eBlendSrcFactor; }
//! Returns the destination blending factor for this material.
GLenum GetBlendingDestFactor() const { return _eBlendDstFactor; }
//! Returns true if face culling enabled for this material.
bool IsFaceCullingEnabled() const { return _bFaceCulling; }
//! Returns which faces are culled -- front-facing or back-facing.
GLenum GetFaceCullingMode() const { return _eFaceCullingMode; }
// Setters for basic material properties
//! Sets the material identifier.
void SetMaterialID(int ID) { _iMaterialID = ID; }
//! Sets the diffuse material color.
void SetDiffuse( const Vec4f& d) { _vecDiffuse = d; }
//! Sets the specular material color.
void SetSpecular(const Vec4f& d) { _vecSpecular = d; }
//! Sets the ambient material color.
void SetAmbient( const Vec4f& d) { _vecAmbient = d; }
//! Sets the emissive material color.
void SetEmissive(const Vec4f& d) { _vecEmissive = d; }
//! Sets the material specular power (shininess).
void SetSpecularPower(float power) { _rSpecularPower = power; }
// lighting
//! Enables / Disables lighting for this material.
void EnableLighting(bool bEnable) { _bLighting = bEnable; }
// color material (which material property tracks color calls)
//! Sets which faces (front or back) track color calls.
void SetColorMaterialFace(GLenum eFace) { _eColorMaterialFace = eFace; }
//! Sets which material property tracks color calls.
void SetColorMaterialMode(GLenum eMode) { _eColorMaterialMode = eMode; }
//! Enables / Disables material color tracking for this material.
void EnableColorMaterial(bool bEnable) { _bColorMaterial = bEnable; }
//! Sets the fog density or start / end distance.
SKYRESULT SetFogParameter(GLenum eParameter, float rValue);
//! Sets the fog mode (exponential, linear, etc.)
void SetFogMode(GLenum eMode) { _eFogMode = eMode; }
//! Sets the fog color.
void SetFogColor(const Vec4f& color) { _vecFogColor = color; }
//! Enables / Disables fog for this material.
void EnableFog(bool bEnable) { _bFog = bEnable; }
// texturing
//! Sets the bound texture and texture target for texture unit @a iTextureUnit.
SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture& texture)
{ return _textureState.SetTexture(iTextureUnit, eTarget, texture); }
//! Sets the bound texture and texture target for texture unit @a iTextureUnit.
SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID)
{ return _textureState.SetTexture(iTextureUnit, eTarget, iTextureID); }
//! Enables / Disables texture unit @a iTextureUnit for this material.
SKYRESULT EnableTexture(unsigned int iTextureUnit, bool bEnable)
{ return _textureState.EnableTexture(iTextureUnit, bEnable); }
//! Sets the value of the texture parameter @a eParameter for texture unit @a iTextureUnit.
SKYRESULT SetTextureParameter(unsigned int iTextureUnit, GLenum eParameter, GLenum eMode)
{ return _textureState.SetTextureParameter(iTextureUnit, eParameter, eMode); }
//! Sets the texture application mode of the texture environment.
void SetTextureApplicationMode(GLenum eMode){ _eTextureEnvMode = eMode;}
// depth test
//! Enables / Disables depth test for this material.
void EnableDepthTest(bool bEnable) { _bDepthTest = bEnable; }
//! Sets the depth test function (greater, less than, equal, etc.).
void SetDepthFunc(GLenum eDepthFunc) { _eDepthFunc = eDepthFunc;}
//! If @a bDepthMask is true, then depth writes are enabled, otherwise they are not.
void SetDepthMask(bool bDepthMask) { _bDepthMask = bDepthMask;}
// alpha test
//! Enables / Disables alpha test for this material.
void EnableAlphaTest(bool bEnable) { _bAlphaTest = bEnable; }
//! Sets the alpha test function (greater, less than, equal, etc.).
void SetAlphaFunc(GLenum eAlphaFunc) { _eAlphaFunc = eAlphaFunc;}
//! Sets the reference value against which fragment alpha values are compared.
void SetAlphaRef(float rAlphaRef) { _rAlphaRef = rAlphaRef; }
// blending
//! Enables / Disables blending for this material.
void EnableBlending(bool bEnable) { _bBlending = bEnable; }
//! Sets the source and destination blending factors for this material.
void SetBlendFunc(GLenum eSrcFactor, GLenum eDstFactor)
{ _eBlendSrcFactor = eSrcFactor; _eBlendDstFactor = eDstFactor; }
//! Enables / Disables face culling for this material.
void EnableFaceCulling(bool bEnable) { _bFaceCulling = bEnable; }
//! Sets which faces will be culled -- front facing or back facing.
void SetFaceCullingMode(GLenum eMode) { _eFaceCullingMode = eMode; }
protected:
int _iMaterialID;
Vec4f _vecDiffuse;
Vec4f _vecSpecular;
Vec4f _vecAmbient;
Vec4f _vecEmissive;
float _rSpecularPower;
bool _bLighting;
GLenum _eColorMaterialFace;
GLenum _eColorMaterialMode;
bool _bColorMaterial;
enum SkyFogParams
{
SKY_FOG_DENSITY,
SKY_FOG_START,
SKY_FOG_END,
SKY_FOG_NUM_PARAMS
};
Vec4f _vecFogColor;
GLenum _eFogMode;
float _rFogParams[SKY_FOG_NUM_PARAMS];
bool _bFog;
GLenum _eDepthFunc;
bool _bDepthMask;
bool _bDepthTest;
GLenum _eAlphaFunc;
float _rAlphaRef;
bool _bAlphaTest;
GLenum _eBlendSrcFactor;
GLenum _eBlendDstFactor;
bool _bBlending;
bool _bFaceCulling;
GLenum _eFaceCullingMode;
SkyTextureState _textureState;
GLenum _eTextureEnvMode;
};
#endif //__SKYMATERIAL_HPP__

View File

@@ -0,0 +1,322 @@
//------------------------------------------------------------------------------
// File : SkyMinMaxBox.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyMinMaxBox.cpp
*
* Implementation of a bounding box class. Modified from Wes Hunt's BoundingBox.
*/
#include "SkyMinMaxBox.hpp"
#include "camutils.hpp"
#include <GL/glut.h>
#include <float.h>
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::SkyMinMaxBox
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::SkyMinMaxBox()
* @brief Constructor
*/
SkyMinMaxBox::SkyMinMaxBox()
{
Clear();
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::Clear
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::Clear()
* @brief Reset the min and max to floating point extremes.
*
*/
void SkyMinMaxBox::Clear()
{
_min.x = FLT_MAX;
_min.y = FLT_MAX;
_min.z = FLT_MAX;
_max.x = -FLT_MAX;
_max.y = -FLT_MAX;
_max.z = -FLT_MAX;
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::PointInBBox
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::PointInBBox( const Vec3f &pt ) const
* @brief Queries pt to see if it is inside the SkyMinMaxBox.
*
*/
bool SkyMinMaxBox::PointInBBox( const Vec3f &pt ) const
{
if( (pt.x >= _min.x) && ( pt.x <= _max.x ) )
{
if( (pt.y >= _min.y) && ( pt.y <= _max.y ) )
{
if( (pt.z >= _min.z) && ( pt.z <= _max.z ) )
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::AddPoint
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::AddPoint( float x , float y , float z )
* @brief Adds a point and adjusts bounds if necessary.
*/
void SkyMinMaxBox::AddPoint( float x , float y , float z )
{
if( x > _max.x )
_max.x = x;
if( x < _min.x )
_min.x = x;
if( y > _max.y )
_max.y = y;
if( y < _min.y )
_min.y = y;
if( z > _max.z )
_max.z = z;
if( z < _min.z )
_min.z = z;
// update the center and radius
_UpdateSphere();
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::AddPoint
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::AddPoint( const Vec3f &pt )
* @brief Adds a point and adjusts bounds if necessary.
*/
void SkyMinMaxBox::AddPoint( const Vec3f &pt )
{
if( pt.x > _max.x )
_max.x = pt.x;
if( pt.x < _min.x )
_min.x = pt.x;
if( pt.y > _max.y )
_max.y = pt.y;
if( pt.y < _min.y )
_min.y = pt.y;
if( pt.z > _max.z )
_max.z = pt.z;
if( pt.z < _min.z )
_min.z = pt.z;
// update the center and radius
_UpdateSphere();
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::ViewFrustumCull( const Camera &cam, const Mat44f &mat )
* @brief Returns true if bounding volume culled against cam.
*
* This function must transform the object space min and max then adjust the new
* min and max box by expanding it. Each of the 8 points must be tested. This
* is faster then doing an xform of all the geometry points and finding a tight
* fitting min max box, however this will be enlarged.
*/
bool SkyMinMaxBox::ViewFrustumCull( const Camera &cam, const Mat44f &mat )
{
SkyMinMaxBox xBV; // Xformed Bounding Volume
Vec3f xMin = mat * _min; // Xformed _min
Vec3f xMax = mat * _max; // Xformed _max
Vec3f offset = _max - _min; // Offset for sides of MinMaxBox
Vec3f tmp;
xBV.Clear(); // Clear the values first
// First find the new minimum x,y,z
// Find min + x
tmp.Set(mat.M[0], mat.M[4], mat.M[8]);
tmp *= offset.x;
tmp += xMin;
xBV.AddPoint(tmp);
// Find min + y
tmp.Set(mat.M[1], mat.M[5], mat.M[9]);
tmp *= offset.y;
tmp += xMin;
xBV.AddPoint(tmp);
// Find min + z
tmp.Set(mat.M[3], mat.M[6], mat.M[10]);
tmp *= offset.z;
tmp += xMin;
xBV.AddPoint(tmp);
// Second find the new maximum x,y,z
// Find max - x
tmp.Set(mat.M[0], mat.M[4], mat.M[8]);
tmp *= -offset.x;
tmp += xMax;
xBV.AddPoint(tmp);
// Find max - y
tmp.Set(mat.M[1], mat.M[5], mat.M[9]);
tmp *= -offset.y;
tmp += xMax;
xBV.AddPoint(tmp);
// Find max - z
tmp.Set(mat.M[3], mat.M[6], mat.M[10]);
tmp *= -offset.z;
tmp += xMax;
xBV.AddPoint(tmp);
// Use the camera utility function that already exists for minmax boxes
return VFC(&cam, xBV.GetMin(), xBV.GetMax());
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::Transform
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::Transform(const Mat44f& mat)
* @brief @todo <WRITE BRIEF SkyMinMaxBox::Transform DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyMinMaxBox::Transform FUNCTION DOCUMENTATION>
*/
void SkyMinMaxBox::Transform(const Mat44f& mat)
{
Vec3f verts[8];
_CalcVerts(verts);
Clear();
for (int i = 0; i < 8; ++i)
{
AddPoint(mat * verts[i]);
}
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::_UpdateSphere
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::_UpdateSphere()
* @brief Updates the bounding sphere based on min and max.
*/
void SkyMinMaxBox::_UpdateSphere()
{
_vecCenter = _min;
_vecCenter += _max;
_vecCenter *= 0.5f;
Vec3f rad = _max;
rad -= _vecCenter;
_rRadius = rad.Length();
}
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::Display() const
* @brief @todo <WRITE BRIEF SkyMinMaxBox::Display DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyMinMaxBox::Display FUNCTION DOCUMENTATION>
*/
void SkyMinMaxBox::Display() const
{
Vec3f V[8];
_CalcVerts(V);
glPushAttrib(GL_LINE_BIT);
glLineWidth(1.0);
glBegin(GL_LINE_LOOP); // TOP FACE
glVertex3fv(V[4]); glVertex3fv(V[5]); glVertex3fv(V[1]); glVertex3fv(V[0]);
glEnd();
glBegin(GL_LINE_LOOP); // BOTTOM FACE
glVertex3fv(V[3]); glVertex3fv(V[2]); glVertex3fv(V[6]); glVertex3fv(V[7]);
glEnd();
glBegin(GL_LINE_LOOP); // LEFT FACE
glVertex3fv(V[1]); glVertex3fv(V[5]); glVertex3fv(V[6]); glVertex3fv(V[2]);
glEnd();
glBegin(GL_LINE_LOOP); // RIGHT FACE
glVertex3fv(V[0]); glVertex3fv(V[3]); glVertex3fv(V[7]); glVertex3fv(V[4]);
glEnd();
glBegin(GL_LINE_LOOP); // NEAR FACE
glVertex3fv(V[1]); glVertex3fv(V[2]); glVertex3fv(V[3]); glVertex3fv(V[0]);
glEnd();
glBegin(GL_LINE_LOOP); // FAR FACE
glVertex3fv(V[4]); glVertex3fv(V[7]); glVertex3fv(V[6]); glVertex3fv(V[5]);
glEnd();
glPopAttrib();
}
//-----------------------------------------------------------------------------
// Calculates the eight corner vertices of the MinMaxBox.
// V must be prealloced.
// 5---4
// / /|
// 1---0 | VERTS : 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
// | | 7 (L,R, B,T, N,F) = (Left,Right, Bottom,Top, Near,Far)
// | |/
// 2---3
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Function : SkyMinMaxBox::_CalcVerts
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyMinMaxBox::_CalcVerts(Vec3f pVerts[8]) const
* @brief @todo <WRITE BRIEF SkyMinMaxBox::_CalcVerts DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyMinMaxBox::_CalcVerts FUNCTION DOCUMENTATION>
*/
void SkyMinMaxBox::_CalcVerts(Vec3f pVerts[8]) const
{
pVerts[0].Set(_max); pVerts[4].Set(_max.x, _max.y, _min.z);
pVerts[1].Set(_min.x, _max.y, _max.z); pVerts[5].Set(_min.x, _max.y, _min.z);
pVerts[2].Set(_min.x, _min.y, _max.z); pVerts[6].Set(_min);
pVerts[3].Set(_max.x, _min.y, _max.z); pVerts[7].Set(_max.x, _min.y, _min.z);
}

View File

@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
// File : SkyMinMaxBox.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyMinMaxBox.hpp
*
* Interface definition for a min-max bounding box class for bounding volume hierarchies.
*/
#ifndef __SKYMINMAXBOX_HPP__
#define __SKYMINMAXBOX_HPP__
#include "SkyBoundingVolume.hpp"
//------------------------------------------------------------------------------
/**
* @class SkyMinMaxBox
* @brief An AABB class that can be used in bounding volume hierarchies.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyMinMaxBox : public SkyBoundingVolume
{
public:
SkyMinMaxBox();
//! Destructor
virtual ~SkyMinMaxBox() {}
void AddPoint( const Vec3f &pt );
void AddPoint( float x , float y , float z );
//! Expand this box to contain @a box.
void Union(const SkyMinMaxBox& box) { AddPoint(box.GetMin()); AddPoint(box.GetMax()); }
//! Returns the minimum corner of the bounding box.
const Vec3f &GetMin() const { return _min; }
//! Returns the maximum corner of the bounding box.
const Vec3f &GetMax() const { return _max; }
//! Sets the minimum corner of the bounding box.
void SetMin(const Vec3f &min) { _min = min; _UpdateSphere(); }
//! Sets the maximum corner of the bounding box.
void SetMax(const Vec3f &max) { _max = max; _UpdateSphere(); }
//! Returns the X width of the bounding box.
float GetWidthInX() const { return _max.x - _min.x;}
//! Returns the Y width of the bounding box.
float GetWidthInY() const { return _max.y - _min.y;}
//! Returns the Z width of the bounding box.
float GetWidthInZ() const { return _max.z - _min.z;}
bool PointInBBox( const Vec3f &pt ) const;
bool ViewFrustumCull( const Camera &cam, const Mat44f &mat );
void Transform(const Mat44f& mat);
// Reset the bounding box
void Clear();
void Display() const;
protected:
void _UpdateSphere();
void _CalcVerts(Vec3f pVerts[8]) const;
private:
Vec3f _min; // Original object space BV
Vec3f _max;
};
#endif //__SKYMINMAXBOX_HPP__

View File

@@ -0,0 +1,116 @@
//------------------------------------------------------------------------------
// File : SkyRenderable.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
//------------------------------------------------------------------------------
// File : SkyRenderable.hpp
//------------------------------------------------------------------------------
// Sky : Copyright 2002 Mark J. Harris and Andrew Zaferakis
//------------------------------------------------------------------------------
/**
* @file SkyRenderable.hpp
*
* Abstract base class definition for SkyRenderable, a renderable object class.
*/
#ifndef __SKYRENDERABLE_HPP__
#define __SKYRENDERABLE_HPP__
#pragma warning( disable : 4786)
#include <string>
#include "SkyUtil.hpp"
// forward to reduce unnecessary dependencies
class SkyMinMaxBox;
class SkyRenderableInstance;
class Camera;
//------------------------------------------------------------------------------
/**
* @class SkyRenderable
* @brief An base class for renderable objects.
*
* Each SkyRenderable object should know how to Display itself, however some
* objects may not have a bounding volume that is useful (skybox, etc.)
*/
class SkyRenderable
{
public:
//! Constructor
SkyRenderable() {}
//! Destructor
virtual ~SkyRenderable() { }
//------------------------------------------------------------------------------
// Function : SetName
// Description :
//------------------------------------------------------------------------------
/**
* @fn SetName(const std::string &name)
* @brief Set a name for this renderable.
*/
void SetName(const std::string &name) { _name = name; }
//------------------------------------------------------------------------------
// Function : GetName
// Description :
//------------------------------------------------------------------------------
/**
* @fn GetName() const
* @brief Get the name of this renderable.
*/
const std::string& GetName() const { return _name; }
//------------------------------------------------------------------------------
// Function : Update
// Description :
//------------------------------------------------------------------------------
/**
* @fn Update(const Camera &cam, SkyRenderableInstance *pInstance)
* @brief Update the state of the renderable.
*
* This method is optional, as some renderables will need periodic updates
* (i.e. for animation) and others will not.
*/
virtual SKYRESULT Update(const Camera &cam, SkyRenderableInstance *pInstance = NULL)
{ return SKYRESULT_OK; }
//------------------------------------------------------------------------------
// Function : Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn Display(const Camera &cam, SkyRenderableInstance *pInstance)
* @brief Display the object.
*/
virtual SKYRESULT Display(const Camera &cam, SkyRenderableInstance *pInstance = NULL) = 0;
//------------------------------------------------------------------------------
// Function : CopyBoundingVolume
// Description :
//------------------------------------------------------------------------------
/**
* @fn CopyBoundingVolume() const
* @brief Create a copy of the object's bounding volume, useful for collision, VFC, etc.
*/
virtual SkyMinMaxBox* CopyBoundingVolume() const = 0;// { return 0; }
protected:
std::string _name; // the name of this renderable.
};
#endif //__SKYRENDERABLE_HPP__

View File

@@ -0,0 +1,202 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstance.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyRenderableInstance.hpp
*
* Interface definition for SkyRenderableInstance, an instance of a renderable object.
*/
#ifndef __SKYRENDERABLEINSTANCE_HPP__
#define __SKYRENDERABLEINSTANCE_HPP__
#include <vector>
#include <mat33.hpp>
#include <mat44.hpp>
#include "SkyUtil.hpp"
// forward to reduce unnecessary dependencies
class Camera;
class SkyMinMaxBox;
// forward so we can make the following typedefs easily visible in the header.
// rather than buried under the class definition.
class SkyRenderableInstance;
//! A dynamic array of SkyRenderableInstance pointers.
typedef std::vector<SkyRenderableInstance*> InstanceArray;
//! An instance array iterator.
typedef InstanceArray::iterator InstanceIterator;
//------------------------------------------------------------------------------
/**
* @class SkyRenderableInstance
* @brief An instance of a SkyRenderable object.
*
* An instance contains a pointer to a SkyRenderable object. The
* instance contains attributes such as position, orientation,
* scale, etc. that vary between instances.
*/
class SkyRenderableInstance
{
public:
//! Constructor.
SkyRenderableInstance()
: _bCulled(false), _bAlive(true), _vecPosition(0, 0, 0), _rScale(1), _rSquareSortDistance(0)
{
_matRotation.Identity(); _matInvRotation.Identity();
}
//! Constructor.
SkyRenderableInstance(const Vec3f &position,
const Mat33f &rotation,
const float scale)
: _bCulled(false), _bAlive(true), _vecPosition(position),
_matRotation(rotation), _rScale(scale), _rSquareSortDistance(0)
{
_matInvRotation = _matRotation;
_matInvRotation.Transpose();
}
//! Destructor
virtual ~SkyRenderableInstance() {}
// Setters / Getters
//! Set the world space position of the instance.
virtual void SetPosition(const Vec3f &position) { _vecPosition = position; }
//! Set the world space rotation of the instance.
virtual void SetRotation(const Mat33f &rotation) { _matRotation = rotation;
_matInvRotation = rotation;
_matInvRotation.Transpose(); }
//! Set the world space scale of the instance.
virtual void SetScale( const float &scale) { _rScale = scale; }
//! Returns the world space position of the instance.
virtual const Vec3f& GetPosition() const { return _vecPosition; }
//! Returns the world space rotation matrix of the instance.
virtual const Mat33f& GetRotation() const { return _matRotation; }
//! Returns the inverse of the world space rotation matrix of the instance.
virtual const Mat33f& GetInverseRotation() const { return _matInvRotation; }
//! Returns the world space scale of the instance.
virtual float GetScale() const { return _rScale; }
//! Update the instance based on the given camera, @a cam.
virtual SKYRESULT Update(const Camera &cam) { return SKYRESULT_OK; }
//! Render the instance.
virtual SKYRESULT Display() { return SKYRESULT_OK; }
//! Returns the transform matrix from model space to world space.
inline virtual void GetModelToWorldTransform(Mat44f &mat) const;
//! Returns the transform matrix from world space to model space.
inline virtual void GetWorldToModelTransform(Mat44f &mat) const;
//! Returns the object-space bounding volume for this instance, or NULL if none is available.
virtual SkyMinMaxBox* GetBoundingVolume() const { return NULL; }
//! Returns true if and only if the bounding volume of this instance lies entirely outside @a cam.
virtual bool ViewFrustumCull(const Camera &cam) { return false; }
//! Returns true if the instance was culled.
virtual bool IsCulled() { return _bCulled; }
//! Sets the culled state of the instance.
virtual void SetCulled(bool bCulled) { _bCulled = bCulled; }
//! Returns true if the instance is currently active.
virtual bool IsAlive() { return _bAlive; }
//! Activates or deactivates the instance.
virtual void SetIsAlive(bool bAlive) { _bAlive = bAlive; }
//! Sets the distance of this object from the sort position. Used to sort instances.
virtual void SetSquareSortDistance(float rSqrDist) { _rSquareSortDistance = rSqrDist; }
//! Returns the distance of this object from the sort position. (Set with SetSquareSortDistance())
virtual float GetSquareSortDistace() const { return _rSquareSortDistance; }
//! This operator is used to sort instance arrays.
bool operator<(const SkyRenderableInstance& instance) const
{
return (_rSquareSortDistance > instance._rSquareSortDistance);
}
protected:
bool _bCulled; // Culled flag
bool _bAlive; // Alive object flag
Vec3f _vecPosition; // Position
Mat33f _matRotation; // Rotation
Mat33f _matInvRotation; // inverse rotation
float _rScale; // Scale
// for sorting particles during shading
float _rSquareSortDistance;
};
//------------------------------------------------------------------------------
// Function : SkyRenderableInstance::GetModelToWorldTransform
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstance::GetModelToWorldTransform(Mat44f &mat) const
* @brief Returns the 4x4 transformation matrix from world to model space.
*/
inline void SkyRenderableInstance::GetModelToWorldTransform(Mat44f &mat) const
{
mat[0] = _matRotation.M[0]; mat[4] = _matRotation.M[3];
mat[8] = _matRotation.M[6]; mat[12] = 0;
mat[1] = _matRotation.M[1]; mat[5] = _matRotation.M[4];
mat[9] = _matRotation.M[7]; mat[13] = 0;
mat[2] = _matRotation.M[2]; mat[6] = _matRotation.M[5];
mat[10] = _matRotation.M[8]; mat[14] = 0;
mat[3] = 0; mat[7] = 0; mat[11] = 0; mat[15] = 0;
// Scale the matrix (we don't want to scale translation or mat[15] which is 1)
if (_rScale != 1)
mat *= _rScale;
// Set the translation and w coordinate after the potential scaling
mat[12] = _vecPosition.x; mat[13] = _vecPosition.y; mat[14] = _vecPosition.z;
mat[15] = 1;
}
//------------------------------------------------------------------------------
// Function : Mat44f& SkyRenderableInstance::GetWorldToModelTransform
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstance::GetWorldToModelTransform(Mat44f &mat) const
* @brief Returns the 4x4 transformation matrix from world to model space.
*/
inline void SkyRenderableInstance::GetWorldToModelTransform(Mat44f &mat) const
{
mat[0] = _matRotation.M[0]; mat[4] = _matRotation.M[1];
mat[8] = _matRotation.M[2]; mat[12] = 0;
mat[1] = _matRotation.M[3]; mat[5] = _matRotation.M[4];
mat[9] = _matRotation.M[5]; mat[13] = 0;
mat[2] = _matRotation.M[6]; mat[6] = _matRotation.M[7];
mat[10] = _matRotation.M[8]; mat[14] = 0;
mat[3] = 0; mat[7] = 0; mat[11] = 0; mat[15] = 0;
// Scale the matrix (we don't want to scale translation or mat[15] which is 1)
if (_rScale != 1)
mat *= (1 / _rScale);
// Set the translation and w coordinate after the potential scaling
mat[12] = -_vecPosition.x; mat[13] = -_vecPosition.y; mat[14] = -_vecPosition.z;
mat[15] = 1;
}
#endif //__SKYRENDERABLEINSTANCE_HPP__

View File

@@ -0,0 +1,705 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceCloud.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyRenderableInstanceCloud.cpp
*
* Implementation of class SkyRenderableInstanceCloud.
*/
#include "SkyUtil.hpp"
#include "SkyCloud.hpp"
#include "SkyMaterial.hpp"
#include "SkyBoundingVolume.hpp"
#include "SkyRenderableInstanceCloud.hpp"
#include "SkyDynamicTextureManager.hpp"
//! Set this to 1 to see verbose messages about impostor updates.
#define SKYCLOUD_VERBOSE 0
//! Set this to control the number of frames a cloud has to be culled before its textures are released.
#define SKYCLOUD_CULL_RELEASE_COUNT 100
//------------------------------------------------------------------------------
// Static declarations.
//------------------------------------------------------------------------------
unsigned int SkyRenderableInstanceCloud::s_iCount = 0;
float SkyRenderableInstanceCloud::s_rErrorToleranceAngle = SKYDEGREESTORADS * 0.125f;
SkyMaterial* SkyRenderableInstanceCloud::s_pMaterial = NULL;
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, bool bUseOffScreenBuffer)
* @brief Constructor.
*/
SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud,
bool bUseOffScreenBuffer /* = true */)
: SkyRenderableInstance(),
_iCloudID(-1),
_pCloud(pCloud),
_pWorldSpaceBV(NULL),
_rRadius(0),
_bScreenImpostor(false),
_bImageExists(false),
_bEnabled(true),
_bUseOffScreenBuffer(bUseOffScreenBuffer),
_bSplit(false),
_vecSplit(0, 0, 0),
_vecNearPoint(0, 0, 0),
_vecFarPoint(0, 0, 0),
_iLogResolution(0),
_pBackTexture(NULL),
_pFrontTexture(NULL),
_iCulledCount(0)
{
_Initialize();
cout << "Cloud Instance created" << endl;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, const Vec3f &position, const Mat33f &rotation, const float scale, bool bUseOffScreenBuffer)
* @brief Constructor.
*/
SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud,
const Vec3f &position,
const Mat33f &rotation,
const float scale,
bool bUseOffScreenBuffer /* = true */)
: SkyRenderableInstance(position, rotation, scale),
_iCloudID(-1),
_pCloud(pCloud),
_pWorldSpaceBV(NULL),
_rRadius(0),
_bScreenImpostor(false),
_bImageExists(false),
_bEnabled(true),
_bUseOffScreenBuffer(false),
_bSplit(false),
_vecSplit(0, 0, 0),
_vecNearPoint(0, 0, 0),
_vecFarPoint(0, 0, 0),
_iLogResolution(0),
_pBackTexture(NULL),
_pFrontTexture(NULL)
{
_Initialize();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
* @brief Destructor
*/
SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
{
_pCloud = NULL;
SAFE_DELETE(_pWorldSpaceBV);
s_iCount--;
// delete the offscreen buffer when no one else is using it.
if (0 == s_iCount)
{
//JW?? SAFE_DELETE(s_pRenderBuffer);
SAFE_DELETE(s_pMaterial);
}
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::SetPosition
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SetPosition(const Vec3f &position)
* @brief Set the world space position of the instance.
*
* @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetPosition FUNCTION DOCUMENTATION>
*/
void SkyRenderableInstanceCloud::SetPosition(const Vec3f &position)
{
if (_pCloud)
{
_pCloud->Translate(position - _vecPosition);
}
_vecPosition = position;
_UpdateWorldSpaceBounds();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::SetRotation
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
* @brief Set the world space rotation of the instance.
*
* @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetRotation FUNCTION DOCUMENTATION>
*/
void SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
{
if (_pCloud)
{
_pCloud->Translate(-_vecPosition);
_pCloud->Rotate(_matInvRotation * rotation);
_pCloud->Translate(_vecPosition);
}
_matRotation = rotation;
_matInvRotation = rotation;
_matInvRotation.Transpose();
_UpdateWorldSpaceBounds();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::SetScale
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SetScale(const float &scale)
* @brief Set the world space scale of the instance.
*/
void SkyRenderableInstanceCloud::SetScale(const float &scale)
{
if (_pCloud)
{
_pCloud->Translate(-_vecPosition);
_pCloud->Scale(scale);
_pCloud->Translate(_vecPosition);
}
_rScale = scale;
_UpdateWorldSpaceBounds();
}
//------------------------------------------------------------------------------
// Function : DrawQuad
// Description :
//------------------------------------------------------------------------------
/**
* DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
* @brief Simply draws an OpenGL quad at @a pos.
*
* The quad's size and orientation are determined by the (non-unit) vectors @a x
* and @a y. Its color is given by @a color.
*/
inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
{
glColor4fv(&(color.x));
Vec3f left = pos; left -= y;
Vec3f right = left; right += x;
left -= x;
glTexCoord2f(0, 0); glVertex3fv(&(left.x));
glTexCoord2f(1, 0); glVertex3fv(&(right.x));
left += y; left += y;
right += y; right += y;
glTexCoord2f(1, 1); glVertex3fv(&(right.x));
glTexCoord2f(0, 1); glVertex3fv(&(left.x));
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit)
* @brief Display the instance of the cloud using the impostor image.
*/
SKYRESULT SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit /* = false */)
{
if (!_bImageExists || !_bEnabled)
{
//FAIL_RETURN(DisplayWithoutImpostor(*(GLVU::GetCurrent()->GetCurrentCam())));
FAIL_RETURN(DisplayWithoutImpostor(Camera::Camera()));
}
else
{
//cout << "Using impostor image\n";
if (!_pBackTexture || (bDisplayFrontOfSplit && !_pFrontTexture))
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyRenderableInstanceCloud::Display(): missing texture!");
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, bDisplayFrontOfSplit ? *_pFrontTexture : *_pBackTexture);
if (_bScreenImpostor)
{
s_pMaterial->EnableDepthTest(false);
}
else if (_bSplit)
{
if (!bDisplayFrontOfSplit)
{
s_pMaterial->EnableDepthTest(true);
s_pMaterial->SetDepthMask(false);
}
else
s_pMaterial->EnableDepthTest(false);
}
else
{
s_pMaterial->EnableDepthTest(true);
s_pMaterial->SetDepthMask(true);
}
s_pMaterial->Activate();
Vec3f x, y, z;
if (!_bScreenImpostor)
{
//cout << "Outside the cloud\n";
z = _vecPosition;
z -= _impostorCam.Orig;
z.Normalize();
x = (z ^ _impostorCam.Y);
x.Normalize();
x *= _rRadius;
y = (x ^ z);
y.Normalize();
y *= _rRadius;
glBegin(GL_QUADS);
DrawQuad(_vecPosition, x, y, Vec4f(1, 1, 1, 1));
glEnd();
}
else
{ //cout << "Drawing a polygon - must be inside a cloud\n";
x = _impostorCam.X;
x *= 0.5f * (_impostorCam.wR - _impostorCam.wL);
y = _impostorCam.Y;
y *= 0.5f * (_impostorCam.wT - _impostorCam.wB);
z = -_impostorCam.Z;
z *= _impostorCam.Near;
// draw a polygon with this texture...
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(-1, 1, -1, 1);
glColor4f(1, 1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(-1, -1);
glTexCoord2f(1, 0); glVertex2f(1, -1);
glTexCoord2f(1, 1); glVertex2f(1, 1);
glTexCoord2f(0, 1); glVertex2f(-1, 1);
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::DisplayWithoutImpostor
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
* @brief Displays the cloud directly -- without an impotor.
*
* This is used both when the impostor is disabled and to create the impostor image
* when it needs to be updated.
*/
SKYRESULT SkyRenderableInstanceCloud::DisplayWithoutImpostor(const Camera &cam)
{
// Get and set the world space transformation
/*Mat44f mat;
GetModelToWorldTransform(mat);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(mat.M);*/
FAIL_RETURN_MSG(_pCloud->Display(cam, this), "SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
//glMatrixMode(GL_MODELVIEW);
//glPopMatrix();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
* @brief View frustum cull the object given its world position
*/
bool SkyRenderableInstanceCloud::ViewFrustumCull(const Camera &cam)
{
Mat44f xform;
//GetModelToWorldTransform(xform);
xform.Identity();
_bCulled = (_pWorldSpaceBV == NULL) ? false : _pWorldSpaceBV->ViewFrustumCull(cam, xform);
return _bCulled;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::ReleaseImpostorTextures
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::ReleaseImpostorTextures()
* @brief Causes the instance to release its impostor textures for use by other impostors.
*
* This method is called when the cloud is view frustum culled.
*/
void SkyRenderableInstanceCloud::ReleaseImpostorTextures()
{
_iCulledCount++;
if (_iCulledCount > SKYCLOUD_CULL_RELEASE_COUNT)
{
_iCulledCount = 0;
if (_pBackTexture)
{
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
_pBackTexture = NULL;
}
if (_pFrontTexture)
{
DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
_pFrontTexture = NULL;
}
_bImageExists = false;
}
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::Update
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::Update(const Camera &cam)
* @brief Updates the impostor image to be valid for the current viewpoint.
*
* If the image is already valid, exits early.
*
* @see SetErrorToleranceAngle, IsValid
*/
SKYRESULT SkyRenderableInstanceCloud::Update(const Camera &cam)
{
if (!_bEnabled || IsImpostorValid(cam))
return SKYRESULT_OK;
// since we are going to update it anyway, let's make sure we don't try to use it if something
// goes wrong. This will be set to true on the successful completion of this Update() method.
_bImageExists = false;
//cout << "updating impostor\n";
Mat44f M;
_impostorCam = cam;
float rDistance = (_vecPosition - cam.Orig).Length();
float rRadius = _pWorldSpaceBV->GetRadius();
float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
float rWidth = cam.wR - cam.wL;
float rHeight = cam.wT - cam.wB;
float rMaxdim = (rWidth > rHeight) ? rWidth : rHeight;
if (rRadius * cam.Near / rDistance < 0.5 * rMaxdim && (rDistance - rRadius > rCamRadius))
{ // outside cloud
_impostorCam.TightlyFitToSphere(cam.Orig, cam.Y, _vecPosition, rRadius);
_rRadius = 0.5f * (_impostorCam.wR - _impostorCam.wL) * rDistance / _impostorCam.Near;
_rRadius *= GetScale();
_bScreenImpostor = false;
// store points used in later error estimation
_vecNearPoint = -_impostorCam.Z;
_vecNearPoint *= _impostorCam.Near;
_vecNearPoint += _impostorCam.Orig;
_vecFarPoint = -_impostorCam.Z;
_vecFarPoint *= _impostorCam.Far;
_vecFarPoint += _impostorCam.Orig;
}
else // inside cloud
{
_impostorCam.Far = _impostorCam.Near + 3 * rRadius;
_bScreenImpostor = true;
}
// resolution based on screensize, distance, and object size.
// Cam radius is used to heuristically reduce resolution for clouds very close to the camera.
_iLogResolution = _GetRequiredLogResolution(rDistance, rRadius, rCamRadius);
int iRes = 1 << _iLogResolution;
int iOldVP[4];
glGetIntegerv(GL_VIEWPORT, iOldVP);
_impostorCam.GetProjectionMatrix(M);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadMatrixf(M);
_impostorCam.GetModelviewMatrix(M);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(M);
glViewport(0, 0, iRes, iRes);
s_pMaterial->SetDepthMask(true); // so that the depth buffer gets cleared!
s_pMaterial->Activate();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (!_bSplit)
{
FAIL_RETURN(DisplayWithoutImpostor(_impostorCam));
if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
{
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
_pBackTexture = NULL;
}
if (!_pBackTexture)
{
_pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
}
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture); // shared material for clouds.
s_pMaterial->Activate();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
}
else
{
FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, true, this),
"SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
if (_pBackTexture && _pBackTexture->GetWidth() != iRes)
{
DynamicTextureManager::InstancePtr()->CheckInTexture(_pBackTexture);
_pBackTexture = NULL;
}
if (_pFrontTexture && _pFrontTexture->GetWidth() != iRes)
{
DynamicTextureManager::InstancePtr()->CheckInTexture(_pFrontTexture);
_pFrontTexture = NULL;
}
if (!_pBackTexture)
{
_pBackTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
}
s_pMaterial->SetTexture(0, GL_TEXTURE_2D, *_pBackTexture); // shared material for clouds.
FAIL_RETURN(s_pMaterial->Activate());
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
// now clear and draw the front.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
FAIL_RETURN_MSG(_pCloud->DisplaySplit(cam, _vecSplit, false, this),
"SkyRenderableInstanceCloud:Display(): Cloud's display failed.");
if (!_pFrontTexture)
{
_pFrontTexture = DynamicTextureManager::InstancePtr()->CheckOutTexture(iRes, iRes);
}
s_pMaterial->GetTextureState().SetTexture(0, GL_TEXTURE_2D, *_pFrontTexture);
FAIL_RETURN(s_pMaterial->GetTextureState().Activate());
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, iRes, iRes);
}
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
//GLVU::CheckForGLError("Cloud Impostor Update");
glViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
_bImageExists = true;
// the textures should now exist.
assert(_pBackTexture);
assert(!_bSplit || (_bSplit && _pFrontTexture));
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::IsImpostorValid
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
* @brief Returns true if the impostor image is valid for the given camera.
*
* Will return false if this is a screen impostor, or if there is error in either
* the translation of the camera from the capture point or the impostor image resolution.
*
* @see SetErrorToleranceAngle
*/
bool SkyRenderableInstanceCloud::IsImpostorValid(const Camera& cam)
{
// first make sure there is a current image.
if (!_bImageExists)
return false;
// screen impostors should always be updated
if (_bScreenImpostor)
{
_vecFarPoint = Vec3f::ZERO;
_vecNearPoint = Vec3f::ZERO;
#if SKYCLOUD_VERBOSE
SkyTrace("Screen Impostor Update");
#endif
return false;
}
// impostors are valid from the viewpoint from which they were captured
if (cam.Orig == _impostorCam.Orig)
return true;
if (_bSplit)
{
#if SKYCLOUD_VERBOSE
SkyTrace("Split Impostor Update");
#endif
return false;
}
Vec3f vecX = _vecNearPoint - cam.Orig;
Vec3f vecY = _vecFarPoint - cam.Orig;
float rXLength = vecX.Length();
float rYLength = vecY.Length();
if (rXLength > rYLength)
{
#if SKYCLOUD_VERBOSE
SkyTrace("Backwards Impostor Update");
#endif
return false;
}
vecX /= rXLength;
vecY /= rYLength;
float rCosAlpha = vecX * vecY; // dot product of normalized vectors = cosine
if (fabs(rCosAlpha) < 1.0)
{
float rAlpha = acos(rCosAlpha);
if (rAlpha >= s_rErrorToleranceAngle)
{
#if SKYCLOUD_VERBOSE
SkyTrace("Angle Error Update %f", SKYRADSTODEGREES * rAlpha);
#endif
return false;
}
}
float rDistance = (_vecPosition - cam.Orig).Length();
float rCamRadius = sqrt(cam.wR*cam.wR + cam.Near*cam.Near);
int iRes = _GetRequiredLogResolution(rDistance, _pWorldSpaceBV->GetRadius(), rCamRadius);
if (iRes > _iLogResolution)
{
#if SKYCLOUD_VERBOSE
SkyTrace("Resolution Error Update: Required: %d Actual: %d", iRes, _iLogResolution);
#endif
return false;
}
return true;
}
//------------------------------------------------------------------------------
// Function : SetErrorToleranceAngle
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
* @brief Set the global error tolerance angle for all impostors.
*/
void SkyRenderableInstanceCloud::SetErrorToleranceAngle(float rDegrees)
{
s_rErrorToleranceAngle = SKYDEGREESTORADS * rDegrees;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::_Initialize
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::_Initialize()
* @brief Initializer used by the constructors.
*/
void SkyRenderableInstanceCloud::_Initialize()
{
_UpdateWorldSpaceBounds();
// if (!s_pRenderBuffer && _bUseOffScreenBuffer)
// {
//JW?? s_pRenderBuffer = new SkyOffScreenBuffer(GLUT_SINGLE | GLUT_DEPTH | GLUT_STENCIL);
//JW?? s_pRenderBuffer->Initialize(true);
//JW?? s_pRenderBuffer->MakeCurrent();
// set some GL state:
// glClearColor(0, 0, 0, 0);
//JW?? GLVU::GetCurrent()->MakeCurrent();
// }
if (!s_pMaterial)
{
s_pMaterial = new SkyMaterial;
s_pMaterial->EnableBlending(true);
s_pMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
s_pMaterial->SetAlphaFunc(GL_GREATER);
s_pMaterial->EnableDepthTest(false);
s_pMaterial->SetDepthMask(true);
s_pMaterial->EnableAlphaTest(true);
s_pMaterial->EnableLighting(false);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_pMaterial->EnableTexture(0, true);
}

View File

@@ -0,0 +1,273 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceCloud.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyRenderableInstanceCloud.hpp
*
* Interface for class SkyRenderableInstanceCloud, an instance of a SkyCloud object.
*/
#ifndef __SKYRENDERABLEINSTANCECLOUD_HPP__
#define __SKYRENDERABLEINSTANCECLOUD_HPP__
class SkyCloud;
class SkyTexture;
//class SkyOffScreenBuffer;
#include <vector>
#include "camera.hpp"
#include "SkyContext.hpp"
#include "SkyRenderableInstance.hpp"
#include "SkyRenderableInstanceGeneric.hpp"
#include "SkyCloud.hpp"
//------------------------------------------------------------------------------
/**
* @class SkyRenderableInstanceCloud
* @brief An instance of a cloud. Renders using an impostor.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyRenderableInstanceCloud : public SkyRenderableInstance
{
public:
SkyRenderableInstanceCloud( SkyCloud *pCloud, bool bUseOffScreenBuffer = false);
SkyRenderableInstanceCloud( SkyCloud *pCloud,
const Vec3f &position,
const Mat33f &rotation,
const float scale,
bool bUseOffScreenBuffer = false);
virtual ~SkyRenderableInstanceCloud();
// Setters / Getters
//! Sets the identifier for this cloud (used by SkySceneManager.)
void SetID(int id) { _iCloudID = id; }
virtual void SetPosition(const Vec3f &position);
virtual void SetRotation(const Mat33f &rotation);
virtual void SetScale(const float &scale);
//! Returns SkySceneManager's id for this cloud.
int GetID() const { return _iCloudID; }
//! Returns a pointer to the renderable that this instance represents.
virtual SkyCloud* GetCloud() const { return _pCloud; }
//! Returns the world space bounding box of the cloud instance.
const SkyMinMaxBox& GetWorldSpaceBounds() { return *_pWorldSpaceBV; }
//! Make this into a split impostor. Will be rendered as two halves, around the split point.
void SetSplit(bool bSplit) { _bSplit = bSplit; }
//! Set the distance at which the cloud will be split (from the camera position).
void SetSplitPoint(const Vec3f& vecSplit) { _vecSplit = vecSplit; }
//! Returns true if this is a split impostor (cloud contains objects)
bool IsSplit() const { return _bSplit; }
//! Returns true if the camera is inside this clouds bounding volume.
bool IsScreenImpostor() const { return _bScreenImpostor; }
virtual SKYRESULT Update(const Camera& cam);
virtual SKYRESULT Display(bool bDisplayFrontOfSplit = false);
SKYRESULT DisplayWithoutImpostor(const Camera& cam);
virtual bool ViewFrustumCull( const Camera &cam );
void ReleaseImpostorTextures();
virtual SkyMinMaxBox* GetBoundingVolume() const { return _pWorldSpaceBV; }
//----------------------------------------------------------------------------
// Determine if the current impostor image is valid for the given viewpoint
//----------------------------------------------------------------------------
bool IsImpostorValid(const Camera &cam);
//------------------------------------------------------------------------------
// Function : Enable
// Description :
//------------------------------------------------------------------------------
/**
* @fn Enable(bool bEnable)
* @brief Enable / Disable the use of impostor images (if disabled, displays geometry).
*/
void Enable(bool bEnable) { _bEnabled = bEnable; }
static void SetErrorToleranceAngle(float rDegrees);
protected: // methods
void _Initialize();
inline int _GetRequiredLogResolution(float rObjectDistance, float rObjectRadius, float rCamRadius);
inline void _UpdateWorldSpaceBounds();
protected: // data
int _iCloudID; // used by the scene manager to identify clouds.
SkyCloud *_pCloud; // Pointer to the cloud object
SkyMinMaxBox *_pWorldSpaceBV; // Pointer to bounding volume in object space
float _rRadius; // Radius of the impostor.
bool _bScreenImpostor; // Is this a screen space or world space impostor?
bool _bImageExists; // The impostor image exists and is ready to use.
bool _bEnabled; // if disabled, draw geometry -- otherwise, draw impostor.
bool _bUseOffScreenBuffer; // if enabled, uses off-screen rendering to create impostor images.
bool _bSplit; // true if the cloud contains other object instances.
Vec3f _vecSplit; // the point about which this cloud is split.
Vec3f _vecNearPoint; // Nearest point on bounding sphere to viewpoint.
Vec3f _vecFarPoint; // Farthest point on bounding sphere from viewpoint.
Camera _impostorCam; // camera used to generate this impostor
unsigned int _iLogResolution; // Log base 2 of current impostor image resolution.
SkyTexture *_pBackTexture; // Back texture for split clouds or main texture for unsplit.
SkyTexture *_pFrontTexture; // Front texture for split clouds.
unsigned int _iCulledCount; // used to determine when to release textures
static unsigned int s_iCount; // keep track of number of impostors using the render buffer.
//JW?? static SkyOffScreenBuffer* s_pRenderBuffer;
static float s_rErrorToleranceAngle;
static SkyMaterial *s_pMaterial; // shared material for cloud impostors.
};
//------------------------------------------------------------------------------
/**
* @class SkyContainerCloud
* @brief A class used to organize the rendering order of cloud impostors and the objects in the clouds
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyContainerCloud : public SkyRenderableInstance
{
public: // methods
//! Constructor.
SkyContainerCloud(SkyRenderableInstanceCloud *cloud) : SkyRenderableInstance(), pCloud(cloud) {}
//! Destructor.
~SkyContainerCloud()
{ pCloud = NULL; containedOpaqueInstances.clear(); containedTransparentInstances.clear(); }
virtual SKYRESULT Display()
{
// display the back half of the split impostor.
FAIL_RETURN_MSG(pCloud->Display(false),
"SkySceneManager::Display(): cloud instance display failed.");
if (pCloud->IsSplit())
{
// display contained instances -- first opaque, then transparent.
InstanceIterator ii;
for (ii = containedOpaqueInstances.begin(); ii != containedOpaqueInstances.end(); ++ii)
FAIL_RETURN((*ii)->Display());
for (ii = containedTransparentInstances.begin(); ii != containedTransparentInstances.end(); ++ii)
FAIL_RETURN((*ii)->Display());
// now display the front half of the split impostor.
FAIL_RETURN_MSG(pCloud->Display(true),
"SkySceneManager::Display(): cloud instance display failed.");
}
return SKYRESULT_OK;
}
virtual const Vec3f& GetPosition() const { return pCloud->GetPosition(); }
public: //data -- here the data are public because the interface is minimal.
SkyRenderableInstanceCloud *pCloud;
InstanceArray containedOpaqueInstances;
InstanceArray containedTransparentInstances;
// This operator is used to sort ContainerCloud arrays.
bool operator<(const SkyContainerCloud& container) const
{
return (*((SkyRenderableInstance*)pCloud) < *((SkyRenderableInstance*)container.pCloud));
}
};
//------------------------------------------------------------------------------
// Function : _GetRequiredLogResolution
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::_GetRequiredLogResolution(float rObjectDistance, float rObjectRadius, float rCamRadius)
* @brief Returns the integer logarithm base two of the expected impostor resolution.
*
* Impostor resolution is based on object size, distance, and the FOV of the camera (stored as the
* radius of a sphere centered at the camera position and passing through the corners of the
* projection plane.
*/
inline int SkyRenderableInstanceCloud::_GetRequiredLogResolution(float rObjectDistance,
float rObjectRadius,
float rCamRadius)
{
int iScreenWidth, iScreenHeight;
GraphicsContext::InstancePtr()->GetWindowSize(iScreenWidth, iScreenHeight);
//cout << "SkyRes: w=" << iScreenWidth << "h=" << iScreenHeight << endl; char ff; cin >> ff;
int iScreenResolution = (iScreenWidth > iScreenHeight) ? iScreenWidth : iScreenHeight;
int iLogMinScreenResolution = (iScreenWidth > iScreenHeight) ? iScreenHeight : iScreenWidth;
iLogMinScreenResolution = SkyGetLogBaseTwo(iLogMinScreenResolution) - 1;
int iRes = 2 * iScreenResolution * _pWorldSpaceBV->GetRadius() / rObjectDistance;
int iLogResolution;
if (rObjectDistance - (0.5f * rObjectRadius) < rCamRadius)
{
iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 8);
}
else if (rObjectDistance - rObjectRadius < rCamRadius)
{
iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 4);
}
else if (iRes > iScreenResolution)
{
iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 2);
}
else
{
iLogResolution = SkyGetLogBaseTwo(iRes);
}
// if not rendering to an off screen buffer, make sure the resolution fits in the window!
if (!_bUseOffScreenBuffer && (iLogMinScreenResolution < iLogResolution))
iLogResolution = iLogMinScreenResolution;
return iLogResolution;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds()
* @brief Updates the world space bounding box of the cloud.
*/
inline void SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds()
{
SAFE_DELETE(_pWorldSpaceBV);
_pWorldSpaceBV = _pCloud->CopyBoundingVolume();
_vecPosition = _pCloud->CopyBoundingVolume()->GetCenter();
}
#endif //__SKYRENDERABLEINSTANCECLOUD_HPP__

View File

@@ -0,0 +1,136 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceGeneric.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyRenderableInstanceGeneric.cpp
*
* A basic implementation of SkyRenderableInstance
*/
#include "glvu.hpp"
#include "SkyUtil.hpp"
#include "SkyRenderable.hpp"
#include "SkyMinMaxBox.hpp"
#include "SkyRenderableInstanceGeneric.hpp"
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric(SkyRenderable *object)
* @brief Constructor, store the renderable and set the position to identity
*/
SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric(SkyRenderable *pObject)
: SkyRenderableInstance(),
_pObj(pObject)
{
_pBV = pObject->CopyBoundingVolume();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric(SkyRenderable *object, const Vec3f &position, const Mat33f &rotation, const float scale)
* @brief Constructor, stores the instance information given
*/
SkyRenderableInstanceGeneric::SkyRenderableInstanceGeneric(SkyRenderable *pObject,
const Vec3f &position,
const Mat33f &rotation,
const float scale)
: SkyRenderableInstance(position, rotation, scale),
_pObj(pObject)
{
_pBV = pObject->CopyBoundingVolume();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::~SkyRenderableInstanceGeneric
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::~SkyRenderableInstanceGeneric()
* @brief Destructor
*/
SkyRenderableInstanceGeneric::~SkyRenderableInstanceGeneric()
{
_pObj = NULL;
SAFE_DELETE(_pBV);
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::SetRenderable
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::SetRenderable(SkyRenderable *pRenderable)
* @brief Set the renderable for this instance.
*/
void SkyRenderableInstanceGeneric::SetRenderable(SkyRenderable *pRenderable)
{
_pObj = pRenderable;
SAFE_DELETE(_pBV);
_pBV = pRenderable->CopyBoundingVolume();
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::Display()
* @brief Displays the instance by calling the renderable's display function
*/
SKYRESULT SkyRenderableInstanceGeneric::Display()
{
// Get and set the world space transformation
Mat44f mat;
GetModelToWorldTransform(mat);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(mat.M);
//FAIL_RETURN_MSG(_pObj->Display(*(GLVU::GetCurrent()->GetCurrentCam()), this),
// "SkyRenderableInstanceGeneric:Display(), error returned from object's display");
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGeneric::ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGeneric::ViewFrustumCull(const Camera &cam)
* @brief View frustum cull the object given its world position
*/
bool SkyRenderableInstanceGeneric::ViewFrustumCull(const Camera &cam)
{
Mat44f xform;
GetModelToWorldTransform(xform);
_bCulled = (_pBV == NULL) ? false : _pBV->ViewFrustumCull(cam, xform);
return _bCulled;
}

View File

@@ -0,0 +1,76 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceGeneric.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyRenderableInstanceGeneric.hpp
*
* Interface for a basic implementation of SkyRenderableInstance
*/
#ifndef __SKYRENDERABLEINSTANCEGENERIC_HPP__
#define __SKYRENDERABLEINSTANCEGENERIC_HPP__
#include "SkyRenderableInstance.hpp"
// forward to reduce unnecessary dependencies
class SkyRenderable;
class SkyMinMaxBox;
//------------------------------------------------------------------------------
/**
* @class SkyRenderableInstanceGeneric
* @brief A generic renderable instance
*
* The SkyRenderableInstanceGeneric is a basic implementation of the base class.
* For view frustum culling, the function ViewFrustumCull should be called once
* per frame, at which point a flag is set if the object is culled or not. It
* is possible that the object is then queried multiple times if it is culled or
* not by various other objects before being displayed, that is why the flag is
* stored.
*/
class SkyRenderableInstanceGeneric : public SkyRenderableInstance
{
public:
SkyRenderableInstanceGeneric(SkyRenderable *pObject);
SkyRenderableInstanceGeneric(SkyRenderable *pObject,
const Vec3f &position,
const Mat33f &rotation,
const float scale);
virtual ~SkyRenderableInstanceGeneric();
// Setters / Getters
virtual void SetRenderable(SkyRenderable *pRenderable );
//! Returns a pointer to the renderable that this instance represents.
virtual SkyRenderable* GetRenderable() const { return _pObj; }
virtual SKYRESULT Display();
// Test / Set / Get
virtual bool ViewFrustumCull( const Camera &cam );
virtual SkyMinMaxBox* GetBoundingVolume() const { return _pBV; }
protected:
protected:
SkyRenderable *_pObj; // Pointer to the renderable object
SkyMinMaxBox *_pBV; // Pointer to bounding volume
};
#endif //__SKYRENDERABLEINSTANCEGENERIC_HPP__

View File

@@ -0,0 +1,178 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceGroup.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyRenderableInstanceGroup.cpp
*
* Implementation of class SkyRenderableInstanceGroup, an instance that groups
* other instances.
*/
#include <GL/glut.h>
#include "SkyRenderableInstanceGroup.hpp"
#include "SkySceneManager.hpp"
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::SkyRenderableInstanceGroup
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::SkyRenderableInstanceGroup()
* @brief Constructor.
*/
SkyRenderableInstanceGroup::SkyRenderableInstanceGroup()
: SkyRenderableInstance(),
_pObjectSpaceBV(NULL)
{
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup()
* @brief Destructor.
*/
SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup()
{
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::Update
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::Update(const Camera &cam)
* @brief Processes any per frame updates the instance requires.
*
* This method simply calls the SkyRenderableInstance::Update() method of each of
* its sub-instances.
*/
SKYRESULT SkyRenderableInstanceGroup::Update(const Camera &cam)
{
InstanceIterator ii;
for (ii = _opaqueSubInstances.begin(); ii != _opaqueSubInstances.end(); ++ii)
{
FAIL_RETURN((*ii)->Update(cam));
}
for (ii = _transparentSubInstances.begin(); ii != _transparentSubInstances.end(); ++ii)
{
FAIL_RETURN((*ii)->Update(cam));
}
SkySceneManager::SortInstances(_transparentSubInstances, cam.Orig);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::Display()
* @brief Displays all sub-instances of this instance.
*
* The object-to-world transform of this instance group will be applied to all sub-instances before
* their own object-to-world transforms are applied.
*/
SKYRESULT SkyRenderableInstanceGroup::Display()
{
// Get and set the world space transformation
Mat44f mat;
GetModelToWorldTransform(mat);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(mat.M);
InstanceIterator ii;
/***
for (ii = _opaqueSubInstances.begin(); ii != _opaqueSubInstances.end(); ++ii)
{
FAIL_RETURN((*ii)->Display());
}
for (ii = _transparentSubInstances.begin(); ii != _transparentSubInstances.end(); ++ii)
{
FAIL_RETURN((*ii)->Display());
}
***/
_pObjectSpaceBV->Display();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::ViewFrustumCull
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::ViewFrustumCull(const Camera& cam)
* @brief @todo <WRITE BRIEF SkyRenderableInstanceGroup::ViewFrustumCull DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyRenderableInstanceGroup::ViewFrustumCull FUNCTION DOCUMENTATION>
*/
bool SkyRenderableInstanceGroup::ViewFrustumCull(const Camera& cam)
{
Mat44f xform;
GetModelToWorldTransform(xform);
_bCulled = (_pObjectSpaceBV == NULL) ? false : _pObjectSpaceBV->ViewFrustumCull(cam, xform);
return _bCulled;
}
//------------------------------------------------------------------------------
// Function : SkyRenderableInstanceGroup::AddSubInstance
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyRenderableInstanceGroup::AddSubInstance(SkyRenderableInstance *pInstance, bool bTransparent)
* @brief Adds a sub-instance to the group.
*/
void SkyRenderableInstanceGroup::AddSubInstance(SkyRenderableInstance *pInstance, bool bTransparent)
{
if (!bTransparent)
_opaqueSubInstances.push_back(pInstance);
else
_transparentSubInstances.push_back(pInstance);
// update the bounds...
Mat44f xform;
pInstance->GetModelToWorldTransform(xform);
SkyMinMaxBox *pBV = pInstance->GetBoundingVolume();
if (pBV)
{
Vec3f min = pInstance->GetBoundingVolume()->GetMin();
Vec3f max = pInstance->GetBoundingVolume()->GetMax();
if (!_pObjectSpaceBV)
_pObjectSpaceBV = new SkyMinMaxBox;
_pObjectSpaceBV->AddPoint(xform * min);
_pObjectSpaceBV->AddPoint(xform * max);
}

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// File : SkyRenderableInstanceGroup.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyRenderableInstanceGroup.hpp
*
* Interface definition for class SkyRenderableInstanceGroup, an instance that groups
* other instances.
*/
#ifndef __SKYRENDERABLEINSTANCEGROUP_HPP__
#define __SKYRENDERABLEINSTANCEGROUP_HPP__
#include "SkyRenderableInstance.hpp"
#include "SkyMinMaxBox.hpp"
//------------------------------------------------------------------------------
/**
* @class SkyRenderableInstanceGroup
* @brief A renderable instance that groups other instances.
*
* This class provides a very basic way to implement static hierarchies of objects.
* It is not meant to be a full scene graph --
*/
class SkyRenderableInstanceGroup : public SkyRenderableInstance
{
public:
SkyRenderableInstanceGroup();
virtual ~SkyRenderableInstanceGroup();
//! Update all sub-instances.
virtual SKYRESULT Update(const Camera &cam);
//! Render all sub-instances.
virtual SKYRESULT Display();
//! Returns true if and only if the bounding volume of this instance lies entirely outside @a cam.
virtual bool ViewFrustumCull(const Camera &cam);
//! Adds an instance to the group that this instance represents.
void AddSubInstance(SkyRenderableInstance *pInstance, bool bTransparent);
protected:
InstanceArray _opaqueSubInstances;
InstanceArray _transparentSubInstances;
SkyMinMaxBox *_pObjectSpaceBV; // Pointer to bounding volume in object space
};
#endif //__SKYRENDERABLEINSTANCEGROUP_HPP__

View File

@@ -0,0 +1,232 @@
//------------------------------------------------------------------------------
// File : SkySceneLoader.cpp
//------------------------------------------------------------------------------
// Adapted from SkyWorks for FlightGear by J. Wojnaroski -- castle@mminternet.com
// Copywrite July 2002
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/**
* @file SkySceneLoader.cpp
*
* Implementation of class SkySceneLoader.
*/
#include <plib/ssg.h>
#include <simgear/math/point3d.hxx>
#include "SkySceneLoader.hpp"
#include "SkySceneManager.hpp"
#include "SkyTextureManager.hpp"
#include "SkySceneManager.hpp"
#include "SkyDynamicTextureManager.hpp"
#include "SkyContext.hpp"
//#include "SkyViewManager.hpp"
//#include "SkyRenderableInstanceGroup.hpp"
#include "SkyLight.hpp"
#include "camera.hpp"
ssgLight _sky_ssgLights [ 8 ] ;
static Point3D origin;
Point3D offset;
//int _ssgFrameCounter = 0 ;
Camera *pCam = new Camera();
// Need to add a light here until we figure out how to use the sun position and color
SkyLight::SkyLightType eType = SkyLight::SKY_LIGHT_DIRECTIONAL;
SkyLight *pLight = new SkyLight(eType);
//------------------------------------------------------------------------------
// Function : SkySceneLoader::SkySceneLoader
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneLoader::SkySceneLoader()
* @brief Constructor.
*/
SkySceneLoader::SkySceneLoader()
{
}
//------------------------------------------------------------------------------
// Function : SkySceneLoader::~SkySceneLoader
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneLoader::~SkySceneLoader()
* @brief Destructor.
*/
SkySceneLoader::~SkySceneLoader()
{
SceneManager::Destroy();
DynamicTextureManager::Destroy();
TextureManager::Destroy();
GraphicsContext::Destroy();
}
//------------------------------------------------------------------------------
// Function : SkySceneLoader::Load
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneLoader::Load(std::string filename)
* @brief Loads a SkyWorks scene.
*
* This is a temporary fix, as it loads only limited scenes
* It can however, load any number of Cloud
+
*/
bool SkySceneLoader::Load(std::string filename)
{
SkyArchive archive;
if (SKYFAILED(archive.Load(filename.c_str()))) {
cout << "Archive file not found\n";
return false; }
char *pFilename;
// Need to create the managers
GraphicsContext::Instantiate();
TextureManager::Instantiate();
DynamicTextureManager::Instantiate();
SceneManager::Instantiate();
unsigned int iNumFiles;
if (!SKYFAILED(archive.GetInfo("CloudFile", STRING_TYPE, &iNumFiles)))
{
for (unsigned int i = 0; i < iNumFiles; ++i)
{
FAIL_RETURN(archive.FindString("CloudFile", &pFilename, i));
float rScale = 1.0;
FAIL_RETURN(archive.FindFloat32("CloudScale", &rScale, i));
rScale = 5.0;
SkyArchive cloudArchive;
FAIL_RETURN(cloudArchive.Load(pFilename));
FAIL_RETURN(SceneManager::InstancePtr()->LoadClouds(cloudArchive, rScale));
}
}
Vec3f dir(0, 0, 1);
pLight->SetPosition(Vec3f(0, 0, 7000));
pLight->SetDirection(dir);
pLight->SetAmbient(Vec4f( 0.0f, 0.0f, 0.0f, 0.0f));
pLight->SetDiffuse(Vec4f(1.0f, 1.0f, 1.0f, 0.0f));
//pLight->SetDiffuse(Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
//pLight->SetSpecular(Vec4f(1.0f, 1.0f, 1.0f, 0.0f));
// No attenuation
pLight->SetAttenuation(1.0f, 0.0f, 0.0f);
SceneManager::InstancePtr()->AddLight(pLight);
SceneManager::InstancePtr()->ShadeClouds();
return true;
}
void SkySceneLoader::Set_Cloud_Orig( Point3D *posit )
{ // use this to adjust camera position for a new tile center
origin = *posit; // set origin to current tile center
printf("Cloud marker %f %f %f\n", origin.x(), origin.y(), origin.z() );
}
void SkySceneLoader::Update( sgMat4 viewmat, Point3D *posit )
//void SkySceneLoader::Update()
{
offset = *posit - origin;
cout << "X: " << offset.x() << "Y: " << offset.y() << "Z: " << offset.z() << endl;
SceneManager::InstancePtr()->Update(*pCam);
// need some scheme to reshade selected clouds a few at a time to save frame rate cycles
///SceneManager::InstancePtr()->ShadeClouds();
}
void SkySceneLoader::Resize( double w, double h )
{
pCam->Perspective( (float) h, (float) (w / h), 0.5, 120000.0 );
}
void SkySceneLoader::Draw()
{ // this is a clone of the plib ssgCullAndDraw except there is no scene graph
if ( _ssgCurrentContext == NULL )
{
cout<< "ssg: No Current Context: Did you forgot to call ssgInit()?" ; char x; cin >> x;
}
//ssgForceBasicState () ;
sgMat4 test;
//glMatrixMode ( GL_PROJECTION );
//glLoadIdentity();
//_ssgCurrentContext->loadProjectionMatrix ();
// test/debug section
//_ssgCurrentContext->getProjectionMatrix( test );
/*
printf( "\nFG Projection matrix\n" );
cout << test[0][0] << " " << test[1][0] << " " << test[2][0] << " " << test[3][0] << endl;
cout << test[0][1] << " " << test[1][1] << " " << test[2][1] << " " << test[3][1] << endl;
cout << test[0][2] << " " << test[1][2] << " " << test[2][2] << " " << test[3][2] << endl;
cout << test[0][3] << " " << test[1][3] << " " << test[2][3] << " " << test[3][3] << endl;
*/
sgMat4 m, *pm;
sgVec3 temp;
pm = &m;
// this is the cameraview matrix used by flightgear to render scene
// need to play with this to build a new matrix that accounts for tile crossings
// for now it resets the clouds when a boundary is crossed
_ssgCurrentContext->getModelviewMatrix( m );
///pCam->GetProjectionMatrix( (float *) pm );
//sgCopyMat4( test, m );
/*printf( "\nSkyworks Projection matrix\n" );
cout << test[0][0] << " " << test[1][0] << " " << test[2][0] << " " << test[3][0] << endl;
cout << test[0][1] << " " << test[1][1] << " " << test[2][1] << " " << test[3][1] << endl;
cout << test[0][2] << " " << test[1][2] << " " << test[2][2] << " " << test[3][2] << endl;
cout << test[0][3] << " " << test[1][3] << " " << test[2][3] << " " << test[3][3] << endl;
*/
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity () ;
glLoadMatrixf( (float *) pm );
//sgCopyMat4( test, m );
pCam->SetModelviewMatrix( (float *) pm );
//printf( "\nFG modelview matrix\n" );
//cout << test[0][0] << " " << test[1][0] << " " << test[2][0] << " " << test[3][0] << endl;
//cout << test[0][1] << " " << test[1][1] << " " << test[2][1] << " " << test[3][1] << endl;
//cout << test[0][2] << " " << test[1][2] << " " << test[2][2] << " " << test[3][2] << endl;
//cout << test[0][3] << " " << test[1][3] << " " << test[2][3] << " " << test[3][3] << endl;
//pCam->Print();
//_ssgCurrentContext->cull(r) ;
//_ssgDrawDList () ;
SceneManager::InstancePtr()->Display(*pCam);
//pLight->Display(); // draw the light position to debug with sun position
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity () ;

View File

@@ -0,0 +1,58 @@
//------------------------------------------------------------------------------
// File : SkySceneLoader.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkySceneLoader.hpp
*
* Definition of a simple class for loading scenes into SkyWorks.
*/
#ifndef __SKYSCENELOADER_HPP__
#define __SKYSCENELOADER_HPP__
#include <string>
#include "SkyUtil.hpp"
#include <simgear/math/point3d.hxx>
//------------------------------------------------------------------------------
/**
* @class SkySceneLoader
* @brief A simple scene loader for SkyWorks scenes.
*
* Loads a scene using the Load() method, which is passed the filename of a
* file containing a SkyArchive describing the scene.
*/
class SkySceneLoader
{
public:
SkySceneLoader();
~SkySceneLoader();
bool Load(std::string filename);
void Set_Cloud_Orig( Point3D *posit );
//void Update();
void Update( sgMat4 viewmat, Point3D *posit );
void Resize( double w, double h);
void Draw();
};
#endif //__SKYSCENELOADER_HPP__

View File

@@ -0,0 +1,919 @@
//------------------------------------------------------------------------------
// File : SkySceneManager.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkySceneManager.cpp
*
* Implementation of the singleton class SkySceneManager, which manages objects,
* instances, scene update, visibility, culling, and rendering.
*/
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
#include "SkySceneManager.hpp"
#include "SkyMaterial.hpp"
#include "SkyLight.hpp"
#include "SkyCloud.hpp"
#include "SkyRenderable.hpp"
#include "SkyRenderableInstance.hpp"
#include "SkyRenderableInstanceCloud.hpp"
//#include "SkyHeavens.hpp"
//#include "SkyHeightField.hpp"
#include "camutils.hpp"
#include <algorithm>
//------------------------------------------------------------------------------
// Function : SkySceneManager::SkySceneManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::SkySceneManager()
* @brief Constructor
*/
SkySceneManager::SkySceneManager()
: /*_pSkyBox(NULL),
_pTerrain(NULL),
*/
_bDrawLights(false),
_bDrawTree(false),
_bReshadeClouds(true)
{
_wireframeMaterial.SetColorMaterialMode(GL_DIFFUSE);
_wireframeMaterial.EnableColorMaterial(true);
_wireframeMaterial.EnableLighting(false);
// add the default material with ID -1
// this should avoid errors caused by models without materials exported from MAX
// (because flexporter gives them the ID -1).
SkyMaterial *pDefaultMaterial = new SkyMaterial;
pDefaultMaterial->SetMaterialID(-1);
AddMaterial(pDefaultMaterial);
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::~SkySceneManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::~SkySceneManager()
* @brief Destructor.
*
* This destructor deletes all renderables, instances (renderable instances, cloud instances,
* and otherwise), materials, and lights that were added to the scene using the Add*() functions.
* In other words, the scene manager owns all entities added to the scene. This eases cleanup
* and shutdown.
*/
SkySceneManager::~SkySceneManager()
{
ObjectIterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
SAFE_DELETE(*oi);
_objects.clear();
CloudIterator ci;
for (ci = _clouds.begin(); ci != _clouds.end(); ++ci)
SAFE_DELETE(*ci);
_clouds.clear();
InstanceIterator ii;
for (ii = _instances.begin(); ii != _instances.end(); ++ii)
SAFE_DELETE(*ii);
_instances.clear();
CloudInstanceIterator cii;
for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
SAFE_DELETE(*cii);
_cloudInstances.clear();
ContainerSetIterator cni;
for (cni = _containerClouds.begin(); cni != _containerClouds.end(); ++cni)
SAFE_DELETE(cni->second);
_containerClouds.clear();
MaterialIterator mi;
for (mi = _materials.begin(); mi != _materials.end(); ++mi)
SAFE_DELETE(mi->second);
_materials.clear();
LightIterator li;
for (li = _lights.begin(); li!= _lights.end(); ++li)
SAFE_DELETE(li->second);
_lights.clear();
//SAFE_DELETE(_pSkyBox);
//SAFE_DELETE(_pTerrain);
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddObject(SkyRenderable *pObject)
* @brief Add a new SkyRenderable object to the manager.
*/
SKYRESULT SkySceneManager::AddObject(SkyRenderable *pObject)
{
// Check for null object
if (NULL == pObject)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneManager::AddObject(): Attempting to add NULL Renderable Object.");
}
_objects.push_back(pObject);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddInstance
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent)
* @brief Add a new SkyRenderableInstance to the manager.
*/
SKYRESULT SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent /* = false */)
{
// Check for null instance
if (NULL == pInstance)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneManager::AddObject(): Attempting to add NULL Renderable Instance.");
}
if (!bTransparent)
_instances.push_back(pInstance);
else
_transparentInstances.push_back(pInstance);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddCloud
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddCloud(SkyCloud *pCloud)
* @brief Add a new cloud object to the manager.
*
* @todo <WRITE EXTENDED SkySceneManager::AddCloud FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::AddCloud(SkyCloud *pCloud)
{
if (NULL == pCloud)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Object.");
}
_clouds.push_back(pCloud);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddCloudInstance
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
* @brief Add a new instance of a cloud to the manager.
*
* @todo Note that since cloud instances share shading information, if two instances
* of a cloud have different orientations, one of the instances will have incorrect
* lighting for the scene. For this reason, I recommend that the number of clouds and
* cloud instances is equal.
*/
SKYRESULT SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
{
// Check for null instance
if (NULL == pInstance)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Instance.");
}
pInstance->SetID(_cloudInstances.size());
_cloudInstances.push_back(pInstance);
SkyContainerCloud *pContainer = new SkyContainerCloud(pInstance);
_containerClouds.insert(std::make_pair(pInstance->GetID(), pContainer));
RebuildCloudBVTree();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
* @brief Adds a material to the scene.
*
* Materials are kept in a map with their ID as key. A material can be retrieved
* from the scene manager by passing its ID to GetMaterial.
*
* @see GetMaterial, SkyMaterial
*/
SKYRESULT SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
{
// Check for null instance
if (NULL == pMaterial)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneMananger::AddMaterial(): Attempting to add NULL Material to Scene Manager");
}
_materials.insert(std::make_pair(pMaterial->GetMaterialID(), pMaterial));
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::GetMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::GetMaterial(int iMaterialID)
* @brief Returns the material with ID @a iMaterialID.
*
* If the material is not found, returns NULL.
*
* @see AddMaterial, SkyMaterial
*/
SkyMaterial* SkySceneManager::GetMaterial(int iMaterialID)
{
MaterialIterator mi = _materials.find(iMaterialID);
if (_materials.end() == mi)
{
SkyTrace("SkySceneManager::GetMaterial: Error: invalid material ID");
return NULL;
}
else
return mi->second;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::ActivateMaterial
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::ActivateMaterial(int iMaterialID)
* @brief Makes the specified material active, setting the appropriate rendering state.
*
* @todo <WRITE EXTENDED SkySceneManager::ActivateMaterial FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::ActivateMaterial(int iMaterialID)
{
cout << "Activating material\n"; char mm; cin >> mm;
MaterialIterator mi = _materials.find(iMaterialID);
if (_materials.end() == mi)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneManager::ActivateMaterial: Error: invalid material ID.");
}
else
{
FAIL_RETURN_MSG(mi->second->Activate(),
"SkySceneManager::ActivateMaterial: Error: failed to activate.");
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::AddLight
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::AddLight(SkyLight *pLight)
* @brief @todo <WRITE BRIEF SkySceneManager::AddLight DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::AddLight FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::AddLight(SkyLight *pLight)
{
// Check for null instance
if (NULL == pLight)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkySceneMananger::AddLight(): Attempting to add NULL Light to Scene Manager");
}
_lights.insert(std::make_pair(_lights.size(), pLight));
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::GetLight
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::GetLight(int iLightID)
* @brief @todo <WRITE BRIEF SkySceneManager::GetLight DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::GetLight FUNCTION DOCUMENTATION>
*/
SkyLight* SkySceneManager::GetLight(int iLightID)
{
LightIterator li = _lights.find(iLightID);
if (_lights.end() == li)
{
SkyTrace("SkySceneManager::GetLight: Error: Invalid light ID");
return NULL;
}
else
return li->second;
}
//------------------------------------------------------------------------------
// Function : Alive
// Description :
//------------------------------------------------------------------------------
/**
* @fn Alive(SkyRenderableInstance* pInstance)
* @brief A predicate to determine if an object is dead or not.
*/
bool Alive(SkyRenderableInstance* pInstance)
{
return (pInstance->IsAlive());
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::Update
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::Update(const Camera &cam)
* @brief Iterate through all SkyRenderableInstances and update them.
*/
SKYRESULT SkySceneManager::Update(const Camera &cam)
{
_ResolveVisibility(cam);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::Display
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::Display(const Camera &cam)
* @brief Iterate through all SkyRenderableInstances and display them.
*/
SKYRESULT SkySceneManager::Display( const Camera &cam )
{
_clearMaterial.Activate();
//glClear(GL_DEPTH_BUFFER_BIT);
// set lights (only lights that have changed will be passed to GL).
for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
{
li->second->Activate(li->first);
//if (_bDrawLights)
//li->second->Display();
}
//if (_bDrawTree)
// force the issue and draw
_VisualizeCloudBVTree(cam, _cloudBVTree.GetRoot());
glLineWidth(2.0);
glBegin(GL_LINES);
// red is Cartesian y-axis
glColor3ub( 255, 0, 0 );
glVertex3f( 0.0,0.0,0.0 );
glVertex3f( 0.0, -104000.0, 0.0);
// yellow is Cartesian z-axis
glColor3ub( 255, 255, 0 );
glVertex3f( 0.0, 0.0, 0.0);
glVertex3f( 0.0, 0.0, 104000.0);
// blue is Cartesian x-axis
glColor3ub( 0, 0, 255 );
glVertex3f( 0.0, 0.0, 0.0);
glVertex3f( -104000.0, 0.0, 0.0);
glEnd();
// draw all container clouds and "free" objects not in clouds.
int i = 0;
for (InstanceIterator iter = _visibleInstances.begin(); iter != _visibleInstances.end(); ++iter)
{
FAIL_RETURN_MSG((*iter)->Display(),
"SkySceneManager::Display(): instance display failed.");
i++;
}
//cout << "There are " << i << " visible clouds\n";
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::RebuildCloudBVTree
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::RebuildCloudBVTree()
* @brief Builds an AABB tree of the cloud bounding volumes.
*/
SKYRESULT SkySceneManager::RebuildCloudBVTree()
{
CloudInstanceIterator cii;
SkyMinMaxBox bbox;
_cloudBVTree.BeginTree();
for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
{
bbox = (*cii)->GetWorldSpaceBounds();
_cloudBVTree.AddObject(*cii, bbox);
}
_cloudBVTree.EndTree();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::ShadeClouds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::ShadeClouds()
* @brief @todo <WRITE BRIEF SkySceneManager::ShadeClouds DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::ShadeClouds FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::ShadeClouds()
{
cout << "SkySceneManager::ShadeClouds()\n";
int i=0;
for (CloudInstanceIterator cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
{
for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
{
if (SkyLight::SKY_LIGHT_DIRECTIONAL == li->second->GetType())
{
(*cii)->GetCloud()->Illuminate(li->second, *cii, li == _lights.begin());
printf("Shading Cloud %d of %d with light %d \n", i++, _cloudInstances.size(), *li );
}
}
}
_bReshadeClouds = false;
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::LoadClouds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale)
* @brief @todo <WRITE BRIEF SkySceneManager::LoadClouds DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::LoadClouds FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale /* = 1.0f */)
{
unsigned int iNumClouds = 0;
cloudArchive.FindUInt32("CldNumClouds", &iNumClouds);
SkyArchive subArchive;
//iNumClouds = 5; //set this value to reduce cloud field for debugging
for (int i = 0; i < iNumClouds; ++i)
{
printf("Loading # %d of %d clouds\n", i, iNumClouds);
cloudArchive.FindArchive("Cloud", &subArchive, i);
SkyCloud *pCloud = new SkyCloud();
pCloud->Load(subArchive, rScale);
SkyRenderableInstanceCloud *pInstance = new SkyRenderableInstanceCloud(pCloud, false);
AddCloud(pCloud);
AddCloudInstance(pInstance);
}
RebuildCloudBVTree();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_SortClouds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
* @brief @todo <WRITE BRIEF SkySceneManager::_SortClouds DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_SortClouds FUNCTION DOCUMENTATION>
*/
void SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
{
static InstanceComparator comparator;
for (CloudInstanceIterator cii = clouds.begin(); cii != clouds.end(); ++cii)
{
Vec3f vecPos = (*cii)->GetPosition();
vecPos -= vecSortPoint;
(*cii)->SetSquareSortDistance(vecPos.LengthSqr());
}
std::sort(clouds.begin(), clouds.end(), comparator);
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_SortInstances
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
* @brief @todo <WRITE BRIEF SkySceneManager::_SortInstances DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_SortInstances FUNCTION DOCUMENTATION>
*/
void SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
{
static InstanceComparator comparator;
for (InstanceIterator ii = instances.begin(); ii != instances.end(); ++ii)
{
Vec3f vecPos = (*ii)->GetPosition();
vecPos -= vecSortPoint;
(*ii)->SetSquareSortDistance(vecPos.LengthSqr());
}
std::sort(instances.begin(), instances.end(), comparator);
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_ViewFrustumCullClouds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
* @brief @todo <WRITE BRIEF SkySceneManager::_ViewFrustumCullClouds DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_ViewFrustumCullClouds FUNCTION DOCUMENTATION>
*/
void SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
{
if (!pNode)
return;
int i;
int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
//iResult = COMPLETEIN; // just a hack to force the issue
if (COMPLETEIN == iResult)
{
// trivially add all instances
for (i = 0; i < pNode->GetNumObjs(); ++i)
{
SkyRenderableInstanceCloud* pInstance =
const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
_visibleCloudInstances.push_back(pInstance);
}
}
else if ((PARTIAL == iResult) && pNode->IsLeaf())
{
SkyMinMaxBox bbox;
// check each instance in this node against camera
for (i = 0; i < pNode->GetNumObjs(); ++i)
{
SkyRenderableInstanceCloud* pInstance =
const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
bbox = pInstance->GetWorldSpaceBounds();
iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
if (COMPLETEOUT != iResult)
_visibleCloudInstances.push_back(pInstance);
else
pInstance->ReleaseImpostorTextures();
}
}
else if (PARTIAL == iResult)
{
_ViewFrustumCullClouds(cam, pNode->GetLeftChild());
_ViewFrustumCullClouds(cam, pNode->GetRightChild());
}
else // the node is completely out. All of its child clouds should release their textures.
{
for (i = 0; i < pNode->GetNumObjs(); ++i)
{
SkyRenderableInstanceCloud* pInstance =
const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
pInstance->ReleaseImpostorTextures();
}
}
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_VisualizeCloudBVTree
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
* @brief @todo <WRITE BRIEF SkySceneManager::_VisualizeCloudBVTree DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_VisualizeCloudBVTree FUNCTION DOCUMENTATION>
*/
void SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
{
// set display state.
_wireframeMaterial.Activate();
int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
if (COMPLETEIN == iResult)
{
// draw this node's bounding box in green.
glColor3f(0, 1, 0);
pNode->GetNodeBV().Display();
}
else if (PARTIAL == iResult)
{
SkyMinMaxBox bbox;
if (pNode->IsLeaf())
{
// draw this node's bounding box and the boxes of all of its objects that are visible.
// draw this node's bbox in orange.
glColor3f(1, 0.5, 0);
pNode->GetNodeBV().Display();
int i;
for (i = 0; i < pNode->GetNumObjs(); ++i)
{
SkyRenderableInstanceCloud* pInstance =
const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
bbox = pInstance->GetWorldSpaceBounds();
iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
if (COMPLETEIN == iResult)
{
// draw the box in green
glColor3f(0, 1, 0);
bbox.Display();
}
else if (PARTIAL == iResult)
{
// draw the box in yellow
glColor3f(1, 1, 0);
bbox.Display();
}
}
}
else
{
_VisualizeCloudBVTree(cam, pNode->GetLeftChild());
_VisualizeCloudBVTree(cam, pNode->GetRightChild());
}
}
else
{
// draw the node's bbox in red.
// This should NEVER be visible from the camera from which it was culled!
glColor3f(1, 0, 0);
pNode->GetNodeBV().Display();
}
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_ResolveVisibility
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::_ResolveVisibility(const Camera &cam)
* @brief @todo <WRITE BRIEF SkySceneManager::_ResolveRenderingOrder DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_ResolveRenderingOrder FUNCTION DOCUMENTATION>
*/
SKYRESULT SkySceneManager::_ResolveVisibility(const Camera &cam)
{
InstanceIterator ii;
// clear the free instance array
_visibleInstances.clear();
// clear the contained instance arrays
ContainerSetIterator csi;
for (csi = _containerClouds.begin(); csi != _containerClouds.end(); ++csi)
{
csi->second->containedOpaqueInstances.clear();
csi->second->containedTransparentInstances.clear();
}
// clear the visible cloud array.
_visibleCloudInstances.clear();
// Test each instance for containment inside a cloud's bounding volume.
// If the instance is inside a cloud, it is considered a "contained" instance, and will be
// rendered with the cloud in which it is contained for correct visibility. If the instance is
// not inside any cloud, then it is a "free" instance, and will be rendered after all contained
// instances. Transparent instances of each type are rendered after opaque instances of each
// type.
// opaque instances
for (ii = _instances.begin(); ii != _instances.end(); ++ii)
{
cout << "Opague instance\n"; char zz; cin >> zz;
(*ii)->ViewFrustumCull(cam); // First VFC then check if culled, some instances may
// manually set the culled flag, instead of using VFC
if (!(*ii)->IsCulled())
{
// first update this instance.
FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::_ResolveVisibility(): instance update failed.");
if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, false))
_visibleInstances.push_back(*ii);
}
}
// transparent instances
for (ii = _transparentInstances.begin(); ii != _transparentInstances.end(); ++ii)
{
cout << "Transparent instance\n"; char tt; cin >> tt;
(*ii)->ViewFrustumCull(cam); // First VFC then check if culled, some instances may
// manually set the culled flag, instead of using VFC
if (!(*ii)->IsCulled())
{
// first update this instance.
FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::Update(): instance update failed.");
if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, true))
_visibleInstances.push_back(*ii);
}
}
// view frustum cull the clouds
_ViewFrustumCullClouds(cam, _cloudBVTree.GetRoot());
// Clouds must be rendered in sorted order.
//_SortClouds(_visibleCloudInstances, cam.Orig);
// reshade the clouds if necessary.
if (_bReshadeClouds)
{
printf("ReShading clouds\n");
FAIL_RETURN(ShadeClouds());
}
// Now process the visible clouds. First, go through the container clouds corresponding to the
// clouds, calculate their split points, and update their impostors.
for (CloudInstanceIterator cii = _visibleCloudInstances.begin();
cii != _visibleCloudInstances.end();
++cii)
{
// get the container corresponding to this cloud
ContainerSetIterator csi = _containerClouds.find((*cii)->GetID());
if (csi == _containerClouds.end())
{
SkyTrace("Error: SkySceneManager::_ResolveVisibility(): Invalid cloud instance %d.",
(*cii)->GetID());
return SKYRESULT_FAIL;
}
if (csi->second->containedOpaqueInstances.size() > 0 ||
csi->second->containedTransparentInstances.size() > 0)
{
SortInstances(csi->second->containedOpaqueInstances, cam.Orig);
SortInstances(csi->second->containedTransparentInstances, cam.Orig);
SkyRenderableInstance *pOpaque = (csi->second->containedOpaqueInstances.size() > 0) ?
csi->second->containedOpaqueInstances.back() : NULL;
SkyRenderableInstance *pTransparent = (csi->second->containedTransparentInstances.size() > 0) ?
csi->second->containedTransparentInstances.back() : NULL;
// find the closest contained instance to the camera
if (pOpaque && pTransparent)
{
if (*pOpaque < *pTransparent)
(*cii)->SetSplitPoint(pOpaque->GetPosition());
else
(*cii)->SetSplitPoint(pTransparent->GetPosition());
}
else if (pOpaque)
(*cii)->SetSplitPoint(pOpaque->GetPosition());
else if (pTransparent)
(*cii)->SetSplitPoint(pTransparent->GetPosition());
else
(*cii)->SetSplit(false);
}
else
(*cii)->SetSplit(false);
// add the container to the list of visiblie clouds to be rendered this frame.
_visibleInstances.push_back(csi->second);
// now update the impostors
FAIL_RETURN_MSG((*cii)->Update(cam),
"SkySceneManager::_ResolveVisibility(): cloud instance update failed.");
}
SortInstances(_visibleInstances, cam.Orig);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkySceneManager::_TestInsertInstanceIntoClouds
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam, const CloudBVTree::Node *pNode, SkyRenderableInstance *pInstanceToInsert, bool bTransparent)
* @brief @todo <WRITE BRIEF SkySceneManager::_TestInsertInstanceIntoClouds DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkySceneManager::_TestInsertInstanceIntoClouds FUNCTION DOCUMENTATION>
*/
bool SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam,
const CloudBVTree::Node *pNode,
SkyRenderableInstance *pInstanceToInsert,
bool bTransparent)
{
if (_clouds.size() <= 0)
return false;
if (pNode->GetNodeBV().PointInBBox(pInstanceToInsert->GetPosition()))
{
if (pNode->IsLeaf())
{
SkyMinMaxBox bbox;
int i;
// check the instance against each cloud in this leaf node.
for (i = 0; i < pNode->GetNumObjs(); ++i)
{
SkyRenderableInstanceCloud* pCloud =
const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
bbox = pCloud->GetWorldSpaceBounds();
if (bbox.PointInBBox(pInstanceToInsert->GetPosition()))
{
// get the container cloud struct for this cloud instance, and add this instance.
ContainerSetIterator csi = _containerClouds.find(pCloud->GetID());
if (csi == _containerClouds.end())
{
SkyTrace(
"Error: SkySceneManager::_TestInsertInstanceIntoClouds(): Invalid cloud instance %d.",
pCloud->GetID());
return false;
}
else // this instance is inside a cloud. Set up for split cloud rendering.
{
if (!bTransparent)
csi->second->containedOpaqueInstances.push_back(pInstanceToInsert);
else
csi->second->containedTransparentInstances.push_back(pInstanceToInsert);
csi->second->pCloud->SetSplit(true);
return true;
}
}
}
return false;
}
else
{
if (!_TestInsertInstanceIntoClouds(cam, pNode->GetLeftChild(), pInstanceToInsert, bTransparent))

View File

@@ -0,0 +1,188 @@
//------------------------------------------------------------------------------
// File : SkySceneManager.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkySceneManager.hpp
*
* The SkySceneManager class manages all of the renderable objects and
* instances. This class maintains lists of each object and instance.
* The scene manager decides what to display, it can make use of various
* techniques such as view frustum culling, material grouping, etc.
*/
#ifndef __SKYSCENEMANAGER_HPP__
#define __SKYSCENEMANAGER_HPP__
// warning for truncation of template name for browse info
#pragma warning( disable : 4786)
#include "vec3f.hpp"
#include <vector>
#include <map>
#include "SkyUtil.hpp"
#include "SkySingleton.hpp"
#include "SkyRenderableInstance.hpp"
#include "SkyMaterial.hpp"
#include "SkyAABBTree.hpp"
#include "SkyRenderableInstanceCloud.hpp"
// forward to reduce unnecessary dependencies
class Camera;
class SkyRenderable;
class SkyRenderableInstance;
class SkyMaterial;
class SkyLight;
class SkyCloud;
//class SkyHeavens;
//class SkyHeightField;
//------------------------------------------------------------------------------
/**
* @class SkySceneManager
* @brief Manages all of the renderable objects and instances.
*/
class SkySceneManager; // Forward declaration
//! A singleton of the SkySceneManager. Can only create the SceneManager with SceneManager::Instantiate();
typedef SkySingleton<SkySceneManager> SceneManager;
class SkySceneManager
{
public:
SKYRESULT AddObject( SkyRenderable *pObject);
SKYRESULT AddInstance( SkyRenderableInstance *pInstance, bool bTransparent = false);
SKYRESULT AddCloud( SkyCloud *pCloud);
SKYRESULT AddCloudInstance(SkyRenderableInstanceCloud *pInstance);
SKYRESULT AddMaterial( SkyMaterial *pMaterial);
SkyMaterial* GetMaterial( int iMaterialID);
SKYRESULT ActivateMaterial(int iMaterialID);
SKYRESULT AddLight( SkyLight *pLight);
SkyLight* GetLight( int iLightID);
//! Set the sky box for this scene.
// void SetSkyBox( SkyHeavens *pSkyBox) { _pSkyBox = pSkyBox; }
//! Set the terrain for this scene.
//void SetTerrain( SkyHeightField *pTerrain) { _pTerrain = pTerrain; }
//! Enable wireframe display of lights (for debugging).
void EnableDrawLights(bool bEnable) { _bDrawLights = bEnable; }
//! Enable wireframe display of bounding volume tree of clouds.
void EnableDrawBVTree(bool bEnable) { _bDrawTree = bEnable; }
//! Returns true if wireframe display of lights is enabled.
bool IsDrawLightsEnabled() const { return _bDrawLights; }
//! Returns true if wireframe display of the cloud bounding volume tree is enabled.
bool IsDrawBVTreeEnabled() const { return _bDrawTree; }
SKYRESULT Update( const Camera &cam);
SKYRESULT Display( const Camera &cam);
SKYRESULT RebuildCloudBVTree();
SKYRESULT ShadeClouds();
//! Force the illumination of all clouds to be recomputed in the next update.
void ForceReshadeClouds() { _bReshadeClouds = true; }
// sort instances in @a instances from back to front.
static void SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint);
// load a set of clouds from an archive file.
SKYRESULT LoadClouds(SkyArchive& cloudArchive, float rScale = 1.0f);
protected: // datatypes
// Typedef the vectors into cleaner names
typedef std::vector<SkyRenderable*> ObjectArray;
typedef std::map<int, SkyMaterial*> MaterialSet;
typedef std::map<int, SkyLight*> LightSet;
typedef std::vector<SkyRenderableInstanceCloud*> CloudInstanceArray;
typedef std::vector<SkyCloud*> CloudArray;
typedef std::map<int, SkyContainerCloud*> ContainerCloudSet;
typedef SkyAABBTree<SkyRenderableInstanceCloud*> CloudBVTree;
typedef ObjectArray::iterator ObjectIterator;
typedef CloudArray::iterator CloudIterator;
typedef CloudInstanceArray::iterator CloudInstanceIterator;
typedef MaterialSet::iterator MaterialIterator;
typedef LightSet::iterator LightIterator;
typedef ContainerCloudSet::iterator ContainerSetIterator;
class InstanceComparator
{
public:
bool operator()(SkyRenderableInstance* pA, SkyRenderableInstance *pB)
{
return ((*pA) < (*pB));
}
};
class ContainerComparator
{
public:
bool operator()(SkyContainerCloud* pA, SkyContainerCloud *pB)
{
return ((*pA) < (*pB));
}
};
protected: // methods
SkySceneManager();
~SkySceneManager();
void _SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint);
void _ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode);
void _VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode);
SKYRESULT _ResolveVisibility(const Camera &cam);
bool _TestInsertInstanceIntoClouds(const Camera &cam,
const CloudBVTree::Node *pNode,
SkyRenderableInstance *pInstanceToInsert,
bool bTransparent);
private: // data
ObjectArray _objects;
CloudArray _clouds;
InstanceArray _instances;
InstanceArray _transparentInstances;
InstanceArray _visibleInstances; //! @TODO: change this to "_freeInstances"
CloudInstanceArray _cloudInstances;
CloudInstanceArray _visibleCloudInstances;
ContainerCloudSet _containerClouds;
MaterialSet _materials;
LightSet _lights;
SkyMaterial _wireframeMaterial; // used for rendering the wireframes for debugging
SkyMaterial _clearMaterial; // used to maintain state consistency when clearing.
CloudBVTree _cloudBVTree;
//SkyHeavens *_pSkyBox;
//SkyHeightField *_pTerrain;
bool _bDrawLights;
bool _bDrawTree;
bool _bReshadeClouds;
};
#endif //__SKYSCENEMANAGER_HPP__

View File

@@ -0,0 +1,292 @@
//------------------------------------------------------------------------------
// File : SkySingleton.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkySingleton.hpp
*
* A generic singleton template wrapper to make classes into singletons
*/
#ifndef __SKYSINGLETON_HPP__
#define __SKYSINGLETON_HPP__
#include "SkyUtil.hpp"
#include <assert.h>
#include <stdlib.h>
//------------------------------------------------------------------------------
/**
* @class SkySingleton
* @brief A singleton template class.
*
* Usage : Use this template container class to make any class into a
* singleton. I usually do this:
*
* @code
* class MyClass
* {
* public:
* // normal class stuff, but don't put ctor/dtor here.
* int GetData() { return _someData; }
* protected:
* // Make the ctor(s)/dtor protected, so this can only be
* // instantiated as a singleton. Note: singleton will still
* // work on classes that do not follow this (public ctors)
* // but violation of the singleton is possible then, since non-
* // singleton versions of the class can be instantiated.
* MyClass() : _someData(5) {}
* MyClass(int arg) : _someData(arg) {} // etc...
* // don't implement the copy constructor, because singletons
* // shouldn't be copied!
* MyClass(const MyClass& mc) {}
* ~MyClass() {}
* private:
* int _someData;
* };
*
* // now create a singleton of MyClass
* typedef SkySingleton<MyClass> MyClassSingleton;
*
* @endcode
* Later, in your program code, you can instantiate the singleton and access
* its members like so:
*
* @code
* void somefunc()
* {
* // instantiate the MyClassSingleton
* MyClassSingleton::Instantiate();
* // could also call MyClassSingleton::Instantiate(10);
* // since we have a constructor of that form in MyClass.
*
* // access the methods in MyClass:
* int data1 = MyClassSingleton::InstancePtr()->GetData();
* // or...
* int data2 = MyClassSingleton::InstanceRef().GetData();
*
* // now destroy the singleton
* MyClassSingleton::Destroy();
* }
* @endcode
*/
template <class T>
class SkySingleton : protected T
{
public:
//------------------------------------------------------------------------------
// Function : Instantiate
// Description :
//------------------------------------------------------------------------------
/**
* @fn Instantiate()
* @brief Creates the singleton instance for class T.
*
* Assures (by assertion) that the instance will only be created once.
* This works for default constructors.
*/
static void Instantiate()
{
assert(!s_pInstance);
s_pInstance = new SkySingleton();
}
//------------------------------------------------------------------------------
// Function : Destroy
// Description :
//------------------------------------------------------------------------------
/**
* @fn Destroy() { SAFE_DELETE(s_pInstance); }
* @brief Destructor, deletes the instance
*/
static void Destroy() { SAFE_DELETE(s_pInstance); }
//------------------------------------------------------------------------------
// Function : InstancePtr
// Description :
//------------------------------------------------------------------------------
/**
* @fn InstancePtr() { assert(s_pInstance); return s_pInstance; }
* @brief Returns a pointer to the instance
*/
static T* InstancePtr() { assert(s_pInstance); return s_pInstance; }
//------------------------------------------------------------------------------
// Function : InstanceRef
// Description :
//------------------------------------------------------------------------------
/**
* @fn InstanceRef() { assert(s_pInstance); return *s_pInstance; }
* @brief Returns a reference to the instance
*/
static T& InstanceRef() { assert(s_pInstance); return *s_pInstance; }
//------------------------------------------------------------------------------
// Function : static void Instantiate
// Description :
//------------------------------------------------------------------------------
/**
* @fn static void Instantiate(const A& a)
* @brief Instantiates class of type T that have constructors with an argument
*
* This might be a source of confusion. These templatized
* functions are used to instantiate classes of type T that
* have constructors with arguments. For n arguments, you
* to add a function below with n arguments. Note, these will
* only be created if they are used, since they are templates.
* I've added 4 below, for 1-4 arguments. If you get a
* compilation error, add one for the number of arguments you
* need. Also need a SkySingleton protected constructor with
* the same number of arguments.
*/
template<class A>
static void Instantiate(const A& a)
{
assert(!s_pInstance);
s_pInstance = new SkySingleton(a);
}
//------------------------------------------------------------------------------
// Function : Instantiate
// Description :
//------------------------------------------------------------------------------
/**
* @fn Instantiate(const A& a, const B& b)
* @brief Instantiates class of type T that have constructors with 2 args
*/
template<class A, class B>
static void Instantiate(const A& a, const B& b)
{
assert(!s_pInstance);
s_pInstance = new SkySingleton(a, b);
}
//------------------------------------------------------------------------------
// Function : Instantiate
// Description :
//------------------------------------------------------------------------------
/**
* @fn Instantiate(const A& a, const B& b, const C& c)
* @brief Instantiates class of type T that have constructors with 3 args
*/
template<class A, class B, class C>
static void Instantiate(const A& a, const B& b, const C& c)
{
assert(!s_pInstance);
s_pInstance = new SkySingleton(a, b, c);
}
//------------------------------------------------------------------------------
// Function : Instantiate
// Description :
//------------------------------------------------------------------------------
/**
* @fn Instantiate(const A& a, const B& b, const C& c, const D& d)
* @brief Instantiates class of type T that have constructors with 4 args
*/
template<class A, class B, class C, class D>
static void Instantiate(const A& a, const B& b, const C& c, const D& d)
{
assert(!s_pInstance);
s_pInstance = new SkySingleton(a, b, c, d);
}
protected:
// although the instance is of type SkySingleton<T>, the Instance***() funcs
// above implicitly cast it to type T.
static SkySingleton* s_pInstance;
private:
//------------------------------------------------------------------------------
// Function : SkySingleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySingleton()
* @brief Hidden so that the singleton can only be instantiated via public static Instantiate function.
*/
SkySingleton() : T() {}
//------------------------------------------------------------------------------
// Function : Singleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn Singleton(const A& a)
* @brief Used by the templatized public Instantiate() functions.
*/
template<class A>
SkySingleton(const A& a) : T(a) {}
//------------------------------------------------------------------------------
// Function : Singleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn Singleton(const A& a, const B& b)
* @brief Used by the templatized public Instantiate() functions.
*/
template<class A, class B>
SkySingleton(const A& a, const B& b) : T(a, b) {}
//------------------------------------------------------------------------------
// Function : Singleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn Singleton(const A& a, const B& b, const C& c)
* @brief Used by the templatized public Instantiate() functions.
*/
template<class A, class B, class C>
SkySingleton(const A& a, const B& b, const C& c) : T(a, b, c) {}
//------------------------------------------------------------------------------
// Function : Singleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn Singleton(const A& a, const B& b, const C &c, const D& d)
* @brief Used by the templatized public Instantiate() functions.
*/
template<class A, class B, class C, class D>
SkySingleton(const A& a, const B& b, const C &c, const D& d) : T(a, b, c, d) {}
//------------------------------------------------------------------------------
// Function : SkySingleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkySingleton(const SkySingleton&)
* @brief Hidden because you can't copy a singleton!
*/
SkySingleton(const SkySingleton&) {} // hide the copy ctor: singletons can'
//------------------------------------------------------------------------------
// Function : ~SkySingleton
// Description :
//------------------------------------------------------------------------------
/**
* @fn ~SkySingleton()
* @brief Destructor, hidden, destroy via the public static Destroy() method.
*/
~SkySingleton() {} // hide the dtor:
};
// declare the static instance pointer
template<class T> SkySingleton<T>* SkySingleton<T>::s_pInstance = NULL;
#endif //__SKYSINGLETON_HPP__

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
// File : SkyTexture.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyTexture.hpp
*
* Interface definition for class SkyTexture, a texture class.
*/
#ifndef __SKYTEXTURE_HPP__
#define __SKYTEXTURE_HPP__
#pragma warning( disable : 4786 )
#include <GL/glut.h>
//------------------------------------------------------------------------------
/**
* @class SkyTexture
* @brief A basic texture class.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyTexture
{
public:
//! Default Constructor.
SkyTexture() : _iID(0), _iWidth(0), _iHeight(0) {}
//! Constructor.
SkyTexture(unsigned int iWidth, unsigned int iHeight, unsigned int iTextureID)
: _iID(iTextureID), _iWidth(iWidth), _iHeight(iHeight) {}
//! Destructor.
~SkyTexture() {}
//! Sets the texture width in texels.
void SetWidth(unsigned int iWidth) { _iWidth = iWidth; }
//! Sets the texture height in texels.
void SetHeight(unsigned int iHeight) { _iHeight = iHeight; }
//! Sets the texture ID as created by OpenGL.
void SetID(unsigned int iTextureID) { _iID = iTextureID; }
//! Returns the texture width in texels.
unsigned int GetWidth() const { return _iWidth; }
//! Returns the texture height in texels.
unsigned int GetHeight() const { return _iHeight; }
//! Returns the texture ID as created by OpenGL.
unsigned int GetID() const { return _iID; }
inline SKYRESULT Destroy();
protected:
unsigned int _iID;
unsigned int _iWidth;
unsigned int _iHeight;
};
//------------------------------------------------------------------------------
// Function : SkyTexture::Destroy
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTexture::Destroy()
* @brief Destroys the OpenGL texture object represented by this SkyTexture object.
*
* Fails if the GL texture has not been created (i.e. its ID is zero).
*/
inline SKYRESULT SkyTexture::Destroy()
{
if (0 == _iID)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL,
"SkyTexture::Destroy(): Error: attempt to destroy unallocated texture.");
}
else
{
glDeleteTextures(1, &_iID);
_iID = 0;
}
return SKYRESULT_OK;
}
#endif //__SKYTEXTURE_HPP__

View File

@@ -0,0 +1,883 @@
//------------------------------------------------------------------------------
// File : SkyTextureManager.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyTextureManager.cpp
*
* Implementation of a manager that keeps track of texture resource locations and sharing.
*/
#pragma warning( disable : 4786)
#include "SkyTextureManager.hpp"
#include "SkyContext.hpp"
//#include "glvu.hpp"
//#include "ppm.hpp"
//#include "tga.hpp"
//#include "fileutils.hpp"
bool SkyTextureManager::s_bSlice3DTextures = false;
//------------------------------------------------------------------------------
// Function : SkyTextureManager::SkyTextureManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::SkyTextureManager(bool bSlice3DTextures)
* @brief Constructor.
*
*/
SkyTextureManager::SkyTextureManager(bool bSlice3DTextures /* = false */)
{
s_bSlice3DTextures = bSlice3DTextures;
// this should be put somewhere more safe -- like done once in the functions that actually
// use these extensions.
/*GraphicsContext::InstancePtr()->InitializeExtensions("GL_ARB_texture_cube_map "
"GL_VERSION_1_2");*/
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::~SkyTextureManager
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::~SkyTextureManager()
* @brief destructor.
*
* @todo <WRITE EXTENDED SkyTextureManager::~SkyTextureManager FUNCTION DOCUMENTATION>
*/
SkyTextureManager::~SkyTextureManager()
{
_texturePaths.clear();
for ( TextureIterator iter = _textures.begin();
iter != _textures.end();
++iter)
{
DestroyTextureObject(iter->second);
}
_textures.clear();
for ( TextureList::iterator uncachedIter = _uncachedTextures.begin();
uncachedIter != _uncachedTextures.end();
++uncachedIter)
{
DestroyTextureObject(*uncachedIter);
}
_uncachedTextures.clear();
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::AddPath
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::AddPath(const string &path)
* @brief Adds a texture path to the list of active search paths.
*
*/
void SkyTextureManager::AddPath(const string &path)
{
_texturePaths.push_back(path);
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Get2DTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Get2DTexture(const string& filename, SkyTexture& texture, bool bMipmap)
* @brief Returns a 2D texture object from the texture set.
*
* If the texture is already loaded, it is returned. If it is not, the texture is loaded from
* file, added to the texture set, and returned.
*
* If the image cannot be loaded, returns an error. Otherwise returns success.
*/
SKYRESULT SkyTextureManager::Get2DTexture(const string& filename,
SkyTexture& texture,
bool bMipmap /* = false */)
{
TextureIterator iter = _textures.find(filename);
if (iter != _textures.end())
{ // the texture is already loaded, just return it.
texture = iter->second;
}
else
{ // the texture is being requested for the first time, load and return it
FAIL_RETURN(Clone2DTexture(filename, texture, bMipmap));
_textures.insert(make_pair(filename, texture));
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Get3DTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Get3DTexture(const string& filename, SkyTexture& texture, unsigned int iDepth, bool bMipmap, bool bLoadFromSliceFiles)
* @brief Returns a 3D texture object from the texture set.
*
* If the texture is already loaded, it is returned. If it is not, the texture is loaded from
* file, added to the texture set, and returned. If the image cannot be loaded, returns an error.
* Otherwise returns success.
*
* For 3D textures, this simply loads a 2D image file, and duplicates it across each slice. The
* parameter iDepth must be set in order to use a 2D texture image for a 3D texture.
*/
SKYRESULT SkyTextureManager::Get3DTexture(const string& filename,
SkyTexture& texture,
unsigned int iDepth,
bool bMipmap /* = false */,
bool bLoadFromSliceFiles /* = false */)
{
TextureIterator iter = _textures.find(filename);
if (iter != _textures.end())
{ // the texture is already loaded, just return it.
texture = iter->second;
}
else
{ // the texture is being requested for the first time, load and return it
FAIL_RETURN(Clone3DTexture(filename, texture, iDepth, bMipmap, bLoadFromSliceFiles));
_textures.insert(make_pair(filename, texture));
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : roundPowerOf2
// Description :
//------------------------------------------------------------------------------
static int roundPowerOf2(int n)
{
int m;
for (m = 1; m < n; m *= 2);
// m >= n
if (m - n <= n - m/2)
return m;
else
return m/2;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Clone2DTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Clone2DTexture( const string &filename, SkyTexture& texture, bool bMipmap)
* @brief Returns a 2D texture object.
*
* Ignores texture set. This always loads the file, if it exists, and creates and returns the texture.
*
* If the image cannot be loaded, returns an error. Otherwise returns success.
*/
SKYRESULT SkyTextureManager::Clone2DTexture(const string &filename,
SkyTexture& texture,
bool bMipmap /* = false */)
{
string pathFilename;
unsigned char *pImageData = NULL;
int iWidth = 0;
int iHeight = 0;
int iChannels = 0;
enum ImageType
{
IMAGE_PPM,
IMAGE_TGA
};
ImageType eType;
/****
// first get the image type from its extension.
if (filename.find(".tga") != string.npos || filename.find(".TGA") != string.npos)
eType = IMAGE_TGA;
else if (filename.find(".ppm") != string.npos || filename.find(".PPM") != string.npos)
eType = IMAGE_PPM;
else
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureManager error: invalid image format");
****/
// first try the filename sent in in case it includes a path.
//if (FileUtils::FileExists(filename.c_str()))
//{
// printf("Filename is %s\n", filename.c_str() );
//eType = IMAGE_TGA;
/* switch (eType)
{
case IMAGE_PPM:
LoadPPM(filename.c_str(), pImageData, iWidth, iHeight);
iChannels = 3;
break;
case IMAGE_TGA:
LoadTGA(filename.c_str(), pImageData, iWidth, iHeight, iChannels);
break;
default:
break;
}
*/
//}
if (!pImageData) // image not found in current directory. Check the paths...
{
for ( StringList::iterator iter = _texturePaths.begin();
iter != _texturePaths.end();
++iter)
{ // loop over all texture paths, looking for the filename
// get just the filename without path.
int iPos = filename.find_last_of("/");
if (iPos == filename.npos)
iPos = filename.find_last_of("/");
// tack on the paths from the texture path list.
if (iPos != filename.npos)
pathFilename = (*iter) + "/" + filename.substr(iPos+1);
else
pathFilename = (*iter) + "/" + filename;
//if (FileUtils::FileExists(pathFilename.c_str()))
//{
/* switch (eType)
{
case IMAGE_PPM:
LoadPPM(pathFilename.c_str(), pImageData, iWidth, iHeight);
break;
case IMAGE_TGA:
LoadTGA(pathFilename.c_str(), pImageData, iWidth, iHeight, iChannels);
break;
default:
break;
}
*/
//if (pImageData)
//break;
//}
}
}
if (!pImageData)
{
char buffer[256];
sprintf(buffer, "SkyTextureManager::Clone2DTexture(): Could not load image. %s.\n", filename);
FAIL_RETURN_MSG(SKYRESULT_OK, buffer);
}
// make sure it is power of 2 resolution.
int iNewWidth = roundPowerOf2(iWidth);
int iNewHeight = roundPowerOf2(iHeight);
int iMaxsize;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &iMaxsize );
if (iNewWidth > iMaxsize)
{
iNewWidth = iMaxsize;
}
if (iNewHeight> iMaxsize)
{
iNewHeight = iMaxsize;
}
GLenum eFormat = (4 == iChannels) ? GL_RGBA : GL_RGB;
if (iNewWidth != iWidth || iNewHeight != iHeight)
{
unsigned char *pScaledImageData = new unsigned char[iChannels * iNewWidth * iNewHeight];
gluScaleImage(eFormat, iWidth, iHeight, GL_UNSIGNED_BYTE, pImageData,
iNewWidth, iNewHeight, GL_UNSIGNED_BYTE, pScaledImageData);
SAFE_DELETE_ARRAY(pImageData);
pImageData = pScaledImageData;
}
_Create2DTextureObject( texture, iNewWidth, iNewHeight, eFormat, pImageData);
SAFE_DELETE_ARRAY(pImageData);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Clone3DTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Clone3DTexture( const string &filename, SkyTexture& texture, unsigned int iDepth, bool bMipmap, bool bLoadFromSliceFiles)
* @brief Returns a 3D texture object.
*
* Ignores texture set. This always loads the file, if it exists, and creates and returns the texture.
* If the image cannot be loaded, returns an error. Otherwise returns success.
*/
SKYRESULT SkyTextureManager::Clone3DTexture(const string &filename,
SkyTexture& texture,
unsigned int iDepth,
bool bMipmap /* = false */,
bool bLoadFromSliceFiles /* = false */)
{
string pathFilename;
/*QImage image;
QDir dir;
unsigned char *pBits = NULL;
if (!bLoadFromSliceFiles)
{
// first try the filename sent in in case it includes a path.
if (image.load(filename))
{
image = QGLWidget::convertToGLFormat(image);
}
else
{
image.reset();
for ( QStringList::Iterator iter = _texturePaths.begin();
iter != _texturePaths.end();
iter++)
{ // loop over all texture paths, looking for the filename
pathFilename = (*iter) + "\\" + filename;
if (image.load(pathFilename))
{
image = QGLWidget::convertToGLFormat(image);
break;
}
else
image.reset();
}
}
if (image.isNull())
{
qWarning("SkyTextureManager::GetTexture(): Could not load image "
"%s.\n", filename);
return false;
}
// make sure it is power of 2 resolutions.
int iWidth = roundPowerOf2(image.width());
int iHeight = roundPowerOf2(image.height());
int iMaxsize;
if (s_bSlice3DTextures)
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &iMaxsize );
else
glGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &iMaxsize );
if (iWidth > iMaxsize)
{
iWidth = iMaxsize;
}
if (iHeight> iMaxsize)
{
iHeight = iMaxsize;
}
if (iWidth != image.width() || iHeight != image.height())
image = image.smoothScale(iWidth, iHeight);
// first build an array of repeated 2D textures...
QImage inverted(image.mirror());
pBits = new unsigned char[image.numBytes() * iDepth];
unsigned int iSliceSize = image.numBytes();
int bInverted = false;
int iInvertedCount = 8;
for (unsigned int iSlice = 0; iSlice < iDepth; ++iSlice)
{
memcpy(&(pBits[iSlice * iSliceSize]),
(bInverted) ? inverted.bits() : image.bits(),
image.numBytes());
if (--iInvertedCount <= 0)
{
iInvertedCount = 8;
bInverted = !bInverted;
}
}
}
else /// Load from a set of files matching the file pattern
{
QFileInfo fi(filename);
fi.refresh();
QString baseFilename = fi.baseName();
int truncPos = baseFilename.find(QRegExp("[0-9]"));
if (truncPos >= 0)
baseFilename.truncate(truncPos);
dir.setFilter(QDir::Files);
dir.setNameFilter(baseFilename + "*." + fi.extension());
dir.setSorting(QDir::Name);
QStringList files = dir.entryList();
bool bFound = true;
if (files.count() < iDepth)
{
bFound = false;
for ( QStringList::Iterator iter = _texturePaths.begin();
iter != _texturePaths.end();
iter++)
{
dir.setCurrent(*iter);
files = dir.entryList();
if (files.count() >= iDepth)
{
bFound = true;
break;
}
}
}
if (!bFound)
{
qWarning("SkyTextureManager::Clone3DTexture: ERROR: could not find %d files matching "
"%s", iDepth, filename.latin1());
return false;
}
else
{
unsigned int iSlice = 0;
unsigned int iSliceSize = 0;
for ( QStringList::Iterator iter = files.begin();
iter != files.end() && iSlice < iDepth;
iter++)
{
if (image.load(*iter))
{
image = QGLWidget::convertToGLFormat(image);
// make sure it is power of 2 resolution.
int iWidth = roundPowerOf2(image.width());
int iHeight = roundPowerOf2(image.height());
int iMaxsize;
if (s_bSlice3DTextures)
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &iMaxsize );
else
glGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &iMaxsize );
if (iWidth > iMaxsize)
{
iWidth = iMaxsize;
}
if (iHeight> iMaxsize)
{
iHeight = iMaxsize;
}
if (iWidth != image.width() || iHeight != image.height())
image = image.smoothScale(iWidth, iHeight);
if (0 == iSlice)
{
pBits = new unsigned char[image.numBytes() * iDepth];
iSliceSize = image.numBytes();
}
memcpy(&(pBits[iSlice * iSliceSize]), image.bits(), image.numBytes());
++iSlice;
}
else
{
qWarning("SkyTextureManager::Clone3DTexture: ERROR: could not find %d files matching "
"%s", iDepth, filename);
return false;
}
}
}
}
_Create3DTextureObject(texture,
image.width(),
image.height(),
iDepth,
GL_RGBA,
pBits);
*/
return SKYRESULT_FAIL;
}
//!
/*! */
//------------------------------------------------------------------------------
// Function : SkyTextureManager::GetCubeMapTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::GetCubeMapTexture(const string& filename, SkyTexture& texture, bool bMipmap)
* @brief Returns a cube map texture object from the texture set
*
* If the texture is already loaded, it is returned. If it is not, the texture is loaded from file,
* added to the texture set, and returned. If any of the 6 images cannot be loaded, returns an error.
* Otherwise returns success.
*/
SKYRESULT SkyTextureManager::GetCubeMapTexture( const string& filename,
SkyTexture& texture,
bool bMipmap)
{
TextureIterator iter = _textures.find(filename);
if (iter != _textures.end())
{ // the texture is already loaded, just return it.
texture = iter->second;
}
else
{ // the texture is being requested for the first time, load and return it
if (!CloneCubeMapTexture(filename, texture, bMipmap))
return false;
_textures.insert(make_pair(filename, texture));
}
return true;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::CloneCubeMapTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::CloneCubeMapTexture(const string& filename, SkyTexture& texture, bool bMipmap)
* @brief Returns a cube map texture object.
*
* Ignores the texture set. This always loads the cube map texture, if all 6 face images exist,
* creates the texture, and returns it. If any of the 6 images cannot be loaded, returns an error.
* Otherwise returns success.
*/
SKYRESULT SkyTextureManager::CloneCubeMapTexture( const string& filename,
SkyTexture& texture,
bool bMipmap)
{
string pathFilename;
/*QImage images[6];
GLenum faces [] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB };
char* faceNames[] = {"posx", "negx", "posy", "negy", "posz", "negz" };
for ( QStringList::Iterator iter = _texturePaths.begin();
iter != _texturePaths.end();
iter++)
{ // loop over all texture paths, looking for the filename
for (int i = 0; i < 6; i++)
{
char buffer[FILENAME_MAX];
sprintf(buffer, filename.ascii(), faceNames[i]);
pathFilename = (*iter) + "\\" + buffer;
if (images[i].load(pathFilename))
{
images[i] = QGLWidget::convertToGLFormat(images[i]);
}
else
images[i].reset();
}
}
for (int i = 0; i < 6; i++)
{
if (images[i].isNull())
{
char buffer[FILENAME_MAX];
sprintf(buffer, filename.ascii(), faceNames[i]);
qWarning("SkyTextureManager::GetTexture(): Could not load image "
"%s.\n", buffer);
return false;
}
}
glGenTextures(1, &(texture.iTextureID));
texture.iWidth = images[0].width();
texture.iHeight = images[0].height();
// create and bind a cubemap texture object
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texture.iTextureID);
// enable automipmap generation if needed.
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, bMipmap);
if (bMipmap)
glTexParameterf(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameterf(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
for (i = 0; i < 6; i++)
{
glTexImage2D(faces[i],
0,
GL_RGBA8,
images[i].width(),
images[i].height(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
images[i].bits());
}*/
return true;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::_Create2DTextureObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::_Create2DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iFormat, unsigned char *pData)
* @brief Creates a 2D texture.
*
* Creates an OpenGL texture object and returns its ID and dimensions in a SkyTexture structure.
*/
SKYRESULT SkyTextureManager::_Create2DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iFormat,
unsigned char *pData)
{
bool bNew = false;
unsigned int iTextureID;
if (!texture.GetID())
{
glGenTextures(1, &iTextureID);
texture.SetID(iTextureID);
bNew = true;
}
texture.SetWidth(iWidth);
texture.SetHeight(iHeight);
glBindTexture(GL_TEXTURE_2D, texture.GetID());
if (bNew)
{
unsigned int iInternalFormat;
switch (iFormat)
{
case GL_LUMINANCE:
iInternalFormat = GL_LUMINANCE;
break;
case GL_LUMINANCE_ALPHA:
iInternalFormat = GL_LUMINANCE_ALPHA;
break;
default:
iInternalFormat = GL_RGBA8;
break;
}
glTexImage2D( GL_TEXTURE_2D,
0,
iInternalFormat,
iWidth, iHeight,
0,
iFormat,
GL_UNSIGNED_BYTE,
pData);
}
else
{
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0,
iWidth, iHeight,
iFormat,
GL_UNSIGNED_BYTE,
pData);
}
// set default filtering.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::_Create3DTextureObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::_Create3DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iDepth, unsigned int iFormat, unsigned char *pData)
* @brief Creates a 3D texture
*
* Creates an OpenGL 3D texture object (or a set of 2D slices) and returns its ID and dimensions
* in a SkyTexture structure.
*/
SKYRESULT SkyTextureManager::_Create3DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iDepth,
unsigned int iFormat,
unsigned char *pData)
{
/* bool bNew = false;
if (s_bSlice3DTextures) // create one 2D texture per slice!
{
if (!texture.pSliceIDs)
{
texture.pSliceIDs = new unsigned int[iDepth];
glGenTextures(iDepth, texture.pSliceIDs);
bNew = true;
}
}
else if (!texture.iTextureID)
{
glGenTextures(1, &(texture.iTextureID));
bNew = true;
}
texture.iWidth = iWidth;
texture.iHeight = iHeight;
texture.iDepth = iDepth;
texture.bSliced3D = s_bSlice3DTextures;
if (!s_bSlice3DTextures)
{
glBindTexture(GL_TEXTURE_3D, texture.iTextureID);
if (bNew)
{
unsigned int iInternalFormat;
switch (iFormat)
{
case GL_LUMINANCE:
iInternalFormat = GL_LUMINANCE;
break;
case GL_LUMINANCE_ALPHA:
iInternalFormat = GL_LUMINANCE_ALPHA;
break;
default:
iInternalFormat = GL_RGBA;
break;
}
glTexImage3D( GL_TEXTURE_3D,
0,
iInternalFormat,
iWidth, iHeight, iDepth,
0,
iFormat,
GL_UNSIGNED_BYTE,
pData);
}
else
{
glTexSubImage3D(GL_TEXTURE_3D,
0, 0, 0, 0,
iWidth, iHeight, iDepth,
iFormat,
GL_UNSIGNED_BYTE,
pData);
}
// set default filtering.
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
else
{
unsigned int iInternalFormat = 0;
unsigned int iBytesPerPixel = 0;
switch (iFormat)
{
case GL_LUMINANCE:
iInternalFormat = GL_LUMINANCE;
iBytesPerPixel = 1;
break;
case GL_LUMINANCE_ALPHA:
iInternalFormat = GL_LUMINANCE_ALPHA;
iBytesPerPixel = 2;
break;
case GL_RGBA:
default:
iInternalFormat = GL_RGBA;
iBytesPerPixel = 4;
break;
}
unsigned int iSliceSize = iWidth * iHeight * iBytesPerPixel;
// create iDepth 2D texture slices...
for (unsigned int iSlice = 0; iSlice < iDepth; ++iSlice)
{
glBindTexture(GL_TEXTURE_2D, texture.pSliceIDs[iSlice]);
if (bNew)
{
glTexImage2D( GL_TEXTURE_2D,
0,
iInternalFormat,
iWidth, iHeight,
0,
iFormat,
GL_UNSIGNED_BYTE,
(pData + iSlice * iSliceSize));
}
else
{
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0,
iWidth, iHeight,
iFormat,
GL_UNSIGNED_BYTE,
(pData + iSlice * iSliceSize));
}
// set default filtering.
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
GLVU::CheckForGLError("SkyTextureManager::_Create3DTextureObject()");
return SKYRESULT_OK;*/
return SKYRESULT_FAIL;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::DestroyTextureObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::DestroyTextureObject(SkyTexture &texture)
* @brief destroys a SkyTexture object.
*
* Deletes the data as well as the OpenGL texture ID(s).
*/
void SkyTextureManager::DestroyTextureObject(SkyTexture &texture)
{
/*if (texture.GetID)
glDeleteTextures(1, &(texture.iTextureID));
if (texture.bSliced3D && texture.pSliceIDs)
{

View File

@@ -0,0 +1,208 @@
//------------------------------------------------------------------------------
// File : SkyTextureManager.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
/**
* @file SkyTextureManager.hpp
*
* Definition of a manager that keeps track of texture locations and sharing of texture files. |
*/
#ifndef SKYTEXTUREMANAGER_HPP
#define SKYTEXTUREMANAGER_HPP
#pragma warning( disable : 4786)
#include "SkySingleton.hpp"
#include "SkyTexture.hpp"
#include <string>
#include <list>
#include <map>
using namespace std;
// forward declaration for singleton
class SkyTextureManager;
//! A singleton of the SkyTextureManager. Can only create the TextureManager with TextureManager::Instantiate();
typedef SkySingleton<SkyTextureManager> TextureManager;
//------------------------------------------------------------------------------
/**
* @class SkyTextureManager
* @brief A resource manager for textures.
*
* This manager allows textures to be shared. It keeps a mapping of
* filenames to texture objects, and makes it easy to use the same texture
* for multiple objects without the objects having to be aware of the
* sharing. Supports cube map textures, and 2D textures. Can also be used
* to "clone textures", which creates unmanaged texture objects from files
* that are not kept in the mapping, and thus are not shared.
*/
class SkyTextureManager
{
public: // types
typedef list<string> StringList;
public: // methods
//.-------------------------------------------------------------------------.
//| Paths to texture directories
//.-------------------------------------------------------------------------.
void AddPath(const string& path);
//! Return the list of texture paths that will be searched by Get2DTexture() and Get3DTexture().
const StringList& GetPaths() const { return _texturePaths; }
//! Clear the list of texture paths that will be searched by Get2DTexture() and Get3DTexture().
void ClearPaths() { _texturePaths.clear(); }
//.-------------------------------------------------------------------------.
//| Texture loading
//.-------------------------------------------------------------------------.
SKYRESULT Get2DTexture( const string &filename,
SkyTexture& texture,
bool bMipmap = false);
SKYRESULT Get3DTexture( const string &filename,
SkyTexture& texture,
unsigned int iDepth,
bool bMipmap = false,
bool bLoadFromSliceFiles = false);
SKYRESULT GetCubeMapTexture( const string &filename,
SkyTexture& texture,
bool bMipmap = false);
//.-------------------------------------------------------------------------.
//| Texture cloning: create a duplicate texture object: not added to set!
//.-------------------------------------------------------------------------.
SKYRESULT Clone2DTexture( const string &filename,
SkyTexture& texture,
bool bMipmap = false);
SKYRESULT Clone3DTexture( const string &filename,
SkyTexture& texture,
unsigned int iDepth,
bool bMipmap = false,
bool bLoadFromSliceFiles = false );
SKYRESULT CloneCubeMapTexture( const string &filename,
SkyTexture& texture,
bool bMipmap = false);
//.-------------------------------------------------------------------------.
//| Texture Object Creation: not added to the texture set (no filename!)
//.-------------------------------------------------------------------------.
inline SKYRESULT Create2DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iFormat,
unsigned char *pData);
inline SKYRESULT Create3DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iDepth,
unsigned int iFormat,
unsigned char *pData);
//.-------------------------------------------------------------------------.
//| Texture Object Destruction: use this because texture objects are structs
//| that use shallow copies!
//.-------------------------------------------------------------------------.
static void DestroyTextureObject( SkyTexture &texture);
protected:
SkyTextureManager(bool bSlice3DTextures = false);
~SkyTextureManager();
SKYRESULT _Create2DTextureObject( SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iFormat,
unsigned char *pData);
SKYRESULT _Create3DTextureObject( SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iDepth,
unsigned int iFormat,
unsigned char *pData);
private:
typedef list<SkyTexture> TextureList;
typedef map<string, SkyTexture> TextureSet;
typedef TextureSet::iterator TextureIterator;
//.-------------------------------------------------------------------------.
//| Data
//.-------------------------------------------------------------------------.
// paths searched for textures specified by filename.
StringList _texturePaths;
// cached textures
TextureSet _textures; // loaded textures
// textures created directly, not loaded from file and cached.
TextureList _uncachedTextures;
// if this is true, then 3D textures will be represented as a set of 2D slices.
static bool s_bSlice3DTextures;
};
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Create2DTextureObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Create2DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iFormat, unsigned char *pData)
* @brief Creates a 2D texture.
*
* Creates an OpenGL texture object and returns its ID and dimensions in a SkyTexture structure.
* This texture will be deleted by the texture manager at shutdown.
*
*/
inline SKYRESULT SkyTextureManager::Create2DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iFormat,
unsigned char *pData)
{
SKYRESULT retval = _Create2DTextureObject(texture, iWidth, iHeight, iFormat, pData);
if SKYSUCCEEDED(retval)
_uncachedTextures.push_back(texture);
return retval;
}
//------------------------------------------------------------------------------
// Function : SkyTextureManager::Create3DTextureObject
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureManager::Create3DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iDepth, unsigned int iFormat, unsigned char *pData)
* @brief Creates a 3D texture.
*
* Creates an OpenGL texture object and returns its ID and dimensions in a SkyTexture structure.
* This texture will be deleted by the texture manager at shutdown, and should not be destroyed
* by the user.
*
*/
inline SKYRESULT SkyTextureManager::Create3DTextureObject(SkyTexture &texture,
unsigned int iWidth,
unsigned int iHeight,
unsigned int iDepth,
unsigned int iFormat,
unsigned char *pData)
{
SKYRESULT retval = _Create3DTextureObject(texture, iWidth, iHeight, iDepth, iFormat, pData);
if SKYSUCCEEDED(retval)
_uncachedTextures.push_back(texture);
return retval;
}
#endif //QGLVUTEXTUREMANAGER_HPP

View File

@@ -0,0 +1,271 @@
//------------------------------------------------------------------------------
// File : SkyTextureState.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyTextureState.cpp
*
* Implementation of class SkyTextureState, which encapsulates OpenGL texture state.
*/
#include "SkyTextureState.hpp"
//#include "glvu.hpp"
//------------------------------------------------------------------------------
// Static initializations.
//------------------------------------------------------------------------------
unsigned int SkyTextureState::s_iNumTextureUnits = 0;
//------------------------------------------------------------------------------
// Function : SkyTextureState::SkyTextureState
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::SkyTextureState()
* @brief Constructor.
*/
SkyTextureState::SkyTextureState()
{
if (0 == s_iNumTextureUnits)
{
int iNumTextureUnits = 0;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &iNumTextureUnits);
if (iNumTextureUnits > 0)
s_iNumTextureUnits = iNumTextureUnits;
else
s_iNumTextureUnits = 1;
}
_pTextureUnitState = new TexState[s_iNumTextureUnits];
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::~SkyTextureState
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::~SkyTextureState()
* @brief Destructor.
*/
SkyTextureState::~SkyTextureState()
{
SAFE_DELETE(_pTextureUnitState);
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::Activate
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::Activate()
* @brief @todo <WRITE BRIEF SkyTextureState::Activate DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyTextureState::Activate FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyTextureState::Activate()
{
SkyTextureState *pCurrent = GraphicsContext::InstancePtr()->GetCurrentTextureState();
assert(NULL != pCurrent);
//GLVU::CheckForGLError("SkyTextureState::Activate(8)");
for (unsigned int i = 0; i < s_iNumTextureUnits; ++i)
{
if (s_iNumTextureUnits > 1)
glActiveTextureARB(GL_TEXTURE0_ARB + i);
bool bEnabled = IsTextureEnabled(i);
if (pCurrent->IsTextureEnabled(i) != bEnabled)
{
FAIL_RETURN(pCurrent->EnableTexture(i, bEnabled));
//GLVU::CheckForGLError("SkyTextureState::Activate(7)");
if (bEnabled)
glEnable(GetActiveTarget(i));
else
glDisable(GetActiveTarget(i));
}
//GLVU::CheckForGLError("SkyTextureState::Activate(6)");
if (bEnabled)
{
GLenum eTarget = GetActiveTarget(i);
unsigned int iID = GetTextureID(i);
if ((pCurrent->GetActiveTarget(i) != eTarget) ||
(pCurrent->GetTextureID(i) != iID))
{
FAIL_RETURN(pCurrent->SetTexture(i, eTarget, iID));
glBindTexture(eTarget, iID);
}
//GLVU::CheckForGLError("SkyTextureState::Activate(5)");
GLenum paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_S);
if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_S) != paramValue)
{
FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_S, paramValue));
glTexParameteri(eTarget, GL_TEXTURE_WRAP_S, paramValue);
}
//GLVU::CheckForGLError("SkyTextureState::Activate(4)");
paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_T);
if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_T) != paramValue)
{
FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_T, paramValue));
glTexParameteri(eTarget, GL_TEXTURE_WRAP_T, paramValue);
}
//GLVU::CheckForGLError("SkyTextureState::Activate(3)");
paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_R);
if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_R) != paramValue)
{
FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_R, paramValue));
//glTexParameteri(eTarget, GL_TEXTURE_WRAP_R, paramValue);
}
//GLVU::CheckForGLError("SkyTextureState::Activate(2)");
paramValue = GetTextureParameter(i, GL_TEXTURE_MIN_FILTER);
if (pCurrent->GetTextureParameter(i, GL_TEXTURE_MIN_FILTER) != paramValue)
{
FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_MIN_FILTER, paramValue));
glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, paramValue);
}
//GLVU::CheckForGLError("SkyTextureState::Activate(1)");
paramValue = GetTextureParameter(i, GL_TEXTURE_MAG_FILTER);
if (pCurrent->GetTextureParameter(i, GL_TEXTURE_MAG_FILTER) != paramValue)
{
FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_MAG_FILTER, paramValue));
glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, paramValue);
}
//GLVU::CheckForGLError("SkyTextureState::Activate()");
}
if (s_iNumTextureUnits > 1)
glActiveTextureARB(GL_TEXTURE0_ARB);
}
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::SetTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture& texture)
* @brief @todo <WRITE BRIEF SkyTextureState::BindTexture DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyTextureState::BindTexture FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyTextureState::SetTexture(unsigned int iTextureUnit,
GLenum eTarget,
SkyTexture& texture)
{
if (iTextureUnit >= s_iNumTextureUnits)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::BindTexture(): Invalid texture unit.");
}
_pTextureUnitState[iTextureUnit].eActiveTarget = eTarget;
_pTextureUnitState[iTextureUnit].iBoundTexture = texture.GetID();
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::SetTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID)
* @brief @todo <WRITE BRIEF SkyTextureState::SetTexture DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyTextureState::SetTexture FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyTextureState::SetTexture(unsigned int iTextureUnit,
GLenum eTarget,
unsigned int iTextureID)
{
if (iTextureUnit >= s_iNumTextureUnits)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::BindTexture(): Invalid texture unit.");
}
_pTextureUnitState[iTextureUnit].eActiveTarget = eTarget;
_pTextureUnitState[iTextureUnit].iBoundTexture = iTextureID;
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::EnableTexture
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::EnableTexture(unsigned int iTextureUnit, bool bEnable)
* @brief @todo <WRITE BRIEF SkyTextureState::EnableTexture DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyTextureState::EnableTexture FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyTextureState::EnableTexture(unsigned int iTextureUnit, bool bEnable)
{
if (iTextureUnit >= s_iNumTextureUnits)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::EnableTexture(): Invalid texture unit.");
}
_pTextureUnitState[iTextureUnit].bEnabled = bEnable;
return SKYRESULT_OK;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::SetTextureParameter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::SetTextureParameter(unsigned int iTextureUnit, GLenum eParameter, GLenum eMode)
* @brief @todo <WRITE BRIEF SkyTextureState::SetTextureParameter DOCUMENTATION>
*
* @todo <WRITE EXTENDED SkyTextureState::SetTextureParameter FUNCTION DOCUMENTATION>
*/
SKYRESULT SkyTextureState::SetTextureParameter(unsigned int iTextureUnit,
GLenum eParameter,
GLenum eMode)
{
if (iTextureUnit >= s_iNumTextureUnits)
{
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::SetTextureParameter(): Invalid texture unit.");
}
switch (eParameter)
{
case GL_TEXTURE_WRAP_S:
_pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_S] = eMode;
break;
case GL_TEXTURE_WRAP_T:
_pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_T] = eMode;
break;
case GL_TEXTURE_WRAP_R:
_pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_R] = eMode;
break;
case GL_TEXTURE_MIN_FILTER:
_pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MIN] = eMode;
break;
case GL_TEXTURE_MAG_FILTER:
_pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MAG] = eMode;
break;
default:
FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTExtureState::SetTextureParameter(): Invalid parameter.");
break;
}
return SKYRESULT_OK;
}

View File

@@ -0,0 +1,205 @@
//------------------------------------------------------------------------------
// File : SkyTextureState.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyTextureState.hpp
*
* Interface Definition for class SkyTextureState, which encapsulates OpenGL texture state.
*/
#ifndef __SKYTEXTURESTATE_HPP__
#define __SKYTEXTURESTATE_HPP__
#include "SkyUtil.hpp"
#include "SkyTexture.hpp"
#include "SkyContext.hpp"
#include <map>
//------------------------------------------------------------------------------
/**
* @class SkyTextureState
* @brief A wrapper for texture unit state.
*
* @todo <WRITE EXTENDED CLASS DESCRIPTION>
*/
class SkyTextureState
{
public: // methods
SkyTextureState();
~SkyTextureState();
SKYRESULT Activate();
SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture& texture);
SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID);
SKYRESULT EnableTexture(unsigned int iTextureUnit, bool bEnable);
SKYRESULT SetTextureParameter(unsigned int iTextureUnit,
GLenum eParameter,
GLenum eMode);
inline GLenum GetActiveTarget(unsigned int iTextureUnit) const;
inline unsigned int GetTextureID(unsigned int iTextureUnit) const;
inline bool IsTextureEnabled(unsigned int iTextureUnit) const;
inline GLenum GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const;
protected: // datatypes
struct TexState
{
TexState() : eActiveTarget(GL_TEXTURE_2D), iBoundTexture(0), bEnabled(false)
{
// set state to GL defaults.
int i;
for (i = 0; i < SKY_TEXCOORD_COUNT; ++i) { eWrapMode[i] = GL_REPEAT; }
eFilterMode[SKY_FILTER_MIN] = GL_NEAREST_MIPMAP_LINEAR;
eFilterMode[SKY_FILTER_MAG] = GL_LINEAR;
}
enum TexCoord
{
SKY_TEXCOORD_S,
SKY_TEXCOORD_T,
SKY_TEXCOORD_R,
SKY_TEXCOORD_COUNT
};
enum TexFilter
{
SKY_FILTER_MIN,
SKY_FILTER_MAG,
SKY_FILTER_COUNT
};
GLenum eActiveTarget;
unsigned int iBoundTexture;
bool bEnabled;
GLenum eWrapMode[SKY_TEXCOORD_COUNT];
GLenum eFilterMode[SKY_FILTER_COUNT];
};
protected: // data
TexState *_pTextureUnitState; // one per texture unit
static unsigned int s_iNumTextureUnits;
};
//------------------------------------------------------------------------------
// Function : SkyTextureState::GetActiveTarget
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::GetActiveTarget(unsigned int iTextureUnit) const
* @brief Returns the active texture target for the specified texture unit.
*
* If an invalid texture unit is specifed, returns GL_NONE.
*/
inline GLenum SkyTextureState::GetActiveTarget(unsigned int iTextureUnit) const
{
if (iTextureUnit >= s_iNumTextureUnits)
{
SkyTrace("SkyTextureState::GetActiveTexture(): Invalid texture unit.");
return GL_NONE;
}
return _pTextureUnitState[iTextureUnit].eActiveTarget;
}
//------------------------------------------------------------------------------
// Function : int SkyTextureState::GetTextureID
// Description :
//------------------------------------------------------------------------------
/**
* @fn int SkyTextureState::GetTextureID(unsigned int iTextureUnit) const
* @brief Returns the texture ID associated with the specified texture unit.
*
* If an invalid texture unit is specifed, returns GL_NONE.
*/
inline unsigned int SkyTextureState::GetTextureID(unsigned int iTextureUnit) const
{
if (iTextureUnit >= s_iNumTextureUnits)
{
SkyTrace("SkyTextureState::GetTextureID(): Invalid texture unit.");
return GL_NONE;
}
return _pTextureUnitState[iTextureUnit].iBoundTexture;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::IsTextureEnabled
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::IsTextureEnabled(unsigned int iTextureUnit) const
* @brief Returns the status (enabled or disabled) of the specified texture unit.
*
* If an invalid texture unit is specifed, returns false.
*/
inline bool SkyTextureState::IsTextureEnabled(unsigned int iTextureUnit) const
{
if (iTextureUnit >= s_iNumTextureUnits)
{
SkyTrace("SkyTextureState::IsTextureEnabled(): Invalid texture unit.");
return false;
}
return _pTextureUnitState[iTextureUnit].bEnabled;
}
//------------------------------------------------------------------------------
// Function : SkyTextureState::GetTextureParameter
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyTextureState::GetTextureParameter(unsigned int iTextureUnit, GLenum eParamter) const
* @brief Returns the current value of @eParameter on the specified texture unit.
*
* If an invalid texture unit or parameter is specified, returns GL_NONE.
*/
inline GLenum SkyTextureState::GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const
{
if (iTextureUnit >= s_iNumTextureUnits)
{
SkyTrace("SkyTextureState::GetTextureParamter(): Invalid texture unit.");
return GL_NONE;
}
switch (eParameter)
{
case GL_TEXTURE_WRAP_S:
return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_S];
break;
case GL_TEXTURE_WRAP_T:
return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_T];
break;
case GL_TEXTURE_WRAP_R:
return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_R];
break;
case GL_TEXTURE_MIN_FILTER:
return _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MIN];
break;
case GL_TEXTURE_MAG_FILTER:
return _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MAG];
break;
default:
SkyTrace("SkyTExtureState::SetTextureParameter(): Invalid parameter.");
break;
}
return GL_NONE;
}
#endif //__SKYTEXTURESTATE_HPP__

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
// File : SkyUtil.cpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyUtil.cpp
*
* Implemtation of global utility functions.
*/
#include "SkyUtil.hpp"
//------------------------------------------------------------------------------
// Function : SkyTrace
// Description :
//------------------------------------------------------------------------------
/**
* SkyTrace( char* strMsg, ... )
* @brief Prints formatted output, debug only.
*
* Includes file and line number information automatically.
*/
void SkyTrace( char* strMsg, ... )
{
#if defined(DEBUG) | defined(_DEBUG)
char strBuffer[512];
va_list args;
va_start(args, strMsg);
_vsnprintf( strBuffer, 512, strMsg, args );
va_end(args);
fprintf(stderr, "[SkyTrace] %s(%d): %s\n",__FILE__, __LINE__, strBuffer);
#endif
}

View File

@@ -0,0 +1,192 @@
//------------------------------------------------------------------------------
// File : SkyUtil.hpp
//------------------------------------------------------------------------------
// SkyWorks : Copyright 2002 Mark J. Harris and
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The author(s) and The University of North Carolina at Chapel Hill make no
// representations about the suitability of this software for any purpose.
// It is provided "as is" without express or
// implied warranty.
/**
* @file SkyUtil.hpp
* @brief Safe deallocation functions, result codes, trace functions, and macros.
*/
#ifndef __SKYUTIL_HPP__
#define __SKYUTIL_HPP__
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
//-----------------------------------------------------------------------------
// Useful constants
//-----------------------------------------------------------------------------
//! Pi.
const float SKY_PI = 4.0f * (float) atan(1.0f);
//! 1.0 / Pi
const float SKY_INV_PI = 1.0f / SKY_PI;
//! 1.0 / (4.0 * Pi)
const float SKY_INV_4PI = 1.0f / (4.0f * SKY_PI);
//-----------------------------------------------------------------------------
// Safe deallocation
//-----------------------------------------------------------------------------
//! Delete and set pointer to NULL.
#define SAFE_DELETE(p) { delete (p); (p)=NULL; }
//! Delete an array and set pointer to NULL.
#define SAFE_DELETE_ARRAY(p) { delete[] (p); (p)=NULL; }
//#define SAFE_RELEASE(p) { (p) = NULL; }
//{ if(p) { (p)->Release(); (p)=NULL; } }
//------------------------------------------------------------------------------
// Useful Macros
//------------------------------------------------------------------------------
//! Convert Degrees to Radians
#define SKYDEGREESTORADS 0.01745329252f
//! Convert Radians to Degrees
#define SKYRADSTODEGREES 57.2957795131f
//------------------------------------------------------------------------------
// Function : SkyGetLogBaseTwo
// Description :
//------------------------------------------------------------------------------
/**
* @fn SkyGetLogBaseTwo(int iNum)
* @brief Returns the integer base two logarithm of the integer input.
*/
inline int SkyGetLogBaseTwo(int iNum)
{
int i, n;
for(i = iNum-1, n = 0; i > 0; i >>= 1, n++ );
return n;
}
//------------------------------------------------------------------------------
// Function : SkyTrace
// Description :
//------------------------------------------------------------------------------
void SkyTrace( char* strMsg, ... );
//.----------------------------------------------------------------------------.
//| Result Codes |
//.----------------------------------------------------------------------------.
//! SKYRESULTs are used for returning error information that can be used to trace bugs.
typedef int SKYRESULT;
//! Returns true if the SKYRESULT is a success result.
#define SKYSUCCEEDED(Status) ((SKYRESULT)(Status) >= 0)
//! Returns true if the SKYRESULT is a failure result.
#define SKYFAILED(Status) ((SKYRESULT)(Status) < 0)
//! SKYRESULTs are used for returning error information that can be used to trace bugs.
enum SKYRESULT_CODES
{
// SUCCESS CODES: non-negative
SKYRESULT_OK = 1,
// FAILURE CODES: negative
SKYRESULT_FAIL = -1
};
//-----------------------------------------------------------------------------
// FAIL_RETURN
//-----------------------------------------------------------------------------
// Print debug messages to the WIN32 debug window
//-----------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Function : FAIL_RETURN
// Description :
//------------------------------------------------------------------------------
/**
* @fn FAIL_RETURN(p)
* @brief Prints a trace message if @a p failed, and returns the failure code.
*
* Outputs in a format that can be double-clicked in DevStudio to open the
* appropriate file and location.
*/
#if defined(DEBUG) | defined(_DEBUG)
#define FAIL_RETURN(p) \
{ \
SKYRESULT __SKYUTIL__result__; \
if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
fprintf(stderr, "!!!! FAIL_RETURN TRAP !!!! %s: %d: %d\n",__FILE__, __LINE__, __SKYUTIL__result__); \
return __SKYUTIL__result__; \
} \
}
#else
#define FAIL_RETURN(p) p
#endif
//------------------------------------------------------------------------------
// Function : FAIL_RETURN_MSG
// Description :
//------------------------------------------------------------------------------
/**
* @fn FAIL_RETURN_MSG(p,str)
* @brief Similar to FAIL_RETURN, but also appends a user-supplied message.
*
* @see FAIL_RETURN, FAIL_RETURN_MSG
*/
#if defined(DEBUG) | defined(_DEBUG)
#define FAIL_RETURN_MSG(p,str) \
{ \
SKYRESULT __SKYUTIL__result__; \
if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
fprintf(stderr, "!!!! FAIL_RETURN_MSG TRAP !!!! %s: %d: %d: %s\n",__FILE__,__LINE__,__SKYUTIL__result__,str); \
return __SKYUTIL__result__; \
} \
}
#else
#define FAIL_RETURN_MSG(p,str) p
#endif
//------------------------------------------------------------------------------
// Function : FAIL_RETURN_MSGBOX
// Description :
//------------------------------------------------------------------------------
/**
* @fn FAIL_RETURN_MSGBOX(p,str)
* @brief Similar to FAIL_RETURN_MSG, but also displays the error in a message box (in Windows).
*
* @see FAIL_RETURN_MSG, FAIL_RETURN
*/
#if defined(DEBUG) | defined(_DEBUG)
#ifdef USEWINDOWSOUTPUT
#define FAIL_RETURN_MSGBOX(p,str) \
{ \
SKYRESULT __SKYUTIL__result__; \
if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
char msg[512]; \
sprintf(msg, "%s: %d: %d: %s\n",__FILE__,__LINE__,__SKYUTIL__result__,str); \
MessageBox(NULL, msg, "!!!! FAIL_RETURN_MSG TRAP !!!!", MB_OK); \
return __SKYUTIL__result__; \
} \
}
#else
#define FAIL_RETURN_MSGBOX(p,str) \
{ \
SKYRESULT __SKYUTIL__result__; \
if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
fprintf(stderr, "!!!! FAIL_RETURN_MSG TRAP !!!! %s: %d: %d: %s\n",__FILE__,__LINE__,__D3DUTIL__hres__,str); \
return __SKYUTIL__result__; \
} \
}
#endif
#else
#define FAIL_RETURN_MSGBOX(p,str) p
#endif
#endif //__SKYUTIL_HPP__

View File

@@ -0,0 +1,84 @@
//------------------------------------------------------------------------------
// File : camdisplay.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// camdisplay.cpp
//============================================================================
#include <GL/glut.h>
#include "camera.hpp"
//----------------------------------------------------------------------------
// OPENGL CAMERA FRUSTUM DRAWING ROUTINES
//----------------------------------------------------------------------------
void Camera::Display() const
{
// CALC EIGHT CORNERS OF FRUSTUM (NEAR PTS AND FAR PTS)
Vec3f V[8];
CalcVerts(V);
// DRAW THE FRUSTUM IN WIREFRAME
glBegin(GL_LINE_LOOP); // TOP FACE
glVertex3fv(&(V[4].x)); glVertex3fv(&(V[5].x));
glVertex3fv(&(V[1].x)); glVertex3fv(&(V[0].x));
glEnd();
glBegin(GL_LINE_LOOP); // BOTTOM FACE
glVertex3fv(&(V[3].x)); glVertex3fv(&(V[2].x));
glVertex3fv(&(V[6].x)); glVertex3fv(&(V[7].x));
glEnd();
glBegin(GL_LINE_LOOP); // LEFT FACE
glVertex3fv(&(V[1].x)); glVertex3fv(&(V[5].x));
glVertex3fv(&(V[6].x)); glVertex3fv(&(V[2].x));
glEnd();
glBegin(GL_LINE_LOOP); // RIGHT FACE
glVertex3fv(&(V[0].x)); glVertex3fv(&(V[3].x));
glVertex3fv(&(V[7].x)); glVertex3fv(&(V[4].x));
glEnd();
glBegin(GL_LINE_LOOP); // NEAR FACE
glVertex3fv(&(V[1].x)); glVertex3fv(&(V[2].x));
glVertex3fv(&(V[3].x)); glVertex3fv(&(V[0].x));
glEnd();
glBegin(GL_LINE_LOOP); // FAR FACE
glVertex3fv(&(V[4].x)); glVertex3fv(&(V[7].x));
glVertex3fv(&(V[6].x)); glVertex3fv(&(V[5].x));
glEnd();
// DRAW PROJECTOR LINES FROM EYE TO CORNERS OF VIEWPLANE WINDOW
glBegin(GL_LINES);
glVertex3fv(&(Orig.x)); glVertex3fv(&(V[1].x));
glVertex3fv(&(Orig.x)); glVertex3fv(&(V[2].x));
glVertex3fv(&(Orig.x)); glVertex3fv(&(V[3].x));
glVertex3fv(&(Orig.x)); glVertex3fv(&(V[0].x));
glEnd();
}
void Camera::DisplayInGreen() const
{
//draws the camera in unlit green lines, then restores the GL state
glPushAttrib(GL_LIGHTING_BIT);
glDisable(GL_LIGHTING);
glPushAttrib(GL_LINE_BIT);
glLineWidth(1.0);
glColor3f(0,1,0);
Display();
glPopAttrib();
glPopAttrib();
}

View File

@@ -0,0 +1,409 @@
//------------------------------------------------------------------------------
// File : camera.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// camera.cpp : camera class implementation
//----------------------------------------------------------------------------
// $Id$
//============================================================================
#include "camera.hpp"
#include <iostream.h>
//----------------------------------------------------------------------------
// CONSTRUCTOR: defines a default camera system defined as (45 DEG FOV)
//----------------------------------------------------------------------------
Camera::Camera()
{
X.Set(1,0,0); Y.Set(0,1,0); Z.Set(0,0,1);
Orig.Set(0,0,0);
Near=0.5f; Far=140.0f; wL=-1; wR=1; wT=1; wB=-1;
}
Camera::Camera(const Camera &Cam)
{
Copy(Cam);
}
void Camera::Copy(const Camera &Cam)
{
X=Cam.X; Y=Cam.Y; Z=Cam.Z; Orig=Cam.Orig;
Near=Cam.Near; Far=Cam.Far;
wL=Cam.wL; wR=Cam.wR; wT=Cam.wT; wB=Cam.wB;
}
//----------------------------------------------------------------------------
// OpenGL CAMERA ORIENTATION ROUTINE (glLookAt)
//----------------------------------------------------------------------------
void Camera::LookAt(
const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp)
{
Z = Eye-ViewRefPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
X = ViewUp/Z; X.Normalize();
Y = Z/X; Y.Normalize();
Orig = Eye;
}
//----------------------------------------------------------------------------
// OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (gluPerspective)
// Aspect = Width/Height; Yfov in degrees
//----------------------------------------------------------------------------
void Camera::Perspective(float Yfov, float Aspect, float Ndist, float Fdist)
{
Yfov *= 0.0174532f; // CONVERT TO RADIANS
Near=Ndist; Far=Fdist;
wT=(float)tan(Yfov*0.5f)*Near; wB=-wT;
wR=wT*Aspect; wL=-wR;
}
//----------------------------------------------------------------------------
// OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (glFrustum). Window extents
// are defined on the viewplane at z=-Ndist.
//----------------------------------------------------------------------------
void Camera::Frustum(float l, float r, float b, float t, float Ndist, float Fdist)
{
Near=Ndist; Far=Fdist;
wR=r; wL=l; wB=b; wT=t;
}
//----------------------------------------------------------------------------
// Completely defines a camera as a tight fitting frustum surrounding the
// given bounding sphere. This is useful when most precision
// is required in pixel and depth resolution (for example, shadow-maps).
// The resulting camera is not skewed!
//----------------------------------------------------------------------------
void Camera::TightlyFitToSphere(
const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad)
{
// FIRST DEFINE COORDINATE FRAME
LookAt(Eye,Cntr,ViewUp);
// PROJECTED DIST TO CNTR ALONG VIEWDIR
float DistToCntr = (Cntr-Orig) * ViewDir();
// CALC TIGHT-FITTING NEAR AND FAR PLANES
Near = DistToCntr-Rad;
Far = DistToCntr+Rad;
//x = n*R / sqrt(d2 - r2)
if (Near<=0 || Far<=0)
printf("ERROR (Camera::TightlyFitToSphere) Eye is inside the sphere!\n");
// CALC TIGHT-FITTING SIDES
wT = (Near * Rad) / (float)sqrt(DistToCntr*DistToCntr - Rad*Rad);//(Near * Rad) / DistToCntr;
wB = -wT;
wL = wB;
wR = wT;
}
//----------------------------------------------------------------------------
// Routines to return the Lookat, Perspective, and Frustum params.
// NOTE: Perspective is designed for non-skewed cameras: the viewing
// direction must be centered on the viewplane window. Use frustum
// for off-axis cameras.
//----------------------------------------------------------------------------
void Camera::GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const
{
*Eye = Orig;
*ViewRefPt = Orig - Z;
*ViewUp = Y;
}
void Camera::GetPerspectiveParams(float *Yfov, float *Aspect,
float *Ndist, float *Fdist) const
{
*Yfov = (float)atan(wT/Near) * 57.29578f * 2.0f; // CONVERT TO DEGREES
*Aspect = wR/wT;
*Ndist = Near;
*Fdist = Far;
}
void Camera::GetFrustumParams(float *l, float *r, float *b, float *t,
float *Ndist, float *Fdist) const
{
*l = wL;
*r = wR;
*b = wB;
*t = wT;
*Ndist = Near;
*Fdist = Far;
}
//----------------------------------------------------------------------------
// RETURNS THE COP OR EYE IN WORLD COORDS (ORIG OF CAMERA SYSTEM)
//----------------------------------------------------------------------------
const Vec3f& Camera::wCOP() const
{
return( Orig );
}
//----------------------------------------------------------------------------
// RETURNS THE VIEWING DIRECTION
//----------------------------------------------------------------------------
Vec3f Camera::ViewDir() const
{
return( -Z );
}
Vec3f Camera::ViewDirOffAxis() const
{
float x=(wL+wR)*0.5f, y=(wT+wB)*0.5f; // MIDPOINT ON VIEWPLANE WINDOW
Vec3f ViewDir = X*x + Y*y - Z*Near;
ViewDir.Normalize();
return( ViewDir );
}
//----------------------------------------------------------------------------
// Vec3f WORLD-TO-CAM AND CAM-TO-WORLD ROUTINES
//----------------------------------------------------------------------------
Vec3f Camera::WorldToCam(const Vec3f& wP) const
{
Vec3f sP(wP-Orig);
Vec3f cP(X*sP,Y*sP,Z*sP); return(cP);
}
// Return the z-value of the world point in camera space
float Camera::WorldToCamZ(const Vec3f& wP) const
{
Vec3f sP(wP-Orig);
float zdist = Z*sP;
return(zdist);
}
Vec3f Camera::CamToWorld(const Vec3f& cP) const
{
Vec3f wP(X*cP.x + Y*cP.y + Z*cP.z + Orig); return(wP);
}
//----------------------------------------------------------------------------
// Makes the camera pose be the identity. World and camera space will be the
// same. Window extents and near/far planes are unaffected.
//----------------------------------------------------------------------------
void Camera::LoadIdentityXform()
{
X.Set(1,0,0);
Y.Set(0,1,0);
Z.Set(0,0,1);
Orig.Set(0,0,0);
}
//----------------------------------------------------------------------------
// Applies an OpenGL style premult/col vector xform to the coordinate frame.
// Only rotates, translates, and uniform scales are allowed.
// Window extents and near/far planes are affected by scaling.
//----------------------------------------------------------------------------
void Camera::Xform(const float M[16])
{
X.Set( X.x*M[0] + X.y*M[4] + X.z*M[8],
X.x*M[1] + X.y*M[5] + X.z*M[9],
X.x*M[2] + X.y*M[6] + X.z*M[10] );
Y.Set( Y.x*M[0] + Y.y*M[4] + Y.z*M[8],
Y.x*M[1] + Y.y*M[5] + Y.z*M[9],
Y.x*M[2] + Y.y*M[6] + Y.z*M[10] );
Z.Set( Z.x*M[0] + Z.y*M[4] + Z.z*M[8],
Z.x*M[1] + Z.y*M[5] + Z.z*M[9],
Z.x*M[2] + Z.y*M[6] + Z.z*M[10] );
Orig.Set( Orig.x*M[0] + Orig.y*M[4] + Orig.z*M[8] + M[12],
Orig.x*M[1] + Orig.y*M[5] + Orig.z*M[9] + M[13],
Orig.x*M[2] + Orig.y*M[6] + Orig.z*M[10] + M[14] );
// MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
float Scale = X.Length();
X /= Scale;
Y /= Scale;
Z /= Scale;
// SCALE THE WINDOW EXTENTS AND THE NEAR/FAR PLANES
wL*=Scale;
wR*=Scale;
wB*=Scale;
wT*=Scale;
Near*=Scale;
Far*=Scale;
};
//----------------------------------------------------------------------------
// Translates the camera by the vector amount trans.
//----------------------------------------------------------------------------
void Camera::Translate(const Vec3f& trans)
{
Orig += trans;
}
//----------------------------------------------------------------------------
// Translates the camera about its origin by the rotation matrix M.
//----------------------------------------------------------------------------
void Camera::Rotate(const float M[9])
{
X.Set( X.x*M[0] + X.y*M[3] + X.z*M[6],
X.x*M[1] + X.y*M[4] + X.z*M[7],
X.x*M[2] + X.y*M[5] + X.z*M[8] );
Y.Set( Y.x*M[0] + Y.y*M[3] + Y.z*M[6],
Y.x*M[1] + Y.y*M[4] + Y.z*M[7],
Y.x*M[2] + Y.y*M[5] + Y.z*M[8] );
Z.Set( Z.x*M[0] + Z.y*M[3] + Z.z*M[6],
Z.x*M[1] + Z.y*M[4] + Z.z*M[7],
Z.x*M[2] + Z.y*M[5] + Z.z*M[8] );
}
//----------------------------------------------------------------------------
// Returns the COMPOSITE xform matrix that takes a point in the object space
// to a screen space (pixel) point. The inverse is also provided.
// You have to give the pixel dimensions of the viewport window.
//----------------------------------------------------------------------------
float* Camera::GetXform_Screen2Obj(float* M, int WW, int WH) const
{
Screen2WorldXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
wL,wR,wB,wT,Near,Far,WW,WH);
return(M);
}
float* Camera::GetXform_Obj2Screen(float* M, int WW, int WH) const
{
World2ScreenXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
wL,wR,wB,wT,Near,Far,WW,WH);
return(M);
}
//----------------------------------------------------------------------------
// OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/COL VECT, 4x4 MATRIX)
// A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
// VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
// WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
// Modelview XFORM. The associated inverse matrices are also provided.
//----------------------------------------------------------------------------
float* Camera::GetModelviewMatrix(float* M) const
{
Viewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
return(M);
}
float* Camera::GetInvModelviewMatrix(float* M) const
{
invViewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
return(M);
}
float* Camera::GetProjectionMatrix(float* M) const
{
Frustum16fv(M,wL,wR,wB,wT,Near,Far);
return(M);
}
void Camera::SetModelviewMatrix(const float* M)
{
Viewing2CoordFrame16fv(M, &(X.x), &(Y.x), &(Z.x), &(Orig.x));
}
float* Camera::GetInvProjectionMatrix(float* M) const
{
invFrustum16fv(M,wL,wR,wB,wT,Near,Far);
return(M);
}
float* Camera::GetViewportMatrix(float* M, int WW, int WH) const
{
Viewport16fv(M,WW,WH);
return(M);
}
float* Camera::GetInvViewportMatrix(float* M, int WW, int WH) const
{
invViewport16fv(M,WW,WH);
return(M);
}
//----------------------------------------------------------------------------
// Given a screen pixel location (sx,sy) w/ (0,0) at the lower-left and the
// screen dimensions, return the ray (start,dir) of the ray in world coords.
//----------------------------------------------------------------------------
void Camera::GetPixelRay(float sx, float sy, int ww, int wh,
Vec3f *Start, Vec3f *Dir) const
{
Vec3f wTL = Orig + (X*wL) + (Y*wT) - (Z*Near); // FIND LOWER-LEFT
Vec3f dX = (X*(wR-wL))/(float)ww; // WORLD WIDTH OF PIXEL
Vec3f dY = (Y*(wT-wB))/(float)wh; // WORLD HEIGHT OF PIXEL
wTL += (dX*sx - dY*sy); // INCR TO WORLD PIXEL
wTL += (dX*0.5 - dY*0.5); // INCR TO PIXEL CNTR
*Start = Orig;
*Dir = wTL-Orig;
}
//----------------------------------------------------------------------------
// READ AND WRITE CAMERA AXES AND ORIGIN TO AND FROM A FILE GIVEN A FILE PTR.
//----------------------------------------------------------------------------
void Camera::WriteToFile(FILE *fp) const
{
if (fp==NULL) { printf("ERROR WRITING CAM TO FILE!\n"); return; }
fprintf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f\n",
X.x,X.y,X.z, Y.x,Y.y,Y.z, Z.x,Z.y,Z.z, Orig.x,Orig.y,Orig.z);
}
int Camera::ReadFromFile(FILE *fp) // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
{
int Cond = fscanf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f",
&X.x,&X.y,&X.z, &Y.x,&Y.y,&Y.z,
&Z.x,&Z.y,&Z.z, &Orig.x,&Orig.y,&Orig.z);
return(Cond!=EOF);
}
//----------------------------------------------------------------------------
// 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
// (Left,Right, Bottom,Top, Near,Far)
// In order, near pts counter-clockwise starting with right-top-near (RTN) pt
// and then far pts ccw starting with right-top-far (RTF) pt
//----------------------------------------------------------------------------
void Camera::CalcVerts(Vec3f *V) const // MUST BE PREALLOCED : "Vec3f V[8]"
{
// WINDOW EXTENTS ARE DEFINED ON THE NEAR PLANE, CALC NEAR PTS (IN CAM COORDS)
float NearZ = -Near;
V[0].Set(wR,wT,NearZ);
V[1].Set(wL,wT,NearZ);
V[2].Set(wL,wB,NearZ);
V[3].Set(wR,wB,NearZ);
// CALC FAR PTS (IN CAM COORDS)
float FarZ=-Far, FN=Far/Near;
float fwL=wL*FN, fwR=wR*FN, fwB=wB*FN, fwT=wT*FN;
V[4].Set(fwR,fwT,FarZ);
V[5].Set(fwL,fwT,FarZ);
V[6].Set(fwL,fwB,FarZ);
V[7].Set(fwR,fwB,FarZ);
// XFORM FRUSTUM IN CAM COORDS TO WORLD SPACE
for (int i=0; i<8; i++)
V[i] = CamToWorld(V[i]);
}
//----------------------------------------------------------------------------
// PRINT ROUTINE
//----------------------------------------------------------------------------
void Camera::Print() const
{
printf("Camera System Parameters:\n");
printf(" X: (%.3f, %.3f, %.3f)\n", X.x, X.y, X.z);
printf(" Y: (%.3f, %.3f, %.3f)\n", Y.x, Y.y, Y.z);
printf(" Z: (%.3f, %.3f, %.3f)\n", Z.x, Z.y, Z.z);
printf(" Origin: (%.3f, %.3f, %.3f)\n", Orig.x, Orig.y, Orig.z);
printf(" NFLRBT: (%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
Near,Far,wL,wR,wB,wT);
};

View File

@@ -0,0 +1,102 @@
//------------------------------------------------------------------------------
// File : camera.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// camera.hpp : OPENGL-style camera class definition
// Defines and stores a "camera" composed of 3 coord axes, an origin for
// these axes (center-of-projection or eye location), a near and far plane
// as distances from the origin projected along the viewing direction,
// the viewplane window extents (projection window defined in cam coords
// on the viewplane - near plane). ViewPlane is defined as the near plane.
// Viewing direction is always defined along the -Z axis with eye at origin.
//----------------------------------------------------------------------------
// $Id$
//============================================================================
#ifndef CAMERA
#define CAMERA
#include <stdio.h>
#include <vec3f.hpp>
#include <mat16fv.hpp>
class Camera
{
public:
Vec3f X, Y, Z; // NORMALIZED CAMERA COORDINATE-AXIS VECTORS
Vec3f Orig; // LOCATION OF ORIGIN OF CAMERA SYSTEM IN WORLD COORDS
float wL,wR,wB,wT; // WINDOW EXTENTS DEFINED AS A RECT ON NearPlane
float Near,Far; // DISTANCES TO NEAR AND FAR PLANES (IN VIEWING DIR)
Camera();
Camera(const Camera &Cam);
void Copy(const Camera &Cam);
void LookAt(const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp);
void Perspective(float Yfov, float Aspect, float Ndist, float Fdist);
void Frustum(float l, float r, float b, float t, float Ndist, float Fdist);
void TightlyFitToSphere(
const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad);
void GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const;
void GetPerspectiveParams(float *Yfov, float *Aspect,
float *Ndist, float *Fdist) const;
void GetFrustumParams(float *l, float *r, float *b, float *t,
float *Ndist, float *Fdist) const;
const Vec3f& wCOP() const; // WORLD COORDINATE CENTER-OF-PROJECTION (EYE)
Vec3f ViewDir() const; // VIEWING DIRECTION
Vec3f ViewDirOffAxis() const;
float* GetXform_Screen2Obj(float* M, int WW, int WH) const;
float* GetXform_Obj2Screen(float* M, int WW, int WH) const;
float* GetModelviewMatrix(float* M) const;
float* GetProjectionMatrix(float* M) const;
float* GetViewportMatrix(float* M, int WW, int WH) const;
void SetModelviewMatrix(const float* M);
float* GetInvModelviewMatrix(float* M) const;
float* GetInvProjectionMatrix(float* M) const;
float* GetInvViewportMatrix(float* M, int WW, int WH) const;
Vec3f WorldToCam(const Vec3f &wP) const;
float WorldToCamZ(const Vec3f &wP) const;
Vec3f CamToWorld(const Vec3f &cP) const;
void LoadIdentityXform();
void Xform(const float M[16]);
void Translate(const Vec3f& trans);
void Rotate(const float M[9]);
void GetPixelRay(float sx, float sy, int ww, int wh,
Vec3f *Start, Vec3f *Dir) const;
void WriteToFile(FILE *fp) const;
int ReadFromFile(FILE *fp); // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
void CalcVerts(Vec3f *V) const; // CALCS EIGHT CORNERS OF VIEW-FRUSTUM
void Print() const;
void Display() const;
void DisplaySolid() const;
void DisplayInGreen() const;
};
#endif

View File

@@ -0,0 +1,324 @@
//------------------------------------------------------------------------------
// File : camutils.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// camutils.cpp : a set of camera utility functions
//============================================================================
#include "camutils.hpp"
#include <plane.hpp>
#include <tri.hpp>
#include <minmaxbox.hpp>
//----------------------------------------------------------------------------
// Given a camera's 8 corner vertices and its 6 side planes and a triangle ABC,
// return whether or not the tri overlaps the camera's frustum.
//----------------------------------------------------------------------------
int CamTriOverlap(const Vec3f V[8], const float P[][4],
const Vec3f& A, const Vec3f& B, const Vec3f& C)
{
// TEST TRIANGLE AGAINST ALL PLANES OF CAMERA, FOR EACH VERTEX CLASSIFY
// AS INSIDE OR OUTSIDE OF PLANE (BY SETTING APPROPRIATE BIT IN BITMASK)
// FOR EACH VERTEX, WE HAVE A BITMASK INDICATING WHETHER THE VERTEX
// IS IN OR OUT OF EACH PLANE (LS 6-BITS, SET MEANS "OUT")
unsigned int BitMaskA=0, BitMaskB=0, BitMaskC=0;
unsigned int PlaneBitMask=1; // CURRENT PLANE BEING CHECKED
int i;
for (i=0; i<6; i++)
{
if ( PlanePtOutTest(P[i], &(A.x)) ) BitMaskA |= PlaneBitMask;
if ( PlanePtOutTest(P[i], &(B.x)) ) BitMaskB |= PlaneBitMask;
if ( PlanePtOutTest(P[i], &(C.x)) ) BitMaskC |= PlaneBitMask;
PlaneBitMask<<=1;
}
// TRIVIAL ACCEPTANCE: IF ANY VERTEX IS COMPLETELY INSIDE ALL PLANES (=0)
if (BitMaskA==0 || BitMaskB==0 || BitMaskC==0) return(1);
// TRIVIAL REJECTION: IF ALL VERTICES ARE OUTSIDE OF ANY PLANE
PlaneBitMask=1;
for (i=0; i<6; i++)
{
if ((BitMaskA & BitMaskB & BitMaskC & PlaneBitMask) > 0) return(0);
PlaneBitMask<<=1;
}
// TEST EDGES OF TRIANGLE AGAINST PLANES OF CAMERA
float InT, OutT;
if ( PlanesEdgeIsect(P,6,&(A.x),&(B.x),&InT,&OutT) ) return(1);
if ( PlanesEdgeIsect(P,6,&(B.x),&(C.x),&InT,&OutT) ) return(1);
if ( PlanesEdgeIsect(P,6,&(C.x),&(A.x),&InT,&OutT) ) return(1);
// TEST EDGES OF CAMERA AGAINST TRIANGLE
float IsectPt[3];
if ( EdgeTriIsect(&(V[0].x),&(V[4].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[1].x),&(V[5].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[2].x),&(V[6].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[3].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[1].x),&(V[0].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[5].x),&(V[4].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[6].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[2].x),&(V[3].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[4].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[5].x),&(V[6].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[1].x),&(V[2].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
if ( EdgeTriIsect(&(V[0].x),&(V[3].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
return(0);
}
int CamTriOverlap(const Camera *Cam,
const Vec3f& A, const Vec3f& B, const Vec3f& C)
{
// GET CAMERA VERTICES
Vec3f V[8];
Cam->CalcVerts(V);
// CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
float P[6][4];
CalcCamPlanes(V,P);
return( CamTriOverlap(V,P,A,B,C) );
}
//----------------------------------------------------------------------------
// Temporary implementation of CamQuadOverlap (uses CamTriOverlap).
//----------------------------------------------------------------------------
int CamQuadOverlap(
const Camera *Cam,
const Vec3f& A, const Vec3f& B, const Vec3f& C, const Vec3f& D)
{
if ( CamTriOverlap(Cam,A,B,C) ) return(1);
if ( CamTriOverlap(Cam,C,D,A) ) return(1);
return(0);
}
int CamQuadOverlap(
const Camera *Cam,
const float A[3], const float B[3], const float C[3], const float D[3])
{
Vec3f a(A),b(B),c(C),d(D);
return( CamQuadOverlap(Cam,a,b,c,d) );
}
//----------------------------------------------------------------------------
// Calculate the six planes for a camera. User must have prealloced an array
// of 24 floats (6 planes * 4 coeffs each). Two version: 1 that calculates
// the camera vertices, requires the cam verts to be precomputed
//----------------------------------------------------------------------------
void CalcCamPlanes(const Vec3f *V, float P[][4])
{
PlaneEquation(P[0], &(V[2].x),&(V[5].x),&(V[6].x)); // LEFT
PlaneEquation(P[1], &(V[0].x),&(V[7].x),&(V[4].x)); // RIGHT
PlaneEquation(P[2], &(V[3].x),&(V[6].x),&(V[7].x)); // BOTTOM
PlaneEquation(P[3], &(V[1].x),&(V[4].x),&(V[5].x)); // TOP
PlaneEquation(P[4], &(V[1].x),&(V[2].x),&(V[0].x)); // NEAR
PlaneEquation(P[5], &(V[4].x),&(V[6].x),&(V[5].x)); // FAR
}
void CalcCamPlanes(const Camera *Cam, float P[][4])
{
Vec3f V[8];
Cam->CalcVerts(V);
CalcCamPlanes(V,P);
}
//--------------------------------------------------------------------------
// Camera view-frustum/MinMaxBox (AABB) overlap test: given the extents of the
// AABB returns the type of overlap determined (complete out(1), partial (0),
// complete in (-1)) m and M are the min and max extents of the AABB respectively.
// Version is provided that takes in a precomputed set of camera vertices
// and planes
//--------------------------------------------------------------------------
int CamMinMaxBoxOverlap(
const Camera *Cam, const Vec3f V1[8], const float cP[][4],
const Vec3f& m, const Vec3f& M)
{
// GO FOR TRIVIAL REJECTION OR ACCEPTANCE USING "FASTER OVERLAP TEST"
int CompletelyIn=1; // ASSUME COMPLETELY IN UNTIL ONE COUNTEREXAMPLE
int R; // TEST RETURN VALUE
for (int i=0; i<6; i++)
{
R=PlaneMinMaxBoxOverlap(cP[i],&(m.x),&(M.x));
if(R==COMPLETEOUT) return(COMPLETEOUT);
else if(R==PARTIAL) CompletelyIn=0;
}
if (CompletelyIn) return(COMPLETEIN); // CHECK IF STILL COMPLETELY "IN"
// TEST IF VIEW-FRUSTUM EDGES PROTRUDE THROUGH AABB
float InT, OutT;
if ( EdgeMinMaxBoxIsect(&(V1[0].x),&(V1[4].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[1].x),&(V1[5].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[2].x),&(V1[6].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[3].x),&(V1[7].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[0].x),&(V1[1].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[1].x),&(V1[2].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[2].x),&(V1[3].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[3].x),&(V1[0].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[4].x),&(V1[5].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[5].x),&(V1[6].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[6].x),&(V1[7].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
if ( EdgeMinMaxBoxIsect(&(V1[7].x),&(V1[0].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
// COMPUTE VERTICES OF AABB
float bV[8][3];
GetMinMaxBoxVerts(&(m.x),&(M.x),bV);
// TEST FOR PROTRUSION OF AABB EDGES THROUGH VIEW-FRUSTUM
if ( PlanesEdgeIsect(cP,6,bV[0],bV[4],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[1],bV[5],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[2],bV[6],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[3],bV[7],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[0],bV[1],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[1],bV[2],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[2],bV[3],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[3],bV[0],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[4],bV[5],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[5],bV[6],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[6],bV[7],&InT,&OutT) ) return(PARTIAL);
if ( PlanesEdgeIsect(cP,6,bV[7],bV[0],&InT,&OutT) ) return(PARTIAL);
// VF MUST BE COMPLETELY ENCLOSED SINCE PT IS NOT "OUT "OF ANY AABB PLANE.
//return(COMPLETEOUT);
return (PARTIAL);
};
int CamMinMaxBoxOverlap(
const Camera *Cam, const float m[3], const float M[3])
{
// GET CAMERA VERTICES
Vec3f V1[8];
Cam->CalcVerts(V1);
// CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
float cP[6][4];
CalcCamPlanes(V1,cP);
return( CamMinMaxBoxOverlap(Cam,V1,cP,m,M) );
};
// ----------------------------------------------------------------------
// Returns 1 if and only if the specified box is completely culled away.
bool VFC(const Camera *Cam, const float m[3], const float M[3])
{
return (CamMinMaxBoxOverlap(Cam, m, M) == COMPLETEOUT);
}
//----------------------------------------------------------------------------
// Given the 8 corner vertices and the 6 side planes for two cameras,
// returns the type of overlap (complete out(1), partial (0), complete in (-1))
// with respect to the first camera.
//----------------------------------------------------------------------------
int CamCamOverlap(
const Vec3f V1[8], const float P1[][4],
const Vec3f V2[8], const float P2[][4])
{
int i, NumVertsOutAllPlanes, NumVertsOutOnePlane;
float InT, OutT;
// TEST ALL CAM1 VERTICES AGAINST PLANES OF CAM2
NumVertsOutAllPlanes=0;
for (i=0; i<6; i++)
{
NumVertsOutOnePlane=0;
for (int j=0; j<8; j++)
NumVertsOutOnePlane += PlanePtOutTest(P2[i],&(V1[i].x));
if (NumVertsOutOnePlane==8) return(1); // TRIVIAL REJECT, COMPLETELY OUT!
NumVertsOutAllPlanes+=NumVertsOutOnePlane;
}
if (NumVertsOutAllPlanes==0) return(0); // TRIVIAL ACCEPT, PARTIAL!
// TEST ALL CAM2 VERTICES AGAINST PLANES OF CAM1
NumVertsOutAllPlanes=0;
for (i=0; i<6; i++)
{
NumVertsOutOnePlane=0;
for (int j=0; j<8; j++)
NumVertsOutOnePlane += PlanePtOutTest(P1[i],&(V2[i].x));
if (NumVertsOutOnePlane==8) return(1); // TRIVIAL REJECT, COMPLETELY OUT!
NumVertsOutAllPlanes+=NumVertsOutOnePlane;
}
if (NumVertsOutAllPlanes==0) return(-1); // TRIVIAL ACCEPT, COMPLETELY IN!
// TEST ALL CAM1 EDGES AGAINST SET OF CAM2 PLANES
if ( PlanesEdgeIsect(P2,6,&(V1[0].x),&(V1[4].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[1].x),&(V1[5].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[2].x),&(V1[6].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[3].x),&(V1[7].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[0].x),&(V1[1].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[1].x),&(V1[2].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[2].x),&(V1[3].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[3].x),&(V1[0].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[4].x),&(V1[5].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[5].x),&(V1[6].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[6].x),&(V1[7].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P2,6,&(V1[7].x),&(V1[0].x),&InT,&OutT) ) return(0);
// TEST ALL CAM2 EDGES AGAINST SET OF CAM1 PLANES
if ( PlanesEdgeIsect(P1,6,&(V2[0].x),&(V2[4].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[1].x),&(V2[5].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[2].x),&(V2[6].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[3].x),&(V2[7].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[0].x),&(V2[1].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[1].x),&(V2[2].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[2].x),&(V2[3].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[3].x),&(V2[0].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[4].x),&(V2[5].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[5].x),&(V2[6].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[6].x),&(V2[7].x),&InT,&OutT) ) return(0);
if ( PlanesEdgeIsect(P1,6,&(V2[7].x),&(V2[0].x),&InT,&OutT) ) return(0);
return(1);
}
int CamCamOverlap(const Camera *Cam1, const Camera *Cam2)
{
// GET CAMERA VERTICES
Vec3f V1[8], V2[8];
Cam1->CalcVerts(V1);
Cam2->CalcVerts(V2);
// CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
float P1[6][4], P2[6][4];
CalcCamPlanes(V1,P1);
CalcCamPlanes(V2,P2);
return( CamCamOverlap(V1,P1,V2,P2) );
}
//--------------------------------------------------------------------------
// Given a camera and a plane (defined by four coefficient of implicit
// form: Ax+By+Cz+D=0), reflect the camera about the plane and invert
// back into right-handed system (reflection inverts the space, so we
// have to invert the X-axis and flip the window boundaries).
//--------------------------------------------------------------------------
void CamReflectAboutPlane(Camera *Cam, const float Plane[4])
{
// CREATE PLANAR REFLECTION MATRIX
float M[16];
PlanarReflection16fv(M,Plane);
// XFORM CAMERA
Cam->Xform(M);
// RESULTING CAM IS LEFT-HANDED, FLIP THE X-AXIS, FLIP X WINDOW BOUNDS
Cam->X = -(Cam->X);
float t = -(Cam->wL);
Cam->wL = -(Cam->wR);
Cam->wR = t;
}

View File

@@ -0,0 +1,58 @@
//------------------------------------------------------------------------------
// File : camutils.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// camutils.hpp : a set of camera utility functions
//============================================================================
#include "camera.hpp"
#define COMPLETEOUT 1
#define PARTIAL 0
#define COMPLETEIN -1
int CamTriOverlap(const Vec3f V[8], const float P[][4],
const Vec3f& A, const Vec3f& B, const Vec3f& C);
int CamTriOverlap(const Camera *Cam,
const Vec3f& A, const Vec3f& B, const Vec3f& C);
int CamQuadOverlap(
const Camera *Cam,
const Vec3f& A, const Vec3f& B, const Vec3f& C, const Vec3f& D);
int CamQuadOverlap(
const Camera *Cam,
const float A[3], const float B[3], const float C[3], const float D[3]);
void CalcCamPlanes(const Vec3f V[8], float P[][4]);
void CalcCamPlanes(const Camera *Cam, float P[][4]);
int CamMinMaxBoxOverlap(const Camera *Cam,
const Vec3f cV[8], const float cP[][4],
const Vec3f& m, const Vec3f& M);
int CamMinMaxBoxOverlap(const Camera *Cam,
const float m[3], const float M[3]);
bool VFC(const Camera *Cam, const float m[3], const float M[3]);
int CamCamOverlap(const Vec3f V1[8], const float P1[][4],
const Vec3f V2[8], const float P2[][4]);
int CamCamOverlap(const Camera *Cam1, const Camera *Cam2);
void CamReflectAboutPlane(Camera *Cam, const float Plane[4]);

View File

@@ -0,0 +1,475 @@
//------------------------------------------------------------------------------
// File : mat16fv.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// $Id$
//----------------------------------------------------------------------------
// mat16fv.cpp : opengl-style float[16] matrix routines.
//
// OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/ROW VECT, 4x4 MATRIX)
// A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
// VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
// WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
// Modelview XFORM. The associated inverse matrices are also provided.
// Matrices are of the following form:
// M[16] : 0 4 8 12
// 1 5 9 13
// 2 6 10 14
// 3 7 11 15
//============================================================================
#include <stdio.h>
#include <math.h>
#include "vec3fv.hpp"
float* Copy16fv(float* A, const float* B) // A=B
{
A[0]=B[0]; A[1]=B[1]; A[2]=B[2]; A[3]=B[3];
A[4]=B[4]; A[5]=B[5]; A[6]=B[6]; A[7]=B[7];
A[8]=B[8]; A[9]=B[9]; A[10]=B[10]; A[11]=B[11];
A[12]=B[12]; A[13]=B[13]; A[14]=B[14]; A[15]=B[15];
return A;
}
float* Mult16fv(float* C, const float* A, const float* B) // C=A*B
{
float tC[16];
tC[0] = A[0]*B[0] + A[4]*B[1] + A[8]*B[2] + A[12]*B[3];
tC[1] = A[1]*B[0] + A[5]*B[1] + A[9]*B[2] + A[13]*B[3];
tC[2] = A[2]*B[0] + A[6]*B[1] + A[10]*B[2] + A[14]*B[3];
tC[3] = A[3]*B[0] + A[7]*B[1] + A[11]*B[2] + A[15]*B[3];
tC[4] = A[0]*B[4] + A[4]*B[5] + A[8]*B[6] + A[12]*B[7];
tC[5] = A[1]*B[4] + A[5]*B[5] + A[9]*B[6] + A[13]*B[7];
tC[6] = A[2]*B[4] + A[6]*B[5] + A[10]*B[6] + A[14]*B[7];
tC[7] = A[3]*B[4] + A[7]*B[5] + A[11]*B[6] + A[15]*B[7];
tC[8] = A[0]*B[8] + A[4]*B[9] + A[8]*B[10] + A[12]*B[11];
tC[9] = A[1]*B[8] + A[5]*B[9] + A[9]*B[10] + A[13]*B[11];
tC[10] = A[2]*B[8] + A[6]*B[9] + A[10]*B[10] + A[14]*B[11];
tC[11] = A[3]*B[8] + A[7]*B[9] + A[11]*B[10] + A[15]*B[11];
tC[12] = A[0]*B[12] + A[4]*B[13] + A[8]*B[14] + A[12]*B[15];
tC[13] = A[1]*B[12] + A[5]*B[13] + A[9]*B[14] + A[13]*B[15];
tC[14] = A[2]*B[12] + A[6]*B[13] + A[10]*B[14] + A[14]*B[15];
tC[15] = A[3]*B[12] + A[7]*B[13] + A[11]*B[14] + A[15]*B[15];
Copy16fv(C,tC);
return(C);
}
float* Mult16fv3fv(float *NewV, const float* M, const float *V)
{
NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2];
NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2];
NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2];
return(NewV);
}
float* Mult16fv3fvPerspDiv(float *NewV, const float* M, const float *V)
{
float W = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15];
NewV[0] = (M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]) / W;
NewV[1] = (M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]) / W;
NewV[2] = (M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]) / W;
return(NewV);
}
float* Mult16fv4fv(float *NewV, const float* M, const float *V)
{
NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]*V[3];
NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]*V[3];
NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]*V[3];
NewV[3] = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15]*V[3];
return(NewV);
}
float* Identity16fv(float* M)
{
M[0]=M[5]=M[10]=M[15]=1;
M[1]=M[2]=M[3]=M[4]=M[6]=M[7]=M[8]=M[9]=M[11]=M[12]=M[13]=M[14]=0;
return(M);
}
float* Transpose16fv(float* M)
{
#define SWAP(a,b,t) (t)=(a);(a)=(b);(b)=(t);
float t;
SWAP(M[1],M[4],t);
SWAP(M[2],M[8],t);
SWAP(M[6],M[9],t);
SWAP(M[3],M[12],t);
SWAP(M[7],M[13],t);
SWAP(M[11],M[14],t);
return(M);
}
float* Rotate16fv(float *M, float DegAng, const float Axis[3])
{
float RadAng = DegAng * 0.0174532f;
float ca=(float)cos(RadAng),
sa=(float)sin(RadAng);
if (Axis[0]==1 && Axis[1]==0 && Axis[2]==0) // ABOUT X-AXIS
{
M[0]=1; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
if (Axis[0]==0 && Axis[1]==1 && Axis[2]==0) // ABOUT Y-AXIS
{
M[0]=ca; M[4]=0; M[8]=sa; M[12]=0;
M[1]=0; M[5]=1; M[9]=0; M[13]=0;
M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
if (Axis[0]==0 && Axis[1]==0 && Axis[2]==1) // ABOUT Z-AXIS
{
M[0]=ca; M[4]=-sa; M[8]=0; M[12]=0;
M[1]=sa; M[5]=ca; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=1; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
else // ARBITRARY AXIS
{
float l = Axis[0]*Axis[0]+Axis[1]*Axis[1]+Axis[2]*Axis[2];
float x, y, z;
x=Axis[0],y=Axis[1],z=Axis[2];
if (l > 1.0001f || l < 0.9999f && l!=0)
{
// needs normalization
l=1.0f/(float)sqrt(l);
x*=l; y*=l; z*=l;
}
float x2=x*x, y2=y*y, z2=z*z;
M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
M[15]=1;
}
return(M);
}
float* invRotate16fv(float *M, float DegAng, const float Axis[3])
{
Rotate16fv(M,DegAng,Axis);
Transpose16fv(M);
return(M);
}
float* Scale16fv(float* M, float sx, float sy, float sz)
{
M[0]=sx; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=sy; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=sz; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* invScale16fv(float* M, float sx, float sy, float sz)
{
M[0]=1/sx; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=1/sy; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=1/sz; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* Translate16fv(float* M, float tx, float ty, float tz)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=tx;
M[1]=0; M[5]=1; M[9]=0; M[13]=ty;
M[2]=0; M[6]=0; M[10]=1; M[14]=tz;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* invTranslate16fv(float* M, float tx, float ty, float tz)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=-tx;
M[1]=0; M[5]=1; M[9]=0; M[13]=-ty;
M[2]=0; M[6]=0; M[10]=1; M[14]=-tz;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* LookAt(float* M,
const float Eye[3],
const float LookAtPt[3],
const float ViewUp[3])
{
float X[3], Y[3], Z[3];
Subtract3fv(Z,Eye,LookAtPt); Normalize3fv(Z);
CrossProd3fv(X,ViewUp,Z); Normalize3fv(X);
CrossProd3fv(Y,Z,X); Normalize3fv(Y);
M[0]=X[0]; M[4]=X[1]; M[8]=X[2]; M[12]=-DotProd3fv(X,Eye); // TRANS->ROT
M[1]=Y[0]; M[5]=Y[1]; M[9]=Y[2]; M[13]=-DotProd3fv(Y,Eye);
M[2]=Z[0]; M[6]=Z[1]; M[10]=Z[2]; M[14]=-DotProd3fv(Z,Eye);
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* invLookAt(float* M,
const float Eye[3],
const float LookAtPt[3],
const float ViewUp[3])
{
float X[3], Y[3], Z[3];
Subtract3fv(Z,Eye,LookAtPt); Normalize3fv(Z);
CrossProd3fv(X,ViewUp,Z); Normalize3fv(X);
CrossProd3fv(Y,Z,X); Normalize3fv(Y);
M[0]=X[0]; M[4]=Y[0]; M[8]=Z[0]; M[12]=Eye[0]; // ROT->TRANS
M[1]=X[1]; M[5]=Y[1]; M[9]=Z[1]; M[13]=Eye[1];
M[2]=X[2]; M[6]=Y[2]; M[10]=Z[2]; M[14]=Eye[2];
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* Frustum16fv(float* M, float l, float r, float b, float t,
float n, float f)
{
M[0]=(2*n)/(r-l); M[4]=0; M[8]=(r+l)/(r-l); M[12]=0;
M[1]=0; M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b); M[13]=0;
M[2]=0; M[6]=0; M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
M[3]=0; M[7]=0; M[11]=-1; M[15]=0;
return(M);
}
float* invFrustum16fv(float* M, float l, float r, float b, float t,
float n, float f)
{
M[0]=(r-l)/(2*n); M[4]=0; M[8]=0; M[12]=(r+l)/(2*n);
M[1]=0; M[5]=(t-b)/(2*n); M[9]=0; M[13]=(t+b)/(2*n);
M[2]=0; M[6]=0; M[10]=0; M[14]=-1;
M[3]=0; M[7]=0; M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
return(M);
}
float* Perspective(float* M, float Yfov, float Aspect,
float Ndist, float Fdist)
{
Yfov *= 0.0174532f; // CONVERT TO RADIANS
float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
float wR=wT*Aspect, wL=-wR;
Frustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
return(M);
}
float* invPerspective(float* M, float Yfov, float Aspect,
float Ndist, float Fdist)
{
Yfov *= 0.0174532f; // CONVERT TO RADIANS
float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
float wR=wT*Aspect, wL=-wR;
invFrustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
return(M);
}
float* Viewing16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], const float O[3])
{
M[0]=X[0]; M[4]=X[1]; M[8]=X[2]; M[12]=-DotProd3fv(X,O);
M[1]=Y[0]; M[5]=Y[1]; M[9]=Y[2]; M[13]=-DotProd3fv(Y,O);
M[2]=Z[0]; M[6]=Z[1]; M[10]=Z[2]; M[14]=-DotProd3fv(Z,O);
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
// THE INVERSE OF Viewing16fv,
// THIS TAKES A VIEW MATRIX AND RETURNS VIEWING AXES.
// MATRIX ASSUMED TO BE ORTHONORMAL
void Viewing2CoordFrame16fv(
const float *M, float X[3], float Y[3], float Z[3], float O[3])
{
X[0]=M[0]; X[1]=M[4]; X[2]=M[8]; O[0]=-DotProd3fv(M,M+12);
Y[0]=M[1]; Y[1]=M[5]; Y[2]=M[9]; O[1]=-DotProd3fv(M+4,M+12);
Z[0]=M[2]; Z[1]=M[6]; Z[2]=M[10]; O[2]=-DotProd3fv(M+8,M+12);
};
float* invViewing16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], const float O[3])
{
M[0]=X[0]; M[4]=Y[0]; M[8]=Z[0]; M[12]=O[0];
M[1]=X[1]; M[5]=Y[1]; M[9]=Z[1]; M[13]=O[1];
M[2]=X[2]; M[6]=Y[2]; M[10]=Z[2]; M[14]=O[2];
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* Viewport16fv(float* M, int WW, int WH)
{
float WW2=(float)WW*0.5f, WH2=(float)WH*0.5f;
M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
M[2]=0; M[6]=0; M[10]=0.5f; M[14]=0.5f;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* invViewport16fv(float* M, int WW, int WH)
{
float WW2=2.0f/(float)WW, WH2=2.0f/(float)WH;
M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
//--------------------------------------------------------------------------
// Given the coefficient [A B C D] of a plane in the implicit form
// Ax+By+Cz+D=0 (see plane.hpp), this routine generates a reflection matrix
// that will "reflect" all points/vectors about the given plane.
// NOTE: the plane is assumed to be normalized: normal vector (A,B,C) is
// normalized (unit-length), and D is the negative distance from the origin
// to the plane along the normal.
//--------------------------------------------------------------------------
float* PlanarReflection16fv(float M[16], const float P[4])
{
float AA=P[0]*P[0], AB=P[0]*P[1], AC=P[0]*P[2], AD=P[0]*P[3],
BB=P[1]*P[1], BC=P[1]*P[2], BD=P[1]*P[3],
CC=P[2]*P[2], CD=P[2]*P[3];
M[0]=1-2*AA; M[4]=-2*AB; M[8]=-2*AC; M[12]=-2*AD;
M[1]=-2*AB; M[5]=1-2*BB; M[9]=-2*BC; M[13]=-2*BD;
M[2]=-2*AC; M[6]=-2*BC; M[10]=1-2*CC; M[14]=-2*CD;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
//--------------------------------------------------------------------------
// Returns a matrix that will xform a point from the given object-space
// coordinate frame to world space
// A composite matrix is formed as follows:
// C = Translation * Rotation * Scaling (using column vectors/pre-multiplication)
// WorldPt = C * ModelPt
// The corresponding inverse Xform is also provided (GetWorld2ObjXform)
//--------------------------------------------------------------------------
float* Obj2WorldXform16fv(
float *M,
const float X[3], const float Y[3], const float Z[3],
const float O[3], float Scale)
{
float sX[3], sY[3], sZ[3]; // CREATE SCALED VERSION OF ROT AXES
ScalarMult3fv(sX,X,Scale);
ScalarMult3fv(sY,Y,Scale);
ScalarMult3fv(sZ,Z,Scale);
M[0]=sX[0]; M[4]=sY[0]; M[8]=sZ[0]; M[12]=O[0];
M[1]=sX[1]; M[5]=sY[1]; M[9]=sZ[1]; M[13]=O[1];
M[2]=sX[2]; M[6]=sY[2]; M[10]=sZ[2]; M[14]=O[2];
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
float* World2ObjXform16fv(
float *M,
const float X[3], const float Y[3], const float Z[3],
const float O[3], float Scale)
{
if (Scale<=0) { printf("Too small scale!\n"); Scale=1; }
float invScale = 1/Scale;
float sX[3], sY[3], sZ[3];
ScalarMult3fv(sX,X,invScale);
ScalarMult3fv(sY,Y,invScale);
ScalarMult3fv(sZ,Z,invScale);
M[0]=sX[0]; M[4]=sX[1]; M[8]=sX[2]; M[12]=-DotProd3fv(O,sX);
M[1]=sY[0]; M[5]=sY[1]; M[9]=sY[2]; M[13]=-DotProd3fv(O,sY);
M[2]=sZ[0]; M[6]=sZ[1]; M[10]=sZ[2]; M[14]=-DotProd3fv(O,sZ);
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
return(M);
}
// ONLY TRANSLATES, ROTATES, AND SCALES ARE ALLOWED
float XformCoordFrame16fv(
const float *M, float X[3], float Y[3], float Z[3], float O[3])
{
Set3fv(X, X[0]*M[0] + X[1]*M[4] + X[2]*M[8],
X[0]*M[1] + X[1]*M[5] + X[2]*M[9],
X[0]*M[2] + X[1]*M[6] + X[2]*M[10] );
Set3fv(Y, Y[0]*M[0] + Y[1]*M[4] + Y[2]*M[8],
Y[0]*M[1] + Y[1]*M[5] + Y[2]*M[9],
Y[0]*M[2] + Y[1]*M[6] + Y[2]*M[10] );
Set3fv(Z, Z[0]*M[0] + Z[1]*M[4] + Z[2]*M[8],
Z[0]*M[1] + Z[1]*M[5] + Z[2]*M[9],
Z[0]*M[2] + Z[1]*M[6] + Z[2]*M[10] );
Set3fv(O, O[0]*M[0] + O[1]*M[4] + O[2]*M[8] + M[12],
O[0]*M[1] + O[1]*M[5] + O[2]*M[9] + M[13],
O[0]*M[2] + O[1]*M[6] + O[2]*M[10] + M[14] );
// MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
float Scale = Length3fv(X);
ScalarDiv3fv(X,Scale);
ScalarDiv3fv(Y,Scale);
ScalarDiv3fv(Z,Scale);
// RETURN UNIFORM SCALING OF AXES (how much coordinate frame was scaled)
return(Scale);
};
//----------------------------------------------------------------------------
// Given a complete definition for a particular view (viewing, projection,
// and viewport), returns the COMPOSITE xform matrix that takes a point in the
// world space to a screen space (pixel) point. The inverse is also provided.
//----------------------------------------------------------------------------
float* Screen2WorldXform16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], // VIEWING AXES
const float O[3], // VIEWING ORIGIN
float l, float r, float b, float t, float n, float f, // PROJECTION
int WW, int WH) // VIEWPORT
{
// C = InverseModelview * InverseProjection * InverseViewport
float N[16];
invViewing16fv(M,X,Y,Z,O);
invFrustum16fv(N,l,r,b,t,n,f);
Mult16fv(M,M,N); // M=M*N;
invViewport16fv(N,WW,WH);
Mult16fv(M,M,N); // M=M*N;
return(M);
}
float* World2ScreenXform16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], // VIEWING AXES
const float O[3], // VIEWING ORIGIN
float l, float r, float b, float t, float n, float f, // PROJECTION
int WW, int WH) // VIEWPORT
{
// C = Viewport * Projection * Modelview
float N[16];
Viewport16fv(M,WW,WH);
Frustum16fv(N,l,r,b,t,n,f);
Mult16fv(M,M,N); // M=M*N;
Viewing16fv(N,X,Y,Z,O);
Mult16fv(M,M,N); // M=M*N;
return(M);
}
void Print16fv(const float* M)
{
printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);
}

View File

@@ -0,0 +1,119 @@
//------------------------------------------------------------------------------
// File : mat16fv.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// mat16fv.hpp : opengl-style float[16] matrix routines.
//----------------------------------------------------------------------------
// $Id$
//============================================================================
float* Copy16fv(float* A, const float* B); // A=B
float* Mult16fv(float* C, const float* A, const float* B); // C=A*B
float* Mult16fv3fv(
float *NewV, const float* M, const float *V); // NewV = M * [Vx,Vy,Vz,0]
float* Mult16fv3fvPerspDiv(
float *NewV, const float* M, const float *V); // NewV = M * [Vx,Vy,Vz,1]
float* Mult16fv4fv(
float *NewV, const float* M, const float *V); // NewV = M * [Vx,Vy,Vz,Vw]
float* Identity16fv(float* M);
float* Transpose16fv(float* M);
float* Rotate16fv(float *M, float DegAng, const float Axis[3]);
float* invRotate16fv(float *M, float DegAng, const float Axis[3]);
float* Scale16fv(float* M, float sx, float sy, float sz);
float* invScale16fv(float* M, float sx, float sy, float sz);
float* Translate16fv(float* M, float tx, float ty, float tz);
float* invTranslate16fv(float* M, float tx, float ty, float tz);
float* LookAt(
float* M,
const float Eye[3],
const float LookAtPt[3],
const float ViewUp[3]);
float* invLookAt(
float* M,
const float Eye[3],
const float LookAtPt[3],
const float ViewUp[3]);
float* Frustum16fv(
float* M, float l, float r, float b, float t, float n, float f);
float* invFrustum16fv(
float* M, float l, float r, float b, float t, float n, float f);
float* Perspective(
float* M, float Yfov, float Aspect, float Ndist, float Fdist);
float* invPerspective(
float* M, float Yfov, float Aspect, float Ndist, float Fdist);
float* Viewing16fv(
float* M,
const float X[3], const float Y[3], const float Z[3],
const float O[3]);
float* invViewing16fv(
float* M,
const float X[3], const float Y[3], const float Z[3],
const float O[3]);
void Viewing2CoordFrame16fv(
const float *M, float X[3], float Y[3], float Z[3], float O[3]);
float* Viewport16fv(float* M, int WW, int WH);
float* invViewport16fv(float* M, int WW, int WH);
float* PlanarReflection16fv(float M[16], const float P[4]);
float XformCoordFrame16fv(
const float *M, float X[3], float Y[3], float Z[3], float O[3]);
float* Obj2WorldXform16fv(
float *M, float X[3], float Y[3], float Z[3], float O[3], float Scale);
float* World2ObjXform16fv(
float *M,
const float X[3],
const float Y[3],
const float Z[3],
const float O[3],
float Scale);
float* Screen2WorldXform16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], const float O[3],
float l, float r, float b, float t, float n, float f,
int WW, int WH);
float* World2ScreenXform16fv(
float* M,
const float X[3], const float Y[3], const float Z[3], const float O[3],
float l, float r, float b, float t, float n, float f,
int WW, int WH);
void Print16fv(const float* M);

View File

@@ -0,0 +1,113 @@
//------------------------------------------------------------------------------
// File : mat33.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// mat33.hpp : 3x3 matrix template.
//============================================================================
#ifndef _MAT33_
#define _MAT33_
#include "vec3f.hpp"
#include "mat44.hpp"
static const float Mat33TORADS = 0.0174532f;
static const float Mat33VIEWPORT_TOL = 0.001f;
//----------------------------------------------------------------------------
// M[9] = [ 0 3 6 ]
// [ 1 4 7 ]
// [ 2 5 8 ]
//
//
//
// [ x' y' z' ] = [ 0 3 6 ] [ x ]
// [ 1 4 7 ] * [ y ]
// [ 2 5 8 ] [ z ]
//----------------------------------------------------------------------------
template<class Type>
class Mat33
{
public:
Type M[9]; // 0,1,2 = 1st col; 3,4,5 = 2nd col; etc.
Mat33();
Mat33(const Type *N);
Mat33(Type M0, Type M3, Type M6,
Type M1, Type M4, Type M7,
Type M2, Type M5, Type M8);
Mat33<Type>& operator = (const Mat33& A); // ASSIGNMENT (=)
// ASSIGNMENT (=) FROM AN ARRAY OF Type
Mat33<Type>& operator = (const Type* a);
Mat33<Type> operator * (const Mat33& A) const; // MULTIPLICATION (*)
// MAT-VECTOR MULTIPLICATION (*)
Vec3<Type> operator * (const Vec3<Type>& V) const;
// MAT-VECTOR PRE-MULTIPLICATON (*)
friend Vec3<Type> operator * (const Vec3<Type>& V, const Mat33<Type>& M);
// SCALAR POST-MULTIPLICATION
Mat33<Type> operator * (Type a) const;
// SCALAR PRE-MULTIPLICATION
friend Mat33<Type> operator * (Type a, const Mat44<Type>& M);
Mat33<Type> operator / (Type a) const; // SCALAR DIVISION
Mat33<Type> operator + (Mat33& M) const; // ADDITION (+)
Mat33<Type>& operator += (Mat33& M); // ACCUMULATE ADD (+=)
Mat33<Type>& operator -= (Mat33& M); // ACCUMULATE SUB (-=)
Mat33<Type>& operator *= (Type a); // ACCUMULATE MULTIPLY (*=)
Mat33<Type>& operator /= (Type a); // ACCUMULATE DIVIDE (/=)
bool Inverse(Mat33<Type> &inv, Type tolerance) const;// MATRIX INVERSE
operator const Type*() const; // CAST TO A Type ARRAY
operator Type*(); // CAST TO A Type ARRAY
void RowMajor(Type m[9]); // return array in row-major order
Type& operator()(int col, int row); // 2D ARRAY ACCESSOR
const Type& operator()(int col, int row) const; // 2D ARRAY ACCESSOR
void Set(const Type* a); // SAME AS ASSIGNMENT (=) FROM AN ARRAY OF TypeS
void Set(Type M0, Type M3, Type M6,
Type M1, Type M4, Type M7,
Type M2, Type M5, Type M8);
void Identity();
void Zero();
void Transpose();
void Scale(Type Sx, Type Sy, Type Sz);
void Scale(const Vec3<Type>& S);
void invScale(Type Sx, Type Sy, Type Sz);
void invScale(const Vec3<Type>& S);
void Rotate(Type DegAng, const Vec3<Type>& Axis);
void invRotate(Type DegAng, const Vec3<Type>& Axis);
void Star(const Vec3<Type>& v); // SKEW-SYMM MATRIX EQUIV TO CROSS PROD WITH V
void OuterProduct(const Vec3<Type>& u, const Vec3<Type>& v); // SET TO u * v^t
Type Trace() const;
void Print() const;
void CopyInto(Type *Mat) const;
static void SWAP(Type& a, Type& b) {Type t; t=a;a=b;b=t;}
};
#include "mat33impl.hpp"
typedef Mat33<float> Mat33f;
typedef Mat33<double> Mat33d;
#endif

View File

@@ -0,0 +1,412 @@
//------------------------------------------------------------------------------
// File : mat33impl.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// mat33impl.hpp : 3x3 matrix template.
// This is the template implementation file. It is included by mat33.hpp.
//============================================================================
//---------------------------------------------------------------------------
// CONSTRUCTORS
//---------------------------------------------------------------------------
template<class Type>
Mat33<Type>::Mat33()
{
Identity();
}
template<class Type>
Mat33<Type>::Mat33(const Type *N)
{
M[0]=N[0]; M[3]=N[3]; M[6]=N[6];
M[1]=N[1]; M[4]=N[4]; M[7]=N[7];
M[2]=N[2]; M[5]=N[5]; M[8]=N[8];
}
template<class Type>
Mat33<Type>::Mat33(Type M0, Type M3, Type M6,
Type M1, Type M4, Type M7,
Type M2, Type M5, Type M8)
{
M[0]=M0; M[3]=M3; M[6]=M6;
M[1]=M1; M[4]=M4; M[7]=M7;
M[2]=M2; M[5]=M5; M[8]=M8;
}
//---------------------------------------------------------------------------
// MATRIX/MATRIX AND MATRIX/VECTOR OPERATORS
//---------------------------------------------------------------------------
template<class Type>
Mat33<Type>& Mat33<Type>::operator = (const Mat33& A) // ASSIGNMENT (=)
{
M[0]=A.M[0]; M[3]=A.M[3]; M[6]=A.M[6];
M[1]=A.M[1]; M[4]=A.M[4]; M[7]=A.M[7];
M[2]=A.M[2]; M[5]=A.M[5]; M[8]=A.M[8];
return(*this);
}
template<class Type>
Mat33<Type>& Mat33<Type>::operator = (const Type* a) {
for (int i=0;i<9;i++) {
M[i] = a[i];
}
return *this;
}
template<class Type>
Mat33<Type> Mat33<Type>::operator * (const Mat33& A) const // MULTIPLICATION (*)
{
Mat33<Type> NewM(
M[0]*A.M[0] + M[3]*A.M[1] + M[6]*A.M[2], // ROW 1
M[0]*A.M[3] + M[3]*A.M[4] + M[6]*A.M[5],
M[0]*A.M[6] + M[3]*A.M[7] + M[6]*A.M[8],
M[1]*A.M[0] + M[4]*A.M[1] + M[7]*A.M[2], // ROW 2
M[1]*A.M[3] + M[4]*A.M[4] + M[7]*A.M[5],
M[1]*A.M[6] + M[4]*A.M[7] + M[7]*A.M[8],
M[2]*A.M[0] + M[5]*A.M[1] + M[8]*A.M[2], // ROW 3
M[2]*A.M[3] + M[5]*A.M[4] + M[8]*A.M[5],
M[2]*A.M[6] + M[5]*A.M[7] + M[8]*A.M[8]);
return(NewM);
}
// MAT-VECTOR MULTIPLICATION (*)
template<class Type>
Vec3<Type> Mat33<Type>::operator * (const Vec3<Type>& V) const
{
Vec3<Type> NewV;
NewV.x = M[0]*V.x + M[3]*V.y + M[6]*V.z;
NewV.y = M[1]*V.x + M[4]*V.y + M[7]*V.z;
NewV.z = M[2]*V.x + M[5]*V.y + M[8]*V.z;
return(NewV);
}
// MAT-VECTOR PRE-MULTIPLICATON (*) (non-member)
// interpreted as V^t M
template<class Type>
Vec3<Type> operator *(const Vec3<Type>& V, const Mat33<Type>& A)
{
Vec3<Type> NewV;
NewV.x = A[0]*V.x + A[1]*V.y + A[2]*V.z;
NewV.y = A[3]*V.x + A[4]*V.y + A[5]*V.z;
NewV.z = A[6]*V.x + A[7]*V.y + A[8]*V.z;
return(NewV);
}
// SCALAR POST-MULTIPLICATION
template<class Type>
Mat33<Type> Mat33<Type>::operator * (Type a) const
{
Mat33<Type> NewM;
for (int i = 0; i < 9; i++)
NewM[i] = M[i]*a;
return(NewM);
}
// SCALAR PRE-MULTIPLICATION (non-member)
template <class Type>
Mat33<Type> operator * (Type a, const Mat44<Type>& M)
{
Mat33<Type> NewM;
for (int i = 0; i < 9; i++)
NewM[i] = a*M[i];
return(NewM);
}
template <class Type>
Mat33<Type> Mat33<Type>::operator / (Type a) const // SCALAR DIVISION
{
Mat33<Type> NewM;
Type ainv = Type(1.0)/a;
for (int i = 0; i < 9; i++)
NewM[i] = M[i]*ainv;
return(NewM);
}
template <class Type>
Mat33<Type> Mat33<Type>::operator + (Mat33& N) const // ADDITION (+)
{
Mat33<Type> NewM;
for (int i = 0; i < 9; i++)
NewM[i] = M[i]+N.M[i];
return(NewM);
}
template <class Type>
Mat33<Type>& Mat33<Type>::operator += (Mat33& N) // ACCUMULATE ADD (+=)
{
for (int i = 0; i < 9; i++)
M[i] += N.M[i];
return(*this);
}
template <class Type>
Mat33<Type>& Mat33<Type>::operator -= (Mat33& N) // ACCUMULATE SUB (-=)
{
for (int i = 0; i < 9; i++)
M[i] -= N.M[i];
return(*this);
}
template <class Type>
Mat33<Type>& Mat33<Type>::operator *= (Type a) // ACCUMULATE MULTIPLY (*=)
{
for (int i = 0; i < 9; i++)
M[i] *= a;
return(*this);
}
template <class Type>
Mat33<Type>& Mat33<Type>::operator /= (Type a) // ACCUMULATE DIVIDE (/=)
{
Type ainv = Type(1.0)/a;
for (int i = 0; i < 9; i++)
M[i] *= ainv;
return(*this);
}
template<class Type>
bool Mat33<Type>::Inverse(Mat33<Type> &inv, Type tolerance) const // MATRIX INVERSE
{
// Invert using cofactors.
inv[0] = M[4]*M[8] - M[7]*M[5];
inv[3] = M[6]*M[5] - M[3]*M[8];
inv[6] = M[3]*M[7] - M[6]*M[4];
inv[1] = M[7]*M[2] - M[1]*M[8];
inv[4] = M[0]*M[8] - M[6]*M[2];
inv[7] = M[6]*M[1] - M[0]*M[7];
inv[2] = M[1]*M[5] - M[4]*M[2];
inv[5] = M[3]*M[2] - M[0]*M[5];
inv[8] = M[0]*M[4] - M[3]*M[1];
Type det = M[0]*inv[0] + M[3]*inv[1] + M[6]*inv[2];
if (fabs(det) <= tolerance) // singular
return false;
Type invDet = 1.0f / det;
for (int i = 0; i < 9; i++) {
inv[i] *= invDet;
}
return true;
}
template<class Type>
Mat33<Type>::operator const Type*() const
{
return M;
}
template<class Type>
Mat33<Type>::operator Type*()
{
return M;
}
template<class Type>
void Mat33<Type>::RowMajor(Type m[9])
{
m[0] = M[0]; m[1] = M[3]; m[2] = M[6];
m[3] = M[1]; m[4] = M[4]; m[5] = M[7];
m[6] = M[2]; m[7] = M[5]; m[8] = M[8];
}
template<class Type>
Type& Mat33<Type>::operator()(int col, int row)
{
return M[3*col+row];
}
template<class Type>
const Type& Mat33<Type>::operator()(int col, int row) const
{
return M[3*col+row];
}
template<class Type>
void Mat33<Type>::Set(const Type* a)
{
for (int i=0;i<9;i++) {
M[i] = a[i];
}
}
template<class Type>
void Mat33<Type>::Set(Type M0, Type M3, Type M6,
Type M1, Type M4, Type M7,
Type M2, Type M5, Type M8)
{
M[0]=M0; M[3]=M3; M[6]=M6;
M[1]=M1; M[4]=M4; M[7]=M7;
M[2]=M2; M[5]=M5; M[8]=M8;
}
//---------------------------------------------------------------------------
// Standard Matrix Operations
//---------------------------------------------------------------------------
template<class Type>
void Mat33<Type>::Identity()
{
M[0]=M[4]=M[8]=1;
M[1]=M[2]=M[3]=M[5]=M[6]=M[7]=0;
}
template<class Type>
void Mat33<Type>::Zero()
{
M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=M[6]=M[7]=M[8]=0;
}
template<class Type>
void Mat33<Type>::Transpose()
{
SWAP(M[1],M[3]);
SWAP(M[2],M[6]);
SWAP(M[5],M[7]);
}
//---------------------------------------------------------------------------
// Standard Matrix Affine Transformations
//---------------------------------------------------------------------------
template<class Type>
void Mat33<Type>::Scale(Type Sx, Type Sy, Type Sz)
{
M[0]=Sx; M[3]=0; M[6]=0;
M[1]=0; M[4]=Sy; M[7]=0;
M[2]=0; M[5]=0; M[8]=Sz;
}
template<class Type>
void Mat33<Type>::Scale(const Vec3<Type>& S)
{
M[0]=S.x; M[3]=0; M[6]=0;
M[1]=0; M[4]=S.y; M[7]=0;
M[2]=0; M[5]=0; M[8]=S.z;
}
template<class Type>
void Mat33<Type>::invScale(Type Sx, Type Sy, Type Sz)
{
M[0]=1/Sx; M[3]=0; M[6]=0;
M[1]=0; M[4]=1/Sy; M[7]=0;
M[2]=0; M[5]=0; M[8]=1/Sz;
}
template<class Type>
void Mat33<Type>::invScale(const Vec3<Type>& S)
{
M[0]=1/S.x; M[3]=0; M[6]=0;
M[1]=0; M[4]=1/S.y; M[7]=0;
M[2]=0; M[5]=0; M[8]=1/S.z;
}
template<class Type>
void Mat33<Type>::Rotate(Type DegAng, const Vec3<Type>& Axis)
{
Type RadAng = DegAng*Mat33TORADS;
Type ca=(Type)cos(RadAng),
sa=(Type)sin(RadAng);
if (Axis.x==1 && Axis.y==0 && Axis.z==0) // ABOUT X-AXIS
{
M[0]=1; M[3]=0; M[6]=0;
M[1]=0; M[4]=ca; M[7]=-sa;
M[2]=0; M[5]=sa; M[8]=ca;
}
else if (Axis.x==0 && Axis.y==1 && Axis.z==0) // ABOUT Y-AXIS
{
M[0]=ca; M[3]=0; M[6]=sa;
M[1]=0; M[4]=1; M[7]=0;
M[2]=-sa; M[5]=0; M[8]=ca;
}
else if (Axis.x==0 && Axis.y==0 && Axis.z==1) // ABOUT Z-AXIS
{
M[0]=ca; M[3]=-sa; M[6]=0;
M[1]=sa; M[4]=ca; M[7]=0;
M[2]=0; M[5]=0; M[8]=1;
}
else // ARBITRARY AXIS
{
Type l = Axis.LengthSqr();
Type x, y, z;
x=Axis.x, y=Axis.y, z=Axis.z;
if (l > Type(1.0001) || l < Type(0.9999) && l!=0)
{
// needs normalization
l=Type(1.0)/sqrt(l);
x*=l; y*=l; z*=l;
}
Type x2=x*x, y2=y*y, z2=z*z;
M[0]=x2+ca*(1-x2); M[3]=(x*y)+ca*(-x*y)+sa*(-z); M[6]=(x*z)+ca*(-x*z)+sa*y;
M[1]=(x*y)+ca*(-x*y)+sa*z; M[4]=y2+ca*(1-y2); M[7]=(y*z)+ca*(-y*z)+sa*(-x);
M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[5]=(y*z)+ca*(-y*z)+sa*x; M[8]=z2+ca*(1-z2);
}
}
template<class Type>
void Mat33<Type>::invRotate(Type DegAng, const Vec3<Type>& Axis)
{
Rotate(DegAng,Axis);
Transpose();
}
template <class Type>
inline void Mat33<Type>::Star(const Vec3<Type>& v)
{
M[0]= 0; M[3]=-v.z; M[6]= v.y;
M[1]= v.z; M[4]= 0; M[7]=-v.x;
M[2]=-v.y; M[5]= v.x; M[8]= 0;
}
template <class Type>
inline void Mat33<Type>::OuterProduct(const Vec3<Type>& u, const Vec3<Type>& v)
{
M[0]=u.x*v.x; M[3]=u.x*v.y; M[6]=u.x*v.z;
M[1]=u.y*v.x; M[4]=u.y*v.y; M[7]=u.y*v.z;
M[2]=u.z*v.x; M[5]=u.z*v.y; M[8]=u.z*v.z;
}
template<class Type>
inline Type Mat33<Type>::Trace() const
{
return M[0] + M[4] + M[8];
}
//---------------------------------------------------------------------------
// Handy matrix printing routine.
//---------------------------------------------------------------------------
template<class Type>
void Mat33<Type>::Print() const
{
printf("\n%f %f %f\n",M[0],M[3],M[6]);
printf("%f %f %f\n",M[1],M[4],M[7]);
printf("%f %f %f\n",M[2],M[5],M[8]);
}
//---------------------------------------------------------------------------
// Copy contents of matrix into matrix array.
//---------------------------------------------------------------------------
template<class Type>
void Mat33<Type>::CopyInto(Type *Mat) const
{
Mat[0]=M[0]; Mat[3]=M[3]; Mat[6]=M[6];
Mat[1]=M[1]; Mat[4]=M[4]; Mat[7]=M[7];
Mat[2]=M[2]; Mat[5]=M[5]; Mat[8]=M[8];
}

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
// File : mat44.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// mat44.hpp : 4x4 OpenGL-style matrix template.
//============================================================================
#ifndef _MAT44_
#define _MAT44_
#include "vec3f.hpp"
#include "vec4f.hpp"
static const float Mat44TORADS = 0.0174532f;
static const float Mat44VIEWPORT_TOL = 0.001f;
//----------------------------------------------------------------------------
// M[16] = [ 0 4 8 12 ] | 16 floats were used instead of the normal [4][4]
// [ 1 5 9 13 ] | to be compliant with OpenGL. OpenGL uses
// [ 2 6 10 14 ] | premultiplication with column vectors. These
// [ 3 7 11 15 ] | matrices can be fed directly into the OpenGL
// | matrix stack with glLoadMatrix or glMultMatrix.
//
// [ x' y' z' w' ] = [ 0 4 8 12 ] [ x ]
// [ 1 5 9 13 ] * [ y ]
// [ 2 6 10 14 ] [ z ]
// [ 3 7 11 15 ] [ w ]
//
// Loading a [4][4] format matrix directly into the matrix stack (assuming
// premult/col vecs) results in a transpose matrix. M[0]=M[0][0], but
// M[1]!=M[1][0] since M[0][1] would cast to M[1].
//
// However, if we assumed postmult/row vectors we could use [4][4] format,
// but all transformations in this module would be transposed.
//----------------------------------------------------------------------------
template<class Type>
class Mat44
{
public:
Type M[16]; // 0,1,2,3 = 1st col; 4,5,6,7 = 2nd col; etc.
Mat44();
Mat44(const Type *N);
Mat44(Type M0, Type M4, Type M8, Type M12,
Type M1, Type M5, Type M9, Type M13,
Type M2, Type M6, Type M10, Type M14,
Type M3, Type M7, Type M11, Type M15);
Mat44<Type>& operator = (const Mat44& A); // ASSIGNMENT (=)
Mat44<Type>& operator = (const Type* a); // ASSIGNMENT (=) FROM AN ARRAY OF TypeS
Mat44<Type> operator * (const Mat44& A) const; // MULTIPLICATION (*)
Vec3<Type> operator * (const Vec3<Type>& V) const; // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV
Vec3<Type> multNormal(const Vec3<Type>& V) const; // MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV
Vec3<Type> multPoint(const Vec3<Type>& V) const; // MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV
Vec4<Type> operator * (const Vec4<Type>& V) const; // MAT-VECTOR MULTIPLICATION (*)
Mat44<Type> operator * (Type a) const; // SCALAR POST-MULTIPLICATION
Mat44<Type>& operator *= (Type a); // ACCUMULATE MULTIPLY (*=)
////////////// NOT IMPLEMENTED YET. ANY TAKERS?
// friend Vec3<Type> operator * (const Vec3<Type>& V, const Mat44& M); // MAT-VECTOR PRE-MULTIPLICATON (*) W/ PERP DIV
// friend Vec4<Type> operator * (const Vec4<Type>& V, const Mat44& M); // MAT-VECTOR PRE-MULTIPLICATON (*)
// friend Mat44<Type> operator * (Type a, const Mat44& M) const; // SCALAR PRE-MULTIPLICATION
// Mat44<Type> operator / (Type a) const; // SCALAR DIVISION
// Mat44<Type> operator + (Mat44& M) const; // ADDITION (+)
// Mat44<Type>& operator += (Mat44& M); // ACCUMULATE ADD (+=)
// Mat44<Type>& operator /= (Type a); // ACCUMULATE DIVIDE (/=)
// bool Invserse(); // MATRIX INVERSE
////////////// NOT IMPLEMENTED YET. ANY TAKERS?
operator const Type*() const; // CAST TO A Type ARRAY
operator Type*(); // CAST TO A Type ARRAY
Type& operator()(int col, int row); // 2D ARRAY ACCESSOR
const Type& operator()(int col, int row) const; // 2D ARRAY ACCESSOR
void Set(const Type* a); // SAME AS ASSIGNMENT (=) FROM AN ARRAY OF TypeS
void Set(Type M0, Type M4, Type M8, Type M12,
Type M1, Type M5, Type M9, Type M13,
Type M2, Type M6, Type M10, Type M14,
Type M3, Type M7, Type M11, Type M15);
void Identity();
void Transpose();
void Translate(Type Tx, Type Ty, Type Tz);
void Translate(const Vec3<Type>& T);
void invTranslate(Type Tx, Type Ty, Type Tz);
void invTranslate(const Vec3<Type>& T);
void Scale(Type Sx, Type Sy, Type Sz);
void Scale(const Vec3<Type>& S);
void invScale(Type Sx, Type Sy, Type Sz);
void invScale(const Vec3<Type>& S);
void Rotate(Type DegAng, const Vec3<Type>& Axis);
void invRotate(Type DegAng, const Vec3<Type>& Axis);
Type Trace(void) const;
void Frustum(Type l, Type r, Type b, Type t, Type n, Type f);
void invFrustum(Type l, Type r, Type b, Type t, Type n, Type f);
void Perspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist);
void invPerspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist);
void Viewport(int WW, int WH);
void invViewport(int WW, int WH);
void LookAt(const Vec3<Type>& Eye,
const Vec3<Type>& LookAtPt,
const Vec3<Type>& ViewUp);
void invLookAt(const Vec3<Type>& Eye,
const Vec3<Type>& LookAtPt,
const Vec3<Type>& ViewUp);
void Viewport2(int WW, int WH);
void invViewport2(int WW, int WH);
void Print() const;
void CopyInto(Type *Mat) const;
static void SWAP(Type& a, Type& b) {Type t; t=a;a=b;b=t;}
};
#include "mat44impl.hpp"
typedef Mat44<float> Mat44f;
typedef Mat44<double> Mat44d;
#endif

View File

@@ -0,0 +1,536 @@
//------------------------------------------------------------------------------
// File : mat44impl.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// mat44.hpp : 4x4 OpenGL-style matrix template.
// This is the template implementation file. It is included by mat44.hpp.
//============================================================================
//---------------------------------------------------------------------------
// CONSTRUCTORS
//---------------------------------------------------------------------------
template<class Type>
Mat44<Type>::Mat44()
{
Identity();
}
template<class Type>
Mat44<Type>::Mat44(const Type *N)
{
M[0]=N[0]; M[4]=N[4]; M[8]=N[8]; M[12]=N[12];
M[1]=N[1]; M[5]=N[5]; M[9]=N[9]; M[13]=N[13];
M[2]=N[2]; M[6]=N[6]; M[10]=N[10]; M[14]=N[14];
M[3]=N[3]; M[7]=N[7]; M[11]=N[11]; M[15]=N[15];
}
template<class Type>
Mat44<Type>::Mat44(Type M0, Type M4, Type M8, Type M12,
Type M1, Type M5, Type M9, Type M13,
Type M2, Type M6, Type M10, Type M14,
Type M3, Type M7, Type M11, Type M15)
{
M[0]=M0; M[4]=M4; M[8]=M8; M[12]=M12;
M[1]=M1; M[5]=M5; M[9]=M9; M[13]=M13;
M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
}
//---------------------------------------------------------------------------
// MATRIX/MATRIX AND MATRIX/VECTOR OPERATORS
//---------------------------------------------------------------------------
template<class Type>
Mat44<Type>& Mat44<Type>::operator = (const Mat44& A) // ASSIGNMENT (=)
{
M[0]=A.M[0]; M[4]=A.M[4]; M[8]=A.M[8]; M[12]=A.M[12];
M[1]=A.M[1]; M[5]=A.M[5]; M[9]=A.M[9]; M[13]=A.M[13];
M[2]=A.M[2]; M[6]=A.M[6]; M[10]=A.M[10]; M[14]=A.M[14];
M[3]=A.M[3]; M[7]=A.M[7]; M[11]=A.M[11]; M[15]=A.M[15];
return(*this);
}
template<class Type>
Mat44<Type>& Mat44<Type>::operator = (const Type* a) {
for (int i=0;i<16;i++) {
M[i] = a[i];
}
return *this;
}
template<class Type>
Mat44<Type> Mat44<Type>::operator * (const Mat44& A) const // MULTIPLICATION (*)
{
Mat44<Type> NewM( M[0]*A.M[0] + M[4]*A.M[1] + M[8]*A.M[2] + M[12]*A.M[3], // ROW 1
M[0]*A.M[4] + M[4]*A.M[5] + M[8]*A.M[6] + M[12]*A.M[7],
M[0]*A.M[8] + M[4]*A.M[9] + M[8]*A.M[10] + M[12]*A.M[11],
M[0]*A.M[12] + M[4]*A.M[13] + M[8]*A.M[14] + M[12]*A.M[15],
M[1]*A.M[0] + M[5]*A.M[1] + M[9]*A.M[2] + M[13]*A.M[3], // ROW 2
M[1]*A.M[4] + M[5]*A.M[5] + M[9]*A.M[6] + M[13]*A.M[7],
M[1]*A.M[8] + M[5]*A.M[9] + M[9]*A.M[10] + M[13]*A.M[11],
M[1]*A.M[12] + M[5]*A.M[13] + M[9]*A.M[14] + M[13]*A.M[15],
M[2]*A.M[0] + M[6]*A.M[1] + M[10]*A.M[2] + M[14]*A.M[3], // ROW 3
M[2]*A.M[4] + M[6]*A.M[5] + M[10]*A.M[6] + M[14]*A.M[7],
M[2]*A.M[8] + M[6]*A.M[9] + M[10]*A.M[10] + M[14]*A.M[11],
M[2]*A.M[12] + M[6]*A.M[13] + M[10]*A.M[14] + M[14]*A.M[15],
M[3]*A.M[0] + M[7]*A.M[1] + M[11]*A.M[2] + M[15]*A.M[3], // ROW 4
M[3]*A.M[4] + M[7]*A.M[5] + M[11]*A.M[6] + M[15]*A.M[7],
M[3]*A.M[8] + M[7]*A.M[9] + M[11]*A.M[10] + M[15]*A.M[11],
M[3]*A.M[12] + M[7]*A.M[13] + M[11]*A.M[14] + M[15]*A.M[15] );
return(NewM);
}
template<class Type>
Vec3<Type> Mat44<Type>::operator * (const Vec3<Type>& V) const // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV
{
Type W = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15];
Vec3<Type> NewV( (M[0]*V.x + M[4]*V.y + M[8]*V.z + M[12]) / W,
(M[1]*V.x + M[5]*V.y + M[9]*V.z + M[13]) / W,
(M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]) / W );
return(NewV);
}
// MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV
// For transforming normals or other pure vectors.
// Assumes matrix is affine, i.e. bottom row is 0,0,0,1
template<class Type>
Vec3<Type> Mat44<Type>::multNormal(const Vec3<Type>& N) const
{
Vec3<Type> NewN( (M[0]*N.x + M[4]*N.y + M[8]*N.z ),
(M[1]*N.x + M[5]*N.y + M[9]*N.z ),
(M[2]*N.x + M[6]*N.y + M[10]*N.z) );
return (NewN);
}
// MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV
// (for transforming points in space)
// Assumes matrix is affine, i.e. bottom row is 0,0,0,1
template<class Type>
Vec3<Type> Mat44<Type>::multPoint(const Vec3<Type>& P) const
{
Vec3<Type> NewP( (M[0]*P.x + M[4]*P.y + M[8]*P.z + M[12]),
(M[1]*P.x + M[5]*P.y + M[9]*P.z + M[13]),
(M[2]*P.x + M[6]*P.y + M[10]*P.z + M[14]) );
return (NewP);
}
template<class Type>
Vec4<Type> Mat44<Type>::operator * (const Vec4<Type>& V) const // MAT-VECTOR MULTIPLICATION (*)
{
Vec4<Type> NewV;
NewV.x = M[0]*V.x + M[4]*V.y + M[8]*V.z + M[12]*V.w;
NewV.y = M[1]*V.x + M[5]*V.y + M[9]*V.z + M[13]*V.w;
NewV.z = M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]*V.w;
NewV.w = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15]*V.w;
return(NewV);
}
template<class Type>
Mat44<Type> Mat44<Type>::operator * (Type a) const // SCALAR POST-MULTIPLICATION
{
Mat44<Type> NewM( M[0] * a, M[1] * a, M[2] * a, M[3] * a,
M[4] * a, M[5] * a, M[6] * a, M[7] * a,
M[8] * a, M[9] * a, M[10] * a, M[11] * a,
M[12] * a, M[13] * a, M[14] * a, M[15] * a);
return NewM;
}
template<class Type>
Mat44<Type>& Mat44<Type>::operator *= (Type a) // SCALAR ACCUMULATE POST-MULTIPLICATION
{
for (int i = 0; i < 16; i++)
{
M[i] *= a;
}
return *this;
}
template<class Type>
Mat44<Type>::operator const Type*() const
{
return M;
}
template<class Type>
Mat44<Type>::operator Type*()
{
return M;
}
template<class Type>
Type& Mat44<Type>::operator()(int col, int row)
{
return M[4*col+row];
}
template<class Type>
const Type& Mat44<Type>::operator()(int col, int row) const
{
return M[4*col+row];
}
template<class Type>
void Mat44<Type>::Set(const Type* a)
{
for (int i=0;i<16;i++) {
M[i] = a[i];
}
}
template<class Type>
void Mat44<Type>::Set(Type M0, Type M4, Type M8, Type M12,
Type M1, Type M5, Type M9, Type M13,
Type M2, Type M6, Type M10, Type M14,
Type M3, Type M7, Type M11, Type M15)
{
M[0]=M0; M[4]=M4; M[8]=M8; M[12]=M12;
M[1]=M1; M[5]=M5; M[9]=M9; M[13]=M13;
M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
}
//---------------------------------------------------------------------------
// Standard Matrix Operations
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Identity()
{
M[0]=M[5]=M[10]=M[15]=1;
M[1]=M[2]=M[3]=M[4]=M[6]=M[7]=M[8]=M[9]=M[11]=M[12]=M[13]=M[14]=0;
}
template<class Type>
void Mat44<Type>::Transpose()
{
SWAP(M[1],M[4]);
SWAP(M[2],M[8]);
SWAP(M[6],M[9]);
SWAP(M[3],M[12]);
SWAP(M[7],M[13]);
SWAP(M[11],M[14]);
}
//---------------------------------------------------------------------------
// Standard Matrix Affine Transformations
//---------------------------------------------------------------------------
template <class Type>
void Mat44<Type>::Translate(Type Tx, Type Ty, Type Tz)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=Tx;
M[1]=0; M[5]=1; M[9]=0; M[13]=Ty;
M[2]=0; M[6]=0; M[10]=1; M[14]=Tz;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::Translate(const Vec3<Type>& T)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=T.x;
M[1]=0; M[5]=1; M[9]=0; M[13]=T.y;
M[2]=0; M[6]=0; M[10]=1; M[14]=T.z;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invTranslate(Type Tx, Type Ty, Type Tz)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=-Tx;
M[1]=0; M[5]=1; M[9]=0; M[13]=-Ty;
M[2]=0; M[6]=0; M[10]=1; M[14]=-Tz;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invTranslate(const Vec3<Type>& T)
{
M[0]=1; M[4]=0; M[8]=0; M[12]=-T.x;
M[1]=0; M[5]=1; M[9]=0; M[13]=-T.y;
M[2]=0; M[6]=0; M[10]=1; M[14]=-T.z;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::Scale(Type Sx, Type Sy, Type Sz)
{
M[0]=Sx; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=Sy; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=Sz; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::Scale(const Vec3<Type>& S)
{
M[0]=S.x; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=S.y; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=S.z; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invScale(Type Sx, Type Sy, Type Sz)
{
M[0]=1/Sx; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=1/Sy; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=1/Sz; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invScale(const Vec3<Type>& S)
{
M[0]=1/S.x; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=1/S.y; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=1/S.z; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::Rotate(Type DegAng, const Vec3<Type>& Axis)
{
Type RadAng = DegAng*Mat44TORADS;
Type ca=(Type)cos(RadAng),
sa=(Type)sin(RadAng);
if (Axis.x==1 && Axis.y==0 && Axis.z==0) // ABOUT X-AXIS
{
M[0]=1; M[4]=0; M[8]=0; M[12]=0;
M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
else if (Axis.x==0 && Axis.y==1 && Axis.z==0) // ABOUT Y-AXIS
{
M[0]=ca; M[4]=0; M[8]=sa; M[12]=0;
M[1]=0; M[5]=1; M[9]=0; M[13]=0;
M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
else if (Axis.x==0 && Axis.y==0 && Axis.z==1) // ABOUT Z-AXIS
{
M[0]=ca; M[4]=-sa; M[8]=0; M[12]=0;
M[1]=sa; M[5]=ca; M[9]=0; M[13]=0;
M[2]=0; M[6]=0; M[10]=1; M[14]=0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
else // ARBITRARY AXIS
{
Type l = Axis.LengthSqr();
Type x, y, z;
x=Axis.x, y=Axis.y, z=Axis.z;
if (l > Type(1.0001) || l < Type(0.9999) && l!=0)
{
// needs normalization
l=Type(1.0)/sqrt(l);
x*=l; y*=l; z*=l;
}
Type x2=x*x, y2=y*y, z2=z*z;
M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
M[15]=1;
}
}
template<class Type>
void Mat44<Type>::invRotate(Type DegAng, const Vec3<Type>& Axis)
{
Rotate(DegAng,Axis);
Transpose();
}
template<class Type>
inline Type Mat44<Type>::Trace() const
{
return M[0] + M[5] + M[10] + M[15];
}
//---------------------------------------------------------------------------
// Same as glFrustum() : Perspective transformation matrix defined by a
// truncated pyramid viewing frustum that starts at the origin (eye)
// going in the -Z axis direction (viewer looks down -Z)
// with the four pyramid sides passing through the sides of a window
// defined through x=l, x=r, y=b, y=t on the viewplane at z=-n.
// The top and bottom of the pyramid are truncated by the near and far
// planes at z=-n and z=-f. A 4-vector (x,y,z,w) inside this frustum
// transformed by this matrix will have x,y,z values in the range
// [-w,w]. Homogeneous clipping is applied to restrict (x,y,z) to
// this range. Later, a perspective divide by w will result in an NDC
// coordinate 3-vector of the form (x/w,y/w,z/w,w/w)=(x',y',z',1) where
// x', y', and z' all are in the range [-1,1]. Perspectively divided z'
// will be in [-1,1] with -1 being the near plane and +1 being the far.
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Frustum(Type l, Type r, Type b, Type t, Type n, Type f)
{
M[0]=(2*n)/(r-l); M[4]=0; M[8]=(r+l)/(r-l); M[12]=0;
M[1]=0; M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b); M[13]=0;
M[2]=0; M[6]=0; M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
M[3]=0; M[7]=0; M[11]=-1; M[15]=0;
}
template<class Type>
void Mat44<Type>::invFrustum(Type l, Type r, Type b, Type t, Type n, Type f)
{
M[0]=(r-l)/(2*n); M[4]=0; M[8]=0; M[12]=(r+l)/(2*n);
M[1]=0; M[5]=(t-b)/(2*n); M[9]=0; M[13]=(t+b)/(2*n);
M[2]=0; M[6]=0; M[10]=0; M[14]=-1;
M[3]=0; M[7]=0; M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
}
//---------------------------------------------------------------------------
// Same as gluPerspective : calls Frustum()
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Perspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
{
Yfov *= 0.0174532f; // CONVERT TO RADIANS
Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
Type wR=wT*Aspect, wL=-wR;
Frustum(wL,wR,wB,wT,Ndist,Fdist);
}
template<class Type>
void Mat44<Type>::invPerspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
{
Yfov *= 0.0174532f; // CONVERT TO RADIANS
Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
Type wR=wT*Aspect, wL=-wR;
invFrustum(wL,wR,wB,wT,Ndist,Fdist);
}
//---------------------------------------------------------------------------
// OpenGL VIEWPORT XFORM MATRIX : given Window width and height in pixels
// Transforms the x,y,z NDC values in [-1,1] to (x',y') pixel values and
// normalized z' in [0,1] (near and far respectively).
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Viewport(int WW, int WH)
{
Type WW2=(Type)WW*0.5f, WH2=(Type)WH*0.5f;
M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
M[2]=0; M[6]=0; M[10]=0.5; M[14]=0.5;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invViewport(int WW, int WH)
{
Type WW2=2.0f/(Type)WW, WH2=2.0f/(Type)WH;
M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
//---------------------------------------------------------------------------
// Same as gluLookAt()
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::LookAt(const Vec3<Type>& Eye,
const Vec3<Type>& LookAtPt,
const Vec3<Type>& ViewUp)
{
Vec3<Type> Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
Vec3<Type> X = ViewUp/Z; X.Normalize();
Vec3<Type> Y = Z/X; Y.Normalize();
Vec3<Type> Tr = -Eye;
M[0]=X.x; M[4]=X.y; M[8]=X.z; M[12]=X*Tr; // TRANS->ROT
M[1]=Y.x; M[5]=Y.y; M[9]=Y.z; M[13]=Y*Tr;
M[2]=Z.x; M[6]=Z.y; M[10]=Z.z; M[14]=Z*Tr;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invLookAt(const Vec3<Type>& Eye,
const Vec3<Type>& LookAtPt,
const Vec3<Type>& ViewUp)
{
Vec3<Type> Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
Vec3<Type> X = ViewUp/Z; X.Normalize();
Vec3<Type> Y = Z/X; Y.Normalize();
M[0]=X.x; M[4]=Y.x; M[8]=Z.x; M[12]=Eye.x; // ROT->TRANS
M[1]=X.y; M[5]=Y.y; M[9]=Z.y; M[13]=Eye.y;
M[2]=X.z; M[6]=Y.z; M[10]=Z.z; M[14]=Eye.z;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
//---------------------------------------------------------------------------
// VIEWPORT TRANFORMATION MATRIX : given Window width and height in pixels
// FROM "JIM BLINN'S CORNER" JULY '91. This function transforms an
// 4-vector in homogeneous space of the form (x,y,z,w) where
// -w<=x,y,z<=w into (x',y',z',1) where (x',y') is the vectors
// projected pixel location in ([0,WW-1],[0,WH-1]) and z' is the
// normalized depth value mapped into [0,1]; 0 is the near plane
// and 1 is the far plane. Mat44VIEWPORT_TOL is introduced to have correct
// mappings. (-1,-1,?,?) in NDC refers to the bottom-left of the
// viewplane window and (0,0,?,?) in screen space refers to the
// bottom-left pixel.
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Viewport2(int WW, int WH)
{
Type WW2=(WW-Mat44VIEWPORT_TOL)*0.5f, WH2=(WH-Mat44VIEWPORT_TOL)*0.5f;
M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
M[2]=0; M[6]=0; M[10]=0.5; M[14]=0.5;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
template<class Type>
void Mat44<Type>::invViewport2(int WW, int WH)
{
Type WW2=2.0f/(WW-Mat44VIEWPORT_TOL), WH2=2.0f/(WH-Mat44VIEWPORT_TOL);
M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
M[3]=0; M[7]=0; M[11]=0; M[15]=1;
}
//---------------------------------------------------------------------------
// Handy matrix printing routine.
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::Print() const
{
printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);
}
//---------------------------------------------------------------------------
// Copy contents of matrix into matrix array.
//---------------------------------------------------------------------------
template<class Type>
void Mat44<Type>::CopyInto(Type *Mat) const
{
Mat[0]=M[0]; Mat[4]=M[4]; Mat[8]=M[8]; Mat[12]=M[12];
Mat[1]=M[1]; Mat[5]=M[5]; Mat[9]=M[9]; Mat[13]=M[13];
Mat[2]=M[2]; Mat[6]=M[6]; Mat[10]=M[10]; Mat[14]=M[14];
Mat[3]=M[3]; Mat[7]=M[7]; Mat[11]=M[11]; Mat[15]=M[15];
}

View File

@@ -0,0 +1,66 @@
//------------------------------------------------------------------------------
// File : mat44test.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//----------------------------------------------------------------------------
// mat44test -- test compilation of all the functions in mat44 library
//----------------------------------------------------------------------------
// $Id$
//----------------------------------------------------------------------------
#include <iostream.h>
#include <vec3f.hpp>
#include <mat44.hpp>
int main(int argc, char *argv[])
{
cout << "This is not a comprehensive correctness test. " << endl
<< "It merely tests whether all the functions in mat44 will compile." <<endl;
Mat44f m;
float m2[16];
Vec3f v(1.0, 1.0, 1.0);
Vec3f up(0.0, 1.0, 0.0);
m.Identity();
m.Transpose();
m.Translate(1.0, 1.0, 1.0);
m.Translate(v);
m.invTranslate(v);
m.Scale(1.0, 1.0, 1.0);
m.Scale(v);
m.invScale(1.0, 1.0, 1.0);
m.invScale(v);
m.Rotate(90, v);
m.invRotate(90, v);
m.Frustum(-1.0, 1.0, -1.0, 1.0, 0.01, 20);
m.invFrustum(-1.0, 1.0, -1.0, 1.0, 0.01, 20);
m.Perspective(60, 1.4, 0.01, 20);
m.invPerspective(60, 1.4, 0.01, 20);
m.Viewport(200, 200);
m.invViewport(200, 200);
m.LookAt(Vec3f::ZERO, v, up);
m.invLookAt(Vec3f::ZERO, v, up);
m.Viewport2(200, 200);
m.invViewport2(200, 200);
m.Print();
m.Transpose();
m.Print();
// These two should be transpose of one another
m.CopyInto(m2);
cout << "Ok there is this one test to make sure Transpose() is correct.\n"
"The above two matricies should be the transpose of one another.\n" << endl;
}

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
// File : minmaxbox.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//=========================================================================
// minmaxbox.cpp : min-max box routines
//=========================================================================
//-----------------------------------------------------------------------------
// Calculates the eight corner vertices of the MinMaxBox.
// V must be prealloced.
// 5---4
// / /|
// 1---0 | VERTS : 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
// | | 7 (L,R, B,T, N,F) = (Left,Right, Bottom,Top, Near,Far)
// | |/
// 2---3
//-----------------------------------------------------------------------------
void GetMinMaxBoxVerts(const float Min[3], const float Max[3], float V[8][3])
{
#define SET(v,x,y,z) v[0]=x; v[1]=y; v[2]=z;
SET(V[0],Max[0],Max[1],Max[2]); SET(V[4],Max[0],Max[1],Min[2]);
SET(V[1],Min[0],Max[1],Max[2]); SET(V[5],Min[0],Max[1],Min[2]);
SET(V[2],Min[0],Min[1],Max[2]); SET(V[6],Min[0],Min[1],Min[2]);
SET(V[3],Max[0],Min[1],Max[2]); SET(V[7],Max[0],Min[1],Min[2]);
}
//--------------------------------------------------------------------------
// Ray-MinMaxBox intersection test. Returns 0 or 1, calcs In-Out "HitTimes"
// IsectPts can be calculated as:
// InIsectPt = Start + Dir * InT (if InT>0)
// OutIsectPt = Start + Dir * OutT (if OutT>0)
//--------------------------------------------------------------------------
int RayMinMaxBoxIsect(const float Start[3], const float Dir[3],
const float Min[3], const float Max[3],
float *InT, float *OutT)
{
*InT=-99999, *OutT=99999; // INIT INTERVAL T-VAL ENDPTS TO -/+ "INFINITY"
float NewInT, NewOutT; // STORAGE FOR NEW T VALUES
// X-SLAB (PARALLEL PLANES PERPENDICULAR TO X-AXIS) INTERSECTION (Xaxis is Normal)
if (Dir[0] == 0) // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
{ if ((Start[0] < Min[0]) || (Start[0] > Max[0])) return(0); }
else
{
NewInT = (Min[0]-Start[0])/Dir[0]; // CALC Tval ENTERING MIN PLANE
NewOutT = (Max[0]-Start[0])/Dir[0]; // CALC Tval ENTERING MAX PLANE
if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT; if (NewOutT<*OutT) *OutT=NewOutT; }
else { if (NewOutT>*InT) *InT=NewOutT; if (NewInT<*OutT) *OutT=NewInT; }
if (*InT>*OutT) return(0);
}
// Y-SLAB (PARALLEL PLANES PERPENDICULAR TO Y-AXIS) INTERSECTION (Yaxis is Normal)
if (Dir[1] == 0) // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
{ if ((Start[1] < Min[1]) || (Start[1] > Max[1])) return(0); }
else
{
NewInT = (Min[1]-Start[1])/Dir[1]; // CALC Tval ENTERING MIN PLANE
NewOutT = (Max[1] - Start[1])/Dir[1]; // CALC Tval ENTERING MAX PLANE
if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT; if (NewOutT<*OutT) *OutT=NewOutT; }
else { if (NewOutT>*InT) *InT=NewOutT; if (NewInT<*OutT) *OutT=NewInT; }
if (*InT>*OutT) return(0);
}
// Z-SLAB (PARALLEL PLANES PERPENDICULAR TO Z-AXIS) INTERSECTION (Zaxis is Normal)
if (Dir[2] == 0) // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
{ if ((Start[2] < Min[2]) || (Start[2] > Max[2])) return(0); }
else
{
NewInT = (Min[2]-Start[2])/Dir[2]; // CALC Tval ENTERING MIN PLANE
NewOutT = (Max[2]-Start[2])/Dir[2]; // CALC Tval ENTERING MAX PLANE
if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT; if (NewOutT<*OutT) *OutT=NewOutT; }
else { if (NewOutT>*InT) *InT=NewOutT; if (NewInT<*OutT) *OutT=NewInT; }
if (*InT>*OutT) return(0);
}
// CHECK IF INTERSECTIONS ARE "AT OR BEYOND" THE START OF THE RAY
if (*InT>=0 || *OutT>=0) return(1);
return(0);
}
//--------------------------------------------------------------------------
// returns whether or not an edge intersects a MinMaxBox. The hit times
// are returned just as in the ray isect test.
//--------------------------------------------------------------------------
int EdgeMinMaxBoxIsect(const float A[3], const float B[3],
const float Min[3], const float Max[3],
float *InT, float *OutT)
{
float Dir[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
if ( RayMinMaxBoxIsect(A,Dir,Min,Max,InT,OutT) )
if (*InT>=0 && *InT<=1) return(1);
else if (*OutT>=0 && *OutT<=1) return(1);
return(0);
}

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// File : minmaxbox.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//=========================================================================
// minmaxbox.hpp : min-max box routines
//=========================================================================
void GetMinMaxBoxVerts(const float Min[3], const float Max[3], float V[8][3]);
int RayMinMaxBoxIsect(const float Start[3], const float Dir[3],
const float Min[3], const float Max[3],
float *InT, float *OutT);
int EdgeMinMaxBoxIsect(const float A[3], const float B[3],
const float Min[3], const float Max[3],
float *InT, float *OutT);

View File

@@ -0,0 +1,302 @@
//------------------------------------------------------------------------------
// File : plane.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//=========================================================================
// plane.cpp
//=========================================================================
#include <math.h>
//--------------------------------------------------------------------------
// Calculates the plane equation coeffients P = [ A B C D ] for the plane
// equation: Ax+By+Cz+D=0 given three vertices defining the plane. The
// normalized plane normal (A,B,C) is defined using the right-hand rule.
//--------------------------------------------------------------------------
float* PlaneEquation(float P[4],
const float p0[3], const float p1[3], const float p2[3])
{
// CALCULATE PLANE NORMAL - FIRST THREE COEFFICIENTS (A,B,C)
float u[3], v[3];
u[0]=p1[0]-p0[0]; u[1]=p1[1]-p0[1]; u[2]=p1[2]-p0[2];
v[0]=p2[0]-p0[0]; v[1]=p2[1]-p0[1]; v[2]=p2[2]-p0[2];
P[0] = u[1]*v[2] - u[2]*v[1]; // CROSS-PROD BETWEEN u AND v
P[1] = u[2]*v[0] - u[0]*v[2]; // DEFINES UNNORMALIZED NORMAL
P[2] = u[0]*v[1] - u[1]*v[0];
float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]); // NORMALIZE NORMAL
P[0]/=l; P[1]/=l; P[2]/=l;
// CALCULATE D COEFFICIENT (USING FIRST PT ON PLANE - p0)
P[3] = -(P[0]*p0[0] + P[1]*p0[1] + P[2]*p0[2]);
return(P);
}
//--------------------------------------------------------------------------
// Calculates the plane equation coeffients P = [ A B C D ] for the plane
// equation: Ax+By+Cz+D=0 given an unnormalized normal N to the plane and
// the distance along the normal to the plane Dist. The dot product between
// the normalized normal and a point on the plane should equal the distance
// along the normal to the plane (Dist): Ax+By+Cz=Dist, so D=-Dist.
//--------------------------------------------------------------------------
float* PlaneEquation(float P[4], const float N[3], float Dist)
{
// COPY AND NORMALIZE NORMAL
P[0]=N[0]; P[1]=N[1]; P[2]=N[2];
float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
P[0]/=l; P[1]/=l; P[2]/=l;
// CALCULATE D COEFFICIENT
P[3]=-Dist;
return(P);
}
//--------------------------------------------------------------------------
// Calculates the plane equation coeffients P = [ A B C D ] for the plane
// equation: Ax+By+Cz+D=0 given an unnormalized normal N to the plane and
// a point pt on the plane. The dot product between the normalized normal
// and the point should equal the distance along the normal to the plane,
// thus equalling negative D.
//--------------------------------------------------------------------------
float* PlaneEquation(float P[4], const float N[3], const float pt[3])
{
// COPY AND NORMALIZE NORMAL
P[0]=N[0]; P[1]=N[1]; P[2]=N[2];
float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
P[0]/=l; P[1]/=l; P[2]/=l;
// CALCULATE D COEFFICIENT (USING PT ON PLANE)
P[3] = -(P[0]*pt[0] + P[1]*pt[1] + P[2]*pt[2]);
return(P);
}
//--------------------------------------------------------------------------
// Transforms a plane by a 4x4 matrix (col-major order, assumes premult/col vect).
// The given plane coefficients are altered. The normal (A,B,C) is normalized.
// see HOFF tech report: "4x4 matrix transformation of the implicit form of the plane"
//--------------------------------------------------------------------------
void XformPlane(const float M[16], float P[4])
{
float NewP[4], L2, L;
NewP[0] = M[0]*P[0] + M[4]*P[1] + M[8]*P[2];
NewP[1] = M[1]*P[0] + M[5]*P[1] + M[9]*P[2];
NewP[2] = M[2]*P[0] + M[6]*P[1] + M[10]*P[2];
L2 = NewP[0]*NewP[0] + NewP[1]*NewP[1] + NewP[2]*NewP[2];
L = (float)sqrt(L2);
P[0] = NewP[0] / L;
P[1] = NewP[1] / L;
P[2] = NewP[2] / L;
P[3] = P[3]*L2 - (NewP[0]*M[12] + NewP[1]*M[13] + NewP[2]*M[14]);
}
//--------------------------------------------------------------------------
// return 1 if point is "outside" (normal side) of plane, 0 if "inside" or on
//--------------------------------------------------------------------------
int PlanePtOutTest(const float P[4], const float Pt[3])
{
return( (P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2]) > -P[3] );
}
//--------------------------------------------------------------------------
// returns -1 inside, 0 on, 1 outside (normal side)
//--------------------------------------------------------------------------
int PlanePtInOutTest(const float P[4], const float Pt[3])
{
float DotProd = P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2];
if (DotProd < -P[3]) return(-1);
if (DotProd > -P[3]) return(1);
return(0);
}
//--------------------------------------------------------------------------
// Calculates the "signed" distance of a point from a plane (in units of
// the normal length, if not normalized). +Dist is on normal dir side of plane.
//--------------------------------------------------------------------------
float PlaneDistToPt(const float P[4], const float Pt[3])
{
return( P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2] + P[3] );
}
//--------------------------------------------------------------------------
// returns 1 if ray (Start,Dir) intersects plane, 0 if not
//--------------------------------------------------------------------------
int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3])
{
float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
float NdotStart = P[0]*Start[0] + P[1]*Start[1] + P[2]*Start[2];
if (NdotDir==(float)0) return(0);
float t = (-P[3] - NdotStart) / NdotDir;
if (t>=0) return(1);
return(0);
}
//--------------------------------------------------------------------------
// Also computes intersection point, if possible
//--------------------------------------------------------------------------
int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3],
float IsectPt[3])
{
float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
float NdotStart = P[0]*Start[0] + P[1]*Start[1] + P[2]*Start[2];
if (NdotDir==(float)0) return(0);
float t = (-P[3] - NdotStart) / NdotDir;
if (t>=0)
{
IsectPt[0] = Start[0] + Dir[0]*t;
IsectPt[1] = Start[1] + Dir[1]*t;
IsectPt[2] = Start[2] + Dir[2]*t;
return(1);
}
return(0);
}
//--------------------------------------------------------------------------
// Intersects a line with a plane with normal (0,0,-1) with distance d
// from the origin. The line is given by position Start and direction Dir.
//--------------------------------------------------------------------------
int ZPlaneLineIsect(float d, const float Start[3], const float Dir[3],
float IsectPt[3])
{
float NdotDir = -Dir[2];
if (NdotDir==(float)0) return(0);
float t = (d + Start[2]) / NdotDir;
IsectPt[0] = Start[0] + Dir[0]*t;
IsectPt[1] = Start[1] + Dir[1]*t;
IsectPt[2] = Start[2] + Dir[2]*t;
return(1);
}
//--------------------------------------------------------------------------
// returns 1 if edge AB intersects plane, 0 if not
//--------------------------------------------------------------------------
int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3])
{
float Dir[3] = { B[0]-A[0], B[1]-A[1], B[2]-A[2] };
float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
float NdotA = P[0]*A[0] + P[1]*A[1] + P[2]*A[2];
if (NdotDir==(float)0) return(0);
float t = (-P[3] - NdotA) / NdotDir;
if (t>=0 && t<=1) return(1);
return(0);
}
//--------------------------------------------------------------------------
// Also computes intersection point, if possible
//--------------------------------------------------------------------------
int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3],
float IsectPt[3])
{
float Dir[3] = { B[0]-A[0], B[1]-A[1], B[2]-A[2] };
float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
float NdotA = P[0]*A[0] + P[1]*A[1] + P[2]*A[2];
if (NdotDir==(float)0) return(0);
float t = (-P[3] - NdotA) / NdotDir;
if (t>=0 && t<=1)
{
IsectPt[0] = A[0] + Dir[0]*t;
IsectPt[1] = A[1] + Dir[1]*t;
IsectPt[2] = A[2] + Dir[2]*t;
return(1);
}
return(0);
}
//---------------------------------------------------------------------------
// Box (m,M)/ Plane P overlap test.
// returns type of overlap: 1=OUT (side of normal dir), -1=IN, 0=Overlapping
// Finds the "closest" and "farthest" points from the plane with respect
// to the plane normal dir (the "extremes" of the aabb) and tests for overlap.
// m and M are the Min and Max extents of the AABB.
//---------------------------------------------------------------------------
int PlaneMinMaxBoxOverlap(const float P[4], const float m[3], const float M[3])
{
#define SET(v,x,y,z) v[0]=x; v[1]=y; v[2]=z;
// CALC EXTREME PTS (Neg,Pos) ALONG NORMAL AXIS (Pos in dir of norm, etc.)
float Neg[3], Pos[3];
if(P[0]>0)
if(P[1]>0) { if(P[2]>0) { SET(Pos,M[0],M[1],M[2]); SET(Neg,m[0],m[1],m[2]); }
else { SET(Pos,M[0],M[1],m[2]); SET(Neg,m[0],m[1],M[2]); } }
else { if(P[2]>0) { SET(Pos,M[0],m[1],M[2]); SET(Neg,m[0],M[1],m[2]); }
else { SET(Pos,M[0],m[1],m[2]); SET(Neg,m[0],M[1],M[2]); } }
else
if(P[1]>0) { if(P[2]>0) { SET(Pos,m[0],M[1],M[2]); SET(Neg,M[0],m[1],m[2]); }
else { SET(Pos,m[0],M[1],m[2]); SET(Neg,M[0],m[1],M[2]); } }
else { if(P[2]>0) { SET(Pos,m[0],m[1],M[2]); SET(Neg,M[0],M[1],m[2]); }
else { SET(Pos,m[0],m[1],m[2]); SET(Neg,M[0],M[1],M[2]); } }
// CHECK DISTANCE TO PLANE FROM EXTREMAL POINTS TO DETERMINE OVERLAP
if (PlaneDistToPt(P,Neg) > 0) return(1);
else if (PlaneDistToPt(P,Pos) <= 0) return(-1);
return(0);
}
//---------------------------------------------------------------------------
// Edge/Planes intersection test. Returns 0 or 1, calcs In-Out "HitTimes"
// IsectPts can be calculated as:
// InIsectPt = Start + Dir * InT (if InT>0)
// OutIsectPt = Start + Dir * OutT (if OutT>0)
// Planes is defined as: float Planes[n][4] for n planes.
//---------------------------------------------------------------------------
int PlanesRayIsect(const float Planes[][4], int NumPlanes,
const float Start[3], const float Dir[3],
float *InT, float *OutT)
{
*InT=-99999, *OutT=99999; // INIT INTERVAL T-VAL ENDPTS TO -/+ INFINITY
float NdotDir, NdotStart; // STORAGE FOR REPEATED CALCS NEEDED FOR NewT CALC
float NewT;
for (int i=0; i<NumPlanes; i++) // CHECK INTERSECTION AGAINST EACH VF PLANE
{
NdotDir = Planes[i][0]*Dir[0] + Planes[i][1]*Dir[1] + Planes[i][2]*Dir[2];
NdotStart = Planes[i][0]*Start[0] + Planes[i][1]*Start[1] + Planes[i][2]*Start[2];
if (NdotDir == 0) // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
{
if (NdotStart > -Planes[i][3]) return(0); // IF STARTS "OUTSIDE", NO INTERSECTION
}
else
{
NewT = (-Planes[i][3] - NdotStart) / NdotDir; // FIND HIT "TIME" (DISTANCE)
if (NdotDir < 0) { if (NewT > *InT) *InT=NewT; } // IF "FRONTFACING", MUST BE NEW IN "TIME"
else { if (NewT < *OutT) *OutT=NewT; } // IF "BACKFACING", MUST BE NEW OUT "TIME"
}
if (*InT > *OutT) return(0); // CHECK FOR EARLY EXITS (INTERSECTION INTERVAL "OUTSIDE")
}
// IF AT LEAST ONE THE Tvals ARE IN THE INTERVAL [0,1] WE HAVE INTERSECTION
if (*InT>=0 || *OutT>=0) return(1);
return(0);
}
//--------------------------------------------------------------------------
// returns whether or not an edge AB intersects a set of planes. The hit
// times are returned just as in the ray isect test.
//--------------------------------------------------------------------------
int PlanesEdgeIsect(const float Planes[][4], int NumPlanes,
const float A[3], const float B[3],
float *InT, float *OutT)
{
float Dir[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
if ( PlanesRayIsect(Planes,NumPlanes,A,Dir,InT,OutT) )
if (*InT>=0 && *InT<=1) return(1);
else if (*OutT>=0 && *OutT<=1) return(1);
return(0);
}

View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
// File : plane.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//=========================================================================
// plane.hpp
//=========================================================================
// PLANE EQUATION COEFFICIENT GENERATION FUNCTIONS
float* PlaneEquation(float P[4],
const float p0[3], const float p1[3], const float p2[3]);
float* PlaneEquation(float P[4], const float N[3], float Dist);
float* PlaneEquation(float P[4], const float N[3], const float pt[3]);
int PlanePtOutTest(const float P[4], const float Pt[3]);
int PlanePtInOutTest(const float P[4], const float Pt[3]);
float PlaneDistToPt(const float P[4], const float Pt[3]);
int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3]);
int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3],
float IsectPt[3]);
int ZPlaneLineIsect(float d, const float Start[3], const float Dir[3],
float IsectPt[3]);
int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3]);
int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3],
float IsectPt[3]);
void XformPlane(const float M[16], float P[4]);
int PlaneMinMaxBoxOverlap(const float P[4], const float m[3],
const float M[3]);
int PlanesRayIsect(const float Planes[][4], int NumPlanes,
const float Start[3], const float Dir[3],
float *InT, float *OutT);
int PlanesEdgeIsect(const float Planes[][4], int NumPlanes,
const float A[3], const float B[3],
float *InT, float *OutT);

View File

@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
// File : quat.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
/**************************************************************************
quat.hpp
A quaternion template class
---------------------------------------------------------------------
Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
Modification History:
- Oct 2000, Bill Baxter. Adapted to GLVU coding conventions and
templetized. Also implemented many methods that were declared but
not defined. Added some methods from quatlib and other sources.
**************************************************************************/
#ifndef _QUAT_H_
#define _QUAT_H_
#include "vec3f.hpp"
#include "mat44.hpp"
#include "mat33.hpp"
/****************************************************************
* Quaternion *
****************************************************************/
template <class Type>
class Quat
{
public:
typedef Vec3<Type> qvec;
Type s; /* scalar component */
qvec v; /* quat vector component */
/* Constructors */
Quat(void);
Quat(Type s, Type x, Type y, Type z);
Quat(Type x, Type y, Type z); // s=0
Quat(Type s, const qvec& v);
Quat(const qvec& v, Type s = 0.0);
Quat(const Type *d); /* copy from four-element Type array s,x,y,z */
Quat(const Quat &q); /* copy from other Quat */
/* Setters */
void Set( Type x, Type y, Type z );
void Set( Type s, Type x, Type y, Type z );
void Set( Type s, const qvec& v );
void Set( const qvec& v, Type s=0 );
/* Operators */
Quat &operator = ( const Quat &v ); /* assignment of a Quat */
Quat &operator += ( const Quat &v ); /* incrementation by a Quat */
Quat &operator -= ( const Quat &v ); /* decrementation by a Quat */
Quat &operator *= ( const Type d ); /* multiplication by a scalar */
Quat &operator *= ( const Quat &v ); /* quat product (this*v) */
Quat &operator /= ( const Type d ); /* division by a scalar */
Type &operator [] ( int i); /* indexing s=0,x=1,y=2,z=3 */
/* special functions */
Type Length(void) const; /* length of a Quat */
Type LengthSqr(void) const; /* squared length of a Quat */
Type Norm(void) const; /* also squared length of a Quat */
Quat &Normalize(void); /* normalize a Quat */
Quat &Invert(void); /* q = q^-1 */
Quat &Conjugate(void); /* q = q* */
qvec Xform( const qvec &v ) const; /* q*v*q-1 */
Quat &Log(void); /* log(q) */
Quat &Exp(void); /* exp(q) */
qvec GetAxis( void ) const; /* Get rot axis */
Type GetAngle( void ) const; /* Get rot angle (radians) */
void SetAngle( Type rad_ang ); /* set rot angle (radians) */
void ScaleAngle( Type f ); /* scale rot angle */
void Print( ) const; /* print Quat */
/* Conversions */
Mat44<Type>& ToMat( Mat44<Type> &dest ) const; /* to 4x4 matrix */
Mat33<Type>& ToMat( Mat33<Type> &dest ) const; /* to 3x3 matrix */
Quat& FromMat( const Mat44<Type>& src ); /* from 4x4 rot matrix */
Quat& FromMat( const Mat33<Type>& src ); /* from 3x3 rot matrix */
void ToAngleAxis( Type &ang, qvec &ax ) const; /* to rot angle AND axis */
Quat& FromAngleAxis( Type ang, const qvec &ax );/*from rot angle AND axis */
Quat& FromTwoVecs(const qvec &a, const qvec& b); /* quat from a to b */
// to/from Euler Angles (XYZ-Fixed/ZYX-Relative, angles in radians)
// See quatimpl.hpp for more detailed comments.
Quat& FromEuler( Type yaw_Z, Type pitch_Y, Type roll_X);
void ToEuler(Type &yaw_Z, Type &pitch_Y, Type &roll_X) const;
// HELPERS
static Type DEG2RAD(Type d);
static Type RAD2DEG(Type d);
static Type Sin(double d);
static Type Cos(double d);
static Type ACos(double d);
static Type ASin(double d);
static Type ATan(double d);
static Type ATan2(double n, double d);
// CONSTANTS
static Type FUDGE();
static Quat ZERO();
static Quat IDENTITY();
};
/* Utility functions */
template <class Type>
Quat<Type>& QuatSlerp(
Quat<Type> &dest, const Quat<Type>& from, const Quat<Type>& to, Type t );
template <class Type>
Quat<Type> QuatSlerp(const Quat<Type>& from, const Quat<Type>& to, Type t );
/* "Friends" */
template <class Type>
Quat<Type> operator -(const Quat<Type> &v); // -q1
template <class Type>
Quat<Type> operator +(const Quat<Type> &a, const Quat<Type> &b); // q1 + q2
template <class Type>
Quat<Type> operator -(const Quat<Type> &a, const Quat<Type> &b); // q1 - q2
template <class Type>
Quat<Type> operator *(const Quat<Type> &a, const Type d); // q1 * 3.0
template <class Type>
Quat<Type> operator *(const Type d, const Quat<Type> &a); // 3.0 * q1
template <class Type>
Quat<Type> operator *(const Quat<Type> &a, const Quat<Type> &b); // q1 * q2
template <class Type>
Quat<Type> operator /(const Quat<Type> &a, const Type d); // q1 / 3.0
template <class Type>
bool operator ==(const Quat<Type> &a, const Quat<Type> &b); // q1 == q2 ?
template <class Type>
bool operator !=(const Quat<Type> &a, const Quat<Type> &b); // q1 != q2 ?
#include "quatimpl.hpp"
typedef Quat<float> Quatf;
typedef Quat<double> Quatd;
#endif

View File

@@ -0,0 +1,886 @@
//------------------------------------------------------------------------------
// File : quatimpl.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
/***********************************************************************
quatimpl.hpp
A quaternion template class
-------------------------------------------------------------------
Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
Oct 2000, Bill Baxter
Modification History:
- See main header file, quat.hpp
************************************************************************/
#include "quat.hpp"
#include <math.h>
#include <assert.h>
//============================================================================
// CONSTRUCTORS
//============================================================================
template <class Type>
Quat<Type>::Quat( void )
{
// do nothing so default construction is fast
}
template <class Type>
Quat<Type>::Quat( Type _s, Type x, Type y, Type z )
{
s = _s;
v.Set( x, y, z );
}
template <class Type>
Quat<Type>::Quat( Type x, Type y, Type z )
{
s = 0.0;
v.Set( x, y, z );
}
template <class Type>
Quat<Type>::Quat( const qvec& _v, Type _s )
{
Set( _v, _s );
}
template <class Type>
Quat<Type>::Quat( Type _s, const qvec& _v )
{
Set( _v, _s );
}
template <class Type>
Quat<Type>::Quat( const Type *d )
{
s = *d++;
v.Set(d);
}
template <class Type>
Quat<Type>::Quat( const Quat &q )
{
s = q.s;
v = q.v;
}
//============================================================================
// SETTERS
//============================================================================
template <class Type>
void Quat<Type>::Set( Type _s, Type x, Type y, Type z )
{
s = _s;
v.Set(x,y,z);
}
template <class Type>
void Quat<Type>::Set( Type x, Type y, Type z )
{
s = 0.0;
v.Set(x,y,z);
}
template <class Type>
void Quat<Type>::Set( const qvec& _v, Type _s )
{
s = _s;
v = _v;
}
template <class Type>
void Quat<Type>::Set( Type _s, const qvec& _v )
{
s = _s;
v = _v;
}
//============================================================================
// OPERATORS
//============================================================================
template <class Type>
Quat<Type>& Quat<Type>::operator = (const Quat& q)
{
v = q.v; s = q.s; return *this;
}
template <class Type>
Quat<Type>& Quat<Type>::operator += ( const Quat &q )
{
v += q.v; s += q.s; return *this;
}
template <class Type>
Quat<Type>& Quat<Type>::operator -= ( const Quat &q )
{
v -= q.v; s -= q.s; return *this;
}
template <class Type>
Quat<Type> &Quat<Type>::operator *= ( const Type d )
{
v *= d; s *= d; return *this;
}
template <class Type>
Quat<Type> &Quat<Type>::operator *= ( const Quat& q )
{
#if 0
// Quaternion multiplication with
// temporary object construction minimized (hopefully)
Type ns = s*q.s - v*q.v;
qvec nv(v^q.v);
v *= q.s;
v += nv;
nv.Set(s*q.v);
v += nv;
s = ns;
return *this;
#else
// optimized (12 mults, and no compiler-generated temp objects)
Type A, B, C, D, E, F, G, H;
A = (s + v.x)*(q.s + q.v.x);
B = (v.z - v.y)*(q.v.y - q.v.z);
C = (s - v.x)*(q.v.y + q.v.z);
D = (v.y + v.z)*(q.s - q.v.x);
E = (v.x + v.z)*(q.v.x + q.v.y);
F = (v.x - v.z)*(q.v.x - q.v.y);
G = (s + v.y)*(q.s - q.v.z);
H = (s - v.y)*(q.s + q.v.z);
v.x = A - (E + F + G + H) * Type(0.5);
v.y = C + (E - F + G - H) * Type(0.5);
v.z = D + (E - F - G + H) * Type(0.5);
s = B + (-E - F + G + H) * Type(0.5);
return *this;
#endif
}
template <class Type>
Quat<Type> &Quat<Type>::operator /= ( const Type d )
{
Type r = Type(1.0)/d;
v *= r;
s *= r;
return *this;
}
template <class Type>
Type &Quat<Type>::operator [] ( int i)
{
switch (i) {
case 0: return s;
case 1: return v.x;
case 2: return v.y;
case 3: return v.z;
}
assert(false);
return s;
}
//============================================================================
// SPECIAL FUNCTIONS
//============================================================================
template <class Type>
inline Type Quat<Type>::Length( void ) const
{
return Type( sqrt( v*v + s*s ) );
}
template <class Type>
inline Type Quat<Type>::LengthSqr( void ) const
{
return Norm();
}
template <class Type>
inline Type Quat<Type>::Norm( void ) const
{
return v*v + s*s;
}
template <class Type>
inline Quat<Type>& Quat<Type>::Normalize( void )
{
*this *= Type(1.0) / Type(sqrt(v*v + s*s));
return *this;
}
template <class Type>
inline Quat<Type>& Quat<Type>::Invert( void )
{
Type scale = Type(1.0)/Norm();
v *= -scale;
s *= scale;
return *this;
}
template <class Type>
inline Quat<Type>& Quat<Type>::Conjugate( void )
{
v.x = -v.x;
v.y = -v.y;
v.z = -v.z;
return *this;
}
//----------------------------------------------------------------------------
// Xform
//----------------------------------------------------------------------------
// Transform a vector by this quaternion using q * v * q^-1
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>::qvec Quat<Type>::Xform( const qvec &vec ) const
{
/* copy vector into temp quaternion for multiply */
Quat vecQuat(vec);
/* invert multiplier */
Quat inverse(*this);
inverse.Invert();
/* do q * vec * q(inv) */
Quat tempVecQuat(*this * vecQuat);
tempVecQuat *= inverse;
/* return vector part */
return tempVecQuat.v;
}
//----------------------------------------------------------------------------
// Log
//----------------------------------------------------------------------------
// Natural log of quat
//----------------------------------------------------------------------------
template <class Type>
Quat<Type> &Quat<Type>::Log(void)
{
Type theta, scale;
scale = v.Length();
theta = ATan2(scale, s);
if (scale > 0.0)
scale = theta/scale;
v *= scale;
s = 0.0;
return *this;
}
//----------------------------------------------------------------------------
// Exp
//----------------------------------------------------------------------------
// e to the quat: e^quat
// -- assuming scalar part 0
//----------------------------------------------------------------------------
template <class Type>
Quat<Type> &Quat<Type>::Exp(void)
{
Type scale;
Type theta = v.Length();
if (theta > FUDGE()) {
scale = Sin(theta)/theta ;
v *= scale;
}
s = Cos(theta) ;
return *this;
}
//----------------------------------------------------------------------------
// SetAngle (radians)
//----------------------------------------------------------------------------
template <class Type>
void Quat<Type>::SetAngle( Type f )
{
qvec axis(GetAxis());
f *= Type(0.5);
s = Cos( f );
v = axis * Sin( f );
}
//----------------------------------------------------------------------------
// ScaleAngle
//----------------------------------------------------------------------------
template <class Type>
inline void Quat<Type>::ScaleAngle( Type f )
{
SetAngle( f * GetAngle() );
}
//----------------------------------------------------------------------------
// GetAngle (radians)
//----------------------------------------------------------------------------
// get rot angle in radians. Assumes s is between -1 and 1, which will always
// be the case for unit quaternions.
//----------------------------------------------------------------------------
template <class Type>
inline Type Quat<Type>::GetAngle( void ) const
{
return ( Type(2.0) * ACos( s ) );
}
//----------------------------------------------------------------------------
// GetAxis
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>::qvec Quat<Type>::GetAxis( void ) const
{
Type scale;
scale = Sin( acos( s ) ) ;
if ( scale < FUDGE() && scale > -FUDGE() )
return qvec( 0.0, 0.0, 0.0 );
else
return v / scale;
}
//----------------------------------------------------------------------------
// Print
//----------------------------------------------------------------------------
template <class Type>
inline void Quat<Type>::Print( ) const
{
printf( "(%3.2f, <%3.2f %3.2f %3.2f>)\n", s, v.x, v.y, v.z );
}
//============================================================================
// CONVERSIONS
//============================================================================
template <class Type>
Mat44<Type>& Quat<Type>::ToMat( Mat44<Type>& dest ) const
{
Type t, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
qvec a, c, b, d;
t = Type(2.0) / (v*v + s*s);
const Type ONE(1.0);
xs = v.x*t; ys = v.y*t; zs = v.z*t;
wx = s*xs; wy = s*ys; wz = s*zs;
xx = v.x*xs; xy = v.x*ys; xz = v.x*zs;
yy = v.y*ys; yz = v.y*zs; zz = v.z*zs;
dest.Set( ONE-(yy+zz), xy-wz, xz+wy, 0.0,
xy+wz, ONE-(xx+zz), yz-wx, 0.0,
xz-wy, yz+wx, ONE-(xx+yy), 0.0,
0.0, 0.0, 0.0, ONE );
return dest;
}
template <class Type>
Mat33<Type>& Quat<Type>::ToMat( Mat33<Type>& dest ) const
{
Type t, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
qvec a, c, b, d;
t = Type(2.0) / Norm();
const Type ONE(1.0);
xs = v.x*t; ys = v.y*t; zs = v.z*t;
wx = s*xs; wy = s*ys; wz = s*zs;
xx = v.x*xs; xy = v.x*ys; xz = v.x*zs;
yy = v.y*ys; yz = v.y*zs; zz = v.z*zs;
dest.Set( ONE-(yy+zz), xy-wz, xz+wy,
xy+wz, ONE-(xx+zz), yz-wx,
xz-wy, yz+wx, ONE-(xx+yy) );
return dest;
}
//----------------------------------------------------------------------------
// FromMat
//----------------------------------------------------------------------------
// Convert rotation matrix to quaternion
// Results will be bad if matrix is not (very close to) orthonormal
// Modified from gamasutra.com article:
// http://www.gamasutra.com/features/programming/19980703/quaternions_07.htm
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>& Quat<Type>::FromMat( const Mat44<Type>& m )
{
Type tr = m.Trace();
// check the diagonal
if (tr > 0.0) {
Type scale = Type( sqrt (tr) );
s = scale * Type(0.5);
scale = Type(0.5) / scale;
v.x = (m(1,2) - m(2,1)) * scale;
v.y = (m(2,0) - m(0,2)) * scale;
v.z = (m(0,1) - m(1,0)) * scale;
} else {
// diagonal is negative or zero
int i, j, k;
i = 0;
if (m(1,1) > m(0,0)) i = 1;
if (m(2,2) > m(i,i)) i = 2;
int nxt[3] = {1, 2, 0};
j = nxt[i];
k = nxt[j];
Type scale = Type( sqrt (Type(1.0) + m(i,i) - (m(j,j) + m(k,k)) ) );
v[i] = scale * Type(0.5);
if (scale != 0.0) scale = Type(0.5) / scale;
s = (m(j,k) - m(k,j)) * scale;
v[j] = (m(i,j) + m(j,i)) * scale;
v[k] = (m(i,k) + m(k,i)) * scale;
}
return *this;
}
template <class Type>
Quat<Type>& Quat<Type>::FromMat( const Mat33<Type>& m )
{
Type tr = m.Trace();
// check the diagonal
if (tr > 0.0) {
Type scale = Type( sqrt (tr + Type(1.0)) );
s = scale * Type(0.5);
scale = Type(0.5) / scale;
v.x = (m(1,2) - m(2,1)) * scale;
v.y = (m(2,0) - m(0,2)) * scale;
v.z = (m(0,1) - m(1,0)) * scale;
} else {
// diagonal is negative or zero
int i, j, k;
i = 0;
if (m(1,1) > m(0,0)) i = 1;
if (m(2,2) > m(i,i)) i = 2;
int nxt[3] = {1, 2, 0};
j = nxt[i];
k = nxt[j];
Type scale = Type( sqrt (Type(1.0) + m(i,i) - (m(j,j) + m(k,k)) ) );
v[i] = scale * Type(0.5);
if (scale != 0.0) scale = Type(0.5) / scale;
s = (m(j,k) - m(k,j)) * scale;
v[j] = (m(i,j) + m(j,i)) * scale;
v[k] = (m(i,k) + m(k,i)) * scale;
}
return *this;
}
//----------------------------------------------------------------------------
// ToAngleAxis (radians)
//----------------------------------------------------------------------------
// Convert to angle & axis representation
//----------------------------------------------------------------------------
template <class Type>
void Quat<Type>::ToAngleAxis( Type &angle, qvec &axis ) const
{
Type cinv = ACos( s );
angle = Type(2.0) * cinv;
Type scale;
scale = Sin( cinv );
if ( scale < FUDGE() && scale > -FUDGE() )
axis = qvec::ZERO;
else {
axis = v;
axis /= scale;
}
}
//----------------------------------------------------------------------------
// FromAngleAxis (radians)
//----------------------------------------------------------------------------
// Convert to quat from angle & axis representation
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>& Quat<Type>::FromAngleAxis( Type angle, const qvec &axis )
{
/* normalize vector */
Type length = axis.Length();
/* if zero vector passed in, just set to identity quaternion */
if ( length < FUDGE() )
{
*this = IDENTITY();
return *this;
}
length = Type(1.0)/length;
angle *= 0.5;
v = axis;
v *= length;
v *= Sin(angle);
s = Cos(angle);
return *this;
}
//----------------------------------------------------------------------------
// FromTwoVecs
//----------------------------------------------------------------------------
// Return the quat that rotates vector a into vector b
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>& Quat<Type>::FromTwoVecs(const qvec &a, const qvec& b)
{
qvec u1(a);
qvec u2(b);
double theta ; /* angle of rotation about axis */
double theta_complement ;
double crossProductMagnitude ;
// Normalize both vectors and take cross product to get rotation axis.
u1.Normalize();
u2.Normalize();
qvec axis( u1 ^ u2 );
// | u1 X u2 | = |u1||u2|sin(theta)
//
// Since u1 and u2 are normalized,
//
// theta = arcsin(|axis|)
crossProductMagnitude = axis.Length();
// Occasionally, even though the vectors are normalized, the
// magnitude will be calculated to be slightly greater than one. If
// this happens, just set it to 1 or asin() will barf.
if( crossProductMagnitude > Type(1.0) )
crossProductMagnitude = Type(1.0) ;
// Take arcsin of magnitude of rotation axis to compute rotation
// angle. Since crossProductMagnitude=[0,1], we will have
// theta=[0,pi/2].
theta = ASin( crossProductMagnitude ) ;
theta_complement = Type(3.14159265358979323846) - theta ;
// If cos(theta) < 0, use complement of theta as rotation angle.
if( u1 * u2 < 0.0 )
{
double tmp = theta;
theta = theta_complement ;
theta_complement = tmp;
}
// if angle is 0, just return identity quaternion
if( theta < FUDGE() )
{
*this = IDENTITY();
}
else
{
if( theta_complement < FUDGE() )
{
// The two vectors are opposed. Find some arbitrary axis vector.
// First try cross product with x-axis if u1 not parallel to x-axis.
if( (u1.y*u1.y + u1.z*u1.z) >= FUDGE() )
{
axis.Set( 0.0, u1.z, -u1.y ) ;
}
else
{
// u1 is parallel to to x-axis. Use z-axis as axis of rotation.
axis.Set(0.0, 0.0, 1.0);
}
}
axis.Normalize();
FromAngleAxis(Type(theta), axis);
Normalize();
}
return *this;
}
//----------------------------------------------------------------------------
// FromEuler
//----------------------------------------------------------------------------
// converts 3 euler angles (in radians) to a quaternion
//
// angles are in radians; Assumes roll is rotation about X, pitch is
// rotation about Y, yaw is about Z. (So thinking of
// Z as up) Assumes order of yaw, pitch, roll applied as follows:
//
// p' = roll( pitch( yaw(p) ) )
//
// Where yaw, pitch, and roll are defined in the BODY coordinate sys.
// In other words these are ZYX-relative (or XYZ-fixed) Euler Angles.
//
// For a complete Euler angle implementation that handles all 24 angle
// sets, see "Euler Angle Conversion" by Ken Shoemake, in "Graphics
// Gems IV", Academic Press, 1994
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>& Quat<Type>::FromEuler(Type yaw, Type pitch, Type roll)
{
Type cosYaw, sinYaw, cosPitch, sinPitch, cosRoll, sinRoll;
Type half_roll, half_pitch, half_yaw;
/* put angles into radians and divide by two, since all angles in formula
* are (angle/2)
*/
const Type HALF(0.5);
half_yaw = yaw * HALF;
half_pitch = pitch * HALF;
half_roll = roll * HALF;
cosYaw = Cos(half_yaw);
sinYaw = Sin(half_yaw);
cosPitch = Cos(half_pitch);
sinPitch = Sin(half_pitch);
cosRoll = Cos(half_roll);
sinRoll = Sin(half_roll);
Type cpcy = cosPitch * cosYaw;
Type spsy = sinPitch * sinYaw;
v.x = sinRoll * cpcy - cosRoll * spsy;
v.y = cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw;
v.z = cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw;
s = cosRoll * cpcy + sinRoll * spsy;
return *this;
}
//----------------------------------------------------------------------------
// ToEuler
//----------------------------------------------------------------------------
// converts a quaternion to 3 euler angles (in radians)
//
// See FromEuler for details of which set of Euler Angles are returned
//----------------------------------------------------------------------------
template <class Type>
void Quat<Type>::ToEuler(Type& yaw, Type& pitch, Type& roll) const
{
// This is probably wrong
Mat33<Type> M;
ToMat(M);
const int i = 0, j = 1, k = 2;
double cy = sqrt(M(i,i)*M(i,i) + M(i,j)*M(i,j));
if (cy > FUDGE()) {
roll = ATan2(M(j,k), M(k,k));
pitch = ATan2(-M(i,k), cy);
yaw = ATan2(M(i,j), M(i,i));
} else {
roll = ATan2(-M(k,j), M(j,j));
pitch = ATan2(-M(i,k), cy);
yaw = 0;
}
}
//============================================================================
// QUAT FRIENDS
//============================================================================
template <class Type>
Quat<Type> operator + (const Quat<Type> &a, const Quat<Type> &b)
{
return Quat<Type>( a.s+b.s, a.v+b.v );
}
template <class Type>
Quat<Type> operator - (const Quat<Type> &a, const Quat<Type> &b)
{
return Quat<Type>( a.s-b.s, a.v-b.v );
}
template <class Type>
Quat<Type> operator - (const Quat<Type> &a )
{
return Quat<Type>( -a.s, -a.v );
}
template <class Type>
Quat<Type> operator * ( const Quat<Type> &a, const Quat<Type> &b)
{
#if 0
// 16 mults
return Quat<Type>( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v );
#else
// optimized (12 mults, and no compiler-generated temp objects)
Type A, B, C, D, E, F, G, H;
A = (a.s + a.v.x)*(b.s + b.v.x);
B = (a.v.z - a.v.y)*(b.v.y - b.v.z);
C = (a.s - a.v.x)*(b.v.y + b.v.z);
D = (a.v.y + a.v.z)*(b.s - b.v.x);
E = (a.v.x + a.v.z)*(b.v.x + b.v.y);
F = (a.v.x - a.v.z)*(b.v.x - b.v.y);
G = (a.s + a.v.y)*(b.s - b.v.z);
H = (a.s - a.v.y)*(b.s + b.v.z);
return Quat<Type>(
B + (-E - F + G + H) * Type(0.5),
A - (E + F + G + H) * Type(0.5),
C + (E - F + G - H) * Type(0.5),
D + (E - F - G + H) * Type(0.5));
#endif
}
template <class Type>
Quat<Type> operator * ( const Quat<Type> &a, const Type t)
{
return Quat<Type>( a.v * t, a.s * t );
}
template <class Type>
Quat<Type> operator * ( const Type t, const Quat<Type> &a )
{
return Quat<Type>( a.v * t, a.s * t );
}
template <class Type>
Quat<Type> operator / ( const Quat<Type> &a, const Type t )
{
return Quat<Type>( a.v / t, a.s / t );
}
template <class Type>
bool operator == (const Quat<Type> &a, const Quat<Type> &b)
{
return (a.s == b.s && a.v == b.v);
}
template <class Type>
bool operator != (const Quat<Type> &a, const Quat<Type> &b)
{
return (a.s != b.s || a.v != b.v);
}
//============================================================================
// UTILS
//============================================================================
template <class Type>
inline Type Quat<Type>::DEG2RAD(Type d)
{
return d * Type(0.0174532925199432957692369076848861);
}
template <class Type>
inline Type Quat<Type>::RAD2DEG(Type d)
{
return d * Type(57.2957795130823208767981548141052);
}
template <class Type>
inline Type Quat<Type>::Sin(double d) { return Type(sin(d)); }
template <class Type>
inline Type Quat<Type>::Cos(double d) { return Type(cos(d)); }
template <class Type>
inline Type Quat<Type>::ACos(double d) { return Type(acos(d)); }
template <class Type>
inline Type Quat<Type>::ASin(double d) { return Type(asin(d)); }
template <class Type>
inline Type Quat<Type>::ATan(double d) { return Type(atan(d)); }
template <class Type>
inline Type Quat<Type>::ATan2(double n, double d) {return Type(atan2(n,d));}
template <class Type>
inline Quat<Type> Quat<Type>::ZERO() {return Quat(0,0,0,0); }
template <class Type>
inline Quat<Type> Quat<Type>::IDENTITY() {return Quat(1,0,0,0); }
template<class Type>
inline Type Quat<Type>::FUDGE() { return 1e-6; }
template<>
inline double Quat<double>::FUDGE() { return 1e-10; }
//----------------------------------------------------------------------------
// QuatSlerp
//----------------------------------------------------------------------------
template <class Type>
Quat<Type>& QuatSlerp(
Quat<Type> &dest,
const Quat<Type> &from, const Quat<Type> &to, Type t )
{
#if 0
// compact mathematical version
// exp(t*log(to*from^-1))*from
Quat<Type> fminv(from);
Quat<Type> tofrom(to*fminv.Invert());
Quat<Type> slerp = t*tofrom.Log();
slerp.Exp();
slerp *= from;
return slerp;
#endif
Quat<Type> to1;
double omega, cosom, sinom, scale0, scale1;
/* calculate cosine */
cosom = from.v * to.v + from.s + to.s;
/* Adjust signs (if necessary) so we take shorter path */
if ( cosom < 0.0 ) {
cosom = -cosom;
to1 = -to;
}
else
{
to1 = to;
}
/* Calculate coefficients */
if ((1.0 - cosom) > Quat<Type>::FUDGE ) {
/* standard case (slerp) */
omega = acos( cosom );
sinom = sin( omega );
scale0 = sin((1.0 - t) * omega) / sinom;
scale1 = sin(t * omega) / sinom;
}
else {
/* 'from' and 'to' are very close - just do linear interpolation */
scale0 = 1.0 - t;
scale1 = t;
}
dest = from;
dest *= Type(scale0);
dest += Type(scale1) * to1;
return dest;
}
// This version creates more temporary objects
template <class Type>
inline Quat<Type> QuatSlerp(
const Quat<Type>& from, const Quat<Type>& to, Type t )
{
Quat<Type> q;
return QuatSlerp(q, from, to, t);
}

View File

@@ -0,0 +1,196 @@
//------------------------------------------------------------------------------
// File : quattest.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//----------------------------------------------------------------------------
// Quattest.cpp
// Quaternion coverage (and maybe functionality) test.
// The main objective is to just make sure every API gets called
// to flush out lurking template bugs that might not otherwise get tickled.
// A few checks to make sure things are functioning properly are also
// included.
//
// For the API coverage, if the thing simply compiles then it was a success.
//----------------------------------------------------------------------------
#include "quat.hpp"
void coverage_test()
{
float x = 0.5f, y = 1.1f, z = -0.1f, s = 0.2f;
// TEST CONSTRUCTORS
Quatf q1;
Quatf q2 = Quatf(x, y, z, s);
Quatf q3(x, y, z);
Quatf q4(Vec3f(1,2,3));
Quatf q5(Vec3f(2,3,4), 2.0);
Quatf q6(1.0, Vec3f(-1,-2,-3));
float floatarray[4] = { 1, 2, 3, 4 };
Quatf q7(floatarray);
Quatf q8(q7);
// TEST SETTERS
q1.Set(1,2,3);
q2.Set(1,2,3,4);
q3.Set(Vec3f(1.0,1.0,1.0));
q3.Set(Vec3f(1.0,1.0,1.0),-0.5);
// TEST OPERATORS
// Quat &operator = ( const Quat &v ); /* assignment of a Quat */
q4 = q6;
// Quat &operator += ( const Quat &v ); /* incrementation by a Quat */
q3 += q2;
// Quat &operator -= ( const Quat &v ); /* decrementation by a Quat */
q3 -= q2;
// Quat &operator *= ( const Type d ); /* multiplication by a scalar */
q4 *= 0.5f;
// Quat &operator *= ( const Quat &v ); /* quat product (this*v) */
q2 *= q1;
// Quat &operator /= ( const Type d ); /* division by a scalar */
q5 /= 2.0f;
// Type &operator [] ( int i); /* indexing x=0, s=3 */
float c0 = q1[0];
float c1 = q1[1];
float c2 = q1[2];
float c3 = q1[3];
// TEST SPECIAL FUNCTIONS
// Type Length(void) const; /* length of a Quat */
float l = q4.Length();
// Type LengthSqr(void) const; /* squared length of a Quat */
l = q4.LengthSqr();
// Type LengthSqr(void) const; /* squared length of a Quat */
l = q4.Norm();
// Quat &Normalize(void); /* normalize a Quat */
Quatf q9 = q4.Normalize();
// Quat &Invert(void); /* q = q^-1 */
q9 = q4.Invert();
// Quat &Conjugate(void); /* q = q* */
q9 = q4.Conjugate();
// qvec Xform( const qvec &v ); /* q*v*q-1 */
Vec3f v1 = q4.Xform(Vec3f(1.0,1.0,1.0));
// Quat &Log(void); /* log(q) */
q9 = q4.Log();
// Quat &Exp(void); /* exp(q) */
q9 = q4.Exp();
// qvec GetAxis( void ) const; /* Get rot axis */
v1 = q5.GetAxis();
// Type GetAngle( void ) const; /* Get rot angle (radians) */
float a = q5.GetAngle();
// void SetAngle( Type rad_ang ); /* set rot angle (radians) */
q2.SetAngle(a);
// void ScaleAngle( Type f ); /* scale rot angle */
q2.ScaleAngle(1.5);
// void Print( ) const; /* print Quat */
q3.Print();
/* TEST CONVERSIONS */
Mat44f m44;
Mat33f m33;
//Mat44& ToMat( Mat44 &dest ) const;
//Mat33& ToMat( Mat33 &dest ) const;
// Quat& FromMat( const Mat44<Type>& src ) const;
// Quat& FromMat( const Mat33<Type>& src ) const;
q3.Normalize();
m44 = q3.ToMat(m44);
m33 = q3.ToMat(m33);
q5 = q3.FromMat(m44);
q5 = q3.FromMat(m33);
//void ToAngleAxis( Type &ang, qvec &ax ) const;
q3.ToAngleAxis( a, v1 );
//Quat& FromAngleAxis( Type ang, const qvec &ax );
q4 = q3.FromAngleAxis( a, v1 );
//Quat& FromTwoVecs(const qvec &a, const qvec& b);
Vec3f v2(-1,-2,-3);
q4 = q3.FromTwoVecs( v2, v1 );
//Quat& FromEuler( Type yaw, Type pitch, Type roll);
q4 = q3.FromEuler( 2.2f, 1.2f, -0.4f );
//void ToEuler(Type &yaw, Type &pitch, Type &roll) const;
float p=0.3f,r=-1.57f; y= 0.1f;
q3.ToEuler( y,p,r );
/* TEST FRIENDS */
//friend Quat operator - (const Quat &v); /* -q1 */
q1 = -q2;
//friend Quat operator + (const Quat &a, const Quat &b); /* q1 + q2 */
q1 = q2 + q3;
//friend Quat operator - (const Quat &a, const Quat &b); /* q1 - q2 */
q1 = q2 - q3;
//friend Quat operator * (const Quat &a, const Type d); /* q1 * 3.0 */
q1 = q2 * 0.2f;
//friend Quat operator * (const Type d, const Quat &a); /* 3.0 * q1 */
q1 = 0.2f * q2;
//friend Quat operator * (const Quat &a, const Quat &b); /* q1 * q2 */
q1 = q2 * q3;
//friend Quat operator / (const Quat &a, const Type d); /* q1 / 3.0 */
q1 = q2 / 1.2f;
//friend bool operator == (const Quat &a, const Quat &b); /* q1 == q2 ? */
bool eq = (q1 == q2);
//friend bool operator != (const Quat &a, const Quat &b); /* q1 != q2 ? */
bool neq = (q1 != q2);
// HELPERS
// static Type DEG2RAD(Type d);
// static Type RAD2DEG(Type d);
a = Quatf::RAD2DEG(a);
a = Quatf::DEG2RAD(a);
a = Quatf::Sin(a);
a = Quatf::Cos(a);
a = Quatf::ACos(a);
a = Quatf::ASin(a);
a = Quatf::ATan(a);
a = Quatf::ATan2(a, p);
// CONSTANTS
// static const Type FUDGE;
// static const Quat ZERO;
// static const Quat IDENTITY;
a = Quatf::FUDGE;
q3 = Quatf::ZERO();
q4 = Quatf::IDENTITY();
q1 = QuatSlerp(q1, q3, q4, 0.5f );
q1 = QuatSlerp(q3, q4, 0.5f );
}
Quatf StatQuat(Quatf::IDENTITY());
Quatf StatQuat2 = Quatf::IDENTITY();
void functional_test()
{
printf("The ZERO quat: ");
Quatf::ZERO().Print();
printf("The IDENTITY quat: ");
Quatf::IDENTITY().Print();
printf("Statically constructed copy of IDENTITY quat: ");
StatQuat.Print();
printf("A different static copy of IDENTITY quat: ");
StatQuat2.Print();
}
int main(int argc, char *argv[])
{
coverage_test();
functional_test();
return (0);
}

View File

@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
// File : tri.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// tri.cpp : triangle defs and intersection routines.
//============================================================================
#include <math.h>
//----------------------------------------------------------------------------
// CHECKS IF 2D POINT P IS IN A 2D TRI ABC.
//----------------------------------------------------------------------------
int PtInTri2D(float Px, float Py,
float Ax, float Ay, float Bx, float By, float Cx, float Cy)
{
float dABx=Bx-Ax, dABy=By-Ay, dBCx=Cx-Bx, dBCy=Cy-By; // "REPEATS"
if (dABx*dBCy < dABy*dBCx) // CW
{
if (dABx*(Py-Ay) >= dABy*(Px-Ax)) return(0); // ABxAP
if (dBCx*(Py-By) >= dBCy*(Px-Bx)) return(0); // BCxBP
if ((Ax-Cx)*(Py-Cy) >= (Ay-Cy)*(Px-Cx)) return(0); // CAxCP
}
else // CCW
{
if (dABx*(Py-Ay) < dABy*(Px-Ax)) return(0); // ABxAP
if (dBCx*(Py-By) < dBCy*(Px-Bx)) return(0); // BCxBP
if ((Ax-Cx)*(Py-Cy) < (Ay-Cy)*(Px-Cx)) return(0); // CAxCP
}
return(1); // "INSIDE" EACH EDGE'S IN-HALF-SPACE (PT P IS INSIDE TRIANGLE)
};
//----------------------------------------------------------------------------
// CHECKS IF 3D POINT P (ON ABC'S PLANE) IS IN 3D TRI ABC.
// P=PtOnTriPlane, N=PlaneNormal (does not have to be normalized)
//----------------------------------------------------------------------------
int PtInTri3D(const float P[3], float N[3],
const float A[3], const float B[3], const float C[3])
{
#define ABS(x) (((x)<0)?(-(x)):x) // HANDY UNIVERSAL ABSOLUTE VALUE FUNC
// DETERMINE LARGEST COMPONENT OF NORMAL (magnitude, since we want the largest projection)
N[0]=ABS(N[0]); N[1]=ABS(N[1]); N[2]=ABS(N[2]);
// PROJECT ONTO PLANE WHERE PERPENDICULAR TO LARGEST NORMAL COMPONENT AXIS
if (N[0]>N[1] && N[0]>N[2]) // X IS LARGEST SO PROJECT ONTO YZ-PLANE
return( PtInTri2D(P[1],P[2], A[1],A[2], B[1],B[2], C[1],C[2]) );
else if (N[1]>N[0] && N[1]>N[2]) // Y IS LARGEST SO PROJECT ONTO XZ-PLANE
return( PtInTri2D(P[0],P[2], A[0],A[2], B[0],B[2], C[0],C[2]) );
else // Z IS LARGEST SO PROJECT ONTO XY-PLANE
return( PtInTri2D(P[0],P[1], A[0],A[1], B[0],B[1], C[0],C[1]) );
}
//--------------------------------------------------------------------------
// Checks if an edge UV intersects a triangle ABC. Returns whether or
// not the edge intersects the plane (0 or 1) and the IsectPt.
//--------------------------------------------------------------------------
int EdgeTriIsect(const float U[3], const float V[3],
const float A[3], const float B[3], const float C[3],
float IsectPt[3])
{
// CALCULATE PLANE EQUATION COEFFICIENTS P FOR TRI ABC
float P[4];
float u[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
float v[3] = {C[0]-A[0],C[1]-A[1],C[2]-A[2]};
P[0] = u[1]*v[2] - u[2]*v[1]; // CROSS-PROD BETWEEN u AND v
P[1] = u[2]*v[0] - u[0]*v[2]; // DEFINES UNNORMALIZED NORMAL
P[2] = u[0]*v[1] - u[1]*v[0];
float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]); // NORMALIZE NORMAL
P[0]/=l; P[1]/=l; P[2]/=l;
P[3] = -(P[0]*A[0] + P[1]*A[1] + P[2]*A[2]);
// FIND INTERSECTION OF EDGE UV WITH PLANE P
int EdgeIsectsPlane=0;
float Dir[3] = { V[0]-U[0], V[1]-U[1], V[2]-U[2] };
float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
float NdotU = P[0]*U[0] + P[1]*U[1] + P[2]*U[2];
if (NdotDir==(float)0) return(0);
float t = (-P[3] - NdotU) / NdotDir;
if (t>=0 && t<=1)
{
IsectPt[0] = U[0] + Dir[0]*t;
IsectPt[1] = U[1] + Dir[1]*t;
IsectPt[2] = U[2] + Dir[2]*t;
EdgeIsectsPlane=1;
}
// FIRST, DOES THE EDGE INTERSECT THE PLANE?
if (!EdgeIsectsPlane) return(0);
// SEE IF ISECT PT IS IN THE TRI
return( PtInTri3D(IsectPt,P,A,B,C) );
}

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// File : tri.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// tri.hpp : triangle defs and intersection routines.
//============================================================================
int PtInTri2D(float Px, float Py,
float Ax, float Ay, float Bx, float By, float Cx, float Cy);
int PtInTri3D(const float P[3], float N[3],
const float A[3], const float B[3], const float C[3]);
int EdgeTriIsect(const float U[3], const float V[3],
const float A[3], const float B[3], const float C[3],
float IsectPt[3]);

View File

@@ -0,0 +1,137 @@
//-----------------------------------------------------------------------------
// File : vec2f.hpp
//-----------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//-----------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without
// fee, provided that the above copyright notice appear in all copies
// and that both that copyright notice and this permission notice
// appear in supporting documentation. Binaries may be compiled with
// this software without any royalties or restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//==========================================================================
// vec2.hpp : 2d vector class template. Works for any integer or real type.
//==========================================================================
#ifndef VEC2_H
#define VEC2_H
#include <stdio.h>
#include <math.h>
template<class Type>
class Vec2
{
public:
Type x, y;
Vec2 (void) {};
Vec2 (const Type X, const Type Y) { x=X; y=Y; };
Vec2 (const Vec2& v) { x=v.x; y=v.y; };
Vec2 (const Type v[2]) { x=v[0]; y=v[1]; };
void Set (const Type X, const Type Y) { x=X; y=Y; }
void Set (const Type v[2]) { x=v[0]; y=v[1]; };
operator Type*() // Type * CONVERSION
{ return (Type *)&x; }
operator const Type*() const // CONST Type * CONVERSION
{ return &x; }
Vec2& operator = (const Vec2& A) // ASSIGNMENT (=)
{ x=A.x; y=A.y;
return(*this); };
bool operator == (const Vec2& A) const // COMPARISON (==)
{ return (x==A.x && y==A.y); }
bool operator != (const Vec2& A) const // COMPARISON (!=)
{ return (x!=A.x || y!=A.y); }
Vec2 operator + (const Vec2& A) const // ADDITION (+)
{ Vec2 Sum(x+A.x, y+A.y);
return(Sum); }
Vec2 operator - (const Vec2& A) const // SUBTRACTION (-)
{ Vec2 Diff(x-A.x, y-A.y);
return(Diff); }
Type operator * (const Vec2& A) const // DOT-PRODUCT (*)
{ Type DotProd = x*A.x+y*A.y;
return(DotProd); }
Type operator / (const Vec2& A) const // CROSS-PRODUCT (/)
{ Type CrossProd = x*A.y-y*A.x;
return(CrossProd); }
Type operator ^ (const Vec2& A) const // ALSO CROSS-PRODUCT (^)
{ Type CrossProd = x*A.y-y*A.x;
return(CrossProd); }
Vec2 operator * (const Type s) const // MULTIPLY BY SCALAR (*)
{ Vec2 Scaled(x*s, y*s);
return(Scaled); }
Vec2 operator / (const Type s) const // DIVIDE BY SCALAR (/)
{ Vec2 Scaled(x/s, y/s);
return(Scaled); }
Vec2 operator & (const Vec2& A) const // COMPONENT MULTIPLY (&)
{ Vec2 CompMult(x*A.x, y*A.y);
return(CompMult); }
friend inline Vec2 operator *(Type s, const Vec2& v) // SCALAR MULT s*V
{ return Vec2(v.x*s, v.y*s); }
Vec2& operator += (const Vec2& A) // ACCUMULATED VECTOR ADDITION (+=)
{ x+=A.x; y+=A.y; return *this; }
Vec2& operator -= (const Vec2& A) // ACCUMULATED VECTOR SUBTRACTION (-=)
{ x-=A.x; y-=A.y; return *this; }
Vec2& operator *= (const Type s) // ACCUMULATED SCALAR MULT (*=)
{ x*=s; y*=s; return *this; }
Vec2& operator /= (const Type s) // ACCUMULATED SCALAR DIV (/=)
{ x/=s; y/=s; return *this; }
Vec2& operator &= (const Vec2& A) // ACCUMULATED COMPONENT MULTIPLY (&=)
{ x*=A.x; y*=A.y; return *this; }
Vec2 operator - (void) const // NEGATION (-)
{ Vec2 Negated(-x, -y);
return(Negated); };
/*
const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
{ return( (i==0)?x:y ); };
Type & operator [] (const int i)
{ return( (i==0)?x:y ); };
*/
Type Length (void) const // LENGTH OF VECTOR
{ return ((Type)sqrt(x*x+y*y)); };
Type LengthSqr (void) const // LENGTH OF VECTOR (SQUARED)
{ return (x*x+y*y); };
Vec2& Normalize (void) // NORMALIZE VECTOR
{ Type L = Length(); // CALCULATE LENGTH
if (L>0) { x/=L; y/=L; }
return *this;
}; // DIV COMPONENTS BY LENGTH
Vec2 Perpendicular() const // RETURNS A PERPENDICULAR
{ Vec2 Perp(-y,x);
return(Perp); }
void UpdateMinMax(Vec2 &Min, Vec2 &Max)
{
if (x<Min.x) Min.x=x; else if (x>Max.x) Max.x=x;
if (y<Min.y) Min.y=y; else if (y>Max.y) Max.y=y;
}
void Print() const
{ printf("(%.3f, %.3f)\n",x, y); }
static Vec2 ZERO;
};
typedef Vec2<float> Vec2f;
typedef Vec2<double> Vec2d;
template<class Type> Vec2<Type> Vec2<Type>::ZERO = Vec2<Type>(0,0);
#endif

View File

@@ -0,0 +1,244 @@
//-----------------------------------------------------------------------------
// File : vec3f.hpp
//-----------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//-----------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without
// fee, provided that the above copyright notice appear in all copies
// and that both that copyright notice and this permission notice
// appear in supporting documentation. Binaries may be compiled with
// this software without any royalties or restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//==========================================================================
// Vec3.hpp : 3d vector class template. Works for any integer or real type.
//==========================================================================
#ifndef VEC3_H
#define VEC3_H
#include <stdio.h>
#include <math.h>
/**
* @class Vec3
* @brief A templated 3-vector class
*
* Everybody in graphics has to write their own basic 3-vector class.
* And we're no exception. This one uses templates, so that with one
* definition of the class you can have a 3-vector of floats or doubles
* depending on how precise you are, or you can make 3-vectors of ints
* or unsigned char, handy for representing colors.
*
* A couple of typedefs for common instatiations are provided by
* default: Vec3f, and Vec3d, the float and double versions,
* respectively.
*
*/
template<class Type>
class Vec3
{
public:
Type x, y, z; ///< The storage for the three components of the vector
/// Default constructor.
/// Note: does \em not initialize x, y, and z!
Vec3 (void)
{};
/// Three component constructor
Vec3 (const Type X, const Type Y, const Type Z)
{ x=X; y=Y; z=Z; };
/// Copy constructor
Vec3 (const Vec3& v)
{ x=v.x; y=v.y; z=v.z; };
/// Construct from array
Vec3 (const Type v[3])
{ x=v[0]; y=v[1]; z=v[2]; };
/// Set from components
void Set (const Type X, const Type Y, const Type Z)
{ x=X; y=Y; z=Z; }
/// Set from array
void Set (const Type v[3])
{ x=v[0]; y=v[1]; z=v[2]; };
operator Type*() /// Type * CONVERSION
{ return (Type *)&x; }
operator const Type*() const /// CONST Type * CONVERSION
{ return &x; }
bool operator == (const Vec3& A) const /// COMPARISON (==)
{ return (x==A.x && y==A.y && z==A.z); }
bool operator != (const Vec3& A) const /// COMPARISON (!=)
{ return (x!=A.x || y!=A.y || z!=A.z); }
Vec3& operator = (const Vec3& A) /// ASSIGNMENT (=)
{ x=A.x; y=A.y; z=A.z;
return(*this); };
Vec3 operator + (const Vec3& A) const /// ADDITION (+)
{ Vec3 Sum(x+A.x, y+A.y, z+A.z);
return(Sum); };
Vec3 operator - (const Vec3& A) const /// SUBTRACTION (-)
{ Vec3 Diff(x-A.x, y-A.y, z-A.z);
return(Diff); };
Type operator * (const Vec3& A) const /// DOT-PRODUCT (*)
{ Type DotProd = x*A.x+y*A.y+z*A.z;
return(DotProd); };
Vec3 operator / (const Vec3& A) const /// CROSS-PRODUCT (/)
{ Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
return(CrossProd); };
Vec3 operator ^ (const Vec3& A) const /// ALSO CROSS-PRODUCT (^)
{ Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
return(CrossProd); };
Vec3 operator * (const Type s) const /// MULTIPLY BY SCALAR V*s (*)
{ Vec3 Scaled(x*s, y*s, z*s);
return(Scaled); };
Vec3 operator / (const Type s) const /// DIVIDE BY SCALAR (/)
{ Vec3 Scaled(x/s, y/s, z/s);
return(Scaled); };
Vec3 operator & (const Vec3& A) const /// COMPONENT MULTIPLY (&)
{ Vec3 CompMult(x*A.x, y*A.y, z*A.z);
return(CompMult); }
friend inline Vec3 operator *(Type s, const Vec3& v) /// SCALAR MULT s*V
{ return Vec3(v.x*s, v.y*s, v.z*s); }
Vec3& operator += (const Vec3& A) /// ACCUMULATED VECTOR ADDITION (+=)
{ x+=A.x; y+=A.y; z+=A.z;
return *this;}
Vec3& operator -= (const Vec3& A) /// ACCUMULATED VECTOR SUBTRACTION (-=)
{ x-=A.x; y-=A.y; z-=A.z;
return *this; }
Vec3& operator *= (const Type s) /// ACCUMULATED SCALAR MULT (*=)
{ x*=s; y*=s; z*=s;
return *this; }
Vec3& operator /= (const Type s) /// ACCUMULATED SCALAR DIV (/=)
{ x/=s; y/=s; z/=s;
return *this; }
Vec3& operator &= (const Vec3& A) /// ACCUMULATED COMPONENT MULTIPLY (&=)
{ x*=A.x; y*=A.y; z*=A.z; return *this; }
Vec3 operator - (void) const /// NEGATION (-)
{ Vec3 Negated(-x, -y, -z);
return(Negated); };
/*
const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
{ return( (i==0)?x:((i==1)?y:z) ); };
Type & operator [] (const int i)
{ return( (i==0)?x:((i==1)?y:z) ); };
*/
Type Length (void) const /// LENGTH OF VECTOR
{ return ((Type)sqrt(x*x+y*y+z*z)); };
Type LengthSqr (void) const /// LENGTH OF VECTOR (SQUARED)
{ return (x*x+y*y+z*z); };
Vec3& Normalize (void) /// NORMALIZE VECTOR
{ Type L = Length(); // CALCULATE LENGTH
if (L>0) { x/=L; y/=L; z/=L; } // DIV COMPONENTS BY LENGTH
return *this;
};
/// Returns the 'star' matrix for a vector
/** This is the skew-symmetric matrix \b A such that
* \b A \b v == \p this x \b v
* (the cross-product of \p this and \b v), for any vector \b v.
* The matrix looks like this given vector (x,y,z):
* @verbatim
| 0 -z y|
| z 0 -x|
|-y x 0|
@endverbatim
*
* Return format is just an array in row-major (OpenGL/Fortran) order.
* That is [0, -z, y, z, 0, -x, -y, x, 0].
*/
Type* Star() const {
Type s[] = ( 0, -z, y,
z, 0, -x,
-y, x, 0);
return s;
}
/// Update \p Min and \p Max to enclose \p this
/** A very handy routine for working with min-max or axis aligned
* bounding boxes.
*/
void UpdateMinMax(Vec3 &Min, Vec3 &Max) const
{
if (x<Min.x) Min.x=x; else if (x>Max.x) Max.x=x;
if (y<Min.y) Min.y=y; else if (y>Max.y) Max.y=y;
if (z<Min.z) Min.z=z; else if (z>Max.z) Max.z=z;
}
/// Construct an orthonormal basis from \p this
/** Compute two unit vectors \p U and \p V that are orthogonal
* to this vector and to each other. Note that \p *this need
* not be a unit vector.
*
* The algorithm works as follows:
* Find smallest component of L (this), zero it,
* negate one of the other two and swap them. Then normalize.
* Ex. if x1 is the smallest, assign (x2,y2,z2):=(0,z1,-y1)
* Clearly now v1 dot v2 = x1*0 + y1*z1 + z1*-y1 = 0;
* Zeroing out the smallest means that the magnitude of
* the remaining vector will be as big as possible so that
* when we normalize, we are safe from dividing by anything
* close to zero (unless *this was near 0 magnitude to
* begin with, in which case lack of precision can't be avoided)
*/
void CompleteOrthonormalBasis(Vec3 &U, Vec3 &V) const
{
U = *this;
unsigned char s[3] = {0, 1, 2};
unsigned char tmpa;
U.x = U.x < 0 ? -U.x : -U.x;
U.y = U.y < 0 ? -U.y : -U.y;
U.z = U.z < 0 ? -U.z : -U.z;
if ( U[0] > U[1] )
{
tmpa = s[0];
s[0] = s[1];
s[1] = tmpa;
}
// xy min in s[0] now.
if ( U[s[0]] > U[2] ) {
tmpa = s[2];
s[2] = s[0];
s[0] = tmpa;
}
// xyz min in s[0] now
U = *this;
U[s[0]] = 0;
// Voila U is now perpendicular to *this
U.Normalize();
// And so it's easy to find a v that is too, with cross product.
V = *this ^ U;
// Or by removing components projected onto other two...
// I think the cross product may be cheaper
// V = something - V * (*this.Normalize() + U);
V.Normalize(); // wouldn't be necessary if we knew *this were normalized
}
/// Dump the vector to \c stdout in a pretty way
void Print() const
{ printf("(%.3f, %.3f, %.3f)\n",x, y, z); }
/// This is a handy way to get the zero vector just use Vec3<Type>::ZERO
static Vec3 ZERO;
};
typedef Vec3<float> Vec3f;
typedef Vec3<double> Vec3d;
template<class Type> Vec3<Type> Vec3<Type>::ZERO = Vec3<Type>(0,0,0);
#endif

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
// File : vec3fv.cpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// vec3fv.cpp
//============================================================================
#include <stdio.h>
#include <math.h>
void Set3fv(float v[3], float x, float y, float z)
{
v[0]=x;
v[1]=y;
v[2]=z;
}
void Copy3fv(float A[3], const float B[3]) // A=B
{
A[0]=B[0];
A[1]=B[1];
A[2]=B[2];
}
void ScalarMult3fv(float c[3], const float a[3], float s) // c=a*s
{
c[0] = a[0] * s;
c[1] = a[1] * s;
c[2] = a[2] * s;
}
void ScalarDiv3fv(float v[3], float s)
{
v[0] /= s;
v[1] /= s;
v[2] /= s;
}
void Add3fv(float c[3], const float a[3], const float b[3]) // c = a + b
{
c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
}
void Subtract3fv(float c[3], const float a[3], const float b[3]) // c = a - b
{
c[0] = a[0] - b[0];
c[1] = a[1] - b[1];
c[2] = a[2] - b[2];
}
void Negate3fv(float a[3], const float b[3]) // a = -b
{
a[0] = -b[0];
a[1] = -b[1];
a[2] = -b[2];
}
float Length3fv(const float v[3])
{
return( (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
}
void Normalize3fv(float v[3])
{
float l = Length3fv(v);
v[0] /= l;
v[1] /= l;
v[2] /= l;
}
float DotProd3fv(const float a[3], const float b[3])
{
return( a[0]*b[0] + a[1]*b[1] + a[2]*b[2] );
}
void CrossProd3fv(float* C, const float* A, const float* B) // C = A X B
{
Set3fv(C, A[1]*B[2]-A[2]*B[1], A[2]*B[0]-A[0]*B[2], A[0]*B[1]-A[1]*B[0]);
}

View File

@@ -0,0 +1,34 @@
//------------------------------------------------------------------------------
// File : vec3fv.hpp
//------------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//------------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appear in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Binaries may be compiled with this software without any royalties or
// restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//============================================================================
// vec3fv.hpp
//============================================================================
void Set3fv(float v[3], float x, float y, float z);
void Copy3fv(float A[3], const float B[3]); // A=B
void ScalarMult3fv(float c[3], const float a[3], float s);
void ScalarDiv3fv(float v[3], float s);
void Add3fv(float c[3], const float a[3], const float b[3]); // c = a + b
void Subtract3fv(float c[3], const float a[3], const float b[3]); // c = a - b
void Negate3fv(float a[3], const float b[3]); // a = -b
float Length3fv(const float v[3]);
void Normalize3fv(float v[3]);
float DotProd3fv(const float a[3], const float b[3]);
void CrossProd3fv(float* C, const float* A, const float* B); // C = A X B

View File

@@ -0,0 +1,136 @@
//-----------------------------------------------------------------------------
// File : vec4f.hpp
//-----------------------------------------------------------------------------
// GLVU : Copyright 1997 - 2002
// The University of North Carolina at Chapel Hill
//-----------------------------------------------------------------------------
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without
// fee, provided that the above copyright notice appear in all copies
// and that both that copyright notice and this permission notice
// appear in supporting documentation. Binaries may be compiled with
// this software without any royalties or restrictions.
//
// The University of North Carolina at Chapel Hill makes no representations
// about the suitability of this software for any purpose. It is provided
// "as is" without express or implied warranty.
//==========================================================================
// vec4.hpp : 4d vector class template. Works for any integer or real type.
//==========================================================================
#ifndef VEC4_H
#define VEC4_H
#include <stdio.h>
#include <math.h>
template <class Type>
class Vec4
{
public:
Type x, y, z, w;
Vec4 (void)
{};
Vec4 (const Type X, const Type Y, const Type Z, const Type W)
{ x=X; y=Y; z=Z; w=W; };
Vec4 (const Vec4& v)
{ x=v.x; y=v.y; z=v.z; w=v.w; };
Vec4 (const Type v[4])
{ x=v[0]; y=v[1]; z=v[2]; w=v[3]; };
void Set (const Type X, const Type Y, const Type Z, const Type W)
{ x=X; y=Y; z=Z; w=W; }
void Set (const Type v[4])
{ x=v[0]; y=v[1]; z=v[2]; w=v[3]; };
operator Type*() // Type * CONVERSION
{ return (Type *)&x; }
operator const Type*() const // CONST Type * CONVERSION
{ return &x; }
Vec4& operator = (const Vec4& A) // ASSIGNMENT (=)
{ x=A.x; y=A.y; z=A.z; w=A.w;
return(*this); };
bool operator == (const Vec4& A) const // COMPARISON (==)
{ return (x==A.x && y==A.y &&
z==A.z && w==A.w); }
bool operator != (const Vec4& A) const // COMPARISON (!=)
{ return (x!=A.x || y!=A.y ||
z!=A.z || w!=A.w); }
Vec4 operator + (const Vec4& A) const // ADDITION (+)
{ Vec4 Sum(x+A.x, y+A.y, z+A.z, w+A.w);
return(Sum); };
Vec4 operator - (const Vec4& A) const // SUBTRACTION (-)
{ Vec4 Diff(x-A.x, y-A.y, z-A.z, w-A.w);
return(Diff); };
Type operator * (const Vec4& A) const // DOT-PRODUCT (*)
{ Type DotProd = x*A.x+y*A.y+z*A.z+w*A.w;
return(DotProd); };
Vec4 operator * (const Type s) const // MULTIPLY BY SCALAR (*)
{ Vec4 Scaled(x*s, y*s, z*s, w*s);
return(Scaled); };
Vec4 operator / (const Type s) const // DIVIDE BY SCALAR (/)
{ Vec4 Scaled(x/s, y/s, z/s, w/s);
return(Scaled); };
Vec4 operator & (const Vec4& A) const // COMPONENT MULTIPLY (&)
{ Vec4 CompMult(x*A.x, y*A.y, z*A.z, w*A.w);
return(CompMult); }
friend inline Vec4 operator *(Type s, const Vec4& v) // SCALAR MULT s*V
{ return Vec4(v.x*s, v.y*s, v.z*s, v.w*s); }
Vec4& operator += (const Vec4& A) // ACCUMULATED VECTOR ADDITION (+=)
{ x+=A.x; y+=A.y; z+=A.z; w+=A.w;
return *this; }
Vec4& operator -= (const Vec4& A) // ACCUMULATED VECTOR SUBTRCT (-=)
{ x-=A.x; y-=A.y; z-=A.z; w-=A.w;
return *this; }
Vec4& operator *= (const Type s) // ACCUMULATED SCALAR MULT (*=)
{ x*=s; y*=s; z*=s; w*=s;
return *this; }
Vec4& operator /= (const Type s) // ACCUMULATED SCALAR DIV (/=)
{ x/=s; y/=s; z/=s; w/=s;
return *this; }
Vec4& operator &= (const Vec4& A) // ACCUMULATED COMPONENT MULTIPLY (&=)
{ x*=A.x; y*=A.y; z*=A.z; w*=A.w; return *this; }
Vec4 operator - (void) const // NEGATION (-)
{ Vec4 Negated(-x, -y, -z, -w);
return(Negated); };
/*
const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
{ return( (i==0)?x:((i==1)?y:((i==2)?z:w)) ); };
Type & operator [] (const int i)
{ return( (i==0)?x:((i==1)?y:((i==2)?z:w)) ); };
*/
Type Length (void) const // LENGTH OF VECTOR
{ return ((Type)sqrt(x*x+y*y+z*z+w*w)); };
Type LengthSqr (void) const // LENGTH OF VECTOR (SQUARED)
{ return (x*x+y*y+z*z+w*w); };
Vec4& Normalize (void) // NORMALIZE VECTOR
{ Type L = Length(); // CALCULATE LENGTH
if (L>0) { x/=L; y/=L; z/=L; w/=L; }
return *this;
}; // DIV COMPONENTS BY LENGTH
void Wdiv(void)
{ x/=w; y/=w; z/=w; w=1; }
void Print() const
{ printf("(%.3f, %.3f, %.3f, %.3f)\n",x, y, z, w); }
static Vec4 ZERO;
};
typedef Vec4<float> Vec4f;
typedef Vec4<double> Vec4d;
template<class Type> Vec4<Type> Vec4<Type>::ZERO = Vec4<Type>(0,0,0,0);
#endif