From 01113e82f3486f62dccc95400bf5d9e546620d65 Mon Sep 17 00:00:00 2001 From: curt Date: Fri, 13 Sep 2002 20:29:04 +0000 Subject: [PATCH] Initial revision. --- simgear/scene/sky/clouds3d/Makefile.am | 30 + simgear/scene/sky/clouds3d/SkyAABBTree.hpp | 19 + simgear/scene/sky/clouds3d/SkyArchive.cpp | 1201 +++++++++++++++++ simgear/scene/sky/clouds3d/SkyArchive.hpp | 243 ++++ simgear/scene/sky/clouds3d/SkyBVTree.hpp | 297 ++++ .../scene/sky/clouds3d/SkyBVTreeSplitter.hpp | 242 ++++ .../scene/sky/clouds3d/SkyBoundingVolume.hpp | 151 +++ simgear/scene/sky/clouds3d/SkyCloud.cpp | 966 +++++++++++++ simgear/scene/sky/clouds3d/SkyCloud.hpp | 175 +++ .../scene/sky/clouds3d/SkyCloudParticle.hpp | 175 +++ simgear/scene/sky/clouds3d/SkyContext.cpp | 283 ++++ simgear/scene/sky/clouds3d/SkyContext.hpp | 141 ++ simgear/scene/sky/clouds3d/SkyControlled.hpp | 65 + simgear/scene/sky/clouds3d/SkyController.hpp | 56 + .../sky/clouds3d/SkyDynamicTextureManager.cpp | 278 ++++ .../sky/clouds3d/SkyDynamicTextureManager.hpp | 80 ++ simgear/scene/sky/clouds3d/SkyLight.cpp | 221 +++ simgear/scene/sky/clouds3d/SkyLight.hpp | 97 ++ simgear/scene/sky/clouds3d/SkyMaterial.cpp | 322 +++++ simgear/scene/sky/clouds3d/SkyMaterial.hpp | 268 ++++ simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp | 322 +++++ simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp | 85 ++ simgear/scene/sky/clouds3d/SkyRenderable.hpp | 116 ++ .../sky/clouds3d/SkyRenderableInstance.hpp | 202 +++ .../clouds3d/SkyRenderableInstanceCloud.cpp | 705 ++++++++++ .../clouds3d/SkyRenderableInstanceCloud.hpp | 273 ++++ .../clouds3d/SkyRenderableInstanceGeneric.cpp | 136 ++ .../clouds3d/SkyRenderableInstanceGeneric.hpp | 76 ++ .../clouds3d/SkyRenderableInstanceGroup.cpp | 178 +++ .../clouds3d/SkyRenderableInstanceGroup.hpp | 63 + simgear/scene/sky/clouds3d/SkySceneLoader.cpp | 232 ++++ simgear/scene/sky/clouds3d/SkySceneLoader.hpp | 58 + .../scene/sky/clouds3d/SkySceneManager.cpp | 919 +++++++++++++ .../scene/sky/clouds3d/SkySceneManager.hpp | 188 +++ simgear/scene/sky/clouds3d/SkySingleton.hpp | 292 ++++ simgear/scene/sky/clouds3d/SkyTexture.hpp | 96 ++ .../scene/sky/clouds3d/SkyTextureManager.cpp | 883 ++++++++++++ .../scene/sky/clouds3d/SkyTextureManager.hpp | 208 +++ .../scene/sky/clouds3d/SkyTextureState.cpp | 271 ++++ .../scene/sky/clouds3d/SkyTextureState.hpp | 205 +++ simgear/scene/sky/clouds3d/SkyUtil.cpp | 50 + simgear/scene/sky/clouds3d/SkyUtil.hpp | 192 +++ simgear/scene/sky/clouds3d/camdisplay.cpp | 84 ++ simgear/scene/sky/clouds3d/camera.cpp | 409 ++++++ simgear/scene/sky/clouds3d/camera.hpp | 102 ++ simgear/scene/sky/clouds3d/camutils.cpp | 324 +++++ simgear/scene/sky/clouds3d/camutils.hpp | 58 + simgear/scene/sky/clouds3d/mat16fv.cpp | 475 +++++++ simgear/scene/sky/clouds3d/mat16fv.hpp | 119 ++ simgear/scene/sky/clouds3d/mat33.hpp | 113 ++ simgear/scene/sky/clouds3d/mat33impl.hpp | 412 ++++++ simgear/scene/sky/clouds3d/mat44.hpp | 135 ++ simgear/scene/sky/clouds3d/mat44impl.hpp | 536 ++++++++ simgear/scene/sky/clouds3d/mat44test.cpp | 66 + simgear/scene/sky/clouds3d/minmaxbox.cpp | 108 ++ simgear/scene/sky/clouds3d/minmaxbox.hpp | 30 + simgear/scene/sky/clouds3d/plane.cpp | 302 +++++ simgear/scene/sky/clouds3d/plane.hpp | 51 + simgear/scene/sky/clouds3d/quat.hpp | 166 +++ simgear/scene/sky/clouds3d/quatimpl.hpp | 886 ++++++++++++ simgear/scene/sky/clouds3d/quattest.cpp | 196 +++ simgear/scene/sky/clouds3d/tri.cpp | 106 ++ simgear/scene/sky/clouds3d/tri.hpp | 30 + simgear/scene/sky/clouds3d/vec2f.hpp | 137 ++ simgear/scene/sky/clouds3d/vec3f.hpp | 244 ++++ simgear/scene/sky/clouds3d/vec3fv.cpp | 95 ++ simgear/scene/sky/clouds3d/vec3fv.hpp | 34 + simgear/scene/sky/clouds3d/vec4f.hpp | 136 ++ 68 files changed, 16414 insertions(+) create mode 100644 simgear/scene/sky/clouds3d/Makefile.am create mode 100644 simgear/scene/sky/clouds3d/SkyAABBTree.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyArchive.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyArchive.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyBVTree.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyBVTreeSplitter.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyBoundingVolume.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyCloud.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyCloud.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyCloudParticle.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyContext.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyContext.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyControlled.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyController.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyDynamicTextureManager.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyLight.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyLight.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyMaterial.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyMaterial.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderable.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstance.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.hpp create mode 100644 simgear/scene/sky/clouds3d/SkySceneLoader.cpp create mode 100644 simgear/scene/sky/clouds3d/SkySceneLoader.hpp create mode 100644 simgear/scene/sky/clouds3d/SkySceneManager.cpp create mode 100644 simgear/scene/sky/clouds3d/SkySceneManager.hpp create mode 100644 simgear/scene/sky/clouds3d/SkySingleton.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyTexture.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyTextureManager.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyTextureManager.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyTextureState.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyTextureState.hpp create mode 100644 simgear/scene/sky/clouds3d/SkyUtil.cpp create mode 100644 simgear/scene/sky/clouds3d/SkyUtil.hpp create mode 100644 simgear/scene/sky/clouds3d/camdisplay.cpp create mode 100644 simgear/scene/sky/clouds3d/camera.cpp create mode 100644 simgear/scene/sky/clouds3d/camera.hpp create mode 100644 simgear/scene/sky/clouds3d/camutils.cpp create mode 100644 simgear/scene/sky/clouds3d/camutils.hpp create mode 100644 simgear/scene/sky/clouds3d/mat16fv.cpp create mode 100644 simgear/scene/sky/clouds3d/mat16fv.hpp create mode 100644 simgear/scene/sky/clouds3d/mat33.hpp create mode 100644 simgear/scene/sky/clouds3d/mat33impl.hpp create mode 100644 simgear/scene/sky/clouds3d/mat44.hpp create mode 100644 simgear/scene/sky/clouds3d/mat44impl.hpp create mode 100644 simgear/scene/sky/clouds3d/mat44test.cpp create mode 100644 simgear/scene/sky/clouds3d/minmaxbox.cpp create mode 100644 simgear/scene/sky/clouds3d/minmaxbox.hpp create mode 100644 simgear/scene/sky/clouds3d/plane.cpp create mode 100644 simgear/scene/sky/clouds3d/plane.hpp create mode 100644 simgear/scene/sky/clouds3d/quat.hpp create mode 100644 simgear/scene/sky/clouds3d/quatimpl.hpp create mode 100644 simgear/scene/sky/clouds3d/quattest.cpp create mode 100644 simgear/scene/sky/clouds3d/tri.cpp create mode 100644 simgear/scene/sky/clouds3d/tri.hpp create mode 100644 simgear/scene/sky/clouds3d/vec2f.hpp create mode 100644 simgear/scene/sky/clouds3d/vec3f.hpp create mode 100644 simgear/scene/sky/clouds3d/vec3fv.cpp create mode 100644 simgear/scene/sky/clouds3d/vec3fv.hpp create mode 100644 simgear/scene/sky/clouds3d/vec4f.hpp diff --git a/simgear/scene/sky/clouds3d/Makefile.am b/simgear/scene/sky/clouds3d/Makefile.am new file mode 100644 index 00000000..06cf29f9 --- /dev/null +++ b/simgear/scene/sky/clouds3d/Makefile.am @@ -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 diff --git a/simgear/scene/sky/clouds3d/SkyAABBTree.hpp b/simgear/scene/sky/clouds3d/SkyAABBTree.hpp new file mode 100644 index 00000000..81fecddc --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyAABBTree.hpp @@ -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 SkyAABBTree : public SkyBVTree > +{}; + +#endif //__SKYAABBTREE_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyArchive.cpp b/simgear/scene/sky/clouds3d/SkyArchive.cpp new file mode 100644 index 00000000..4b6bcc9f --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyArchive.cpp @@ -0,0 +1,1201 @@ +//------------------------------------------------------------------------------ +// File : SkyArchive.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 SkyArchive.cpp + * + * Implementation of class SkyArchive. + */ +#include "SkyArchive.hpp" + +#include + +struct SkyArchiveEntry +{ + SkyArchiveEntry() : type(0), pData(NULL), iDataSize(0) {} + unsigned char type; + void* pData; + unsigned int iDataSize; +}; + +struct SkyArchiveFileEntry +{ + SkyArchiveFileEntry() : type(0), iDataSize(0) {} + unsigned char type; + char pName[32]; + unsigned int iDataSize; +}; + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::SkyArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::SkyArchive() + * @brief Default constructor. Creates an empty, unnamed archive. | + */ +SkyArchive::SkyArchive() +: _pName(NULL) +{ +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::SkyArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::SkyArchive(const char* pName) + * @brief Constructor. Creates an empty, named archive. + */ +SkyArchive::SkyArchive(const char* pName) +{ + _pName = new char[::strlen(pName)+1]; + ::strcpy( _pName, pName); +} + + +//.---------------------------------------------------------------------------. +//| Function : SkyArchive::SkyArchive | +//| Description: +//.---------------------------------------------------------------------------. + +//------------------------------------------------------------------------------ +// Function : SkyArchive::SkyArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::SkyArchive(const SkyArchive& src) + * @brief Copy constructor. Deep-copies the contents of one archive to another. + */ +SkyArchive::SkyArchive(const SkyArchive& src) +{ + _pName = new char[::strlen(src._pName)+1]; + ::strcpy( _pName, src._pName); + + _CopyDataTable( src._dataTable); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::~SkyArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::~SkyArchive() + * @brief Destructor. + */ +SkyArchive::~SkyArchive() +{ + MakeEmpty(); + SAFE_DELETE_ARRAY(_pName); +} + + +//.---------------------------------------------------------------------------. +//| Function : SkyArchive::operator= | +//| Description: | +//.---------------------------------------------------------------------------. + +//------------------------------------------------------------------------------ +// Function : SkyArchive::operator= +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::operator=( const SkyArchive& src) + * @brief @todo Deep-copies the contents of one archive to another. + */ +SkyArchive& SkyArchive::operator=( const SkyArchive& src) +{ + if (this != &src) + { + MakeEmpty(); + SAFE_DELETE_ARRAY(_pName); + _pName = new char[::strlen(src._pName)+1]; + ::strcpy( _pName, src.GetName()); + + _CopyDataTable( src._dataTable); + } + return *this; +} + + + +//============================================================================= +// Adding Content to SkyArchive +//============================================================================= + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddData +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyArchive::AddData(const char* pName, +SkyArchiveTypeCode eType, +const void* pData, +unsigned int iNumBytes, +unsigned int iNumItems) +* @brief Adds a new data field to the archive. +* +* Makes a copy of the data, stores it in a SkyArchiveEntry, and adds it to the +* database. All specialized functions for the base types are implemented using +* this function. +* +* PARAMETERS +* @param name Field name. This is used as the key for the database entry. +* @param type Data type of the field. +* @param pData Pointer to the data to be added to the archive. +* @param iNumBytes Size of each individual item in the data +* @param iNumItems Number of items to copy +*/ +SKYRESULT SkyArchive::AddData(const char* pName, + SkyArchiveTypeCode eType, + const void* pData, + unsigned int iNumBytes, + unsigned int iNumItems /* = 1 */) +{ + // fill out a new archive entry with the supplied data + SkyArchiveEntry* pNewEntry = new SkyArchiveEntry; + pNewEntry->type = eType; + pNewEntry->iDataSize = iNumBytes * iNumItems; + + if (eType != ARCHIVE_TYPE) + { + pNewEntry->pData = new unsigned char[pNewEntry->iDataSize]; + ::memcpy(pNewEntry->pData, pData, pNewEntry->iDataSize); + } + else + { + pNewEntry->pData = (void*)pData; + } + + char* pInternalName = new char[::strlen(pName)+1]; + ::strcpy( pInternalName, pName); + _dataTable.insert(std::make_pair(pInternalName, pNewEntry)); + + return SKYRESULT_OK; +} + + +//----------------------------------------------------------------------------- +// SkyArchive :: AddBool( const char* pName, bool aBool) +// SkyArchive :: AddInt8( const char* pName, Int8 anInt8) +// SkyArchive :: AddInt16( const char* pName, Int16 anInt16) +// SkyArchive :: AddInt32( const char* pName, Int32 anInt32) +// ... +//----------------------------------------------------------------------------- +// +// Specialized functions for the most common base types +// +//----------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddBool +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddBool(const char* pName, bool aBool) + * @brief Adds a named bool to the archive. + */ +SKYRESULT SkyArchive::AddBool(const char* pName, bool aBool) +{ + return AddData( pName, BOOL_TYPE, &aBool, sizeof(bool)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddInt8 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddInt8(const char* pName, char anInt8) + * @brief Adds a named 8-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddInt8(const char* pName, char anInt8) +{ + return AddData( pName, INT8_TYPE, &anInt8, sizeof(char)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddInt16 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddInt16(const char* pName, short anInt16) + * @brief Adds a named 16-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddInt16(const char* pName, short anInt16) +{ + return AddData( pName, INT16_TYPE, &anInt16, sizeof(short)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddInt32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddInt32(const char* pName, int anInt32) + * @brief Adds a named 32-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddInt32(const char* pName, int anInt32) +{ + return AddData( pName, INT32_TYPE, &anInt32, sizeof(int)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddUInt8 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddUInt8(const char* pName, unsigned char anUInt8) + * @brief Adds a named unsigned 8-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddUInt8(const char* pName, unsigned char anUInt8) +{ + return AddData( pName, UINT8_TYPE, &anUInt8, sizeof(unsigned char)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddUInt16 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddUInt16(const char* pName, unsigned short anUInt16) + * @brief Adds a named unsigned 16-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddUInt16(const char* pName, unsigned short anUInt16) +{ + return AddData( pName, UINT16_TYPE, &anUInt16, sizeof(unsigned short)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddUInt32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddUInt32(const char* pName, unsigned int anUInt32) + * @brief Adds a named unsigned 32-bit integer to the archive. + */ +SKYRESULT SkyArchive::AddUInt32(const char* pName, unsigned int anUInt32) +{ + return AddData( pName, UINT32_TYPE, &anUInt32, sizeof(unsigned int)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddFloat32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddFloat32(const char* pName, float aFloat32) + * @brief Adds a named 32-bit real number to the archive. + */ +SKYRESULT SkyArchive::AddFloat32(const char* pName, float aFloat32) +{ + return AddData( pName, FLOAT32_TYPE, &aFloat32, sizeof(float)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddFloat64 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddFloat64(const char* pName, double aFloat64) + * @brief Adds a named 64-bit real number to the archive. + */ +SKYRESULT SkyArchive::AddFloat64(const char* pName, double aFloat64) +{ + return AddData( pName, FLOAT64_TYPE, &aFloat64, sizeof(double)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddString +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddString(const char* pName, const char* pString) + * @brief Adds a named string to the archive. + */ +SKYRESULT SkyArchive::AddString(const char* pName, const char* pString) +{ + return AddData( pName, STRING_TYPE, pString, ::strlen(pString)+1); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddArchive(const SkyArchive& anArchive) + * @brief Adds a subarchive to this archive. + * + * This method allows hierarchical data structures to be stored in an archive. + */ +SKYRESULT SkyArchive::AddArchive(const SkyArchive& anArchive) +{ + SkyArchive* pCopy = new SkyArchive(anArchive); + return AddData( pCopy->GetName(), ARCHIVE_TYPE, pCopy, sizeof(SkyArchive)); +} + +//----------------------------------------------------------------------------- +// Adding Vector types +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddVec2f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddVec2f(const char* pName, const Vec2f& aVec2f) + * @brief Adds a 2-component 32-bit real number vector to the archive. + */ +SKYRESULT SkyArchive::AddVec2f(const char* pName, const Vec2f& aVec2f) +{ + return AddData( pName, VEC2F_TYPE, &aVec2f, sizeof(Vec2f)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddVec3f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddVec3f(const char* pName, const Vec3f& aVec3f) + * @brief Adds a 3-component 32-bit real number vector to the archive. + */ +SKYRESULT SkyArchive::AddVec3f(const char* pName, const Vec3f& aVec3f) +{ + return AddData( pName, VEC3F_TYPE, &aVec3f, sizeof(Vec3f)); +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AddVec4f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AddVec4f(const char* pName, const Vec4f& aVec4f) + * @brief Adds a 4-component 32-bit real number vector to the archive. + */ +SKYRESULT SkyArchive::AddVec4f(const char* pName, const Vec4f& aVec4f) +{ + return AddData( pName, VEC4F_TYPE, &aVec4f, sizeof(Vec4f)); +} + +//============================================================================= +// Retrieving Content from SkyArchive +//============================================================================= + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindData +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindData(const char* pName, + SkyArchiveTypeCode eType, + void** const pData, + unsigned int* pNumBytes, + unsigned int index) const + * @brief Retrieves datafield from _dataTable. + * + * PARAMETERS + * @param name The field name. used as the key for the multimap entry. + * @param type Data type of the field. + * @param pData Pointer to the returned data. + * @param pNumBytes Returns the size of the field entry returned. + * @param index Which item of the given \a name to locate. + */ +SKYRESULT SkyArchive::FindData(const char* pName, + SkyArchiveTypeCode eType, + void** const pData, + unsigned int* pNumBytes, + unsigned int index /* = 0 */) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, eType); + if (pEntry) + { + if (pData) + { + *pData = new unsigned char[pEntry->iDataSize]; + ::memcpy( ((void*)*pData), pEntry->pData, pEntry->iDataSize); + } + + if (pNumBytes) + { + *pNumBytes = pEntry->iDataSize; + } + + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + + +//----------------------------------------------------------------------------- +// SkyArchive :: FindBool( const char* pName, bool* aBool) +// SkyArchive :: FindInt8( const char* pName, Int8* anInt8) +// SkyArchive :: FindInt16( const char* pName, Int16* anInt16) +// SkyArchive :: FindInt32( const char* pName, Int32* anInt32) +// ... +//----------------------------------------------------------------------------- +// +// specialized function for the most common base types +// +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindBool +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindBool(const char* pName, bool* pBool, unsigned int index) const + * @brief Finds a named bool in the archive. + */ +SKYRESULT SkyArchive::FindBool(const char* pName, bool* pBool, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, BOOL_TYPE); + if (pEntry) + { + bool* pData = (bool*)(pEntry->pData); + *pBool = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindInt8 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindInt8(const char* pName, char* pInt8, unsigned int index) const + * @brief Finds a named 8-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindInt8(const char* pName, char* pInt8, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT8_TYPE); + if (pEntry) + { + char* pData = (char*)(pEntry->pData); + *pInt8 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindInt16 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindInt16(const char* pName, short* pInt16, unsigned int index) const + * @brief Finds a named 16-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindInt16(const char* pName, short* pInt16, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT16_TYPE); + if (pEntry) + { + short* pData = (short*)(pEntry->pData); + *pInt16 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindInt32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindInt32(const char* pName, int* pInt32, unsigned int index) const + * @brief Finds a named 32-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindInt32(const char* pName, int* pInt32, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, INT32_TYPE); + if (pEntry) + { + int* pData = (int*)(pEntry->pData); + *pInt32 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindUInt8 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindUInt8(const char* pName, unsigned char* pUInt8, unsigned int index) const + * @brief Finds a named unsigned 8-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindUInt8(const char* pName, unsigned char* pUInt8, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT8_TYPE); + if (pEntry) + { + unsigned char* pData = (unsigned char*)(pEntry->pData); + *pUInt8 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindUInt16 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindUInt16(const char* pName, unsigned short* pUInt16, unsigned int index) const + * @brief Finds a named unsigned 16-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindUInt16(const char* pName, unsigned short* pUInt16, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT16_TYPE); + if (pEntry) + { + unsigned short* pData = (unsigned short*)(pEntry->pData); + *pUInt16 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindUInt32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindUInt32(const char* pName, unsigned int* pUInt32, unsigned int index) const + * @brief Finds a named unsigned 32-bit integer in the archive. + */ +SKYRESULT SkyArchive::FindUInt32(const char* pName, unsigned int* pUInt32, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, UINT32_TYPE); + if (pEntry) + { + unsigned int* pData = (unsigned int*)(pEntry->pData); + *pUInt32 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindFloat32 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindFloat32(const char* pName, float* pFloat32, unsigned int index) const + * @brief Finds a named 32-bit real number in the archive. + */ +SKYRESULT SkyArchive::FindFloat32(const char* pName, float* pFloat32, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, FLOAT32_TYPE); + if (pEntry) + { + float* pData = (float*)(pEntry->pData); + *pFloat32 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindFloat64 +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindFloat64(const char* pName, double* pFloat64, unsigned int index) const + * @brief Finds a named 64-bit real number in the archive. + */ +SKYRESULT SkyArchive::FindFloat64(const char* pName, double* pFloat64, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, FLOAT64_TYPE); + if (pEntry) + { + double* pData = (double*)(pEntry->pData); + *pFloat64 = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindString +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindString(const char* pName, char** const pString, unsigned int index) const + * @brief Finds a named string in the archive. + */ +SKYRESULT SkyArchive::FindString(const char* pName, char** const pString, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, STRING_TYPE); + if (pEntry) + { + char* pData = (char*)(pEntry->pData); + *pString = new char[pEntry->iDataSize]; + ::strcpy((char*)*pString, pData); + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index) const + * @brief Finds a named sub-archive in the archive. + */ +SKYRESULT SkyArchive::FindArchive(const char* pName, SkyArchive* pArchive, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, ARCHIVE_TYPE); + if (pEntry) + { + SkyArchive* pData = (SkyArchive*)(pEntry->pData); + *pArchive = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindVec2f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindVec2f(const char* pName, Vec2f* pVec2f, unsigned int index) const + * @brief Finds a 2-component 32-bit real number vector in the archive. + */ +SKYRESULT SkyArchive::FindVec2f(const char* pName, Vec2f* pVec2f, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC2F_TYPE); + if (pEntry) + { + Vec2f* pData = (Vec2f*)(pEntry->pData); + *pVec2f = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindVec3f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindVec3f(const char* pName, Vec3f* pVec3f, unsigned int index) const + * @brief Finds a 3-component 32-bit real number vector in the archive. + */ +SKYRESULT SkyArchive::FindVec3f(const char* pName, Vec3f* pVec3f, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC3F_TYPE); + if (pEntry) + { + Vec3f* pData = (Vec3f*)(pEntry->pData); + *pVec3f = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::FindVec4f +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::FindVec4f(const char* pName, Vec4f* pVec4f, unsigned int index) const + * @brief Finds a 4-component 32-bit real number vector in the archive. + */ +SKYRESULT SkyArchive::FindVec4f(const char* pName, Vec4f* pVec4f, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, VEC4F_TYPE); + if (pEntry) + { + Vec4f* pData = (Vec4f*)(pEntry->pData); + *pVec4f = *pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::AccessArchive +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index) const + * @brief Accesses a named sub-archive in an archive directly. + * + * Note: The data are not copied! + */ +SKYRESULT SkyArchive::AccessArchive(const char* pName, SkyArchive** pArchive, unsigned int index) const +{ + const SkyArchiveEntry* pEntry = _FindEntry(pName, index, ARCHIVE_TYPE); + if (pEntry) + { + SkyArchive* pData = (SkyArchive*)(pEntry->pData); + *pArchive = pData; + return SKYRESULT_OK; + } + return SKYRESULT_FAIL; +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::GetInfo +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::GetInfo(const char* pName, SkyArchiveTypeCode eType, unsigned int* pNumFound) const + * @brief Computes the number of fields that contain the given name and type. + * + * PARAMETERS + * @param pName Field name to search for. + * @param eType Field type to search for. + * @param pNumFound Returns the number of fields that contain given name and type. + */ +SKYRESULT SkyArchive::GetInfo(const char* pName, + SkyArchiveTypeCode eType, + unsigned int* pNumFound) const +{ + // + // Find the range of entries in the mmap with the key matching pName + // + std::pair b = _dataTable.equal_range((char*)pName); + + unsigned int count = 0; + for ( SkyMMapConstIter i = b.first; i != b.second; ++i ) + { + // + // The entry's type must match... + // + const SkyArchiveEntry* pEntry = (*i).second; + if (pEntry->type == eType || ANY_TYPE == eType) + { + // only increment the count when the type matches + ++count; + } + } + + if (pNumFound) + { + *pNumFound = count; + } + + if (0 == count) + return SKYRESULT_FAIL; + + return SKYRESULT_OK; +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::GetInfo +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::GetInfo(unsigned int iNameIndex, char** pNameFound, SkyArchiveTypeCode* pTypeCode, unsigned int* pNumFound) + * @brief Returns information about the key at the specified index. + * + * PARAMETERS + * @param nameIndex Key index to look up. + * @param pNameFound Key name is returned here. + * @param pTypeCode Key type is returned here. + * @param pNumFound Number of fields held under key name is returned here. + */ +SKYRESULT SkyArchive::GetInfo(unsigned int iNameIndex, + char** pNameFound, + SkyArchiveTypeCode* pTypeCode, + unsigned int* pNumFound) +{ + assert( pNameFound != NULL); + + if (!pNameFound) + return SKYRESULT_FAIL; + + unsigned int iCurrentKeyIndex = 0; + SkyMMapConstIter iter; + const char* pLastKey = ""; + + for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++) + { + const char* pKey = (*iter).first; + if (::strcmp( pLastKey, pKey)) + { + if (iCurrentKeyIndex == iNameIndex) + { + *pNameFound = new char[::strlen(pKey) + 1]; + ::strcpy(*pNameFound, pKey); + + if (pTypeCode) + { + const SkyArchiveEntry* pEntry = (*iter).second; + *pTypeCode = (SkyArchiveTypeCode)pEntry->type; + } + + if (pNumFound) + { + return GetInfo( *pNameFound, *pTypeCode, pNumFound); + } + return SKYRESULT_OK; + } + + pLastKey = pKey; + ++iCurrentKeyIndex; + } + } + return SKYRESULT_FAIL; +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::GetNumUniqueNames +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyArchive::GetNumUniqueNames() const +* @brief Computes the number of unique key names in _dataTable. +*/ +unsigned int SkyArchive::GetNumUniqueNames() const +{ + // duh! + if (IsEmpty()) + return 0; + + unsigned int iNumKeys = 0; + SkyMMapConstIter iter; + const char* pLastKey = ""; + + for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++) + { + const char* pKey = (*iter).first; + if (::strcmp( pLastKey, pKey)) + { + ++iNumKeys; + pLastKey = pKey; + } + } + return iNumKeys; +} + + +//============================================================================= +// Removing Contents of SkyArchive +//============================================================================= + +//------------------------------------------------------------------------------ +// Function : SkyArchive::MakeEmpty +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyArchive::MakeEmpty() +* @brief Remove all the contents of the database. +*/ +SKYRESULT SkyArchive::MakeEmpty() +{ + SkyMMapIter iter; + + for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++) + { + SkyArchiveEntry* pEntry = (*iter).second; + char* pName = (*iter).first; + SAFE_DELETE_ARRAY(pName); + + if (ARCHIVE_TYPE == pEntry->type) + { + SkyArchive* pArchive = (SkyArchive*)(pEntry->pData); + SAFE_DELETE(pArchive); + } + else + { + SAFE_DELETE_ARRAY(pEntry->pData); + } + SAFE_DELETE(pEntry); + } + + _dataTable.clear(); + + return SKYRESULT_OK; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::IsEmpty +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyArchive::IsEmpty() const +* @brief returns true if the archive is empty, false if it contains any data. +*/ +bool SkyArchive::IsEmpty() const +{ + return (0 == _dataTable.size()); +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::Load +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::Load(const char* pFileName) + * @brief Load the contents of a SkyArchive from file storage. + */ +SKYRESULT SkyArchive::Load(const char* pFileName) +{ + if (!pFileName) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Load(): file name is NULL."); + + FILE* pSrcFile = NULL; + + if (NULL == (pSrcFile = fopen(pFileName, "rb"))) // file opened successfully + { + SkyTrace("Error: SkyArchive::Load(): failed to open file for reading."); + return SKYRESULT_FAIL; + } + + SKYRESULT retVal = _Load(pSrcFile); + fclose(pSrcFile); + + FAIL_RETURN(retVal); + return SKYRESULT_OK; +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::Commit +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::Save(const char* pFilename) const + * @brief Commit Contents of SkyArchive to file storage. + */ +SKYRESULT SkyArchive::Save(const char* pFileName) const +{ + if (!pFileName) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Save(): file name is NULL."); + + FILE* pDestFile = NULL; + + if (NULL == (pDestFile = fopen(pFileName, "wb"))) // file opened successfully + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::Save(): failed to open file for writing."); + + SKYRESULT retVal = _Save(pDestFile); + fflush(pDestFile); + fclose(pDestFile); + + FAIL_RETURN(retVal); + return SKYRESULT_OK; +} + + +//============================================================================= +// Private helper functions +//============================================================================= + +//------------------------------------------------------------------------------ +// Function : SkyArchive::_FindEntry +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::_FindEntry(const char* pName, unsigned int index, SkyArchiveTypeCode eType) const + * @brief Locates and returns the SkyArchiveEntry with the specified name, index, and type. + * + * PARAMETERS + * @param pName Entry name to locate (this is used as the database key) + * @param index Entry index to locate (in case of multiple entries) + * @param type Entry must have this type (@see SkyArchiveTypeCode) + * + * Returns a pointer to the entry or NULL if no matching entry could be located. + */ +const SkyArchiveEntry* SkyArchive::_FindEntry(const char* pName, + unsigned int index, + SkyArchiveTypeCode eType) const +{ + // + // Find the range of entries in the mmap with the key matching /name/ + // + std::pair< SkyMMapConstIter, SkyMMapConstIter > b = _dataTable.equal_range((char*)pName); + + unsigned int count = 0; + for (SkyMMapConstIter i = b.first; (i != b.second) && (count <= index); ++i) + { + // + // The entry's type and index must match... + // + const SkyArchiveEntry* pEntry = (*i).second; + if (pEntry->type == eType) + { + if (count == index) + { + return pEntry; + } + + // only increment the count when the type matches + ++count; + } + } + return NULL; +} + + +//.---------------------------------------------------------------------------. +//| Function : SkyArchive::_CopyDataTable | +//| Description: | +//.---------------------------------------------------------------------------. +void SkyArchive::_CopyDataTable( const SkyArchiveMMap& src) +{ + SkyMMapConstIter iter; + + for (iter = src.begin(); iter != src.end(); iter++) + { + const SkyArchiveEntry* pSrcEntry = (*iter).second; + const char* pSrcName = (*iter).first; + + if (ARCHIVE_TYPE == pSrcEntry->type) + { + SkyArchive* pSrcArchive = (SkyArchive*)pSrcEntry->pData; + AddArchive(*pSrcArchive); + } + else + { + SkyArchiveEntry* pNewEntry = new SkyArchiveEntry; + pNewEntry->type = pSrcEntry->type; + pNewEntry->iDataSize = pSrcEntry->iDataSize; + pNewEntry->pData = new unsigned char[pNewEntry->iDataSize]; + ::memcpy( pNewEntry->pData, pSrcEntry->pData, pNewEntry->iDataSize); + + char* pName = new char[::strlen(pSrcName)+1]; + ::strcpy( pName, pSrcName ); + _dataTable.insert(std::make_pair(pName, pNewEntry)); + } + } +} + +//------------------------------------------------------------------------------ +// Function : SkyArchive::_Save +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkyArchive::_Save(FILE* pDestFile) const + * @brief Saves data to a file (possibly recursively in the case of subarchives). + */ +SKYRESULT SkyArchive::_Save(FILE* pDestFile) const +{ + // fill out a record for this archive & write it + SkyArchiveFileEntry me; + me.type = ARCHIVE_TYPE; + ::strncpy( me.pName, _pName, 32); + me.iDataSize = _dataTable.size(); + + size_t iNumItemsWritten = fwrite((const void*)&me, sizeof(SkyArchiveFileEntry), 1, pDestFile); + + if (1 > iNumItemsWritten) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive header."); + + SkyMMapConstIter iter; + for (iter = _dataTable.begin(); iter != _dataTable.end(); iter++) + { + // fill out a record for each item in _dataTable & write it + const SkyArchiveEntry* pEntry = (*iter).second; + switch(pEntry->type) + { + case ARCHIVE_TYPE: + { + ((SkyArchive*)(pEntry->pData))->_Save(pDestFile); + break; + } + + default: + { + SkyArchiveFileEntry item; + item.type = pEntry->type; + ::strncpy( item.pName, (*iter).first, 32); + item.iDataSize = pEntry->iDataSize; + + iNumItemsWritten = fwrite((const void*)&item, sizeof(SkyArchiveFileEntry), 1, pDestFile); + if (1 > iNumItemsWritten) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive Entry header."); + iNumItemsWritten = fwrite((const void*)pEntry->pData, pEntry->iDataSize, 1, pDestFile); + if (1 > iNumItemsWritten) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Save(): failed to write Archive Entry data."); + break; + } + } + } + return SKYRESULT_OK; +} + + +//------------------------------------------------------------------------------ +// Function : SkyArchive::_Load +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyArchive::_Load( FILE* pSrcFile) +* @brief Loads data from a file (possibly recursively in the case of subarchives). +*/ +SKYRESULT SkyArchive::_Load( FILE* pSrcFile) +{ + // first make sure the file is open and readable. + + // load the first record + SkyArchiveFileEntry thisItem; + size_t iNumItemsRead = fread((void*)&thisItem, sizeof(SkyArchiveFileEntry), 1, pSrcFile); + if (1 > iNumItemsRead) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read Archive header."); + + _pName = new char[::strlen(thisItem.pName)+1]; + ::strcpy( _pName, thisItem.pName); + + for (unsigned int iNumItems = 0; iNumItems < thisItem.iDataSize; ++iNumItems) + { + SkyArchiveFileEntry embeddedItem; + long iFileLoc = ftell(pSrcFile); // store location before the read + iNumItemsRead = fread((void*)&embeddedItem, sizeof(SkyArchiveFileEntry), 1, pSrcFile); + if (1 > iNumItemsRead) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read embedded archive item."); + + switch( embeddedItem.type) + { + case ARCHIVE_TYPE: + { + if (0 != fseek(pSrcFile, iFileLoc, SEEK_SET)) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to set the file position."); + SkyArchive newArchive; + newArchive._Load(pSrcFile); // recursively load the subarchive + AddArchive(newArchive); // add the loaded archive to the database in memory. + } + break; + default: + { + void* pData = new unsigned char[embeddedItem.iDataSize]; + iNumItemsRead = fread((void*)pData, embeddedItem.iDataSize, 1, pSrcFile); + if (1 > iNumItemsRead) + FAIL_RETURN_MSG(SKYRESULT_FAIL, "Error: SkyArchive::_Load(): failed to read item data."); + AddData( embeddedItem.pName, + (SkyArchiveTypeCode)embeddedItem.type, + pData, + embeddedItem.iDataSize); + delete[] pData; + break; + } + } + } + return SKYRESULT_OK; +} diff --git a/simgear/scene/sky/clouds3d/SkyArchive.hpp b/simgear/scene/sky/clouds3d/SkyArchive.hpp new file mode 100644 index 00000000..a6aae02b --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyArchive.hpp @@ -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 // 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 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyBVTree.hpp b/simgear/scene/sky/clouds3d/SkyBVTree.hpp new file mode 100644 index 00000000..d7aaa012 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyBVTree.hpp @@ -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 +#include + +//----------------------------------------------------------------------------- +// SkyBaseBVTree +//----------------------------------------------------------------------------- +// See header description for details. +//----------------------------------------------------------------------------- +template +class SkyBaseBVTree +{ +public: + typedef BoundingVolume BV; + class NodeObject; + +public: + class Node + { + friend class SkyBaseBVTree; + 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& 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 +void ClearVector(std::vector& vec) +{ + std::vector().swap(vec); +} + + +//----------------------------------------------------------------------------- +// SkyBVTree +//----------------------------------------------------------------------------- +// See header description for details. +//----------------------------------------------------------------------------- +template +class SkyBVTree : public SkyBaseBVTree +{ +public: + typedef SkyBaseBVTree 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 _nodes; + std::vector _objList; +}; + +#endif //__SKYBVTREE_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyBVTreeSplitter.hpp b/simgear/scene/sky/clouds3d/SkyBVTreeSplitter.hpp new file mode 100644 index 00000000..83f25134 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyBVTreeSplitter.hpp @@ -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 +//#if _MSC_VER == 1200 +//#include +//#endif +//---------------------------------------------------------------------------- +//-- Forward Declarations ---------------------------------------------------- +//---------------------------------------------------------------------------- +// A strategy for splitting nodes compatible with bounding boxes and spheres. +template class SkyBoundingBoxSplitter; +// SkyBVTree compatible node splitters implemented using the above strategy. +template class SkyAABBTreeSplitter; +//template 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 SkyBoundingBoxSplitter +{ +public: + typedef SkyBaseBVTree::NodeObject NodeObjectBox; + //typedef SkyBaseBVTree::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 + SkyBoundingBoxSplitter(const SkyBaseBVTree::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 + bool SplitLeft(const nodeObj& obj) const + { + if (_bIsolateLongObjects) + return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength; + else + return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue; + } + + template + bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const + { + return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV()); + } + + const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; } + +private: + template + 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 SkyAABBTreeSplitter +{ +public: + typedef SkyMinMaxBox BV; + typedef SkyBaseBVTree::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 _splitter; +}; + +//---------------------------------------------------------------------------- +// SkySphereTreeSplitter +//---------------------------------------------------------------------------- +// A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere. +// Implemented using the SkyBoundingBoxSplitter strategy. +//---------------------------------------------------------------------------- +/*template +class SkySphereTreeSplitter +{ +public: + typedef SkyBoundingSphere BV; + typedef SkyBaseBVTree::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 _splitter; +};*/ + +#endif //__SKYBVTREESPLITTER_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyBoundingVolume.hpp b/simgear/scene/sky/clouds3d/SkyBoundingVolume.hpp new file mode 100644 index 00000000..9f2242cd --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyBoundingVolume.hpp @@ -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 +#include + +// 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 ¢er) + * @brief Sets the center of the bounding volume. + */ + virtual void SetCenter(const Vec3f ¢er) { _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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyCloud.cpp b/simgear/scene/sky/clouds3d/SkyCloud.cpp new file mode 100644 index 00000000..26640d3c --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyCloud.cpp @@ -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 + +//! 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 +*/ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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; y1) 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 Rayleigh + * scattering. The phase function for Rayleigh scattering is + * p(q) = 0.75*(1 + cos2(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)) +} diff --git a/simgear/scene/sky/clouds3d/SkyCloud.hpp b/simgear/scene/sky/clouds3d/SkyCloud.hpp new file mode 100644 index 00000000..6eeb5bbc --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyCloud.hpp @@ -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 l, 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 l. 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 ParticleArray; + typedef ParticleArray::iterator ParticleIterator; + typedef ParticleArray::const_iterator ParticleConstIterator; + + typedef std::vector 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyCloudParticle.hpp b/simgear/scene/sky/clouds3d/SkyCloudParticle.hpp new file mode 100644 index 00000000..0b9c15b7 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyCloudParticle.hpp @@ -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 + +//------------------------------------------------------------------------------ +/** + * @class SkyCloudParticle + * @brief A class for particles that make up a cloud. + * + * @todo + */ +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 _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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyContext.cpp b/simgear/scene/sky/clouds3d/SkyContext.cpp new file mode 100644 index 00000000..b8727f07 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyContext.cpp @@ -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 +#include + +//#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 +*/ +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 + */ +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 + * + * @todo + */ +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::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::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::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::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; +} diff --git a/simgear/scene/sky/clouds3d/SkyContext.hpp b/simgear/scene/sky/clouds3d/SkyContext.hpp new file mode 100644 index 00000000..e6d08040 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyContext.hpp @@ -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 +#include +#include + +// 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 GraphicsContext; + +//------------------------------------------------------------------------------ +/** + * @class SkyContext + * @brief A manager / proxy for the state of OpenGL contexts. + * + * @todo + */ +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 ContextMaterialMap; + typedef ContextMaterialMap::iterator ContextMaterialIterator; + typedef std::map ContextTextureStateMap; + typedef ContextTextureStateMap::iterator ContextTextureStateIterator; + + ContextMaterialMap _currentMaterials; + ContextTextureStateMap _currentTextureState; + + //------------------------------------------------------------------------------ + // Messaging system to handle notification of mode changes + //------------------------------------------------------------------------------ + typedef std::pair 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 _listeners; + +}; + +#endif //__SKYCONTEXT_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyControlled.hpp b/simgear/scene/sky/clouds3d/SkyControlled.hpp new file mode 100644 index 00000000..7c6b43cf --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyControlled.hpp @@ -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 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 +class SkyControlled +{ +public: + //! Constructor. + SkyControlled() { _pController = NULL; } + //! Destructor + virtual ~SkyControlled() { _pController = NULL; } + + //! Sets the controller which will control this controlled object. + void SetController(SkyController *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 *_pController; + ControlStateType _controlState; +}; + +#endif //__SKYCONTROLLED_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyController.hpp b/simgear/scene/sky/clouds3d/SkyController.hpp new file mode 100644 index 00000000..38a64a01 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyController.hpp @@ -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 +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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp b/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp new file mode 100644 index 00000000..a15dc17d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp @@ -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; +} diff --git a/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.hpp b/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.hpp new file mode 100644 index 00000000..57f09bbd --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyDynamicTextureManager.hpp @@ -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 +#include +#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 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 TextureSubset; + typedef multimap TextureSet; + +protected: // data + TextureSet _availableTexturePool; + TextureSubset _checkedOutTexturePool; + + unsigned int _iAvailableSizeCounts[11][11]; + + unsigned int _iNumTextureBytesUsed; + unsigned int _iNumTextureBytesCheckedOut; + unsigned int _iNumTextureBytesCheckedIn; +}; + +#endif //__SKYDYNAMICTEXTUREMANAGER_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyLight.cpp b/simgear/scene/sky/clouds3d/SkyLight.cpp new file mode 100644 index 00000000..b3d4cb3c --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyLight.cpp @@ -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 + +SkyMaterial* SkyLight::s_pMaterial = NULL; + +//------------------------------------------------------------------------------ +// Function : SkyLight::SkyLight +// Description : +//------------------------------------------------------------------------------ +/** +* @fn SkyLight::SkyLight(SkyLightType eType) +* @brief @todo +* +* @todo +*/ +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 +* +* @todo +*/ +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 + * + * @todo + */ +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; +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyLight.hpp b/simgear/scene/sky/clouds3d/SkyLight.hpp new file mode 100644 index 00000000..b78fb11e --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyLight.hpp @@ -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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyMaterial.cpp b/simgear/scene/sky/clouds3d/SkyMaterial.cpp new file mode 100644 index 00000000..7b6aaa7a --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyMaterial.cpp @@ -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 + * + * @todo + */ +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; +} + + diff --git a/simgear/scene/sky/clouds3d/SkyMaterial.hpp b/simgear/scene/sky/clouds3d/SkyMaterial.hpp new file mode 100644 index 00000000..cf3a1d50 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyMaterial.hpp @@ -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 + +// 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp b/simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp new file mode 100644 index 00000000..968470fe --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp @@ -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 +#include + + +//------------------------------------------------------------------------------ +// 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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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); +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp b/simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp new file mode 100644 index 00000000..6a385198 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp @@ -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 +*/ +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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderable.hpp b/simgear/scene/sky/clouds3d/SkyRenderable.hpp new file mode 100644 index 00000000..83640953 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderable.hpp @@ -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 + +#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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstance.hpp b/simgear/scene/sky/clouds3d/SkyRenderableInstance.hpp new file mode 100644 index 00000000..c483999a --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstance.hpp @@ -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 +#include +#include +#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 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp new file mode 100644 index 00000000..2f404034 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp @@ -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 + */ +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 + */ +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); + } + s_iCount++; +} diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.hpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.hpp new file mode 100644 index 00000000..e7bac3de --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.hpp @@ -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 +#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 + */ +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 + */ +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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.cpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.cpp new file mode 100644 index 00000000..7a9c3bb7 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.cpp @@ -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; +} diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.hpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.hpp new file mode 100644 index 00000000..b69d26a2 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.hpp @@ -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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.cpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.cpp new file mode 100644 index 00000000..dbd8871d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.cpp @@ -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 +#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 + * + * @todo + */ +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); + } +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.hpp b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.hpp new file mode 100644 index 00000000..1557003b --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.hpp @@ -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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkySceneLoader.cpp b/simgear/scene/sky/clouds3d/SkySceneLoader.cpp new file mode 100644 index 00000000..6ccfe80d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkySceneLoader.cpp @@ -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 +#include + +#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 () ; + +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkySceneLoader.hpp b/simgear/scene/sky/clouds3d/SkySceneLoader.hpp new file mode 100644 index 00000000..7e9cf44d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkySceneLoader.hpp @@ -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 +#include "SkyUtil.hpp" + +#include + +//------------------------------------------------------------------------------ +/** + * @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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkySceneManager.cpp b/simgear/scene/sky/clouds3d/SkySceneManager.cpp new file mode 100644 index 00000000..726eed3f --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkySceneManager.cpp @@ -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 + +//------------------------------------------------------------------------------ +// 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 + */ +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 + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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(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(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(pNode->GetObj(i)); + pInstance->ReleaseImpostorTextures(); + } + } +} + + +//------------------------------------------------------------------------------ +// Function : SkySceneManager::_VisualizeCloudBVTree +// Description : +//------------------------------------------------------------------------------ +/** + * @fn SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode) + * @brief @todo + * + * @todo + */ +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(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 + * + * @todo + */ +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 + * + * @todo + */ +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(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)) + return _TestInsertInstanceIntoClouds(cam, pNode->GetRightChild(), pInstanceToInsert, bTransparent); + else + return true; + } + } + else + return false; +} diff --git a/simgear/scene/sky/clouds3d/SkySceneManager.hpp b/simgear/scene/sky/clouds3d/SkySceneManager.hpp new file mode 100644 index 00000000..054c5176 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkySceneManager.hpp @@ -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 +#include + +#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 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 ObjectArray; + + typedef std::map MaterialSet; + typedef std::map LightSet; + + typedef std::vector CloudInstanceArray; + typedef std::vector CloudArray; + typedef std::map ContainerCloudSet; + + typedef SkyAABBTree 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkySingleton.hpp b/simgear/scene/sky/clouds3d/SkySingleton.hpp new file mode 100644 index 00000000..e8aeaf6f --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkySingleton.hpp @@ -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 +#include + +//------------------------------------------------------------------------------ +/** + * @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 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 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 + 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 + 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 + 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 + 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, 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 + 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 + 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 + 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 + 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 SkySingleton* SkySingleton::s_pInstance = NULL; + +#endif //__SKYSINGLETON_HPP__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyTexture.hpp b/simgear/scene/sky/clouds3d/SkyTexture.hpp new file mode 100644 index 00000000..50790118 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyTexture.hpp @@ -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 + +//------------------------------------------------------------------------------ +/** + * @class SkyTexture + * @brief A basic texture class. + * + * @todo + */ +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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyTextureManager.cpp b/simgear/scene/sky/clouds3d/SkyTextureManager.cpp new file mode 100644 index 00000000..715971b7 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyTextureManager.cpp @@ -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 + */ +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) + { + glDeleteTextures(texture.iDepth, texture.pSliceIDs); + delete [] texture.pSliceIDs; + }*/ +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyTextureManager.hpp b/simgear/scene/sky/clouds3d/SkyTextureManager.hpp new file mode 100644 index 00000000..0bda600d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyTextureManager.hpp @@ -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 +#include +#include + +using namespace std; + +// forward declaration for singleton +class SkyTextureManager; + +//! A singleton of the SkyTextureManager. Can only create the TextureManager with TextureManager::Instantiate(); +typedef SkySingleton 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 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 TextureList; + typedef map 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 diff --git a/simgear/scene/sky/clouds3d/SkyTextureState.cpp b/simgear/scene/sky/clouds3d/SkyTextureState.cpp new file mode 100644 index 00000000..5495ce1c --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyTextureState.cpp @@ -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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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 + * + * @todo + */ +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; +} \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyTextureState.hpp b/simgear/scene/sky/clouds3d/SkyTextureState.hpp new file mode 100644 index 00000000..1df2d39d --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyTextureState.hpp @@ -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 + +//------------------------------------------------------------------------------ +/** +* @class SkyTextureState +* @brief A wrapper for texture unit state. +* +* @todo +*/ +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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/SkyUtil.cpp b/simgear/scene/sky/clouds3d/SkyUtil.cpp new file mode 100644 index 00000000..ceeeab1b --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyUtil.cpp @@ -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 +} + + diff --git a/simgear/scene/sky/clouds3d/SkyUtil.hpp b/simgear/scene/sky/clouds3d/SkyUtil.hpp new file mode 100644 index 00000000..9e020f69 --- /dev/null +++ b/simgear/scene/sky/clouds3d/SkyUtil.hpp @@ -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 +#include +#include + +//----------------------------------------------------------------------------- +// 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__ \ No newline at end of file diff --git a/simgear/scene/sky/clouds3d/camdisplay.cpp b/simgear/scene/sky/clouds3d/camdisplay.cpp new file mode 100644 index 00000000..736305a2 --- /dev/null +++ b/simgear/scene/sky/clouds3d/camdisplay.cpp @@ -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 +#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(); + +} diff --git a/simgear/scene/sky/clouds3d/camera.cpp b/simgear/scene/sky/clouds3d/camera.cpp new file mode 100644 index 00000000..c5b89fa4 --- /dev/null +++ b/simgear/scene/sky/clouds3d/camera.cpp @@ -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 + +//---------------------------------------------------------------------------- +// 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); +}; diff --git a/simgear/scene/sky/clouds3d/camera.hpp b/simgear/scene/sky/clouds3d/camera.hpp new file mode 100644 index 00000000..42a24c89 --- /dev/null +++ b/simgear/scene/sky/clouds3d/camera.hpp @@ -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 +#include +#include + +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 diff --git a/simgear/scene/sky/clouds3d/camutils.cpp b/simgear/scene/sky/clouds3d/camutils.cpp new file mode 100644 index 00000000..53634060 --- /dev/null +++ b/simgear/scene/sky/clouds3d/camutils.cpp @@ -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 +#include +#include + +//---------------------------------------------------------------------------- +// 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; +} diff --git a/simgear/scene/sky/clouds3d/camutils.hpp b/simgear/scene/sky/clouds3d/camutils.hpp new file mode 100644 index 00000000..8f1e34d4 --- /dev/null +++ b/simgear/scene/sky/clouds3d/camutils.hpp @@ -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]); diff --git a/simgear/scene/sky/clouds3d/mat16fv.cpp b/simgear/scene/sky/clouds3d/mat16fv.cpp new file mode 100644 index 00000000..334a056c --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat16fv.cpp @@ -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 +#include +#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]); +} + diff --git a/simgear/scene/sky/clouds3d/mat16fv.hpp b/simgear/scene/sky/clouds3d/mat16fv.hpp new file mode 100644 index 00000000..d2786584 --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat16fv.hpp @@ -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); diff --git a/simgear/scene/sky/clouds3d/mat33.hpp b/simgear/scene/sky/clouds3d/mat33.hpp new file mode 100644 index 00000000..ca997822 --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat33.hpp @@ -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 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& operator = (const Mat33& A); // ASSIGNMENT (=) + // ASSIGNMENT (=) FROM AN ARRAY OF Type + Mat33& operator = (const Type* a); + Mat33 operator * (const Mat33& A) const; // MULTIPLICATION (*) + // MAT-VECTOR MULTIPLICATION (*) + Vec3 operator * (const Vec3& V) const; + // MAT-VECTOR PRE-MULTIPLICATON (*) + friend Vec3 operator * (const Vec3& V, const Mat33& M); + // SCALAR POST-MULTIPLICATION + Mat33 operator * (Type a) const; + // SCALAR PRE-MULTIPLICATION + friend Mat33 operator * (Type a, const Mat44& M); + + Mat33 operator / (Type a) const; // SCALAR DIVISION + Mat33 operator + (Mat33& M) const; // ADDITION (+) + Mat33& operator += (Mat33& M); // ACCUMULATE ADD (+=) + Mat33& operator -= (Mat33& M); // ACCUMULATE SUB (-=) + Mat33& operator *= (Type a); // ACCUMULATE MULTIPLY (*=) + Mat33& operator /= (Type a); // ACCUMULATE DIVIDE (/=) + + bool Inverse(Mat33 &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& S); + void invScale(Type Sx, Type Sy, Type Sz); + void invScale(const Vec3& S); + void Rotate(Type DegAng, const Vec3& Axis); + void invRotate(Type DegAng, const Vec3& Axis); + void Star(const Vec3& v); // SKEW-SYMM MATRIX EQUIV TO CROSS PROD WITH V + void OuterProduct(const Vec3& u, const Vec3& 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 Mat33f; +typedef Mat33 Mat33d; + +#endif + + + + diff --git a/simgear/scene/sky/clouds3d/mat33impl.hpp b/simgear/scene/sky/clouds3d/mat33impl.hpp new file mode 100644 index 00000000..9d7a8f1f --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat33impl.hpp @@ -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 +Mat33::Mat33() +{ + Identity(); +} + +template +Mat33::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 +Mat33::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 +Mat33& Mat33::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 +Mat33& Mat33::operator = (const Type* a) { + for (int i=0;i<9;i++) { + M[i] = a[i]; + } + return *this; +} + +template +Mat33 Mat33::operator * (const Mat33& A) const // MULTIPLICATION (*) +{ + Mat33 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 +Vec3 Mat33::operator * (const Vec3& V) const +{ + Vec3 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 +Vec3 operator *(const Vec3& V, const Mat33& A) +{ + Vec3 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 +Mat33 Mat33::operator * (Type a) const +{ + Mat33 NewM; + for (int i = 0; i < 9; i++) + NewM[i] = M[i]*a; + return(NewM); +} + +// SCALAR PRE-MULTIPLICATION (non-member) +template +Mat33 operator * (Type a, const Mat44& M) +{ + Mat33 NewM; + for (int i = 0; i < 9; i++) + NewM[i] = a*M[i]; + return(NewM); +} + +template +Mat33 Mat33::operator / (Type a) const // SCALAR DIVISION +{ + Mat33 NewM; + Type ainv = Type(1.0)/a; + for (int i = 0; i < 9; i++) + NewM[i] = M[i]*ainv; + return(NewM); +} + +template +Mat33 Mat33::operator + (Mat33& N) const // ADDITION (+) +{ + Mat33 NewM; + for (int i = 0; i < 9; i++) + NewM[i] = M[i]+N.M[i]; + return(NewM); +} +template +Mat33& Mat33::operator += (Mat33& N) // ACCUMULATE ADD (+=) +{ + for (int i = 0; i < 9; i++) + M[i] += N.M[i]; + return(*this); +} + +template +Mat33& Mat33::operator -= (Mat33& N) // ACCUMULATE SUB (-=) +{ + for (int i = 0; i < 9; i++) + M[i] -= N.M[i]; + return(*this); +} + +template +Mat33& Mat33::operator *= (Type a) // ACCUMULATE MULTIPLY (*=) +{ + for (int i = 0; i < 9; i++) + M[i] *= a; + return(*this); +} +template +Mat33& Mat33::operator /= (Type a) // ACCUMULATE DIVIDE (/=) +{ + Type ainv = Type(1.0)/a; + for (int i = 0; i < 9; i++) + M[i] *= ainv; + return(*this); +} + +template +bool Mat33::Inverse(Mat33 &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 +Mat33::operator const Type*() const +{ + return M; +} + +template +Mat33::operator Type*() +{ + return M; +} + +template +void Mat33::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 +Type& Mat33::operator()(int col, int row) +{ + return M[3*col+row]; +} + +template +const Type& Mat33::operator()(int col, int row) const +{ + return M[3*col+row]; +} + +template +void Mat33::Set(const Type* a) +{ + for (int i=0;i<9;i++) { + M[i] = a[i]; + } +} + +template +void Mat33::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 +void Mat33::Identity() +{ + M[0]=M[4]=M[8]=1; + M[1]=M[2]=M[3]=M[5]=M[6]=M[7]=0; +} +template +void Mat33::Zero() +{ + M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=M[6]=M[7]=M[8]=0; +} + +template +void Mat33::Transpose() +{ + SWAP(M[1],M[3]); + SWAP(M[2],M[6]); + SWAP(M[5],M[7]); +} + +//--------------------------------------------------------------------------- +// Standard Matrix Affine Transformations +//--------------------------------------------------------------------------- +template +void Mat33::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 +void Mat33::Scale(const Vec3& 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 +void Mat33::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 +void Mat33::invScale(const Vec3& 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 +void Mat33::Rotate(Type DegAng, const Vec3& 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 +void Mat33::invRotate(Type DegAng, const Vec3& Axis) +{ + Rotate(DegAng,Axis); + Transpose(); +} + +template +inline void Mat33::Star(const Vec3& 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 +inline void Mat33::OuterProduct(const Vec3& u, const Vec3& 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 +inline Type Mat33::Trace() const +{ + return M[0] + M[4] + M[8]; +} + +//--------------------------------------------------------------------------- +// Handy matrix printing routine. +//--------------------------------------------------------------------------- +template +void Mat33::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 +void Mat33::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]; +} + diff --git a/simgear/scene/sky/clouds3d/mat44.hpp b/simgear/scene/sky/clouds3d/mat44.hpp new file mode 100644 index 00000000..1d657b43 --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat44.hpp @@ -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 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& operator = (const Mat44& A); // ASSIGNMENT (=) + Mat44& operator = (const Type* a); // ASSIGNMENT (=) FROM AN ARRAY OF TypeS + Mat44 operator * (const Mat44& A) const; // MULTIPLICATION (*) + Vec3 operator * (const Vec3& V) const; // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV + Vec3 multNormal(const Vec3& V) const; // MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV + Vec3 multPoint(const Vec3& V) const; // MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV + Vec4 operator * (const Vec4& V) const; // MAT-VECTOR MULTIPLICATION (*) + Mat44 operator * (Type a) const; // SCALAR POST-MULTIPLICATION + Mat44& operator *= (Type a); // ACCUMULATE MULTIPLY (*=) +////////////// NOT IMPLEMENTED YET. ANY TAKERS? +// friend Vec3 operator * (const Vec3& V, const Mat44& M); // MAT-VECTOR PRE-MULTIPLICATON (*) W/ PERP DIV +// friend Vec4 operator * (const Vec4& V, const Mat44& M); // MAT-VECTOR PRE-MULTIPLICATON (*) +// friend Mat44 operator * (Type a, const Mat44& M) const; // SCALAR PRE-MULTIPLICATION +// Mat44 operator / (Type a) const; // SCALAR DIVISION +// Mat44 operator + (Mat44& M) const; // ADDITION (+) +// Mat44& operator += (Mat44& M); // ACCUMULATE ADD (+=) +// Mat44& 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& T); + void invTranslate(Type Tx, Type Ty, Type Tz); + void invTranslate(const Vec3& T); + void Scale(Type Sx, Type Sy, Type Sz); + void Scale(const Vec3& S); + void invScale(Type Sx, Type Sy, Type Sz); + void invScale(const Vec3& S); + void Rotate(Type DegAng, const Vec3& Axis); + void invRotate(Type DegAng, const Vec3& 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& Eye, + const Vec3& LookAtPt, + const Vec3& ViewUp); + void invLookAt(const Vec3& Eye, + const Vec3& LookAtPt, + const Vec3& 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 Mat44f; +typedef Mat44 Mat44d; + +#endif + + + + diff --git a/simgear/scene/sky/clouds3d/mat44impl.hpp b/simgear/scene/sky/clouds3d/mat44impl.hpp new file mode 100644 index 00000000..5acbf136 --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat44impl.hpp @@ -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 +Mat44::Mat44() +{ + Identity(); +} + +template +Mat44::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 +Mat44::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 +Mat44& Mat44::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 +Mat44& Mat44::operator = (const Type* a) { + for (int i=0;i<16;i++) { + M[i] = a[i]; + } + return *this; +} + +template +Mat44 Mat44::operator * (const Mat44& A) const // MULTIPLICATION (*) +{ + Mat44 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 +Vec3 Mat44::operator * (const Vec3& 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 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 +Vec3 Mat44::multNormal(const Vec3& N) const +{ + Vec3 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 +Vec3 Mat44::multPoint(const Vec3& P) const +{ + Vec3 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 +Vec4 Mat44::operator * (const Vec4& V) const // MAT-VECTOR MULTIPLICATION (*) +{ + Vec4 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 +Mat44 Mat44::operator * (Type a) const // SCALAR POST-MULTIPLICATION +{ + Mat44 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 +Mat44& Mat44::operator *= (Type a) // SCALAR ACCUMULATE POST-MULTIPLICATION +{ + for (int i = 0; i < 16; i++) + { + M[i] *= a; + } + + return *this; +} + +template +Mat44::operator const Type*() const +{ + return M; +} + +template +Mat44::operator Type*() +{ + return M; +} + +template +Type& Mat44::operator()(int col, int row) +{ + return M[4*col+row]; +} + +template +const Type& Mat44::operator()(int col, int row) const +{ + return M[4*col+row]; +} + +template +void Mat44::Set(const Type* a) +{ + for (int i=0;i<16;i++) { + M[i] = a[i]; + } + +} + +template +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::Translate(const Vec3& 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 +void Mat44::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 +void Mat44::invTranslate(const Vec3& 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 +void Mat44::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 +void Mat44::Scale(const Vec3& 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 +void Mat44::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 +void Mat44::invScale(const Vec3& 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 +void Mat44::Rotate(Type DegAng, const Vec3& 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 +void Mat44::invRotate(Type DegAng, const Vec3& Axis) +{ + Rotate(DegAng,Axis); + Transpose(); +} + +template +inline Type Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::LookAt(const Vec3& Eye, + const Vec3& LookAtPt, + const Vec3& ViewUp) +{ + Vec3 Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD) + Vec3 X = ViewUp/Z; X.Normalize(); + Vec3 Y = Z/X; Y.Normalize(); + Vec3 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 +void Mat44::invLookAt(const Vec3& Eye, + const Vec3& LookAtPt, + const Vec3& ViewUp) +{ + Vec3 Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD) + Vec3 X = ViewUp/Z; X.Normalize(); + Vec3 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 +void Mat44::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 +void Mat44::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 +void Mat44::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 +void Mat44::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]; +} + diff --git a/simgear/scene/sky/clouds3d/mat44test.cpp b/simgear/scene/sky/clouds3d/mat44test.cpp new file mode 100644 index 00000000..c99b809c --- /dev/null +++ b/simgear/scene/sky/clouds3d/mat44test.cpp @@ -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 +#include +#include + +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." <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); +} diff --git a/simgear/scene/sky/clouds3d/minmaxbox.hpp b/simgear/scene/sky/clouds3d/minmaxbox.hpp new file mode 100644 index 00000000..9a8e8081 --- /dev/null +++ b/simgear/scene/sky/clouds3d/minmaxbox.hpp @@ -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); + diff --git a/simgear/scene/sky/clouds3d/plane.cpp b/simgear/scene/sky/clouds3d/plane.cpp new file mode 100644 index 00000000..6af97a62 --- /dev/null +++ b/simgear/scene/sky/clouds3d/plane.cpp @@ -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 + +//-------------------------------------------------------------------------- +// 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 -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); +} diff --git a/simgear/scene/sky/clouds3d/plane.hpp b/simgear/scene/sky/clouds3d/plane.hpp new file mode 100644 index 00000000..7d843efb --- /dev/null +++ b/simgear/scene/sky/clouds3d/plane.hpp @@ -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); diff --git a/simgear/scene/sky/clouds3d/quat.hpp b/simgear/scene/sky/clouds3d/quat.hpp new file mode 100644 index 00000000..6d8098b1 --- /dev/null +++ b/simgear/scene/sky/clouds3d/quat.hpp @@ -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 Quat +{ +public: + typedef Vec3 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& ToMat( Mat44 &dest ) const; /* to 4x4 matrix */ + Mat33& ToMat( Mat33 &dest ) const; /* to 3x3 matrix */ + Quat& FromMat( const Mat44& src ); /* from 4x4 rot matrix */ + Quat& FromMat( const Mat33& 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 +Quat& QuatSlerp( + Quat &dest, const Quat& from, const Quat& to, Type t ); +template +Quat QuatSlerp(const Quat& from, const Quat& to, Type t ); + +/* "Friends" */ +template +Quat operator -(const Quat &v); // -q1 +template +Quat operator +(const Quat &a, const Quat &b); // q1 + q2 +template +Quat operator -(const Quat &a, const Quat &b); // q1 - q2 +template +Quat operator *(const Quat &a, const Type d); // q1 * 3.0 +template +Quat operator *(const Type d, const Quat &a); // 3.0 * q1 +template +Quat operator *(const Quat &a, const Quat &b); // q1 * q2 +template +Quat operator /(const Quat &a, const Type d); // q1 / 3.0 +template +bool operator ==(const Quat &a, const Quat &b); // q1 == q2 ? +template +bool operator !=(const Quat &a, const Quat &b); // q1 != q2 ? + + + +#include "quatimpl.hpp" + + + +typedef Quat Quatf; +typedef Quat Quatd; + +#endif diff --git a/simgear/scene/sky/clouds3d/quatimpl.hpp b/simgear/scene/sky/clouds3d/quatimpl.hpp new file mode 100644 index 00000000..0d6fb560 --- /dev/null +++ b/simgear/scene/sky/clouds3d/quatimpl.hpp @@ -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 +#include + + +//============================================================================ +// CONSTRUCTORS +//============================================================================ + +template +Quat::Quat( void ) +{ + // do nothing so default construction is fast +} + +template +Quat::Quat( Type _s, Type x, Type y, Type z ) +{ + s = _s; + v.Set( x, y, z ); +} +template +Quat::Quat( Type x, Type y, Type z ) +{ + s = 0.0; + v.Set( x, y, z ); +} + +template +Quat::Quat( const qvec& _v, Type _s ) +{ + Set( _v, _s ); +} + +template +Quat::Quat( Type _s, const qvec& _v ) +{ + Set( _v, _s ); +} + + +template +Quat::Quat( const Type *d ) +{ + s = *d++; + v.Set(d); +} + +template +Quat::Quat( const Quat &q ) +{ + s = q.s; + v = q.v; +} + +//============================================================================ +// SETTERS +//============================================================================ + +template +void Quat::Set( Type _s, Type x, Type y, Type z ) +{ + s = _s; + v.Set(x,y,z); +} +template +void Quat::Set( Type x, Type y, Type z ) +{ + s = 0.0; + v.Set(x,y,z); +} + +template +void Quat::Set( const qvec& _v, Type _s ) +{ + s = _s; + v = _v; +} +template +void Quat::Set( Type _s, const qvec& _v ) +{ + s = _s; + v = _v; +} + + +//============================================================================ +// OPERATORS +//============================================================================ + +template +Quat& Quat::operator = (const Quat& q) +{ + v = q.v; s = q.s; return *this; +} + +template +Quat& Quat::operator += ( const Quat &q ) +{ + v += q.v; s += q.s; return *this; +} + +template +Quat& Quat::operator -= ( const Quat &q ) +{ + v -= q.v; s -= q.s; return *this; +} + +template +Quat &Quat::operator *= ( const Type d ) +{ + v *= d; s *= d; return *this; +} + +template +Quat &Quat::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 +Quat &Quat::operator /= ( const Type d ) +{ + Type r = Type(1.0)/d; + v *= r; + s *= r; + return *this; +} + +template +Type &Quat::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 +inline Type Quat::Length( void ) const +{ + return Type( sqrt( v*v + s*s ) ); +} + +template +inline Type Quat::LengthSqr( void ) const +{ + return Norm(); +} + +template +inline Type Quat::Norm( void ) const +{ + return v*v + s*s; +} + +template +inline Quat& Quat::Normalize( void ) +{ + *this *= Type(1.0) / Type(sqrt(v*v + s*s)); + return *this; +} + +template +inline Quat& Quat::Invert( void ) +{ + Type scale = Type(1.0)/Norm(); + v *= -scale; + s *= scale; + return *this; +} + +template +inline Quat& Quat::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 +Quat::qvec Quat::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 +Quat &Quat::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 +Quat &Quat::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 +void Quat::SetAngle( Type f ) +{ + qvec axis(GetAxis()); + f *= Type(0.5); + s = Cos( f ); + v = axis * Sin( f ); +} + +//---------------------------------------------------------------------------- +// ScaleAngle +//---------------------------------------------------------------------------- +template +inline void Quat::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 +inline Type Quat::GetAngle( void ) const +{ + return ( Type(2.0) * ACos( s ) ); +} + +//---------------------------------------------------------------------------- +// GetAxis +//---------------------------------------------------------------------------- +template +Quat::qvec Quat::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 +inline void Quat::Print( ) const +{ + printf( "(%3.2f, <%3.2f %3.2f %3.2f>)\n", s, v.x, v.y, v.z ); +} + + +//============================================================================ +// CONVERSIONS +//============================================================================ + +template +Mat44& Quat::ToMat( Mat44& 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 +Mat33& Quat::ToMat( Mat33& 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 +Quat& Quat::FromMat( const Mat44& 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 +Quat& Quat::FromMat( const Mat33& 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 +void Quat::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 +Quat& Quat::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 +Quat& Quat::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 +Quat& Quat::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 +void Quat::ToEuler(Type& yaw, Type& pitch, Type& roll) const +{ + // This is probably wrong + Mat33 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 +Quat operator + (const Quat &a, const Quat &b) +{ + return Quat( a.s+b.s, a.v+b.v ); +} + +template +Quat operator - (const Quat &a, const Quat &b) +{ + return Quat( a.s-b.s, a.v-b.v ); +} + +template +Quat operator - (const Quat &a ) +{ + return Quat( -a.s, -a.v ); +} + +template +Quat operator * ( const Quat &a, const Quat &b) +{ +#if 0 + // 16 mults + return Quat( 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( + 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 +Quat operator * ( const Quat &a, const Type t) +{ + return Quat( a.v * t, a.s * t ); +} + +template +Quat operator * ( const Type t, const Quat &a ) +{ + return Quat( a.v * t, a.s * t ); +} +template +Quat operator / ( const Quat &a, const Type t ) +{ + return Quat( a.v / t, a.s / t ); +} + +template +bool operator == (const Quat &a, const Quat &b) +{ + return (a.s == b.s && a.v == b.v); +} +template +bool operator != (const Quat &a, const Quat &b) +{ + return (a.s != b.s || a.v != b.v); +} + + +//============================================================================ +// UTILS +//============================================================================ +template +inline Type Quat::DEG2RAD(Type d) +{ + return d * Type(0.0174532925199432957692369076848861); +} +template +inline Type Quat::RAD2DEG(Type d) +{ + return d * Type(57.2957795130823208767981548141052); +} + +template +inline Type Quat::Sin(double d) { return Type(sin(d)); } +template +inline Type Quat::Cos(double d) { return Type(cos(d)); } +template +inline Type Quat::ACos(double d) { return Type(acos(d)); } +template +inline Type Quat::ASin(double d) { return Type(asin(d)); } +template +inline Type Quat::ATan(double d) { return Type(atan(d)); } +template +inline Type Quat::ATan2(double n, double d) {return Type(atan2(n,d));} + +template +inline Quat Quat::ZERO() {return Quat(0,0,0,0); } +template +inline Quat Quat::IDENTITY() {return Quat(1,0,0,0); } + +template +inline Type Quat::FUDGE() { return 1e-6; } +template<> +inline double Quat::FUDGE() { return 1e-10; } + +//---------------------------------------------------------------------------- +// QuatSlerp +//---------------------------------------------------------------------------- +template +Quat& QuatSlerp( + Quat &dest, + const Quat &from, const Quat &to, Type t ) +{ +#if 0 + // compact mathematical version + // exp(t*log(to*from^-1))*from + Quat fminv(from); + Quat tofrom(to*fminv.Invert()); + Quat slerp = t*tofrom.Log(); + slerp.Exp(); + slerp *= from; + return slerp; +#endif + Quat 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::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 +inline Quat QuatSlerp( + const Quat& from, const Quat& to, Type t ) +{ + Quat q; + return QuatSlerp(q, from, to, t); +} + + diff --git a/simgear/scene/sky/clouds3d/quattest.cpp b/simgear/scene/sky/clouds3d/quattest.cpp new file mode 100644 index 00000000..1c15fea3 --- /dev/null +++ b/simgear/scene/sky/clouds3d/quattest.cpp @@ -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& src ) const; + // Quat& FromMat( const Mat33& 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); +} diff --git a/simgear/scene/sky/clouds3d/tri.cpp b/simgear/scene/sky/clouds3d/tri.cpp new file mode 100644 index 00000000..e4dc465a --- /dev/null +++ b/simgear/scene/sky/clouds3d/tri.cpp @@ -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 + +//---------------------------------------------------------------------------- +// 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) ); +} diff --git a/simgear/scene/sky/clouds3d/tri.hpp b/simgear/scene/sky/clouds3d/tri.hpp new file mode 100644 index 00000000..f4480da4 --- /dev/null +++ b/simgear/scene/sky/clouds3d/tri.hpp @@ -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]); diff --git a/simgear/scene/sky/clouds3d/vec2f.hpp b/simgear/scene/sky/clouds3d/vec2f.hpp new file mode 100644 index 00000000..6398462f --- /dev/null +++ b/simgear/scene/sky/clouds3d/vec2f.hpp @@ -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 +#include + +template +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 (xMax.x) Max.x=x; + if (yMax.y) Max.y=y; + } + + void Print() const + { printf("(%.3f, %.3f)\n",x, y); } + + static Vec2 ZERO; +}; + +typedef Vec2 Vec2f; +typedef Vec2 Vec2d; + +template Vec2 Vec2::ZERO = Vec2(0,0); + +#endif + + diff --git a/simgear/scene/sky/clouds3d/vec3f.hpp b/simgear/scene/sky/clouds3d/vec3f.hpp new file mode 100644 index 00000000..f39dedee --- /dev/null +++ b/simgear/scene/sky/clouds3d/vec3f.hpp @@ -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 +#include + +/** + * @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 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 (xMax.x) Max.x=x; + if (yMax.y) Max.y=y; + if (zMax.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::ZERO + static Vec3 ZERO; +}; + +typedef Vec3 Vec3f; +typedef Vec3 Vec3d; + +template Vec3 Vec3::ZERO = Vec3(0,0,0); + +#endif + + diff --git a/simgear/scene/sky/clouds3d/vec3fv.cpp b/simgear/scene/sky/clouds3d/vec3fv.cpp new file mode 100644 index 00000000..27113266 --- /dev/null +++ b/simgear/scene/sky/clouds3d/vec3fv.cpp @@ -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 +#include + +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]); +} diff --git a/simgear/scene/sky/clouds3d/vec3fv.hpp b/simgear/scene/sky/clouds3d/vec3fv.hpp new file mode 100644 index 00000000..d0cb2a82 --- /dev/null +++ b/simgear/scene/sky/clouds3d/vec3fv.hpp @@ -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 diff --git a/simgear/scene/sky/clouds3d/vec4f.hpp b/simgear/scene/sky/clouds3d/vec4f.hpp new file mode 100644 index 00000000..6de765e7 --- /dev/null +++ b/simgear/scene/sky/clouds3d/vec4f.hpp @@ -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 +#include + +template +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 Vec4f; +typedef Vec4 Vec4d; + +template Vec4 Vec4::ZERO = Vec4(0,0,0,0); + +#endif + + -- 2.39.5