]> git.mxchange.org Git - simgear.git/commitdiff
Initial revision.
authorcurt <curt>
Fri, 13 Sep 2002 20:29:04 +0000 (20:29 +0000)
committercurt <curt>
Fri, 13 Sep 2002 20:29:04 +0000 (20:29 +0000)
68 files changed:
simgear/scene/sky/clouds3d/Makefile.am [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyAABBTree.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyArchive.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyArchive.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyBVTree.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyBVTreeSplitter.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyBoundingVolume.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyCloud.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyCloud.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyCloudParticle.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyContext.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyContext.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyControlled.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyController.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyDynamicTextureManager.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyLight.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyLight.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyMaterial.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyMaterial.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyMinMaxBox.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyMinMaxBox.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderable.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstance.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceCloud.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceGeneric.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyRenderableInstanceGroup.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkySceneLoader.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkySceneLoader.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkySceneManager.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkySceneManager.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkySingleton.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyTexture.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyTextureManager.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyTextureManager.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyTextureState.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyTextureState.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyUtil.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/SkyUtil.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/camdisplay.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/camera.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/camera.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/camutils.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/camutils.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat16fv.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat16fv.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat33.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat33impl.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat44.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat44impl.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/mat44test.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/minmaxbox.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/minmaxbox.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/plane.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/plane.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/quat.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/quatimpl.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/quattest.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/tri.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/tri.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/vec2f.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/vec3f.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/vec3fv.cpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/vec3fv.hpp [new file with mode: 0644]
simgear/scene/sky/clouds3d/vec4f.hpp [new file with mode: 0644]

diff --git a/simgear/scene/sky/clouds3d/Makefile.am b/simgear/scene/sky/clouds3d/Makefile.am
new file mode 100644 (file)
index 0000000..06cf29f
--- /dev/null
@@ -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 (file)
index 0000000..81fecdd
--- /dev/null
@@ -0,0 +1,19 @@
+//============================================================================
+// File          : SkyAABBTree.hpp
+// 
+// Author        : Wesley Hunt
+// 
+// Content       : axis-aligned bounding box tree
+// 
+//============================================================================
+#ifndef __SKYAABBTREE_HPP__
+#define __SKYAABBTREE_HPP__
+
+#include "SkyBVTree.hpp"
+#include "SkyBVTreeSplitter.hpp"
+
+template <class object>
+class SkyAABBTree : public SkyBVTree<object, SkyMinMaxBox, SkyAABBTreeSplitter<object> > 
+{};
+
+#endif //__SKYAABBTREE_HPP__
\ 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 (file)
index 0000000..4b6bcc9
--- /dev/null
@@ -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 <assert.h>
+
+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<SkyMMapConstIter, SkyMMapConstIter> 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 (file)
index 0000000..a6aae02
--- /dev/null
@@ -0,0 +1,243 @@
+//------------------------------------------------------------------------------
+// File : SkyArchive.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyArchive.hpp
+ * 
+ * A hierarchical archive Class for storing data.                           
+ */
+#ifndef __SKYARCHIVE_HPP__
+#define __SKYARCHIVE_HPP__
+
+#pragma warning( disable : 4786 )
+
+#include "vec2f.hpp"
+#include "vec3f.hpp"
+#include "vec4f.hpp"
+#include "SkyUtil.hpp"
+
+#include <map> // for std::multimap
+
+//! Types supported by the archive system
+enum SkyArchiveTypeCode
+{
+    BOOL_TYPE,
+    INT8_TYPE,
+    INT16_TYPE,
+    INT32_TYPE,
+    UINT8_TYPE,
+    UINT16_TYPE,
+    UINT32_TYPE,
+    FLOAT32_TYPE,
+    FLOAT64_TYPE,
+    STRING_TYPE,
+    VEC2F_TYPE,
+    VEC3F_TYPE,
+    VEC4F_TYPE,
+    ARCHIVE_TYPE,
+    ANY_TYPE,
+    NULL_TYPE
+};
+
+struct SkyArchiveEntry;
+
+struct StringLessFunctor
+{
+    bool operator() (const char* p1, const char* p2) const
+    {
+       return ::strcmp( p1, p2) < 0;
+    }
+};
+
+//============================================================================
+//
+//  Class       :   SkyArchive
+//             
+//! A simple hierarchical archive file useful for loading and saving data.
+//
+/*! SkyArchive bundles information so that an application can store, 
+    manipulate, and retrieve data in a storage-independent manner.  Information 
+    stored in an SkyArchive file can be modified without breaking 
+    compatibility with the code that retrieves the data.  In essence, it can be 
+    thought of as a very basic database mechanism.
+
+    A SkyArchive is simply a container.  The class defines methods that allow 
+    you to put information in a SkyArchive, determine the information in a
+    SkyArchive, and retrieve information from a SkyArchive.  It's important 
+    to note that the SkyArchive is a recursive storage mechanism; a 
+    SkyArchive itself can hold one or more other SkyArchives.
+
+    Data are added to an archive in fields.  The datum in a field is associated 
+    with a name, number of bytes, and a type code.  The name can be anything you 
+    choose and is not required to be unique.  The number of bytes must be accurate.  
+    The type code must be one of the SkyArchiveTypeCode enums.  Several of the Add 
+    functions have been specialized for the common base types.  It isn't necessary 
+    to provide the number of bytes when using the specialized functions, since it can be 
+    inferred from the type code.
+
+    The functions that retrieve fields from an archive are similar to the ones 
+    that add data, only their roles are reversed.  As with the Add functions, 
+    there are several specialized functions for the common base types while 
+    custom information can be retrieved using the generic FindData function.
+    
+    Querying the contents of an archive is provided through the GetInfo 
+    functions.  These functions are important as they allow you to write 
+    code that can intelligently determine how to retrieve information at 
+    run-time: you no longer have to hardcode the order in which you retrieve 
+    data from your files.
+
+    archive data fields are held in using an STL multimap.  The multimap key
+    is a QString (field name) and the data is held in a SkyArchiveEntry
+    structure (see SkyArchive.cpp for details of this structure).
+    The fields are stored in alphabetical order based on the key names.
+*/
+class SkyArchive
+{
+public:
+    //=========================================================================
+    // Creation & Destruction
+    //=========================================================================
+    // Empty archive: no name, no data fields.
+    SkyArchive();
+    // Creates a named archive with no data fields.
+    SkyArchive( const char* pName);
+    // Deep copy the contents of one archive to another.
+    SkyArchive( const SkyArchive& src);
+    // Deep copy the contents of one archive to another.
+    SkyArchive& operator=( const SkyArchive& src);
+    
+    ~SkyArchive();
+
+    //=========================================================================
+    //  Basic SkyArchive Information
+    //=========================================================================
+    // Returns true if the archive contains no data fields.
+    bool        IsEmpty() const;
+    //! Returns the archive's name.
+    const char* GetName() const { return _pName; }; 
+
+    //=========================================================================
+    //  Adding Content to SkyArchive
+    //=========================================================================
+    // Adds a new datafield to the archive.
+    SKYRESULT AddData(const char*         pName, 
+                      SkyArchiveTypeCode  eType, 
+                      const void*         pData,
+                      unsigned int        iNumBytes, 
+                      unsigned int        iNumItems = 1);
+
+    SKYRESULT AddBool(    const char* pName, bool           aBool);
+    SKYRESULT AddInt8(    const char* pName, char           anInt8);
+    SKYRESULT AddInt16(   const char* pName, short          anInt16);
+    SKYRESULT AddInt32(   const char* pName, int            anInt32);
+    SKYRESULT AddUInt8(   const char* pName, unsigned char  anUInt8);
+    SKYRESULT AddUInt16(  const char* pName, unsigned short anUInt16);
+    SKYRESULT AddUInt32(  const char* pName, unsigned int   anUInt32);
+    SKYRESULT AddFloat32( const char* pName, float          aFloat32);
+    SKYRESULT AddFloat64( const char* pName, double         aFloat64);
+    SKYRESULT AddString(  const char* pName, const char*    pString);
+       
+    SKYRESULT AddArchive( const SkyArchive& anArchive);
+   
+    // Vector types (MJH::    only supports float versions for now!!!)
+    SKYRESULT AddVec2f(   const char* pName, const Vec2f&   aPoint2f);
+    SKYRESULT AddVec3f(   const char* pName, const Vec3f&   aPoint3f);
+    SKYRESULT AddVec4f(   const char* pName, const Vec4f&   aPoint4f);
+   
+    //=========================================================================
+    // Retrieving Content from SkyArchive
+    //=========================================================================
+    // Retrieves the specified datafield the archive, if it exists.
+    SKYRESULT FindData(   const char*         pName, 
+                          SkyArchiveTypeCode  eType, 
+                          void** const        pData,
+                          unsigned int*       pNumBytes, 
+                          unsigned int        index = 0) const;
+
+    SKYRESULT FindBool(   const char* pName, bool*           pBool,    unsigned int index = 0) const;
+    SKYRESULT FindInt8(   const char* pName, char*           pInt8,    unsigned int index = 0) const;
+    SKYRESULT FindInt16(  const char* pName, short*          pInt16,   unsigned int index = 0) const;
+    SKYRESULT FindInt32(  const char* pName, int*            pInt32,   unsigned int index = 0) const;
+    SKYRESULT FindUInt8(  const char* pName, unsigned char*  pUInt8,   unsigned int index = 0) const;
+    SKYRESULT FindUInt16( const char* pName, unsigned short* pUInt16,  unsigned int index = 0) const;
+    SKYRESULT FindUInt32( const char* pName, unsigned int*   pUInt32,  unsigned int index = 0) const;
+    SKYRESULT FindFloat32(const char* pName, float*          pFloat32, unsigned int index = 0) const;
+    SKYRESULT FindFloat64(const char* pName, double*         pFloat64, unsigned int index = 0) const;
+    SKYRESULT FindString( const char* pName, char** const    pString,  unsigned int index = 0) const;
+    SKYRESULT FindArchive(const char* pName, SkyArchive*     pArchive, unsigned int index = 0) const;
+
+    SKYRESULT FindVec2f(  const char* pName, Vec2f*          pVec2f,   unsigned int index = 0) const;
+    SKYRESULT FindVec3f(  const char* pName, Vec3f*          pVec3f,   unsigned int index = 0) const;
+    SKYRESULT FindVec4f(  const char* pName, Vec4f*          pVec4f,   unsigned int index = 0) const;
+
+    SKYRESULT AccessArchive(const char* pName, SkyArchive**  pArchive, unsigned int index = 0) const;
+
+    //=========================================================================
+    // Querying Contents of SkyArchive
+    //=========================================================================
+    // Computes the number of fields that contain the given name and type.
+    SKYRESULT GetInfo(const char*         pName, 
+                      SkyArchiveTypeCode  eType, 
+                      unsigned int*       pNumFound = NULL) const;
+
+    // Returns information about the key at the specified index.
+    SKYRESULT GetInfo(unsigned int        iNameIndex, 
+                      char**              pNameFound, 
+                      SkyArchiveTypeCode* pTypeCode,
+                      unsigned int*       pNumFound);
+                    
+    // Computes the number of unique key names in _dataTableable.
+    unsigned int GetNumUniqueNames() const;
+
+    
+    // Remove the contents of the SkyArchive.
+    SKYRESULT MakeEmpty();
+
+    // Loads the contents from a file.
+    SKYRESULT Load(const char* pFileName);
+    
+    // Commits the contents of a SkyArchive to file storage.
+    SKYRESULT Save(const char* pFileName) const;
+
+private:
+
+    char*           _pName;  // this archive's name
+
+    //=========================================================================
+    //  Data storage
+    //=========================================================================
+    typedef std::multimap<char*, SkyArchiveEntry*, StringLessFunctor> SkyArchiveMMap;
+    typedef SkyArchiveMMap::const_iterator                            SkyMMapConstIter;
+    typedef SkyArchiveMMap::iterator                                  SkyMMapIter;
+
+    SkyArchiveMMap  _dataTable;     // this is where the data reside.
+
+    // Performs a deep-copy of one archive's archive_mmap_t to another.
+    void                    _CopyDataTable( const SkyArchiveMMap& src);
+
+    // Locates an archive entry in _dataTable
+    const SkyArchiveEntry*  _FindEntry( const char*        pName, 
+                                        unsigned int       index, 
+                                        SkyArchiveTypeCode eType) const;
+   
+    // Saves the archive to a file stream.
+    SKYRESULT       _Save(FILE* pDestFile) const;
+    // Initializes the archive from a file stream.
+    SKYRESULT       _Load(FILE* pSrcFile);
+};
+
+#endif //__SKYARCHIVE_HPP__
\ 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 (file)
index 0000000..d7aaa01
--- /dev/null
@@ -0,0 +1,297 @@
+//------------------------------------------------------------------------------
+// File : SkyBVTree.hpp
+//------------------------------------------------------------------------------
+// Empyrean / SkyWorks : Copyright 2002 Mark J. Harris
+//------------------------------------------------------------------------------
+/**
+* @file SkyBVTree.hpp
+* 
+* This source was written by Wesley Hunt.  Many thanks to him for providing it.
+*/
+//-----------------------------------------------------------------------------
+// SkyBVTree.hpp
+//
+// Author:     Wesley Hunt (hunt@cs.unc.edu)
+// Date:       2000/12/19
+//-----------------------------------------------------------------------------
+//     Overview
+//     --------
+//             declare an SkyBVTree with whatever object type and bounding volume type you
+//             want. The hard part is to pass in a NodeSplitter class that determines how
+//             to split a node up. See below for a description of its requirements.
+//             Finally, use that tree like so:
+//                     * BeginTree()
+//                     *   AddObject(Object, ObjectBV)
+//                     *   ...
+//                     * EndTree()
+//                     < Do whatever you want with GetRoot() >
+//                     < Use GetLeftChild() and GetRightChild() to traverse the nodes >
+//
+//             The class hierarchy is designed for a flexible, simple public interface.
+//             This pushes some extra complexity into the class hierarchy, but there are two
+//             main advantages to the final approach:
+//                     1. There are no interface requirements for the Object and BoundingVolume
+//                        template parameters. This means you don't have to modify your existing
+//                        class interfaces to use them with the tree. 
+//                     2. All the dependent logic for dealing with the bounding volumes is pushed 
+//                        into the NodeSplitter class. So there is one centralized location for 
+//                        adapting your bounding volume classes to work with the tree. See the 
+//                        description of the NodeSplitter template requirements for more details.
+//
+//     Class Descriptions
+//     ------------------
+//
+//             SkyBaseBVTree
+//             -------------
+//             declares the node class that the tree holds. It exposes
+//             the public functions of the nodes and defines protected accessors that
+//             the derived tree class can use to manipulate nodes and build the tree.
+//
+//                     Node
+//                     ----
+//                     This is the class that gives access to the tree. You can access each
+//                     object and bounding volume owned by a node, along with that node's
+//                     children.
+//
+//                     NodeObject
+//                     ----------------
+//                     An aggregation of an object and its associated bounding volume.
+//                     Each node in the tree essentially owns an array of NodeObjects. This
+//                     array is passed to the NodeSplitter class to allow it to examine a 
+//                     node's contained objects before making a decision on how to split the 
+//                     node up.
+//
+//             SkyBVTree
+//             ---------
+//             The main tree class. To use it, supply and object type, a bounding volume
+//             type, and a NodeSplitter class that is used to split the nodes up during
+//             tree construction.
+//
+//     Template class requirements
+//     ---------------------------
+//
+//             Object
+//             ------
+//             None
+//
+//             BoundingVolume
+//             --------------
+//             None
+//
+//             NodeSplitter
+//             ------------
+//             This is the user-supplied class that decides how to split a node during
+//             tree construction. It is given an array of NodeObjects that the node owns and 
+//             is responsible for determining the node's bounding volume as well as how to 
+//             split the node up into left and right children.
+//             The required API is as follows:
+//             
+//                     * a constructor that takes an array of NodeObject and an unsigned int giving 
+//                       the size of the array. These are the objects owned by the node to be split.
+//                     * a method GetNodeBV() that returns the BoundingVolume of the  node. 
+//                       Typically this is the union of the bounding volumes of the objects owned 
+//                       by the node.
+//                     * A unary function operator used to partition the objects in the node. The
+//                       operator must take a single NodeObject as a parameter and return as
+//                       a bool whether to place the NodeObject in the left or right child. 
+//                       Basically, it should be compatible with std::partition using NodeObjects.
+//                     * A binary function operator used to sort the objects. If a partition fails, 
+//                       the nodes are then sorted based on this function and half are sent to each child.
+//                       This operator must define a total ordering of the NodeObjects.
+//                       Basically, it should be compatible with std::sort using NodeObjects.
+//                       
+//             Example:
+//                     struct NodeSplitter
+//                     {
+//                             NodeSplitter(const NodeObject* objs, unsigned int numObjs);
+//                             BoundingVolume& GetNodeBV() const;
+//                             // Partition predicate
+//                             bool operator()(const NodeObject& obj) const;
+//                             // Sort predicate
+//                             bool operator()(const NodeObject& obj1, const NodeObject& obj2) const;
+//                     };
+//
+//-----------------------------------------------------------------------------
+#ifndef __SKYBVTREE_HPP__
+#define __SKYBVTREE_HPP__
+
+#include <algorithm>
+#include <vector>
+
+//-----------------------------------------------------------------------------
+// SkyBaseBVTree<Object, BoundingVolume>
+//-----------------------------------------------------------------------------
+// See header description for details.
+//-----------------------------------------------------------------------------
+template <class Object, class BoundingVolume>
+class SkyBaseBVTree
+{
+public:
+  typedef BoundingVolume BV;
+  class NodeObject;
+  
+public:
+  class Node
+  {
+    friend class SkyBaseBVTree<Object, BoundingVolume>;
+  public:
+    Node() : _pObjs(NULL), _iNumObjs(0) {}
+    Node(NodeObject* pObjs, unsigned int iNumObjs) : _pObjs(pObjs), _iNumObjs(iNumObjs)  {}
+  
+    // Public interface
+    const Object& GetObj(unsigned int index) const { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetObj(); }
+    const BV&     GetBV(unsigned int index) const  { assert(_iNumObjs != 0 && _pObjs != NULL && index < _iNumObjs); return _pObjs[index].GetBV(); }
+    unsigned int  GetNumObjs() const      { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs; }
+    const BV&     GetNodeBV() const       { assert(_iNumObjs != 0 && _pObjs != NULL); return _volume; }
+    const Node*   GetLeftChild() const    { assert(_iNumObjs != 0 && _pObjs != NULL); return this+1; }
+    const Node*   GetRightChild() const   { assert(_iNumObjs != 0 && _pObjs != NULL); return this+(GetLeftChild()->GetNumObjs()<<1); }
+    bool          IsLeaf() const          { assert(_iNumObjs != 0 && _pObjs != NULL); return _iNumObjs == 1; }
+  
+  private:
+    // List of Objects owned by the node
+    NodeObject    *_pObjs;
+    unsigned int  _iNumObjs;
+    BV            _volume;
+  };
+
+public:
+  class NodeObject
+  {
+  public:
+    NodeObject(const Object& o, const BV& v) : _obj(o), _volume(v) {}
+  
+    const Object& GetObj() const { return _obj;    }
+    const BV&     GetBV() const  { return _volume; }
+  private:
+    Object _obj;
+    BV     _volume;
+  };
+      
+protected:
+  // Give non-const access to the node for descendant classes to build the tree
+  BV& GetNodeBV(Node* pNode)          { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_volume; }
+  Node* GetLeftChild(Node* pNode)                { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+1; }
+  Node* GetRightChild(Node* pNode)             { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode+(GetLeftChild(pNode)->GetNumObjs()<<1); }
+  NodeObject* GetObjs(Node* pNode)    { assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); return pNode->_pObjs; }
+  
+  // Links a node's children by assigning the given number of objects to each child
+  // assumes the node has already had it's objects partitioned
+  void LinkNodeChildren(Node* pNode, unsigned int iLeftNumObjs)
+  {
+    assert(pNode->_iNumObjs != 0 && pNode->_pObjs != NULL); 
+    GetLeftChild(pNode)->_pObjs     = pNode->_pObjs;
+    GetLeftChild(pNode)->_iNumObjs  = iLeftNumObjs;
+    GetRightChild(pNode)->_pObjs    = pNode->_pObjs + iLeftNumObjs;
+    GetRightChild(pNode)->_iNumObjs = pNode->_iNumObjs - iLeftNumObjs;
+  }        
+};
+
+
+//------------------------------------------------------------------------------
+// Function              : ClearVector
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn ClearVector(std::vector<T>& vec)
+ * @brief This utility function uses the std::vector::swap trick to free the memory of a vector
+ *
+ * This is necessary since clear() doesn't actually free anything.
+ */ 
+template<class T>
+void ClearVector(std::vector<T>& vec)
+{
+  std::vector<T>().swap(vec);
+}
+
+
+//-----------------------------------------------------------------------------
+// SkyBVTree<Object, BoundingVolume, NodeSplitter>
+//-----------------------------------------------------------------------------
+// See header description for details.
+//-----------------------------------------------------------------------------
+template <class Object, class BoundingVolume, class NodeSplitter>
+class SkyBVTree : public SkyBaseBVTree<Object, BoundingVolume>
+{
+public:
+  typedef SkyBaseBVTree<Object, BoundingVolume> BaseTree;
+  typedef BaseTree::BV BV;
+  typedef BaseTree::NodeObject NodeObject;
+  typedef BaseTree::Node Node;
+  
+  void Clear()
+  {
+    BeginTree();
+  }
+  
+  void BeginTree(unsigned int iNumObjs = 0)
+  {
+    ClearVector(_objList);
+    ClearVector(_nodes);
+    if (iNumObjs > 0) _objList.reserve(iNumObjs);
+  }
+  
+  void AddObject(const Object &obj, const BV& volume)
+  {
+    _objList.push_back(NodeObject(obj, volume));
+  }
+  
+  void EndTree()
+  {
+    if (_objList.size() == 0) return;
+    // Initialize the root node with all the objects
+    _nodes.push_back(Node(&_objList[0], _objList.size()));
+    // create room for the other nodes. They are initialized in BuildTree().
+    _nodes.reserve(_objList.size()*2-1);
+    _nodes.resize(_objList.size()*2-1);
+    BuildTree(&_nodes[0]);
+  }
+  
+  const Node *GetRoot() const { return _nodes.empty() ? NULL : &_nodes[0]; }
+  
+  // Memory usage info
+  unsigned int CalcMemUsage() const
+  {
+    unsigned int usage = 0;
+    usage += sizeof(*this);
+    usage += _objList.capacity() * sizeof(_objList[0]);
+    usage += _nodes.capacity() * sizeof(_nodes[0]);
+    return usage;
+  }
+  
+public:
+private:
+  // Does the real work
+  void BuildTree(Node *pCurNode)
+  {
+    int iLeftNumObjs;
+    {
+      // Initialize the node splitter with the current node
+      NodeSplitter splitter(GetObjs(pCurNode), pCurNode->GetNumObjs());
+      
+      // set the node's bounding volume using the splitter
+      GetNodeBV(pCurNode) = splitter.GetNodeBV();
+      
+      // When a node has one object we can stop
+      if (pCurNode->GetNumObjs() == 1) return;
+      
+      // Try and partition the objects
+      iLeftNumObjs = std::partition(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter) - GetObjs(pCurNode);
+      
+      if ((iLeftNumObjs == 0) || (iLeftNumObjs == pCurNode->GetNumObjs()))
+      {
+        // Partition failed. Sort and split again to force a complete tree
+        std::sort(GetObjs(pCurNode), &GetObjs(pCurNode)[pCurNode->GetNumObjs()], splitter);
+        iLeftNumObjs = pCurNode->GetNumObjs() / 2;
+      }
+    }
+    
+    LinkNodeChildren(pCurNode, iLeftNumObjs);
+    BuildTree(GetLeftChild(pCurNode));
+    BuildTree(GetRightChild(pCurNode));
+  }
+  
+  std::vector<Node>       _nodes;
+  std::vector<NodeObject> _objList;
+};
+
+#endif //__SKYBVTREE_HPP__
\ 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 (file)
index 0000000..83f2513
--- /dev/null
@@ -0,0 +1,242 @@
+//============================================================================
+// File          : SkyBVTreeSplitter.hpp
+// 
+// Author        : Wesley Hunt
+// 
+// Content       : NodeSplitter classes for SkyBVTrees using SkyBoundingBox or
+//                 SkyBoundingSphere (not implemented).
+// 
+//============================================================================
+#ifndef __SKYBVTREESPLITTER_HPP__
+#define __SKYBVTREESPLITTER_HPP__
+
+//----------------------------------------------------------------------------
+//-- Includes ----------------------------------------------------------------
+//----------------------------------------------------------------------------
+#include "SkyBVTree.hpp"
+#include "SkyMinMaxBox.hpp"
+//#include <Mlx/MlxBoundingSphere.hpp>
+//#if _MSC_VER == 1200
+//#include <Auxlib/AuxCompileTimeChecker.hpp>
+//#endif
+//----------------------------------------------------------------------------
+//-- Forward Declarations ----------------------------------------------------
+//----------------------------------------------------------------------------
+// A strategy for splitting nodes compatible with bounding boxes and spheres.
+template<class Object> class SkyBoundingBoxSplitter;
+// SkyBVTree compatible node splitters implemented using the above strategy.
+template<class Object> class SkyAABBTreeSplitter;
+//template<class Object> class SkySphereTreeSplitter;
+
+//----------------------------------------------------------------------------
+//-- Defines, Constants, Enumerated Types ------------------------------------
+//----------------------------------------------------------------------------
+const float rLongObjectPercentageTolerance = 0.75f;
+
+//----------------------------------------------------------------------------
+//     SkyBoundingBoxSplitter
+//----------------------------------------------------------------------------
+//     This class defines a NodeSplitter strategy that has the functionality 
+//     required by SkyBVTree's NodeSplitter template class. Can be used with
+//     SkyMinMaxBox and SkyBoundingSphere.
+//
+//     It defines a two-tiered split strategy:
+//
+//     * First it tries to separate large objects from any smaller objects. 
+//     * If there are no large objects, it splits along the midpoint of the longest
+//       axis defined by the objects.
+//     * Finally, if all else fails, it defines a total ordering along the longest
+//       axis based on the center of each node.
+//----------------------------------------------------------------------------
+template<class Object>
+class SkyBoundingBoxSplitter
+{
+public:
+       typedef SkyBaseBVTree<Object, SkyMinMaxBox>::NodeObject NodeObjectBox;
+       //typedef SkyBaseBVTree<Object, SkyBoundingSphere>::NodeObject NodeObjectSphere;
+
+#if _MSC_VER == 1200
+       // !!! WRH HACK MSVC++6 SP5 Workaround.
+       // VC6 can't disambiguate this constructor because it doesn't consider the two
+       // NodeObject templates to be different classes for the purposes of
+       // overloading. It won't recognize that the second template parameters are
+       // different. Forcing them to be explicit template specializations fixes
+       // the problem.
+       template<class BV>
+       SkyBoundingBoxSplitter(const SkyBaseBVTree<Object, BV>::NodeObject*, unsigned int)
+       {
+               //AUX_STATIC_CHECK(false, VisualC_6_WorkAround); ???
+       }
+       template<>
+#endif
+       SkyBoundingBoxSplitter(const NodeObjectBox* pObjs, unsigned int iNumObjs)
+       {
+               for (unsigned int i = 0; i < iNumObjs; ++i)
+               {
+                       _nodeBBox.Union(pObjs[i].GetBV());
+               }
+               Init(pObjs, iNumObjs);
+       }
+/*#if _MSC_VER == 1200
+       template<>
+#endif
+SkyBoundingBoxSplitter(const NodeObjectSphere* objs, 
+#ifdef _PLATFORM_XBOX
+       Int32
+#else
+       UInt32 
+#endif
+       numObjs)
+       {
+               for (int i=0; i<numObjs; ++i)
+               {
+                       SkyMinMaxBox box;
+                       box.AddPoint(objs[i].GetBV().GetCenter());
+                       box.Bloat(objs[i].GetBV().GetRadius());
+                       _nodeBBox.Union(box);
+               }
+               Init(objs, numObjs);
+       }*/
+
+       template<class nodeObj>
+       bool SplitLeft(const nodeObj& obj) const
+       {
+               if (_bIsolateLongObjects) 
+                       return GetSplitAxisLength(obj.GetBV()) < _rMaxObjectLength;
+               else
+                       return GetSplitAxisCenter(obj.GetBV()) < _rSplitValue;
+       }
+
+       template<class nodeObj>
+       bool LessThan(const nodeObj& obj1, const nodeObj& obj2) const
+       {
+               return GetSplitAxisCenter(obj1.GetBV()) < GetSplitAxisCenter(obj2.GetBV());
+       }
+
+       const SkyMinMaxBox& GetNodeBBox() const { return _nodeBBox; }
+
+private:
+       template<class nodeObj>
+       void Init(const nodeObj* pObjs, unsigned int iNumObjs)
+       {
+               _iSplitAxis       = FindSplitAxis(_nodeBBox);
+               _rSplitValue      = FindSplitValue(_nodeBBox, _iSplitAxis);
+               _rMaxObjectLength = GetSplitAxisLength(_nodeBBox) * rLongObjectPercentageTolerance;
+
+               _bIsolateLongObjects = false;
+               for (unsigned int i = 0; i < iNumObjs; ++i)
+               {
+                       if (GetSplitAxisLength(pObjs[i].GetBV()) > _rMaxObjectLength)
+                       {
+                               _bIsolateLongObjects = true;
+                               break;
+                       }
+               }
+       }
+
+       int FindSplitAxis(const SkyMinMaxBox& bbox)
+       {
+               int iAxis = 0, i;
+               Vec3f vecExt = bbox.GetMax() - bbox.GetMin();
+               for (i = 1; i < 3; ++i)  if (vecExt[i] > vecExt[iAxis]) iAxis = i;
+               return iAxis;
+       }
+       float FindSplitValue(const SkyMinMaxBox& bbox, int iSplitAxis)
+       {
+               return (bbox.GetMin()[iSplitAxis] + bbox.GetMax()[iSplitAxis])*0.5f;
+       }
+
+       /*float GetSplitAxisLength(const SkyBoundingSphere& sphere) const
+       {
+               return 2.f*sphere.GetRadius();
+       }*/
+       float GetSplitAxisLength(const SkyMinMaxBox& bbox) const
+       {
+               return bbox.GetMax()[_iSplitAxis] - bbox.GetMin()[_iSplitAxis];
+       }
+
+       float GetSplitAxisCenter(const SkyMinMaxBox& bbox) const
+       {
+               return (bbox.GetMin()[_iSplitAxis] + bbox.GetMax()[_iSplitAxis]) * 0.5f;
+       }
+       /*float GetSplitAxisCenter(const SkyBoundingSphere& sphere) const
+       {
+               return sphere.GetCenter()[SplitAxis];
+       }*/
+
+       int   _iSplitAxis;
+       float _rSplitValue;
+       bool  _bIsolateLongObjects;
+       float _rMaxObjectLength;
+
+       SkyMinMaxBox _nodeBBox;
+};
+
+//----------------------------------------------------------------------------
+//     SkyAABBTreeSplitter
+//----------------------------------------------------------------------------
+//     A NodeSplitter that is compatible with SkyBVTree for SkyMinMaxBox. 
+//     Implemented using the SkyBoundingBoxSplitter strategy.
+//----------------------------------------------------------------------------
+template<class Object>
+class SkyAABBTreeSplitter
+{
+public:
+       typedef SkyMinMaxBox BV;
+       typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
+
+       SkyAABBTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) {}
+
+       const BV& GetNodeBV() const                             { return _splitter.GetNodeBBox(); }
+
+       bool operator()(const NodeObject& obj) const
+       {
+               return _splitter.SplitLeft(obj);
+       }
+
+       bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
+       {
+               return _splitter.LessThan(obj1, obj2);
+       }
+       
+private:
+       SkyBoundingBoxSplitter<Object> _splitter;
+};
+
+//----------------------------------------------------------------------------
+//     SkySphereTreeSplitter
+//----------------------------------------------------------------------------
+//     A NodeSplitter that is compatible with SkyBVTree for SkyBoundingSphere. 
+//     Implemented using the SkyBoundingBoxSplitter strategy.
+//----------------------------------------------------------------------------
+/*template<class Object>
+class SkySphereTreeSplitter
+{
+public:
+       typedef SkyBoundingSphere BV;
+       typedef SkyBaseBVTree<Object, BV>::NodeObject NodeObject;
+
+       MlxSphereTreeSplitter(const NodeObject* pObjs, unsigned int iNumObjs) : _splitter(pObjs, iNumObjs) 
+       {
+               _nodeBV = pObjs[0].GetBV();
+               for (unsigned int i = 1; i < iNumObjs; ++i) _nodeBV.Union(pObjs[i].GetBV());
+       }
+
+       const BV& GetNodeBV() const                             { return _nodeBV; }
+
+       bool operator()(const NodeObject& obj) const
+       {
+               return _splitter.SplitLeft(obj);
+       }
+
+       bool operator()(const NodeObject& obj1, const NodeObject& obj2) const
+       {
+               return _splitter.LessThan(obj1, obj2);
+       }
+
+private:
+       BV _nodeBV;
+       SkyBoundingBoxSplitter<Object> _splitter;
+};*/
+
+#endif //__SKYBVTREESPLITTER_HPP__
\ 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 (file)
index 0000000..9f2242c
--- /dev/null
@@ -0,0 +1,151 @@
+//------------------------------------------------------------------------------
+// File : SkyBoundingVolume.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyBoundingVolume.hpp
+ * 
+ * Base class interface definition for a bounding volume.
+ */
+#ifndef __SKYBOUNDINGVOLUME_HPP__
+#define __SKYBOUNDINGVOLUME_HPP__
+
+#include <vec3f.hpp>
+#include <mat44.hpp>
+
+// forward to reduce unnecessary dependencies
+class Camera;
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyBoundingVolume
+ * @brief An abstract base class for bounding volumes (AABB,OBB,Sphere,etc.)
+ *
+ * This base class maintains a center and a radius, so it is effectively a bounding
+ * sphere.  Derived classes may represent other types of bounding volumes, but they 
+ * should be sure to update the radius and center, because some objects will treat
+ * all bounding volumes as spheres.
+ *
+ */
+class SkyBoundingVolume
+{
+public:
+  //! Constructor
+  SkyBoundingVolume() : _vecCenter(0, 0, 0), _rRadius(0) {}
+  //! Destructor
+  virtual ~SkyBoundingVolume() {}
+
+
+  //------------------------------------------------------------------------------
+  // Function            : SetCenter
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn SetCenter(const Vec3f &center)
+   * @brief Sets the center of the bounding volume.
+   */ 
+  virtual void SetCenter(const Vec3f &center)               { _vecCenter = center; }
+  
+
+  //------------------------------------------------------------------------------
+  // Function            : SetRadius
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn SetRadius(float radius)
+   * @brief Sets the radius of the bounding volume.
+   */ 
+  virtual void SetRadius(float radius)                      { _rRadius = radius;   }
+
+
+  //------------------------------------------------------------------------------
+  // Function            : Vec3f& GetCenter
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Vec3f& GetCenter() const
+   * @brief Returns the center of the bounding volume.
+   */ 
+  virtual const Vec3f& GetCenter() const                    { return _vecCenter;   }
+
+
+  //------------------------------------------------------------------------------
+  // Function            : GetRadius
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn GetRadius() const
+   * @brief Returns the radius ofthe bounding volume.
+   */ 
+  virtual float GetRadius() const                           { return _rRadius;     }
+
+  //------------------------------------------------------------------------------
+  // Function            : ViewFrustumCull
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn ViewFrustumCull( const Camera &cam, const Mat44f &mat )
+   * @brief Cull a bounding volume.
+   * 
+   * Returns false if the bounding volume is entirely outside the camera's frustum,
+   * true otherwise.
+   */ 
+  virtual bool ViewFrustumCull( const Camera &cam, const Mat44f &mat ) = 0;
+
+  //------------------------------------------------------------------------------
+  // Function            : AddPoint
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /*
+   * @fn AddPoint( const Vec3f &pt )
+   * @brief Add a point to a bounding volume.
+   * 
+   * One way to create a bounding volume is to add points.  What should/could happen 
+   * is that the BV will store an object space BV and then when a call to SetPosition 
+   * is called, the stored values will be transformed and stored separately, so that 
+   * the original values always exist.
+   *
+   */ 
+  //virtual void AddPoint( const Vec3f &point )  = 0;
+  
+  //------------------------------------------------------------------------------
+  // Function            : AddPoint
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /*
+   * @fn AddPoint( float x, float y, float z )
+   * @brief Add a point to a bounding volume.
+   * 
+   * @see AddPoint(const Vec3f &pt)
+   */ 
+  //virtual void AddPoint( float x, float y, float z ) = 0;
+
+  //------------------------------------------------------------------------------
+  // Function            : Clear
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /*
+   * @fn Clear()
+   * @brief Clear all data from the bounding volume.
+   */ 
+  //virtual void Clear() = 0;
+
+protected:
+  Vec3f        _vecCenter;
+  float        _rRadius;
+};
+
+#endif //__SKYBOUNDINGVOLUME_HPP__
\ 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 (file)
index 0000000..26640d3
--- /dev/null
@@ -0,0 +1,966 @@
+//------------------------------------------------------------------------------
+// File : SkyCloud.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyCloud.cpp
+ * 
+ * Implementation of class SkyCloud.
+ */
+
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+//#include "glvu.hpp"
+#include "SkyCloud.hpp"
+#include "SkyRenderableInstance.hpp" 
+#include "SkyContext.hpp"
+#include "SkyMaterial.hpp"
+#include "SkyLight.hpp"
+#include "SkyTextureManager.hpp"
+#include "SkySceneManager.hpp"
+#include <algorithm>
+
+//! The version used for cloud archive files.
+#define CLOUD_ARCHIVE_VERSION 0.1f
+
+//------------------------------------------------------------------------------
+// Static initialization
+//------------------------------------------------------------------------------
+SkyMaterial*  SkyCloud::s_pMaterial         = NULL;
+SkyMaterial*  SkyCloud::s_pShadeMaterial    = NULL;
+unsigned int  SkyCloud::s_iShadeResolution  = 32;
+float         SkyCloud::s_rAlbedo           = 0.9f;
+float         SkyCloud::s_rExtinction       = 80.0f;
+float         SkyCloud::s_rTransparency     = exp(-s_rExtinction);
+float         SkyCloud::s_rScatterFactor    = s_rAlbedo * s_rExtinction * SKY_INV_4PI;
+float         SkyCloud::s_rSortAngleErrorTolerance = 0.8f;
+float         SkyCloud::s_rSortSquareDistanceTolerance = 100;
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::SkyCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::SkyCloud()
+ * @brief Constructor.
+ */ 
+SkyCloud::SkyCloud()
+: SkyRenderable(),
+  _bUsePhaseFunction(true),
+  _vecLastSortViewDir(Vec3f::ZERO),
+  _vecLastSortCamPos(Vec3f::ZERO)
+{
+  if (!s_pShadeMaterial)
+  {
+    s_pShadeMaterial = new SkyMaterial;
+    s_pShadeMaterial->SetAmbient(Vec4f(0.1f, 0.1f, 0.1f, 1));
+    s_pShadeMaterial->EnableDepthTest(false);
+    s_pShadeMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+    s_pShadeMaterial->EnableBlending(true);
+    s_pShadeMaterial->SetAlphaFunc(GL_GREATER);
+    s_pShadeMaterial->SetAlphaRef(0);
+    s_pShadeMaterial->EnableAlphaTest(true);
+    s_pShadeMaterial->SetColorMaterialMode(GL_DIFFUSE);
+    s_pShadeMaterial->EnableColorMaterial(true);
+    s_pShadeMaterial->EnableLighting(false);
+    s_pShadeMaterial->SetTextureApplicationMode(GL_MODULATE);
+  }
+  if (!s_pMaterial)
+  {
+    s_pMaterial = new SkyMaterial;
+    s_pMaterial->SetAmbient(Vec4f(0.3f, 0.3f, 0.3f, 1));
+    s_pMaterial->SetDepthMask(false);
+    s_pMaterial->SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+    s_pMaterial->EnableBlending(true);
+    s_pMaterial->SetAlphaFunc(GL_GREATER);
+    s_pMaterial->SetAlphaRef(0);
+    s_pMaterial->EnableAlphaTest(true);
+    s_pMaterial->SetColorMaterialMode(GL_DIFFUSE);
+    s_pMaterial->EnableColorMaterial(true);
+    s_pMaterial->EnableLighting(false);
+    s_pMaterial->SetTextureApplicationMode(GL_MODULATE);
+    _CreateSplatTexture(32); // will assign the texture to both static materials
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::~SkyCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::~SkyCloud()
+ * @brief Destructor.
+ */ 
+SkyCloud::~SkyCloud()
+{
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Update
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyCloud::Update(const Camera &cam, SkyRenderableInstance* pInstance)
+* @brief Currently does nothing.
+*/ 
+SKYRESULT SkyCloud::Update(const Camera &cam, SkyRenderableInstance* pInstance)
+{
+  return SKYRESULT_OK;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Function              : DrawQuad
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
+ * @brief Draw a quad.
+ */ 
+inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
+{
+  glColor4fv(&(color.x));
+  Vec3f left  = pos;  left   -= y; 
+  Vec3f right = left; right  += x; 
+  left  -= x;
+  glTexCoord2f(0, 0); glVertex3fv(&(left.x));
+  glTexCoord2f(1, 0); glVertex3fv(&(right.x));
+  left  += y;  left  += y;
+  right += y;  right += y;
+  glTexCoord2f(1, 1); glVertex3fv(&(right.x));
+  glTexCoord2f(0, 1); glVertex3fv(&(left.x));
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Display(const Camera &camera, SkyRenderableInstance *pInstance)
+ * @brief Renders the cloud.
+ * 
+ * The cloud is rendered by splatting the particles from back to front with respect
+ * to @a camera.  Since instances of clouds each have their own particles, which 
+ * are pre-transformed into world space, @a pInstance is not used.
+ *
+ * An alternative method is to store the particles untransformed, and transform the 
+ * camera and light into cloud space for rendering.  This is more complicated, 
+ * and not as straightforward.  Since I have to store the particles with each instance
+ * anyway, I decided to pre-transform them instead.
+ */ 
+SKYRESULT SkyCloud::Display(const Camera &camera, SkyRenderableInstance *pInstance)
+{
+  // copy the current camera
+  Camera cam(camera);
+  
+  // This cosine computation, along with the if() below, are an optimization.  The goal
+  // is to avoid sorting when it will make no visual difference.  This will be true when the 
+  // cloud particles are almost sorted for the current viewpoint.  This is the case most of the 
+  // time, since the viewpoint does not move very far in a single frame.  Each time we sort,
+  // we cache the current view direction.  Then, each time the cloud is displayed, if the 
+  // current view direction is very close to the current view direction (dot product is nearly 1)
+  // then we do not resort the particles.
+  float rCosAngleSinceLastSort = 
+      _vecLastSortViewDir * cam.ViewDir(); // dot product
+
+  float rSquareDistanceSinceLastSort = 
+    (cam.Orig - _vecLastSortCamPos).LengthSqr();
+
+  if (rCosAngleSinceLastSort < s_rSortAngleErrorTolerance || 
+      rSquareDistanceSinceLastSort > s_rSortSquareDistanceTolerance)
+  {
+    // compute the sort position for particles.
+    // don't just use the camera position -- if it is too far away from the cloud, then
+    // precision limitations may cause the STL sort to hang.  Instead, put the sort position
+    // just outside the bounding sphere of the cloud in the direction of the camera.
+    Vec3f vecSortPos = -cam.ViewDir();
+    vecSortPos *= (1.1 * _boundingBox.GetRadius());
+    
+    // sort the particles from back to front wrt the camera position.
+    _SortParticles(cam.ViewDir(), vecSortPos, SKY_CLOUD_SORT_TOWARD);
+
+    //_vecLastSortViewDir = GLVU::GetCurrent()->GetCurrentCam()->ViewDir();
+    //_vecLastSortCamPos = GLVU::GetCurrent()->GetCurrentCam()->Orig;
+    _vecLastSortViewDir = cam.ViewDir();
+    _vecLastSortCamPos = cam.Orig;
+  } 
+
+  // set the material state / properties that clouds use for rendering:
+  // Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
+  // Enables alpha test to discard completely transparent fragments.
+  // Disables depth test.
+  // Enables texturing, with modulation, and the texture set to the shared splat texture.
+  s_pMaterial->Activate();
+  
+  Vec4f color;
+  Vec3f eyeDir;
+
+  // Draw the particles using immediate mode.
+  glBegin(GL_QUADS);
+
+  int i = 0;
+  for (ParticleIterator iter = _particles.begin(); iter != _particles.end(); iter++)
+  {
+    i++;
+    SkyCloudParticle *p = *iter;
+
+    // Start with ambient light
+    color = p->GetBaseColor();
+    
+    if (_bUsePhaseFunction) // use the phase function for anisotropic scattering.
+    {\r 
+      eyeDir = cam.Orig;
+      eyeDir -= p->GetPosition();     
+      eyeDir.Normalize();
+      float pf;
+          
+      // add the color contribution to this particle from each light source, modulated by
+      // the phase function.  See _PhaseFunction() documentation for details.
+      for (int i = 0; i < p->GetNumLitColors(); i++)
+      {
+        pf = _PhaseFunction(_lightDirections[i], eyeDir);
+        // expand this to avoid temporary vector creation in the inner loop
+        color.x += p->GetLitColor(i).x * pf;
+        color.y += p->GetLitColor(i).y * pf;
+        color.z += p->GetLitColor(i).z * pf;
+      }
+    }
+    else  // just use isotropic scattering instead.
+    {   
+      for (int i = 0; i < (*iter)->GetNumLitColors(); ++i)
+      {
+        color += p->GetLitColor(i);
+      }
+    }
+    
+    // Set the transparency independently of the colors
+    color.w = 1 - s_rTransparency;
+    
+    // draw the particle as a textured billboard.
+    DrawQuad((*iter)->GetPosition(), cam.X * p->GetRadius(), cam.Y * p->GetRadius(), color);
+  }
+  glEnd();
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::DisplaySplit
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::DisplaySplit(const Camera &camera, const Vec3f &vecSplitPoint, bool bBackHalf, SkyRenderableInstance *pInstance)
+ * @brief The same as Display(), except it displays only the particles in front of or behind the split point.
+ * 
+ * This is used to render clouds into two impostor images for displaying clouds that contain objects.
+ *
+ * @see SkyRenderableInstanceCloud
+ */ 
+SKYRESULT SkyCloud::DisplaySplit(const Camera           &camera, 
+                                 const Vec3f            &vecSplitPoint,
+                                 bool                   bBackHalf,
+                                 SkyRenderableInstance  *pInstance /* = NULL */)
+{
+  // copy the current camera
+  Camera cam(camera);
+
+  Vec3f vecCloudSpaceSplit = vecSplitPoint;
+
+  if (bBackHalf) // only sort when rendering the back half.  Reuse sort for front half.
+  {
+    // compute the sort position for particles.
+    // don't just use the camera position -- if it is too far away from the cloud, then
+    // precision limitations may cause the STL sort to hang.  Instead, put the sort position
+    // just outside the bounding sphere of the cloud in the direction of the camera.
+    _vecSortPos = -cam.ViewDir();
+    _vecSortPos *= (1.1 * _boundingBox.GetRadius());
+    
+    // sort the particles from back to front wrt the camera position.
+    _SortParticles(cam.ViewDir(), _vecSortPos, SKY_CLOUD_SORT_TOWARD);
+
+    // we can't use the view direction optimization when the cloud is split, or we get a lot
+    // of popping of objects in and out of cloud cover.  For consistency, though, we need to update
+    // the cached sort direction, since we just sorted the particles.
+    ///_vecLastSortViewDir = GLVU::GetCurrent()->GetCurrentCam()->ViewDir(); 
+
+    // compute the split distance.
+    vecCloudSpaceSplit  -= _vecSortPos;
+    _rSplitDistance = vecCloudSpaceSplit * cam.ViewDir();
+  }
+
+  // set the material state / properties that clouds use for rendering:
+  // Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
+  // Enables alpha test to discard completely transparent fragments.
+  // Disables depth test.
+  // Enables texturing, with modulation, and the texture set to the shared splat texture.
+  s_pMaterial->Activate();
+  
+  Vec4f color;
+  Vec3f eyeDir;
+
+  // Draw the particles using immediate mode.
+  glBegin(GL_QUADS);
+
+  // if bBackHalf is false, then we just continue where we left off.  If it is true, we
+  // reset the iterator to the beginning of the sorted list.
+  static ParticleIterator iter;
+  if (bBackHalf) 
+    iter = _particles.begin();
+  
+  // iterate over the particles and render them.
+  for (; iter != _particles.end(); ++iter)
+  {
+    SkyCloudParticle *p = *iter;
+
+    if (bBackHalf && (p->GetSquareSortDistance() < _rSplitDistance))
+      break;
+
+    // Start with ambient light
+    color = p->GetBaseColor();
+    
+    if (_bUsePhaseFunction) // use the phase function for anisotropic scattering.
+    {
+      eyeDir = cam.Orig;
+      eyeDir -= p->GetPosition();
+      eyeDir.Normalize();
+      float pf;
+          
+      // add the color contribution to this particle from each light source, modulated by
+      // the phase function.  See _PhaseFunction() documentation for details.
+      for (int i = 0; i < p->GetNumLitColors(); i++)
+      {
+        pf = _PhaseFunction(_lightDirections[i], eyeDir);
+        // expand this to avoid temporary vector creation in the inner loop
+        color.x += p->GetLitColor(i).x * pf;
+        color.y += p->GetLitColor(i).y * pf;
+        color.z += p->GetLitColor(i).z * pf;
+      }
+    }
+    else  // just use isotropic scattering instead.
+    {      
+      for (int i = 0; i < p->GetNumLitColors(); ++i)
+      {
+        color += p->GetLitColor(i);
+      }
+    }
+
+    // set the transparency independently of the colors.
+    color.w = 1 - s_rTransparency;
+    
+    // draw the particle as a textured billboard.
+    DrawQuad((*iter)->GetPosition(), cam.X * p->GetRadius(), cam.Y * p->GetRadius(), color);
+  }
+  glEnd();
+  
+  return SKYRESULT_OK;
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Illuminate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Illuminate(SkyLight *pLight, SkyRenderableInstance* pInstance, bool bReset)
+ * @brief Compute the illumination of the cloud by the lightsource @a pLight
+ * 
+ * This method uses graphics hardware to compute multiple forward scattering at each cloud
+ * in the cloud of light from the directional light source @a pLight.  The algorithm works
+ * by successively subtracting "light" from an initially white (fully lit) frame buffer by
+ * using hardware blending and read back.  The method stores the illumination from each light
+ * source passed to it separately at each particle, unless @a bReset is true, in which case
+ * the lists of illumination in the particles are reset before the lighting is computed.
+ * 
+ */ 
+SKYRESULT SkyCloud::Illuminate(SkyLight *pLight, SkyRenderableInstance* pInstance, bool bReset)
+{
+  int iOldVP[4];       
+
+  glGetIntegerv(GL_VIEWPORT, iOldVP);
+  glViewport(0, 0, s_iShadeResolution, s_iShadeResolution);
+
+  Vec3f vecDir(pLight->GetDirection());
+
+  // if this is the first pass through the lights, reset will be true, and the cached light 
+  // directions should be updated.  Light directions are cached in cloud space to accelerate 
+  // computation of the phase function, which depends on light direction and view direction.
+  if (bReset)
+    _lightDirections.clear();
+  _lightDirections.push_back(vecDir); // cache the (unit-length) light direction
+
+  // compute the light/sort position for particles from the light direction.
+  // don't just use the camera position -- if it is too far away from the cloud, then
+  // precision limitations may cause the STL sort to hang.  Instead, put the sort position
+  // just outside the bounding sphere of the cloud in the direction of the camera.
+  Vec3f vecLightPos(vecDir);
+  vecLightPos *= (1.1*_boundingBox.GetRadius());
+  vecLightPos += _boundingBox.GetCenter();
+
+  // Set up a camera to look at the cloud from the light position.  Since the sun is an infinite
+  // light source, this camera will use an orthographic projection tightly fit to the bounding
+  // sphere of the cloud.  
+  Camera cam;
+  
+  // Avoid degenerate camera bases.
+  Vec3f vecUp(0, 1, 0);
+  if (fabs(vecDir * vecUp) - 1 < 1e-6) // check that the view and up directions are not parallel.
+    vecUp.Set(1, 0, 0);
+  
+  cam.LookAt(vecLightPos, _boundingBox.GetCenter(), vecUp);
+
+  // sort the particles away from the light source.
+  _SortParticles(cam.ViewDir(), vecLightPos, SKY_CLOUD_SORT_AWAY);
+
+  // projected dist to cntr along viewdir
+  float DistToCntr = (_boundingBox.GetCenter() - vecLightPos) * cam.ViewDir();
+  
+  // calc tight-fitting near and far distances for the orthographic frustum
+  float rNearDist = DistToCntr - _boundingBox.GetRadius();
+  float rFarDist  = DistToCntr + _boundingBox.GetRadius();
+
+  // set the modelview matrix from this camera.
+  glMatrixMode(GL_MODELVIEW);
+  glPushMatrix();
+  float M[16];
+  cam.GetModelviewMatrix(M);
+  glLoadMatrixf(M);
+  
+  // switch to parallel projection
+  glMatrixMode(GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity();
+  glOrtho(-_boundingBox.GetRadius(), _boundingBox.GetRadius(),
+          -_boundingBox.GetRadius(), _boundingBox.GetRadius(),
+          rNearDist, rFarDist);
+  
+  // set the material state / properties that clouds use for shading:
+  // Enables blending, with blend func (ONE, ONE_MINUS_SRC_ALPHA).
+  // Enables alpha test to discard completely transparent fragments.
+  // Disables depth test.
+  // Enables texturing, with modulation, and the texture set to the shared splat texture.
+  s_pShadeMaterial->Activate();
+
+  // these are used for projecting the particle position to determine where to read pixels.
+  double MM[16], PM[16];
+  int VP[4] = { 0, 0, s_iShadeResolution, s_iShadeResolution };
+  glGetDoublev(GL_MODELVIEW_MATRIX, MM);
+  glGetDoublev(GL_PROJECTION_MATRIX, PM);
+    
+  // initialize back buffer to all white -- modulation darkens areas where cloud particles
+  // absorb light, and lightens it where they scatter light in the forward direction.
+  glClearColor(1, 1, 1, 1);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  float rPixelsPerLength = s_iShadeResolution / (2 * _boundingBox.GetRadius());
+
+  // the solid angle over which we will sample forward-scattered light.
+  float rSolidAngle = 0.09;
+  int i = 0;
+  int iNumFailed = 0;
+  for (ParticleIterator iter = _particles.begin(); iter != _particles.end(); ++iter, ++i)
+  {
+    Vec3f vecParticlePos = (*iter)->GetPosition();
+
+    Vec3f vecOffset(vecLightPos);
+    vecOffset -= vecParticlePos;
+   
+    // compute the pixel area to read back in order to integrate the illumination of the particle
+    // over a constant solid angle.
+    float rDistance  = fabs(cam.ViewDir() * vecOffset) - rNearDist;
+
+    float rArea      = rSolidAngle * rDistance * rDistance;
+    int   iPixelDim  = sqrt(rArea) * rPixelsPerLength;
+    int   iNumPixels = iPixelDim * iPixelDim;
+    if (iNumPixels < 1) 
+    {
+      iNumPixels = 1;
+      iPixelDim = 1;
+    }
+
+    // the scale factor to convert the read back pixel colors to an average illumination of the area.
+    float rColorScaleFactor = rSolidAngle / (iNumPixels * 255.0f);
+
+    unsigned char *c = new unsigned char[4 * iNumPixels];
+    
+    Vec3d vecWinPos;
+    
+    // find the position in the buffer to which the particle position projects.
+    if (!gluProject(vecParticlePos.x, vecParticlePos.y, vecParticlePos.z, 
+                    MM, PM, VP, 
+                    &(vecWinPos.x), &(vecWinPos.y), &(vecWinPos.z)))
+    {
+      FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+                      "Error: SkyCloud::Illuminate(): failed to project particle position.");
+    }
+   
+    // offset the projected window position by half the size of the readback region.
+    vecWinPos.x -= 0.5 * iPixelDim;
+    if (vecWinPos.x < 0) vecWinPos.x = 0;
+    vecWinPos.y -= 0.5 * iPixelDim;
+    if (vecWinPos.y < 0) vecWinPos.y = 0;
+    
+    // read back illumination of this particle from the buffer.
+    glReadBuffer(GL_BACK);
+    glReadPixels(vecWinPos.x, vecWinPos.y, iPixelDim, iPixelDim, GL_RGBA, GL_UNSIGNED_BYTE, c);
+    
+    // scattering coefficient vector.
+    Vec4f vecScatter(s_rScatterFactor, s_rScatterFactor, s_rScatterFactor, 1);
+
+    // add up the read back pixels (only need one component -- its grayscale)
+    int iSum = 0;
+    for (int k = 0; k < 4 * iNumPixels; k+=4)
+      iSum += c[k];
+    delete [] c;
+    
+    // compute the amount of light scattered to this particle by particles closer to the light.
+    // this is the illumination over the solid angle that we measured (using glReadPixels) times
+    // the scattering coefficient (vecScatter);
+    Vec4f vecScatteredAmount(iSum * rColorScaleFactor, 
+                             iSum * rColorScaleFactor, 
+                             iSum * rColorScaleFactor, 
+                             1 - s_rTransparency);
+    vecScatteredAmount &= vecScatter;
+
+    // the color of th particle (iter) contributed by this light source (pLight) is the 
+    // scattered light from the part of the cloud closer to the light, times the diffuse color
+    // of the light source.  The alpha is 1 - the uniform transparency of all particles (modulated
+    // by the splat texture).
+    Vec4f vecColor = vecScatteredAmount;
+    vecColor      &= pLight->GetDiffuse();  
+    vecColor.w     = 1 - s_rTransparency;
+    
+    // add this color to the list of lit colors for the particle.  The contribution from each light
+    // is kept separate because the phase function we apply at runtime depends on the light vector
+    // for each light source separately.  This view-dependent effect is impossible without knowing 
+    // the amount of light contributed for each light.  This, of course, assumes the clouds will
+    // be lit by a reasonably small number of lights (The sun plus some simulation of light reflected
+    // from the sky and / or ground.) This technique works very well for simulating anisotropic 
+    // illumination by skylight.
+    if (bReset)
+    {
+      (*iter)->SetBaseColor(s_pMaterial->GetAmbient());  
+      (*iter)->ClearLitColors();
+      (*iter)->AddLitColor(vecColor);
+    }
+    else
+    {
+      (*iter)->AddLitColor(vecColor);
+    }
+    
+    // the following computation (scaling of the scattered amount by the phase function) is done
+    // after the lit color is stored so we don't add the scattering to this particle twice.
+    vecScatteredAmount *= 1.5; // rayleigh scattering phase function for angle of zero or 180 = 1.5!
+    
+    // clamp the color
+    if (vecScatteredAmount.x > 1) vecScatteredAmount.x = 1;
+    if (vecScatteredAmount.y > 1) vecScatteredAmount.y = 1;
+    if (vecScatteredAmount.z > 1) vecScatteredAmount.z = 1;
+    vecScatteredAmount.w = 1 - s_rTransparency;
+    
+    vecScatteredAmount.x = 0.50;  vecScatteredAmount.y = 0.60;  vecScatteredAmount.z = 0.70; 
+
+    // Draw the particle as a texture billboard.  Use the scattered light amount as the color to 
+    // simulate forward scattering of light by this particle.
+    glBegin(GL_QUADS);
+    DrawQuad(vecParticlePos, cam.X * (*iter)->GetRadius(), cam.Y * (*iter)->GetRadius(), vecScatteredAmount);
+    glEnd();
+
+    //glutSwapBuffers(); // Uncomment this swap buffers to visualize cloud illumination computation.
+  }
+  
+  // Note: here we could optionally store the current back buffer as a shadow image
+  // to be projected from the light position onto the scene.  This way we can have clouds shadow
+  // the environment.
+  
+  // restore matrix stack and viewport.
+  glMatrixMode(GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode(GL_MODELVIEW);
+  glPopMatrix();
+  glViewport(iOldVP[0], iOldVP[1], iOldVP[2], iOldVP[3]);
+
+  return SKYRESULT_OK; 
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::CopyBoundingVolume
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::CopyBoundingVolume() const
+ * @brief Returns a new copy of the SkyMinMaxBox for this cloud.
+ */ 
+SkyMinMaxBox* SkyCloud::CopyBoundingVolume() const
+{
+  SkyMinMaxBox *pBox = new SkyMinMaxBox();
+  pBox->SetMax(_boundingBox.GetMax());
+  pBox->SetMin(_boundingBox.GetMin());
+  return pBox; 
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Load
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Load(const SkyArchive &archive, float rScale, bool bLocal)
+ * @brief Loads the cloud data from @a archive.
+ * 
+ * If @a rScale does not equal 1.0, then the cloud is scaled by an amount rScale.
+ */ 
+SKYRESULT SkyCloud::Load(const SkyArchive &archive, 
+                         float rScale /* = 1.0f */, 
+                         bool bLocal /* = false */)
+{
+  unsigned int iNumParticles;
+  Vec3f vecCenter = Vec3f::ZERO;
+  //Vec3f vecCenter;
+  //float rRadius;
+  //archive.FindVec3f("CldCenter", &vecCenter);
+  //archive.FindFloat32("CldRadius", &rRadius);
+
+  //_boundingBox.SetMin(vecCenter - Vec3f(rRadius, rRadius, rRadius));
+  //_boundingBox.SetMax(vecCenter + Vec3f(rRadius, rRadius, rRadius));
+
+  archive.FindUInt32("CldNumParticles", &iNumParticles);
+  if (!bLocal)
+    archive.FindVec3f("CldCenter", &vecCenter);
+  
+  Vec3f *pParticlePositions = new Vec3f[iNumParticles];
+  float *pParticleRadii     = new float[iNumParticles];
+  Vec4f *pParticleColors    = new Vec4f[iNumParticles];
+
+  unsigned int iNumBytes;
+  archive.FindData("CldParticlePositions", ANY_TYPE, (void**const)&pParticlePositions, &iNumBytes);
+  archive.FindData("CldParticleRadii",     ANY_TYPE, (void**const)&pParticleRadii,     &iNumBytes);
+  archive.FindData("CldParticleColors",    ANY_TYPE, (void**const)&pParticleColors,    &iNumBytes);
+  
+  for (unsigned int i = 0; i < iNumParticles; ++i)
+  {
+    SkyCloudParticle *pParticle = new SkyCloudParticle((pParticlePositions[i] + vecCenter) * rScale,
+                                                       pParticleRadii[i] * rScale,
+                                                       pParticleColors[i]);
+    _boundingBox.AddPoint(pParticle->GetPosition());
+    
+    _particles.push_back(pParticle);
+  }
+  // this is just a bad hack to align cloud field from skyworks with local horizon at KSFO
+  // we need to develop out own scheme for loading and positioning clouds
+  Mat33f rot_mat;
+  Vec3f  moveit;
+  
+  //moveit.Set( -10000.0, 1500.0, 1500.0  );
+  moveit.Set( 0.0, 0.0, 1050.0  );
+  
+  rot_mat.Set( 1, 0, 0,
+                                                0, 0, -1,
+                                                0, 1, 0);
+  // flip the y and z axis
+  Rotate( rot_mat ); 
+    
+   // adjust for lon af KSFO           -122.357                                 
+  rot_mat.Set( -0.5352f, 0.8447f, 0.0f,
+                                                -0.8447f, -0.5352f, 0.0f,
+                                                -0.0f, 0.0f, 1.0f);
+                                                
+  Rotate( rot_mat );
+
+   // and about x for latitude 37.6135
+  rot_mat.Set( 1.0f, 0.0, 0.0f,
+                                                0.0f, 0.7921f, -0.6103f,
+                                                0.0f, 0.6103f, 0.7921f);               
+   
+  Rotate( rot_mat ); 
+  
+  Translate( moveit );
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Save
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyCloud::Save(SkyArchive &archive) const
+* @brief Saves the cloud data to @a archive.
+* 
+* @todo <WRITE EXTENDED SkyCloud::Save FUNCTION DOCUMENTATION>
+*/ 
+SKYRESULT SkyCloud::Save(SkyArchive &archive) const
+{
+  SkyArchive myArchive("Cloud");
+  //myArchive.AddVec3f("CldCenter", _center);
+  //myArchive.AddFloat32("CldRadius", _boundingBox.GetRadius());
+  myArchive.AddUInt32("CldNumParticles", _particles.size());
+  
+  // make temp arrays
+  Vec3f *pParticlePositions = new Vec3f[_particles.size()];
+  float *pParticleRadii     = new float[_particles.size()];
+  Vec4f *pParticleColors    = new Vec4f[_particles.size()];
+  
+  unsigned int i = 0;
+
+  for (ParticleConstIterator iter = _particles.begin(); iter != _particles.end(); ++iter, ++i)
+  {
+    pParticlePositions[i] = (*iter)->GetPosition(); // position around origin
+    pParticleRadii[i]     = (*iter)->GetRadius();
+    pParticleColors[i]    = (*iter)->GetBaseColor();
+  }
+  
+  myArchive.AddData("CldParticlePositions", 
+                    ANY_TYPE, 
+                    pParticlePositions, 
+                    sizeof(Vec3f), 
+                    _particles.size());
+  
+  myArchive.AddData("CldParticleRadii", 
+                    ANY_TYPE, 
+                    pParticleRadii, 
+                    sizeof(float), 
+                    _particles.size());
+  
+  myArchive.AddData("CldParticleColors", 
+                    ANY_TYPE, 
+                    pParticleColors, 
+                    sizeof(Vec3f), 
+                    _particles.size());
+  
+  archive.AddArchive(myArchive);
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Rotate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Rotate(const Mat33f& rot)
+ * @brief @todo <WRITE BRIEF SkyCloud::Rotate DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyCloud::Rotate FUNCTION DOCUMENTATION>
+ */ 
+void SkyCloud::Rotate(const Mat33f& rot)
+{
+  _boundingBox.Clear();
+  for (int i = 0; i < _particles.size(); ++i)
+  {
+    _particles[i]->SetPosition(rot * _particles[i]->GetPosition());
+    _boundingBox.AddPoint(_particles[i]->GetPosition());
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Translate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Translate(const Vec3f& trans)
+ * @brief @todo <WRITE BRIEF SkyCloud::Translate DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyCloud::Translate FUNCTION DOCUMENTATION>
+ */ 
+void SkyCloud::Translate(const Vec3f& trans)
+{
+  for (int i = 0; i < _particles.size(); ++i)
+  {
+    _particles[i]->SetPosition(_particles[i]->GetPosition() + trans);
+  }
+  _boundingBox.SetMax(_boundingBox.GetMax() + trans);
+  _boundingBox.SetMin(_boundingBox.GetMin() + trans);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::Scale
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::Scale(const float scale)
+ * @brief @todo <WRITE BRIEF SkyCloud::Scale DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyCloud::Scale FUNCTION DOCUMENTATION>
+ */ 
+void SkyCloud::Scale(const float scale)
+{
+  _boundingBox.Clear();
+  for (int i = 0; i < _particles.size(); ++i)
+  {
+    _particles[i]->SetPosition(_particles[i]->GetPosition() * scale);
+    _boundingBox.AddPoint(_particles[i]->GetPosition());
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::_SortParticles
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::_SortParticles(const Vec3f& vecViewDir, const Vec3f& sortPoint, SortDirection dir)
+ * @brief Sorts the cloud particles in the direction specified by @a dir.
+ * 
+ * @vecSortPoint is assumed to already be transformed into the basis space of the cloud.
+ */ 
+void SkyCloud::_SortParticles(const Vec3f& vecViewDir,
+                              const Vec3f& vecSortPoint, 
+                              SortDirection dir)
+{
+  Vec3f partPos;
+       for (int i = 0; i < _particles.size(); ++i)
+       {
+               partPos = _particles[i]->GetPosition();
+               partPos -= vecSortPoint;
+               _particles[i]->SetSquareSortDistance(partPos * vecViewDir);//partPos.LengthSqr());
+       }
+
+  switch (dir)
+  {
+  case SKY_CLOUD_SORT_TOWARD:
+    std::sort(_particles.begin(), _particles.end(), _towardComparator);
+    break;
+  case SKY_CLOUD_SORT_AWAY:
+    std::sort(_particles.begin(), _particles.end(), _awayComparator);
+    break;
+  default:
+    break;
+  }
+}
+
+
+
+//------------------------------------------------------------------------------
+// Function              : EvalHermite
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * EvalHermite(float pA, float pB, float vA, float vB, float u)
+ * @brief Evaluates Hermite basis functions for the specified coefficients.
+ */ 
+inline float EvalHermite(float pA, float pB, float vA, float vB, float u)
+{
+  float u2=(u*u), u3=u2*u;
+  float B0 = 2*u3 - 3*u2 + 1;
+  float B1 = -2*u3 + 3*u2;
+  float B2 = u3 - 2*u2 + u;
+  float B3 = u3 - u;
+  return( B0*pA + B1*pB + B2*vA + B3*vB );
+}
+
+// NORMALIZED GAUSSIAN INTENSITY MAP (N must be a power of 2)
+
+//------------------------------------------------------------------------------
+// Function              : CreateGaussianMap
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * CreateGaussianMap(int N)
+ * 
+ * Creates a 2D gaussian image using a hermite surface.
+ */ 
+unsigned char* CreateGaussianMap(int N)
+{
+  float *M = new float[2*N*N];
+  unsigned char *B = new unsigned char[4*N*N];
+  float X,Y,Y2,Dist;
+  float Incr = 2.0f/N;
+  int i=0;  
+  int j = 0;
+  Y = -1.0f;
+  for (int y=0; y<N; y++, Y+=Incr)
+  {
+    Y2=Y*Y;
+    X = -1.0f;
+    for (int x=0; x<N; x++, X+=Incr, i+=2, j+=4)
+    {
+      Dist = (float)sqrt(X*X+Y2);
+      if (Dist>1) Dist=1;
+      M[i+1] = M[i] = EvalHermite(0.4f,0,0,0,Dist);// * (1 - noise);
+      B[j+3] = B[j+2] = B[j+1] = B[j] = (unsigned char)(M[i] * 255);
+    }
+  }
+  SAFE_DELETE_ARRAY(M);
+  return(B);
+}              
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::_CreateSplatTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::_CreateSplatTexture(unsigned int iResolution)
+ * @brief Creates the texture map used for cloud particles.
+ */ 
+void SkyCloud::_CreateSplatTexture(unsigned int iResolution)
+{
+  unsigned char *splatTexture = CreateGaussianMap(iResolution);
+  SkyTexture texture;
+  TextureManager::InstancePtr()->Create2DTextureObject(texture, iResolution, iResolution, 
+                                                       GL_RGBA, splatTexture);
+
+  s_pMaterial->SetTexture(0, GL_TEXTURE_2D, texture);
+  s_pShadeMaterial->SetTexture(0, GL_TEXTURE_2D, texture);
+  s_pMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  s_pMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  s_pShadeMaterial->SetTextureParameter(0, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  s_pMaterial->EnableTexture(0, true);
+  s_pShadeMaterial->EnableTexture(0, true);
+
+  SAFE_DELETE_ARRAY(splatTexture);
+}     
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloud::_PhaseFunction
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloud::_PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir)
+ * @brief Computes the phase (scattering) function of the given light and view directions.
+ * 
+ * A phase function is a transfer function that determines, for any angle between incident 
+ * and outgoing directions, how much of the incident light intensity will be 
+ * scattered in the outgoing direction.  For example, scattering by very small 
+ * particles such as those found in clear air, can be approximated using <i>Rayleigh 
+ * scattering</i>.  The phase function for Rayleigh scattering is 
+ * p(q) = 0.75*(1 + cos<sup>2</sup>(q)), where q  is the angle between incident 
+ * and scattered directions.  Scattering by larger particles is more complicated.  
+ * It is described by Mie scattering theory.  Cloud particles are more in the regime 
+ * of Mie scattering than Rayleigh scattering.  However, we obtain good visual 
+ * results by using the simpler Rayleigh scattering phase function as an approximation.
+ */ 
+float SkyCloud::_PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir)
+{
+  float rCosAlpha = vecLightDir * vecViewDir;
+  return .75f * (1 + rCosAlpha * rCosAlpha); // rayleigh scattering = (3/4) * (1+cos^2(alpha))
+}
diff --git a/simgear/scene/sky/clouds3d/SkyCloud.hpp b/simgear/scene/sky/clouds3d/SkyCloud.hpp
new file mode 100644 (file)
index 0000000..6eeb5bb
--- /dev/null
@@ -0,0 +1,175 @@
+//------------------------------------------------------------------------------
+// File : SkyCloud.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyCloud.hpp
+ * 
+ * Interface definition for class SkyCloud.
+ */
+#ifndef __SKYCLOUD_HPP__
+#define __SKYCLOUD_HPP__
+
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+#include "SkyCloudParticle.hpp"
+#include "SkyRenderable.hpp"
+#include "SkyMinMaxBox.hpp"
+#include "camera.hpp"
+#include "SkyArchive.hpp"
+#include "mat33.hpp"
+
+class SkyMaterial;
+class SkyLight;
+class SkyRenderableInstance;
+
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyCloud
+ * @brief A renderable that represents a volumetric cloud.
+ * 
+ * A SkyCloud is made up of particles, and is rendered using particle splatting.  
+ * SkyCloud is intended to represent realisticly illuminated volumetric clouds
+ * through which the viewer and / or other objects can realistically pass.
+ *
+ * Realistic illumination is performed by the Illuminate() method, which uses a
+ * graphics hardware algorithm to precompute and store multiple forward scattering 
+ * of light by each particle in the cloud.  Clouds may be illuminated by multiple
+ * light sources.  The light from each source is precomputed and stored at each
+ * particle.  Each light's contribution is stored separately so that we can 
+ * compute view-dependent (anisotropic) scattering at run-time.  This gives realistic
+ * effects such as the "silver lining" that you see on a thick cloud when it crosses
+ * in front of the sun.
+ *
+ * At run-time, the cloud is rendered by drawing each particle as a view-oriented 
+ * textured billboard (splat), with lighting computed from the precomputed illumination
+ * as follows: for each light source <i>l</i>, compute the scattering function (See _PhaseFunction())
+ * based on the view direction and the direction from the particle to the viewer.  This 
+ * scattering function modulates the lighting contribution of <i>l</i>.  The modulated 
+ * contributions are then added and used to modulate the color of the particle.  The result
+ * is view-dependent scattering.  
+ * 
+ * If the phase (scattering) function is not enabled (see IsPhaseFunctionEnabled()), then the 
+ * contributions of the light sources are simply added.
+ *
+ * @see SkyRenderableInstanceCloud, SkyCloudParticle, SkySceneManager
+ */
+class SkyCloud : public SkyRenderable
+{
+public:
+  SkyCloud();
+  virtual ~SkyCloud();
+  
+  virtual SKYRESULT           Update(const Camera &cam, SkyRenderableInstance* pInstance = NULL);
+  
+  virtual SKYRESULT           Display(const Camera &camera, SkyRenderableInstance *pInstance = NULL);
+  SKYRESULT                   DisplaySplit(const Camera           &camera, 
+                                           const Vec3f            &vecSplitPoint,
+                                           bool                   bBackHalf,
+                                           SkyRenderableInstance  *pInstance = NULL);
+
+  SKYRESULT                   Illuminate( SkyLight *pLight, 
+                                          SkyRenderableInstance* pInstance,
+                                          bool bReset = false);
+  
+  virtual SkyMinMaxBox*       CopyBoundingVolume() const;
+  
+  //! Enables the use of a scattering function for anisotropic light scattering.
+  void                        EnablePhaseFunction(bool bEnable)   { _bUsePhaseFunction = bEnable; }
+  //! Returns true if the use of a scattering function is enabled.
+  bool                        IsPhaseFunctionEnabled() const      { return _bUsePhaseFunction;    }
+  
+  SKYRESULT                   Save(SkyArchive &archive) const;
+  SKYRESULT                   Load(const SkyArchive &archive, float rScale = 1.0f, bool bLocal = false);
+  
+  void                        Rotate(const Mat33f& rot);
+  void                        Translate(const Vec3f& trans);
+  void                        Scale(const float scale);
+
+protected: // methods
+  enum SortDirection
+  {
+    SKY_CLOUD_SORT_TOWARD,
+    SKY_CLOUD_SORT_AWAY
+  };
+
+  void                                               _SortParticles(   const Vec3f& vecViewDir,
+                                              const Vec3f& vecSortPoint, 
+                                              SortDirection dir);
+  
+  void                        _CreateSplatTexture( unsigned int iResolution);
+  
+  float                       _PhaseFunction(const Vec3f& vecLightDir, const Vec3f& vecViewDir);
+  
+protected: // datatypes 
+  typedef std::vector<SkyCloudParticle*>  ParticleArray;
+  typedef ParticleArray::iterator         ParticleIterator;
+  typedef ParticleArray::const_iterator   ParticleConstIterator;
+  
+  typedef std::vector<Vec3f>              DirectionArray;
+  typedef DirectionArray::iterator        DirectionIterator;
+  
+  class ParticleAwayComparator
+  {
+  public:
+    bool operator()(SkyCloudParticle* pA, SkyCloudParticle *pB)
+    {
+      return ((*pA) < (*pB));
+    }
+  };
+  
+  class ParticleTowardComparator
+  {
+  public:
+    bool operator()(SkyCloudParticle* pA, SkyCloudParticle *pB)
+    {
+      return ((*pA) > (*pB));
+    }
+  };
+
+protected: // data
+  ParticleArray               _particles;       // cloud particles
+  // particle sorting functors for STL sort.
+  ParticleTowardComparator    _towardComparator; 
+  ParticleAwayComparator      _awayComparator; 
+
+  DirectionArray              _lightDirections; // light directions in cloud space (cached)
+
+  SkyMinMaxBox                _boundingBox;     // bounds
+
+  bool                        _bUsePhaseFunction;
+
+  Vec3f                       _vecLastSortViewDir;
+  Vec3f                       _vecLastSortCamPos;
+  Vec3f                       _vecSortPos;
+
+  float                       _rSplitDistance;
+  
+  static SkyMaterial          *s_pMaterial;     // shared material for clouds. 
+  static SkyMaterial          *s_pShadeMaterial;// shared material for illumination pass.
+  static unsigned int         s_iShadeResolution; // the resolution of the viewport used for shading
+  static float                s_rAlbedo;        // the cloud albedo
+  static float                s_rExtinction;    // the extinction of the clouds
+  static float                s_rTransparency;  // the transparency of the clouds
+  static float                s_rScatterFactor; // How much the clouds scatter
+  static float                s_rSortAngleErrorTolerance; // how far the view must turn to cause a resort.
+  static float                s_rSortSquareDistanceTolerance; // how far the view must move to cause a resort.
+};
+
+#endif //__SKYCLOUD_HPP__
\ 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 (file)
index 0000000..0b9c15b
--- /dev/null
@@ -0,0 +1,175 @@
+//------------------------------------------------------------------------------
+// File : SkyCloudParticle.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyCloudParticle.hpp
+ * 
+ * Definition of a simple cloud particle class.
+ */
+#ifndef __SKYCLOUDPARTICLE_HPP__
+#define __SKYCLOUDPARTICLE_HPP__
+
+#include "vec3f.hpp"
+#include "vec4f.hpp"
+#include <vector>
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyCloudParticle
+ * @brief A class for particles that make up a cloud.
+ * 
+ * @todo <WRITE EXTENDED CLASS DESCRIPTION>
+ */
+class SkyCloudParticle
+{
+public:
+  inline SkyCloudParticle();
+  inline SkyCloudParticle(const Vec3f& pos, 
+                          float rRadius, 
+                          const Vec4f& baseColor, 
+                          float rTransparency = 0);
+  inline ~SkyCloudParticle();
+
+  //! Returns the radius of the particle.
+  float               GetRadius() const               { return _rRadius;        }
+  //! Returns the transparency of the particle.
+  float               GetTransparency() const         { return _rTransparency;  }
+  //! Returns the position of the particle.
+  const Vec3f&        GetPosition() const             { return _vecPosition;  }
+  //! Returns the base color of the particle.  This is often used for ambient color.
+  const Vec4f&        GetBaseColor() const            { return _vecBaseColor; }
+  //! Returns the number of light contributions to this particle's color.
+  unsigned int        GetNumLitColors() const         { return _vecLitColors.size();  }
+  //! Returns the light contribution to the color of this particle from light @a index.
+  inline const Vec4f& GetLitColor(unsigned int index) const;
+  //! Returns the square distance from the sort position used for the operator< in sorts / splits.
+  float               GetSquareSortDistance() const   { return _rSquareSortDistance; }
+
+  //! Sets the radius of the particle.
+  void                SetRadius(float rad)            { _rRadius      = rad;    }
+  //! Returns the transparency of the particle.
+  void                SetTransparency(float trans)    { _rTransparency = trans; }
+  //! Sets the position of the particle.
+  void                SetPosition(const Vec3f& pos)   { _vecPosition  = pos;  }
+  //! Sets the base color of the particle.  This is often used for ambient color.
+  void                SetBaseColor(const Vec4f& col)  { _vecBaseColor = col;  }
+  //! Sets the light contribution to the color of this particle from light @a index.
+  void                AddLitColor(const Vec4f& col)   { _vecLitColors.push_back(col); }
+  //! Clears the list of light contributions.
+  void                ClearLitColors()                { _vecLitColors.clear();        }
+  //! Sets the square distance from the sort position used for the operator< in sorts.
+  void                SetSquareSortDistance(float rSquareDistance) { _rSquareSortDistance = rSquareDistance; }
+
+  //! This operator is used to sort particle arrays from nearest to farthes.
+  bool operator<(const SkyCloudParticle& p) const
+       {
+    return (_rSquareSortDistance < p._rSquareSortDistance);
+       }
+
+  //! This operator is used to sort particle arrays from farthest to nearest.
+  bool operator>(const SkyCloudParticle& p) const
+  {
+    return (_rSquareSortDistance > p._rSquareSortDistance);
+  }
+  
+protected: 
+  float               _rRadius;
+  float               _rTransparency;
+  Vec3f               _vecPosition;
+  Vec4f               _vecBaseColor;
+  std::vector<Vec4f>  _vecLitColors;
+  Vec3f               _vecEye; 
+
+  // for sorting particles during shading
+  float               _rSquareSortDistance;
+};
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloudParticle::SkyCloudParticle
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloudParticle::SkyCloudParticle()
+ * @brief Default constructor.
+ */ 
+inline SkyCloudParticle::SkyCloudParticle()
+: _rRadius(0),
+  _rTransparency(0),
+  _vecPosition(0, 0, 0),
+  _vecBaseColor(0, 0, 0, 1),
+  _vecEye(0, 0, 0),
+  _rSquareSortDistance(0)
+{
+  _vecLitColors.clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloudParticle::SkyCloudParticle
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloudParticle::SkyCloudParticle(const Vec3f& pos, float rRadius, const Vec4f& baseColor, float rTransparency)
+ * @brief Constructor.
+ */ 
+inline SkyCloudParticle::SkyCloudParticle(const Vec3f& pos, 
+                                          float rRadius, 
+                                          const Vec4f& baseColor,
+                                          float rTransparency /* = 0 */)
+: _rRadius(rRadius),
+  _rTransparency(rTransparency),
+  _vecPosition(pos),
+  _vecBaseColor(baseColor),
+  _vecEye(0, 0, 0),
+  _rSquareSortDistance(0)
+{
+  _vecLitColors.clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyCloudParticle::~SkyCloudParticle
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyCloudParticle::~SkyCloudParticle()
+ * @brief Destructor.
+ */ 
+inline SkyCloudParticle::~SkyCloudParticle()
+{
+  _vecLitColors.clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : Vec4f& SkyCloudParticle::GetLitColor
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn Vec4f& SkyCloudParticle::GetLitColor(unsigned int index) const
+ * @brief Returns the lit color specified by index.
+ * 
+ * If the index is out of range, returns a zero vector.
+ */ 
+inline const Vec4f& SkyCloudParticle::GetLitColor(unsigned int index) const
+{
+  if (index <= _vecLitColors.size())
+    return _vecLitColors[index];
+  else
+    return Vec4f::ZERO;
+}
+
+#endif //__SKYCLOUDPARTICLE_HPP__
\ 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 (file)
index 0000000..b8727f0
--- /dev/null
@@ -0,0 +1,283 @@
+//------------------------------------------------------------------------------
+// File : SkyContext.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyContext.cpp
+ * 
+ * Graphics Context Interface.  Initializes GL extensions, etc.
+ */
+#include <GL/glut.h>
+#include <GL/glx.h>
+
+//#include "extgl.h"
+
+#include "SkyContext.hpp"
+#include "SkyUtil.hpp"
+#include "SkyMaterial.hpp"
+#include "SkyTextureState.hpp"
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::SkyContext
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::SkyContext()
+ * @brief Constructor.
+ *
+ */ 
+SkyContext::SkyContext()
+{
+  _iWidth  = glutGet(GLUT_WINDOW_WIDTH);
+  _iHeight = glutGet(GLUT_WINDOW_HEIGHT);
+  
+  // materials and structure classes
+  AddCurrentGLContext();
+  // Initialize all the extensions and load the functions - JW (file is extgl.c)
+  #ifdef _WIN32
+  glInitialize();
+  InitializeExtension("GL_ARB_multitexture");
+  #endif
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::~SkyContext
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::~SkyContext()
+ * @brief Destructor.
+ */ 
+SkyContext::~SkyContext()
+{
+  // delete map of materials
+  for (ContextMaterialIterator cmi = _currentMaterials.begin(); cmi != _currentMaterials.end(); ++cmi)
+  {
+    SAFE_DELETE(cmi->second);
+  }
+  _currentMaterials.clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::ProcessReshapeEvent
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::ProcessReshapeEvent(int iWidth, int iHeight)
+ * @brief Handles window resize events, and notifies all context listeners of the event.
+ */ 
+SKYRESULT SkyContext::ProcessReshapeEvent(int iWidth, int iHeight)
+{ 
+  _iWidth = iWidth; 
+  _iHeight = iHeight; 
+  return _SendMessage(SKYCONTEXT_MESSAGE_RESHAPE);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::InitializeExtensions
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyContext::InitializeExtensions(const char *pExtensionNames)
+* @brief Initializes GL extension specified by @a pExtensionNames.      
+*/ 
+SKYRESULT SkyContext::InitializeExtension(const char *pExtensionName)
+{ /***
+  if (!QueryExtension(pExtensionName)) // see query search function defined in extgl.c
+  {
+    SkyTrace(
+      "ERROR: SkyContext::InitializeExtenstions: The following extensions are unsupported: %s\n", 
+      pExtensionName);
+    return SKYRESULT_FAIL;
+  }  **/
+  //set this false to catch all the extensions until we come up with a linux version
+  return SKYRESULT_FAIL;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::GetCurrentMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyContext::GetCurrentMaterial()
+* @brief Returns the current cached material state that is active in this OpenGL context.
+* 
+* @todo <WRITE EXTENDED SkyContext::GetCurrentMaterial FUNCTION DOCUMENTATION>
+*/ 
+SkyMaterial* SkyContext::GetCurrentMaterial()
+{
+  ContextMaterialIterator cmi = _currentMaterials.find(glXGetCurrentContext());
+  if (_currentMaterials.end() != cmi)
+    return cmi->second;
+  else
+  {
+    SkyTrace("SkyContext::GetCurrentMaterial(): Invalid context.");
+    return NULL;
+  }
+  
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::GetCurrentTextureState
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::GetCurrentTextureState()
+ * @brief Returns the current cached texture state that is active in this OpenGL context.
+ * 
+ * @todo <WRITE EXTENDED SkyContext::GetCurrentTextureState FUNCTION DOCUMENTATION>
+ */ 
+SkyTextureState* SkyContext::GetCurrentTextureState()
+{
+  ContextTextureStateIterator ctsi = _currentTextureState.find(glXGetCurrentContext());
+  if (_currentTextureState.end() != ctsi)
+    return ctsi->second;
+  else
+  {
+    SkyTrace("SkyContext::GetCurrentTextureState(): Invalid context.");
+    return NULL;
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::AddCurrentGLContext
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::AddCurrentGLContext()
+ * @brief @todo <WRITE BRIEF SkyContext::AddCurrentGLContext DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyContext::AddCurrentGLContext FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyContext::AddCurrentGLContext()
+{
+  SkyMaterial *pCurrentMaterial = new SkyMaterial;
+  _currentMaterials.insert(std::make_pair(glXGetCurrentContext(), pCurrentMaterial));
+  SkyTextureState *pCurrentTS = new SkyTextureState;
+  _currentTextureState.insert(std::make_pair(glXGetCurrentContext() , pCurrentTS));
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::Register
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::Register(Listener* pListener, int priority)
+ * @brief Register with the messaging system to handle notification of mode changes
+ */ 
+SKYRESULT SkyContext::Register(Listener* pListener, int priority)
+{
+       std::list<ListenerPair>::iterator iter = 
+    std::find_if(_listeners.begin(), _listeners.end(), _ListenerPred(pListener));
+       if (iter == _listeners.end())
+       {
+               // insert the listener, sorted by priority
+               for (iter=_listeners.begin(); iter != _listeners.end(); ++iter)
+               {
+                       if (priority <= iter->first)
+                       {
+                               _listeners.insert(iter, ListenerPair(priority, pListener));
+                               break;
+                       }
+               }
+               if (iter == _listeners.end())
+               {
+                               _listeners.push_back(ListenerPair(priority, pListener));
+               }
+               // Send a message to the pListener if we are already active so it
+               // can intialize itself
+               //FAIL_RETURN(pListener->GraphicsReshapeEvent());
+       } 
+  else
+       {
+               FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyContext: Listener is already registered");
+       }
+       return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyContext::UnRegister
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyContext::UnRegister(Listener *pListener)
+ * @brief UnRegister with the messaging system.
+ */ 
+SKYRESULT SkyContext::UnRegister(Listener *pListener)
+{
+       std::list<ListenerPair>::iterator iter = 
+    std::find_if(_listeners.begin(), _listeners.end(), _ListenerPred(pListener));
+       if (iter == _listeners.end())
+       {
+               FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyContext: Listener is not registered");
+       } 
+  else
+       {
+               _listeners.erase(iter);
+       }
+       return SKYRESULT_OK;
+}
+
+
+/**
+ * @fn SkyContext::_SendMessage(SkyMessageType msg)
+ * @brief Messaging system to handle notification of mode changes
+ */ 
+SKYRESULT SkyContext::_SendMessage(SkyMessageType msg)
+{
+       if (_listeners.size() == 0) return SKYRESULT_OK;
+
+       bool failure = false;
+       SKYRESULT res, failureCode = SKYRESULT_OK;
+       std::list<ListenerPair>::iterator iter;
+       SKYRESULT (Listener::*fnPtr)() = NULL;
+
+       // Make a pointer to the appropriate method
+       switch (msg)
+       {
+       case SKYCONTEXT_MESSAGE_RESHAPE: fnPtr = &Listener::GraphicsReshapeEvent; break;
+       }
+
+       // Notify all listeners of the messag. catch failures, but still call everyone else.
+       // !!! WRH HORRIBLE HACK must cache the current "end" because these functions could register new listeners
+       std::list<ListenerPair>::iterator endIter = _listeners.end();
+       endIter--;
+
+       iter = _listeners.begin();
+       do
+       {
+               if ( SKYFAILED( res = (iter->second->*fnPtr)() ) )
+               {
+                       failureCode = res;
+                       SkyTrace("SkyContext: SendMessage failed");
+               }
+               if (iter == endIter) break;
+               iter++;
+       } while (true);
+
+       FAIL_RETURN(failureCode);
+
+       return SKYRESULT_OK;
+}
diff --git a/simgear/scene/sky/clouds3d/SkyContext.hpp b/simgear/scene/sky/clouds3d/SkyContext.hpp
new file mode 100644 (file)
index 0000000..e6d0804
--- /dev/null
@@ -0,0 +1,141 @@
+//------------------------------------------------------------------------------
+// File : SkyContext.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyContext.hpp
+ * 
+ * Graphics Context Interface.  Initializes GL extensions, etc. 
+ */
+#ifndef __SKYCONTEXT_HPP__
+#define __SKYCONTEXT_HPP__
+
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+#include "SkySingleton.hpp"
+
+
+#ifdef _WIN32
+#include "extgl.h"
+#endif
+
+#include <list>
+#include <map>
+#include <algorithm>
+
+//  ifdef to replace windows stuff for handles-JW
+typedef void *HANDLE;
+typedef HANDLE *PHANDLE;
+#define DECLARE_HANDLE(n)  typedef HANDLE n
+
+DECLARE_HANDLE(HGLRC);
+// end of ifdef
+
+class SkyContext;
+class SkyMaterial;
+class SkyTextureState;
+
+//! Graphics Context Singleton declaration.
+/*! The Context must be created by calling GraphicsContext::Instantiate(). */
+typedef SkySingleton<SkyContext> GraphicsContext;
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyContext
+ * @brief A manager / proxy for the state of OpenGL contexts.
+ * 
+ * @todo <WRITE EXTENDED CLASS DESCRIPTION>
+ */
+class SkyContext
+{
+public: // datatypes
+
+  //------------------------------------------------------------------------------
+  /**
+   * @class Listener
+   * @brief Inherit this class and overide its methods to be notified of context events.
+   */
+  class Listener
+       {
+       public:
+
+    //! Handle a change in the dimensions of the graphics window.
+               virtual SKYRESULT GraphicsReshapeEvent()      { return SKYRESULT_OK; }
+       };
+
+  /**
+   * @enum SkyMessageType messages that the context can generate for it's listeners.
+   */
+       enum SkyMessageType
+       {
+               SKYCONTEXT_MESSAGE_RESHAPE,
+         SKYCONTEXT_MESSAGE_COUNT
+       };
+
+public: // methods
+
+  SKYRESULT        ProcessReshapeEvent(int iWidth, int iHeight);
+  SKYRESULT        InitializeExtension(const char *pExtensionName);
+
+  //! Returns the current dimensions of the window.
+  void             GetWindowSize(int &iWidth, int &iHeight) { iWidth = _iWidth; iHeight = _iHeight; }
+
+  SkyMaterial*     GetCurrentMaterial();
+  SkyTextureState* GetCurrentTextureState();
+
+  SKYRESULT        AddCurrentGLContext();
+
+  //------------------------------------------------------------------------------
+       // Register with the messaging system to handle notification of mode changes
+       //------------------------------------------------------------------------------
+       SKYRESULT        Register(Listener   *pListener, int priority = 0);
+       SKYRESULT        UnRegister(Listener *pLlistener);
+
+protected: // methods
+       SkyContext();
+       ~SkyContext();
+
+protected: // data
+       int _iWidth;
+  int _iHeight;
+
+  typedef std::map<HGLRC, SkyMaterial*>     ContextMaterialMap;
+  typedef ContextMaterialMap::iterator      ContextMaterialIterator;
+  typedef std::map<HGLRC, SkyTextureState*> ContextTextureStateMap;
+  typedef ContextTextureStateMap::iterator  ContextTextureStateIterator;
+
+  ContextMaterialMap      _currentMaterials;
+  ContextTextureStateMap  _currentTextureState;
+
+  //------------------------------------------------------------------------------
+       // Messaging system to handle notification of mode changes
+       //------------------------------------------------------------------------------
+       typedef std::pair<int, Listener*> ListenerPair;
+       class _ListenerPred
+       {
+       public:
+               _ListenerPred(const Listener* l) { _l = l; }
+               bool operator()(const ListenerPair& pair) { return pair.second == _l; }
+       protected:
+               const Listener *_l;
+       };
+
+       SKYRESULT _SendMessage(SkyMessageType msg);
+       std::list<ListenerPair> _listeners;
+
+};
+
+#endif //__SKYCONTEXT_HPP__
\ 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 (file)
index 0000000..7c6b43c
--- /dev/null
@@ -0,0 +1,65 @@
+//------------------------------------------------------------------------------
+// File : SkyControlled.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyControlled.hpp
+ * 
+ * Interface definition for controlled objects.
+ */
+#ifndef __SKYCONTROLLED_HPP__
+#define __SKYCONTROLLED_HPP__
+
+//#include "BHXController.hpp"
+
+template<typename ControlStateType> class SkyController;
+
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyControlled
+ * @brief A base class defining an interface for controlled objects.
+ * 
+ * This class abstracts the control of objects into a simple interface that a
+ * class may inherit that allows it to be controlled by SkyController objects.
+ * A class simply inherits from SkyControlled, which forces the class to implement
+ * the method UpdateStateFromControls().  This method usually uses the SkyController
+ * object passed to SetController() to query the input state via 
+ * SkyController::GetControlState().  
+ *
+ * @see SkyController
+ */
+template<typename ControlStateType>
+class SkyControlled
+{
+public:
+  //! Constructor.
+  SkyControlled()          { _pController = NULL; }
+  //! Destructor
+  virtual ~SkyControlled() { _pController = NULL; }
+
+  //! Sets the controller which will control this controlled object.
+  void SetController(SkyController<ControlStateType> *pController) { _pController = pController; }
+  
+  //! Updates the state of the controlled object based on the controls (received from the controller).
+  virtual SKYRESULT UpdateStateFromControls(SKYTIME timeStep) = 0;
+
+protected:
+  SkyController<ControlStateType>  *_pController;
+  ControlStateType                  _controlState;
+};
+
+#endif //__SKYCONTROLLED_HPP__
\ 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 (file)
index 0000000..38a64a0
--- /dev/null
@@ -0,0 +1,56 @@
+//------------------------------------------------------------------------------
+// File : SkyController.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyController.hpp
+ * 
+ * Abstract base class for game object controllers.
+ */
+#ifndef __SKYCONTROLLER_HPP__
+#define __SKYCONTROLLER_HPP__
+
+#include "SkyUtil.hpp"
+
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyController
+ * @brief A class that defines an interface for translating general control input into game object control.
+ * 
+ * This class abstracts game object control from specific control input, such 
+ * as via user interface devices or via artificial intelligence.  Subclasses of
+ * this class implement the method GetControlState() so that objects controlled
+ * by an instance of a SkyController can query the control state that determines 
+ * their actions.  The object need not know whether it is controlled by a human 
+ * or the computer since either controller provides it the same interface.
+ *
+ * @see SkyControlled
+ */
+template <typename ControlStateType>
+class SkyController
+{
+public:
+  //! Constructor.
+  SkyController() {}
+  //! Destructor.
+  virtual ~SkyController() {}
+  
+  //! Fills out the control state structure passed in with the current state of controls.
+  virtual SKYRESULT GetControlState(ControlStateType &controlState) = 0;
+};
+
+#endif //__SKYCONTROLLER_HPP__
\ 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 (file)
index 0000000..a15dc17
--- /dev/null
@@ -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 (file)
index 0000000..57f09bb
--- /dev/null
@@ -0,0 +1,80 @@
+//------------------------------------------------------------------------------
+// File : SkyDynamicTextureManager.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyDynamicTextureManager.hpp
+ * 
+ * Interface definition of a repository for check out and check in of dynamic textures.
+ */
+#ifndef __SKYDYNAMICTEXTUREMANAGER_HPP__
+#define __SKYDYNAMICTEXTUREMANAGER_HPP__
+  
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+#include <map>
+#include <GL/glut.h>
+#include "SkyUtil.hpp"
+#include "SkySingleton.hpp"
+
+using namespace std;
+
+class SkyTexture;
+class SkyDynamicTextureManager;
+
+//! Dynamic Texture Manager Singleton declaration.
+/*! The DynamicTextureManager must be created by calling DynamicTextureManager::Instantiate(). */
+typedef SkySingleton<SkyDynamicTextureManager> DynamicTextureManager;
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyDynamicTextureManager
+ * @brief A repository that allows check-out and check-in from a pool of dynamic textures.
+ * 
+ * When an object needs a dynamic texture, it checks it out using CheckOutTexture(), passing
+ * the resolution of the texture it needs.  When the object is done with the texture, it
+ * calls CheckInTexture().  New dynamic textures can be allocated by calling CreateDynamicTexture,
+ * but these textures will be unmanaged.
+ */
+class SkyDynamicTextureManager
+{
+public:
+  SkyTexture* CheckOutTexture(unsigned int iWidth, unsigned int iHeight);
+  void        CheckInTexture(SkyTexture* pTexture);
+
+  SkyTexture* CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight);
+  
+protected: // methods
+  SkyDynamicTextureManager(); // these are protected because it is a singleton.
+  ~SkyDynamicTextureManager();
+
+protected: // datatypes
+  typedef multimap<unsigned int, SkyTexture*>    TextureSubset;
+  typedef multimap<unsigned int, TextureSubset*> TextureSet;
+  
+protected: // data
+  TextureSet      _availableTexturePool;
+  TextureSubset   _checkedOutTexturePool;
+
+  unsigned int    _iAvailableSizeCounts[11][11];
+
+  unsigned int    _iNumTextureBytesUsed;
+  unsigned int    _iNumTextureBytesCheckedOut;
+  unsigned int    _iNumTextureBytesCheckedIn;
+};
+
+#endif //__SKYDYNAMICTEXTUREMANAGER_HPP__
\ 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 (file)
index 0000000..b3d4cb3
--- /dev/null
@@ -0,0 +1,221 @@
+//------------------------------------------------------------------------------
+// File : SkyLight.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyLight.cpp
+ * 
+ * Implementation of a class that maintains the state and operation of a light.
+ */
+#pragma warning( disable : 4786)
+
+#include "SkyLight.hpp"
+#include "SkyMaterial.hpp"
+#include "mat44.hpp"
+#include <GL/glut.h>
+
+SkyMaterial* SkyLight::s_pMaterial = NULL;
+
+//------------------------------------------------------------------------------
+// Function              : SkyLight::SkyLight
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyLight::SkyLight(SkyLightType eType)
+* @brief @todo <WRITE BRIEF SkyLight::SkyLight DOCUMENTATION>
+* 
+* @todo <WRITE EXTENDED SkyLight::SkyLight FUNCTION DOCUMENTATION>
+*/ 
+SkyLight::SkyLight(SkyLightType eType)
+: _bEnabled(true),
+_bDirty(true),
+_iLastGLID(-1),
+_eType(eType),
+_vecPosition(0, 0, 1, 1),
+_vecDirection(0, 0, -1, 0),
+_vecDiffuse(1, 1, 1, 1),
+_vecAmbient(0, 0, 0, 0),
+_vecSpecular(1, 1, 1, 1),
+_vecAttenuation(1, 0, 0),
+_rSpotExponent(0),
+_rSpotCutoff(180)  
+{
+  if (!s_pMaterial)
+  {
+    s_pMaterial = new SkyMaterial;
+    s_pMaterial->SetColorMaterialMode(GL_DIFFUSE);
+    s_pMaterial->EnableColorMaterial(true);
+    s_pMaterial->EnableLighting(false);
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyLight::~SkyLight
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyLight::~SkyLight()
+* @brief @todo <WRITE BRIEF SkyLight::~SkyLight DOCUMENTATION>
+* 
+* @todo <WRITE EXTENDED SkyLight::~SkyLight FUNCTION DOCUMENTATION>
+*/ 
+SkyLight::~SkyLight()
+{
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyLight::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyLight::Display() const
+* @brief Displays a wireframe representation of the light.
+* 
+* This is useful for debugging.
+*/ 
+void SkyLight::Display() const
+{
+  s_pMaterial->Activate();
+  //if (_bEnabled)
+    //glColor3fv(&(_vecDiffuse.x));
+  //else
+    glColor3f(0, 0, 0);
+
+  switch(_eType)
+  {
+  case SKY_LIGHT_POINT:
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    {
+      glTranslatef(_vecPosition.x, _vecPosition.y, _vecPosition.z);
+      glutWireSphere(4, 8, 8);
+    }
+    glPopMatrix();
+    break;
+  case SKY_LIGHT_DIRECTIONAL:
+    {
+      glMatrixMode(GL_MODELVIEW);
+      glPushMatrix();
+      {
+        Mat44f mat;
+        Vec3f vecPos(_vecPosition.x, _vecPosition.y, _vecPosition.z);
+        Vec3f vecDir(_vecDirection.x, _vecDirection.y, _vecDirection.z);
+        Vec3f vecUp(0, 1, 0);
+        if (fabs(vecDir * vecUp) - 1 < 1e-6) // check that the view and up directions are not parallel.
+          vecUp.Set(1, 0, 0);
+        
+        mat.invLookAt(vecPos, vecPos + 10 * vecDir, vecUp);
+        
+        glPushMatrix();
+        {
+          glTranslatef(-50 * vecDir.x, -50 * vecDir.y, -50 * vecDir.z);
+          glMultMatrixf(mat);
+          glutWireCone(10, 10, 4, 1);
+        }
+        glPopMatrix(); 
+        
+        glMultMatrixf(mat); 
+        GLUquadric *pQuadric = gluNewQuadric();
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+        gluCylinder(pQuadric, 4, 4, 50, 4, 4);
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+      }
+      glPopMatrix();
+    }
+    break;
+  case SKY_LIGHT_SPOT:
+    {
+      glMatrixMode(GL_MODELVIEW);
+      glPushMatrix();
+      {
+        Mat44f mat;
+        Vec3f vecUp = Vec3f(0, 1, 0);
+        Vec3f vecPos(_vecPosition.x, _vecPosition.y, _vecPosition.z);
+        Vec3f vecDir(_vecDirection.x, _vecDirection.y, _vecDirection.z);
+        if (_vecDirection == vecUp)
+          vecUp.Set(1, 0, 0);
+        mat.invLookAt(vecPos + 50 * vecDir, vecPos + 51 * vecDir, vecUp);
+
+        glMultMatrixf(mat);   
+        float rAlpha= acos(pow(10, (-12 / _rSpotExponent)));
+        //glutWireCone(50 * tan(SKYDEGREESTORADS * rAlpha), 50, 16, 8);
+        glutWireCone(50 * tan(SKYDEGREESTORADS * _rSpotCutoff), 50, 16, 8);
+      }
+      glPopMatrix();
+    }
+    break;
+  default:
+    break;
+  }  
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyLight::Activate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyLight::Activate(int iLightID)
+ * @brief @todo <WRITE BRIEF SkyLight::Activate DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyLight::Activate FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyLight::Activate(int iLightID)
+{
+  glPushMatrix();
+  // set the position every frame
+  if (SKY_LIGHT_DIRECTIONAL != _eType)
+    glLightfv(GL_LIGHT0 + iLightID, GL_POSITION,              &(_vecPosition.x));
+  else
+    glLightfv(GL_LIGHT0 + iLightID, GL_POSITION,              &(_vecDirection.x));
+  
+  if (SKY_LIGHT_SPOT == _eType)
+    glLightfv(GL_LIGHT0 + iLightID, GL_SPOT_DIRECTION,      &(_vecDirection.x));
+
+  // set other light properties only when they change.
+  if (_bDirty || iLightID != _iLastGLID)
+  {     
+    glLightfv(GL_LIGHT0 + iLightID,   GL_DIFFUSE,               &(_vecDiffuse.x));
+    glLightfv(GL_LIGHT0 + iLightID,   GL_AMBIENT,               &(_vecAmbient.x));
+    glLightfv(GL_LIGHT0 + iLightID,   GL_SPECULAR,              &(_vecSpecular.x));
+    glLightf(GL_LIGHT0 + iLightID,    GL_CONSTANT_ATTENUATION,  _vecAttenuation.x);
+    glLightf(GL_LIGHT0 + iLightID,    GL_LINEAR_ATTENUATION,    _vecAttenuation.y);
+    glLightf(GL_LIGHT0 + iLightID,    GL_QUADRATIC_ATTENUATION, _vecAttenuation.z);
+    
+    if (SKY_LIGHT_SPOT == _eType)
+    {
+      glLightf(GL_LIGHT0 + iLightID,  GL_SPOT_CUTOFF,         _rSpotCutoff);
+      glLightf(GL_LIGHT0 + iLightID,  GL_SPOT_EXPONENT,       _rSpotExponent);
+    }
+    else
+    {
+      glLightf(GL_LIGHT0 + iLightID,  GL_SPOT_CUTOFF,         180);
+      glLightf(GL_LIGHT0 + iLightID,  GL_SPOT_EXPONENT,       0);
+    }
+    if (_bEnabled)
+      glEnable(GL_LIGHT0 + iLightID);
+    else
+    {
+      glDisable(GL_LIGHT0 + iLightID);
+    }
+    
+    _iLastGLID = iLightID;
+    _bDirty = false;    
+  }
+  glPopMatrix();
+  return SKYRESULT_OK;
+}
\ 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 (file)
index 0000000..b78fb11
--- /dev/null
@@ -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 (file)
index 0000000..7b6aaa7
--- /dev/null
@@ -0,0 +1,322 @@
+//------------------------------------------------------------------------------
+// File : SkyMaterial.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyMaterial.cpp
+ * 
+ * Implementation of class SkyMaterial, a meterial property object.
+ */
+#include "SkyMaterial.hpp"
+#include "SkyContext.hpp"
+
+//------------------------------------------------------------------------------
+// Function              : SkyMaterial::SkyMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMaterial::SkyMaterial()
+ * @brief Constructor.
+ */ 
+SkyMaterial::SkyMaterial()
+: _iMaterialID(-1),  
+  _vecDiffuse(Vec4f::ZERO),
+  _vecSpecular(Vec4f::ZERO),
+  _vecAmbient(Vec4f::ZERO),
+  _vecEmissive(Vec4f::ZERO),
+  _rSpecularPower(0),
+  _bLighting(true),
+  _eColorMaterialFace(GL_FRONT_AND_BACK),
+  _eColorMaterialMode(GL_AMBIENT_AND_DIFFUSE),
+  _bColorMaterial(false),
+  _vecFogColor(Vec4f::ZERO),
+  _eFogMode(GL_EXP),
+  _bFog(false),
+  _eDepthFunc(GL_LESS),
+  _bDepthMask(true),
+  _bDepthTest(true),
+  _eAlphaFunc(GL_ALWAYS),
+  _rAlphaRef(0),
+  _bAlphaTest(false), 
+  _eBlendSrcFactor(GL_ONE),
+  _eBlendDstFactor(GL_ZERO),
+  _bBlending(false),
+  _bFaceCulling(false),
+  _eFaceCullingMode(GL_BACK),
+  _eTextureEnvMode(GL_MODULATE)
+{
+  _rFogParams[SKY_FOG_DENSITY]  = 1;
+  _rFogParams[SKY_FOG_START]    = 0;
+  _rFogParams[SKY_FOG_END]      = 1;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMaterial::~SkyMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMaterial::~SkyMaterial()
+ * @brief Destructor.
+ */ 
+SkyMaterial::~SkyMaterial()
+{
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMaterial::SetFogParameter
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMaterial::SetFogParameter(GLenum eParameter, float rValue)
+ */ 
+SKYRESULT SkyMaterial::SetFogParameter(GLenum eParameter, float rValue)
+{
+  switch (eParameter)
+  {
+  case GL_FOG_DENSITY:
+    _rFogParams[SKY_FOG_DENSITY] = rValue;
+    break;
+  case GL_FOG_START:
+    _rFogParams[SKY_FOG_START] = rValue;
+    break;
+  case GL_FOG_END:
+    _rFogParams[SKY_FOG_END] = rValue;
+    break;
+  default:
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyMaterial::SetFogParameter(): Invalid parameter.");
+    break;
+  }
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMaterial::GetFogParameter
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMaterial::GetFogParameter(GLenum eParameter) const
+ */ 
+float SkyMaterial::GetFogParameter(GLenum eParameter) const
+{
+  switch (eParameter)
+  {
+  case GL_FOG_DENSITY:
+    return _rFogParams[SKY_FOG_DENSITY];
+    break;
+  case GL_FOG_START:
+    return _rFogParams[SKY_FOG_START];
+    break;
+  case GL_FOG_END:
+    return _rFogParams[SKY_FOG_END];
+    break;
+  default:
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyMaterial::GetFogParameter(): Invalid parameter.");
+    break;
+  }
+  
+  return -1;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMaterial::Activate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMaterial::Activate()
+ * @brief @todo <WRITE BRIEF SkyMaterial::SetMaterialPropertiesForDisplay DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyMaterial::SetMaterialPropertiesForDisplay FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyMaterial::Activate()
+{
+  // Update the cached current material, and only pass values that have changed to the GL.
+  
+  SkyMaterial *pCurrentMaterial = GraphicsContext::InstancePtr()->GetCurrentMaterial();
+  assert(NULL != pCurrentMaterial);
+
+  // basic material properties
+  if (pCurrentMaterial->GetDiffuse() != GetDiffuse())
+  {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &(GetDiffuse().x));
+    pCurrentMaterial->SetDiffuse(GetDiffuse());
+  }
+  if (pCurrentMaterial->GetSpecular() != GetSpecular())
+  {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &(GetSpecular().x));
+    pCurrentMaterial->SetSpecular(GetSpecular());
+  }  
+  if (pCurrentMaterial->GetAmbient() != GetAmbient())
+  {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &(GetAmbient().x));
+    pCurrentMaterial->SetAmbient(GetAmbient());
+  }
+  if (pCurrentMaterial->GetEmissive() != GetEmissive())
+  {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, &(GetEmissive().x));
+    pCurrentMaterial->SetEmissive(GetEmissive());
+  }
+  if (pCurrentMaterial->GetSpecularPower() != GetSpecularPower())
+  {
+    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, GetSpecularPower());
+    pCurrentMaterial->SetSpecularPower(GetSpecularPower());
+  } 
+
+  // lighting
+  if (pCurrentMaterial->IsLightingEnabled() != IsLightingEnabled())
+  {
+    if (IsLightingEnabled())
+      glEnable(GL_LIGHTING);
+    else
+      glDisable(GL_LIGHTING);
+    pCurrentMaterial->EnableLighting(IsLightingEnabled());
+  }
+
+  // color material (which material property tracks color calls)
+  if (pCurrentMaterial->GetColorMaterialFace() != GetColorMaterialFace() ||
+      pCurrentMaterial->GetColorMaterialMode() != GetColorMaterialMode())
+  {
+    glColorMaterial(GetColorMaterialFace(), GetColorMaterialMode());
+    pCurrentMaterial->SetColorMaterialFace(GetColorMaterialFace());
+    pCurrentMaterial->SetColorMaterialMode(GetColorMaterialMode());
+  }
+  if (pCurrentMaterial->IsColorMaterialEnabled() != IsColorMaterialEnabled())
+  {
+    if (IsColorMaterialEnabled()) 
+      glEnable(GL_COLOR_MATERIAL);
+    else
+      glDisable(GL_COLOR_MATERIAL);
+    pCurrentMaterial->EnableColorMaterial(IsColorMaterialEnabled());
+  }
+
+  // fog
+  if (pCurrentMaterial->GetFogMode() != GetFogMode())
+  {
+    glFogf(GL_FOG_MODE, GetFogMode());
+    pCurrentMaterial->SetFogMode(GetFogMode());
+  }
+  if (pCurrentMaterial->GetFogColor() != GetFogColor())
+  {
+    glFogfv(GL_FOG_COLOR, GetFogColor());
+    pCurrentMaterial->SetFogColor(GetFogColor());
+  }
+  if (pCurrentMaterial->GetFogParameter(GL_FOG_DENSITY) != GetFogParameter(GL_FOG_DENSITY))
+  {
+    glFogf(GL_FOG_DENSITY, GetFogParameter(GL_FOG_DENSITY));
+    pCurrentMaterial->SetFogParameter(GL_FOG_DENSITY, GetFogParameter(GL_FOG_DENSITY));
+  }
+  if (pCurrentMaterial->GetFogParameter(GL_FOG_START) != GetFogParameter(GL_FOG_START))
+  {
+    glFogf(GL_FOG_START, GetFogParameter(GL_FOG_START));
+    pCurrentMaterial->SetFogParameter(GL_FOG_START, GetFogParameter(GL_FOG_START));
+  }
+  if (pCurrentMaterial->GetFogParameter(GL_FOG_END) != GetFogParameter(GL_FOG_END))
+  {
+    glFogf(GL_FOG_END, GetFogParameter(GL_FOG_END));
+    pCurrentMaterial->SetFogParameter(GL_FOG_END, GetFogParameter(GL_FOG_END));
+  }
+  if (pCurrentMaterial->IsFogEnabled() != IsFogEnabled())
+  {
+    if (IsFogEnabled())
+      glEnable(GL_FOG);
+    else
+      glDisable(GL_FOG);
+    pCurrentMaterial->EnableFog(IsFogEnabled());
+  }
+
+  // depth test
+  if (pCurrentMaterial->GetDepthFunc() != GetDepthFunc())
+  {
+    glDepthFunc(GetDepthFunc());
+    pCurrentMaterial->SetDepthFunc(GetDepthFunc());
+  }
+  if (pCurrentMaterial->GetDepthMask() != GetDepthMask())
+  {
+    glDepthMask(GetDepthMask());
+    pCurrentMaterial->SetDepthMask(GetDepthMask());
+  }
+  if (pCurrentMaterial->IsDepthTestEnabled() != IsDepthTestEnabled())
+  {
+    if (IsDepthTestEnabled()) 
+      glEnable(GL_DEPTH_TEST);
+    else 
+      glDisable(GL_DEPTH_TEST);
+    pCurrentMaterial->EnableDepthTest(IsDepthTestEnabled());
+  }
+
+  // alpha test
+  if (pCurrentMaterial->GetAlphaFunc() != GetAlphaFunc() ||
+      pCurrentMaterial->GetAlphaRef()  != GetAlphaRef())
+  {
+    glAlphaFunc(GetAlphaFunc(), GetAlphaRef());
+    pCurrentMaterial->SetAlphaFunc(GetAlphaFunc());
+    pCurrentMaterial->SetAlphaRef(GetAlphaRef());
+  }
+  if (pCurrentMaterial->IsAlphaTestEnabled() != IsAlphaTestEnabled())
+  {
+    if (IsAlphaTestEnabled()) 
+      glEnable(GL_ALPHA_TEST);
+    else
+      glDisable(GL_ALPHA_TEST);
+    pCurrentMaterial->EnableAlphaTest(IsAlphaTestEnabled());
+  }
+
+  // blending
+  if (pCurrentMaterial->GetBlendingSourceFactor() != GetBlendingSourceFactor() ||
+      pCurrentMaterial->GetBlendingDestFactor()   != GetBlendingDestFactor())
+  {
+    glBlendFunc(GetBlendingSourceFactor(), GetBlendingDestFactor());
+    pCurrentMaterial->SetBlendFunc(GetBlendingSourceFactor(), GetBlendingDestFactor());
+  }
+  if (pCurrentMaterial->IsBlendingEnabled() != IsBlendingEnabled())
+  {
+    if (IsBlendingEnabled())
+      glEnable(GL_BLEND);
+    else
+      glDisable(GL_BLEND);
+    pCurrentMaterial->EnableBlending(IsBlendingEnabled());
+  }
+
+  if (pCurrentMaterial->GetFaceCullingMode() != GetFaceCullingMode())
+  {
+    glCullFace(GetFaceCullingMode());
+    pCurrentMaterial->SetFaceCullingMode(GetFaceCullingMode());
+  }
+  if (pCurrentMaterial->IsFaceCullingEnabled() != IsFaceCullingEnabled())
+  {
+    if (IsFaceCullingEnabled())
+      glEnable(GL_CULL_FACE);
+    else
+      glDisable(GL_CULL_FACE);
+    pCurrentMaterial->EnableFaceCulling(IsFaceCullingEnabled());
+  }
+
+  // texturing
+  FAIL_RETURN(_textureState.Activate());
+  if (pCurrentMaterial->GetTextureApplicationMode() != GetTextureApplicationMode())
+  {
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GetTextureApplicationMode());
+    pCurrentMaterial->SetTextureApplicationMode(GetTextureApplicationMode());
+  }
+
+  return SKYRESULT_OK;
+}
+
+
diff --git a/simgear/scene/sky/clouds3d/SkyMaterial.hpp b/simgear/scene/sky/clouds3d/SkyMaterial.hpp
new file mode 100644 (file)
index 0000000..cf3a1d5
--- /dev/null
@@ -0,0 +1,268 @@
+//------------------------------------------------------------------------------
+// File : SkyMaterial.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyMaterial.hpp
+ * 
+ * Interface definition for class SkyMaterial, a meterial property object.
+ */
+#ifndef __SKYMATERIAL_HPP__
+#define __SKYMATERIAL_HPP__
+
+#pragma warning( disable : 4786)
+
+#include "vec4f.hpp"
+#include "SkyUtil.hpp"
+#include "SkyTextureManager.hpp"
+#include "SkyTextureState.hpp"
+#include <GL/glut.h>
+
+// forward
+class SkyRenderable;
+
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyMaterial
+ * @brief A class for organizing and caching material state.
+ * 
+ * This class handles setting and querying material state.  By calling the Activate()
+ * method, the material's state can be made current in OpenGL.  The material will not
+ * set states that are currently active in the current OpenGL context.
+ */
+class SkyMaterial
+{
+public:
+  SkyMaterial();
+  ~SkyMaterial();
+  
+  SKYRESULT     Activate();
+
+  // Getters for basic material properties
+
+  //! Returns the material identifier.
+  int           GetMaterialID() const                  { return _iMaterialID;     }
+  //! Returns the material diffuse color.
+  const Vec4f&  GetDiffuse() const                     { return _vecDiffuse;      }
+  //! Returns the material specular color.
+  const Vec4f&  GetSpecular() const                    { return _vecSpecular;     }
+  //! Returns the material ambient color.
+  const Vec4f&  GetAmbient() const                     { return _vecAmbient;      }
+  //! Returns the material emissive color.
+  const Vec4f&  GetEmissive() const                    { return _vecEmissive;     }
+  //! Returns the material specular power (shininess).
+  const float   GetSpecularPower() const               { return _rSpecularPower;  }
+
+  // lighting
+  //! Returns true if lighting is enabled for this material.
+  bool          IsLightingEnabled() const              { return _bLighting;       }
+
+  // color material (which material property tracks color calls)
+  //! Returns the face for which color material tracking is enabled.
+  GLenum        GetColorMaterialFace() const           { return _eColorMaterialFace; }
+  //! Returns the color material tracking mode.
+  GLenum        GetColorMaterialMode() const           { return _eColorMaterialMode; }
+  //! Returns true if color material tracking is enabled.
+  bool          IsColorMaterialEnabled() const         { return _bColorMaterial;     }  
+
+  //! Returns the fog density or start / end distance.
+  float         GetFogParameter(GLenum eParameter) const;
+  //! Returns the fog mode (exponential, linear, etc.)
+  GLenum        GetFogMode() const                     { return _eFogMode;        }
+  //! Returns the fog color.
+  const Vec4f&  GetFogColor() const                    { return _vecFogColor;     }
+  //! Returns true if fog is enabled for this material.
+  bool          IsFogEnabled() const                   { return _bFog;            }
+
+  // texturing
+  //! Returns the active texture target for texture unit @a iTextureUnit.
+  GLenum        GetActiveTarget(unsigned int iTextureUnit) const 
+                { return _textureState.GetActiveTarget(iTextureUnit);   }
+  //! Returns the bound texture ID for texture unit @a iTextureUnit.
+  unsigned int  GetTextureID(unsigned int iTextureUnit) const    
+                { return _textureState.GetTextureID(iTextureUnit);      }
+  //! Returns true if texturing is enabled for texture unit @a iTextureUnit.
+  bool          IsTextureEnabled(unsigned int iTextureUnit) const
+                { return _textureState.IsTextureEnabled(iTextureUnit);  }
+  //! Returns the value of the texture parameter @a eParameter for texture unit @a iTextureUnit.
+  GLenum        GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const
+                { return _textureState.GetTextureParameter(iTextureUnit, eParameter); }
+  //! Returns the texture application mode of the texture environment.
+  GLenum        GetTextureApplicationMode() const      { return _eTextureEnvMode; }
+
+  //! Returns a reference to the texture state object owned by this materal.
+  SkyTextureState& GetTextureState()                   { return _textureState;    }
+
+  // depth test
+  //! Returns true if depth testing is enabled for this material.
+  bool          IsDepthTestEnabled() const             { return _bDepthTest;      }
+  //! Returns the depth test function for this material.
+  GLenum        GetDepthFunc() const                   { return _eDepthFunc;      }
+  //! Returns true if depth writes are enabled for this material, false if not.
+  bool          GetDepthMask() const                   { return _bDepthMask;      }
+  
+  // alpha test
+  //! Returns true if alpha testing is enabled for this material.
+  bool          IsAlphaTestEnabled() const             { return _bAlphaTest;      }
+  //! Returns the alpha test function for this material.
+  GLenum        GetAlphaFunc() const                   { return _eAlphaFunc;      }
+  //! Returns the reference value for alpha comparison.
+  float         GetAlphaRef() const                    { return _rAlphaRef;       }
+  
+  // blending
+  //! Returns true if blending is enabled for this material.
+  bool          IsBlendingEnabled() const              { return _bBlending;       }
+  //! Returns the source blending factor for this material.
+  GLenum        GetBlendingSourceFactor() const        { return _eBlendSrcFactor; }
+  //! Returns the destination blending factor for this material.
+  GLenum        GetBlendingDestFactor() const          { return _eBlendDstFactor; }
+    
+  //! Returns true if face culling enabled for this material.
+  bool          IsFaceCullingEnabled() const           { return _bFaceCulling;    }
+  //! Returns which faces are culled -- front-facing or back-facing.
+  GLenum        GetFaceCullingMode() const             { return _eFaceCullingMode; }
+
+  // Setters for basic material properties
+
+  //! Sets the material identifier.
+  void          SetMaterialID(int ID)                  { _iMaterialID = ID;       }  
+  //! Sets the diffuse material color.
+  void          SetDiffuse( const Vec4f& d)            { _vecDiffuse = d;         }
+  //! Sets the specular material color.
+  void          SetSpecular(const Vec4f& d)            { _vecSpecular = d;        }
+  //! Sets the ambient material color.
+  void          SetAmbient( const Vec4f& d)            { _vecAmbient = d;         }
+  //! Sets the emissive material color.
+  void          SetEmissive(const Vec4f& d)            { _vecEmissive = d;        }
+  //! Sets the material specular power (shininess).
+  void          SetSpecularPower(float power)          { _rSpecularPower = power; }
+
+  // lighting
+  //! Enables / Disables lighting for this material.
+  void          EnableLighting(bool bEnable)           { _bLighting = bEnable;    }
+
+  // color material (which material property tracks color calls)
+  //! Sets which faces (front or back) track color calls.
+  void          SetColorMaterialFace(GLenum eFace)     { _eColorMaterialFace = eFace; }
+  //! Sets which material property tracks color calls.
+  void          SetColorMaterialMode(GLenum eMode)     { _eColorMaterialMode = eMode; }
+  //! Enables / Disables material color tracking for this material.
+  void          EnableColorMaterial(bool bEnable)      { _bColorMaterial = bEnable;   }
+
+  //! Sets the fog density or start / end distance.
+  SKYRESULT     SetFogParameter(GLenum eParameter, float rValue);
+  //! Sets the fog mode (exponential, linear, etc.)
+  void          SetFogMode(GLenum eMode)               { _eFogMode = eMode;           }
+  //! Sets the fog color.
+  void          SetFogColor(const Vec4f& color)        { _vecFogColor = color;        }
+  //! Enables / Disables fog for this material.
+  void          EnableFog(bool bEnable)                { _bFog = bEnable;             }
+  
+  // texturing
+  //! Sets the bound texture and texture target for texture unit @a iTextureUnit.
+  SKYRESULT     SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture& texture)
+                { return _textureState.SetTexture(iTextureUnit, eTarget, texture);    }
+  //! Sets the bound texture and texture target for texture unit @a iTextureUnit.
+  SKYRESULT     SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID)
+                { return _textureState.SetTexture(iTextureUnit, eTarget, iTextureID); }
+  //! Enables / Disables texture unit @a iTextureUnit for this material.
+  SKYRESULT     EnableTexture(unsigned int iTextureUnit, bool bEnable)
+                { return _textureState.EnableTexture(iTextureUnit, bEnable);          }
+  //! Sets the value of the texture parameter @a eParameter for texture unit @a iTextureUnit.
+  SKYRESULT     SetTextureParameter(unsigned int  iTextureUnit, GLenum eParameter, GLenum eMode)
+                { return _textureState.SetTextureParameter(iTextureUnit, eParameter, eMode); }
+
+  //! Sets the texture application mode of the texture environment.
+  void          SetTextureApplicationMode(GLenum eMode){ _eTextureEnvMode = eMode;}
+
+  // depth test
+  //! Enables / Disables depth test for this material.
+  void          EnableDepthTest(bool bEnable)          { _bDepthTest = bEnable;   }
+  //! Sets the depth test function (greater, less than, equal, etc.).
+  void          SetDepthFunc(GLenum  eDepthFunc)       { _eDepthFunc = eDepthFunc;}
+  //! If @a bDepthMask is true, then depth writes are enabled, otherwise they are not.
+  void          SetDepthMask(bool    bDepthMask)       { _bDepthMask = bDepthMask;}
+  
+  // alpha test
+  //! Enables / Disables alpha test for this material.
+  void          EnableAlphaTest(bool bEnable)          { _bAlphaTest = bEnable;   }
+  //! Sets the alpha test function (greater, less than, equal, etc.).
+  void          SetAlphaFunc(GLenum  eAlphaFunc)       { _eAlphaFunc = eAlphaFunc;}
+  //! Sets the reference value against which fragment alpha values are compared.
+  void          SetAlphaRef(float    rAlphaRef)        { _rAlphaRef  = rAlphaRef; }
+  
+  // blending
+  //! Enables / Disables blending for this material.
+  void          EnableBlending(bool bEnable)           { _bBlending  = bEnable;   }
+  //! Sets the source and destination blending factors for this material.
+  void          SetBlendFunc(GLenum eSrcFactor, GLenum eDstFactor) 
+                { _eBlendSrcFactor = eSrcFactor; _eBlendDstFactor = eDstFactor;   }
+
+  //! Enables / Disables face culling for this material.
+  void          EnableFaceCulling(bool bEnable)        { _bFaceCulling = bEnable; }
+  //! Sets which faces will be culled -- front facing or back facing.
+  void          SetFaceCullingMode(GLenum eMode)       { _eFaceCullingMode = eMode; }
+
+protected:
+  int           _iMaterialID;  
+
+  Vec4f         _vecDiffuse;
+  Vec4f         _vecSpecular;
+  Vec4f         _vecAmbient;
+  Vec4f         _vecEmissive;
+  
+  float         _rSpecularPower;
+
+  bool          _bLighting;
+
+  GLenum        _eColorMaterialFace;
+  GLenum        _eColorMaterialMode;
+  bool          _bColorMaterial;
+
+  enum SkyFogParams
+  {
+    SKY_FOG_DENSITY,
+    SKY_FOG_START,
+    SKY_FOG_END,
+    SKY_FOG_NUM_PARAMS
+  };
+
+  Vec4f         _vecFogColor;
+  GLenum        _eFogMode;
+  float         _rFogParams[SKY_FOG_NUM_PARAMS];
+  bool          _bFog;
+
+  GLenum        _eDepthFunc;
+  bool          _bDepthMask;
+  bool          _bDepthTest;
+
+  GLenum        _eAlphaFunc;
+  float         _rAlphaRef;
+  bool          _bAlphaTest;
+
+  GLenum        _eBlendSrcFactor;
+  GLenum        _eBlendDstFactor;
+  bool          _bBlending;
+
+  bool          _bFaceCulling;
+  GLenum        _eFaceCullingMode;
+
+  SkyTextureState _textureState;
+  GLenum        _eTextureEnvMode;
+};
+
+#endif //__SKYMATERIAL_HPP__
\ 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 (file)
index 0000000..968470f
--- /dev/null
@@ -0,0 +1,322 @@
+//------------------------------------------------------------------------------
+// File : SkyMinMaxBox.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyMinMaxBox.cpp
+ * 
+ * Implementation of a bounding box class.  Modified from Wes Hunt's BoundingBox.
+ */
+#include "SkyMinMaxBox.hpp"
+#include "camutils.hpp"
+#include <GL/glut.h>
+#include <float.h>
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::SkyMinMaxBox
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::SkyMinMaxBox()
+ * @brief Constructor
+ */ 
+SkyMinMaxBox::SkyMinMaxBox()
+{
+  Clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::Clear
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::Clear()
+ * @brief Reset the min and max to floating point extremes.
+ * 
+ */ 
+void SkyMinMaxBox::Clear()
+{
+       _min.x =  FLT_MAX;
+       _min.y =  FLT_MAX;
+       _min.z =  FLT_MAX;
+       _max.x = -FLT_MAX;
+       _max.y = -FLT_MAX;
+       _max.z = -FLT_MAX;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::PointInBBox
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::PointInBBox( const Vec3f &pt ) const
+ * @brief Queries pt to see if it is inside the SkyMinMaxBox.
+ * 
+ */ 
+bool SkyMinMaxBox::PointInBBox( const Vec3f &pt ) const
+{
+       if( (pt.x >= _min.x) && ( pt.x <= _max.x ) )
+       {
+               if( (pt.y >= _min.y) && ( pt.y <= _max.y ) )
+               {
+                       if( (pt.z >= _min.z) && ( pt.z <= _max.z ) )
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::AddPoint
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::AddPoint( float x , float y , float z )
+ * @brief Adds a point and adjusts bounds if necessary.             
+ */ 
+void SkyMinMaxBox::AddPoint( float x , float y , float z )
+{
+       if( x > _max.x )
+               _max.x = x;
+       if( x < _min.x )
+               _min.x = x;
+       
+       if( y > _max.y )
+               _max.y = y;
+       if( y < _min.y )
+               _min.y = y;
+
+       if( z > _max.z )
+               _max.z = z;
+       if( z < _min.z )
+               _min.z = z;
+
+  // update the center and radius
+  _UpdateSphere();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::AddPoint
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::AddPoint( const Vec3f &pt )
+ * @brief Adds a point and adjusts bounds if necessary.             
+ */ 
+void SkyMinMaxBox::AddPoint( const Vec3f &pt )
+{
+       if( pt.x > _max.x )
+               _max.x = pt.x;
+       if( pt.x < _min.x )
+               _min.x = pt.x;
+       
+       if( pt.y > _max.y )
+               _max.y = pt.y;
+       if( pt.y < _min.y )
+               _min.y = pt.y;
+
+       if( pt.z > _max.z )
+               _max.z = pt.z;
+       if( pt.z < _min.z )
+               _min.z = pt.z;
+
+  // update the center and radius
+  _UpdateSphere();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::ViewFrustumCull
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::ViewFrustumCull( const Camera &cam, const Mat44f &mat )
+ * @brief Returns true if bounding volume culled against cam.
+ * 
+ * This function must transform the object space min and max then adjust the new 
+ * min and max box by expanding it.  Each of the 8 points must be tested.  This 
+ * is faster then doing an xform of all the geometry points and finding a tight
+ * fitting min max box, however this will be enlarged.
+ */ 
+bool SkyMinMaxBox::ViewFrustumCull( const Camera &cam, const Mat44f &mat )
+{
+  SkyMinMaxBox xBV;                // Xformed Bounding Volume
+  Vec3f xMin   = mat * _min;      // Xformed _min
+  Vec3f xMax   = mat * _max;      // Xformed _max
+  Vec3f offset = _max - _min;     // Offset for sides of MinMaxBox
+  Vec3f tmp;
+
+  xBV.Clear(); // Clear the values first
+
+  // First find the new minimum x,y,z
+  // Find min + x
+  tmp.Set(mat.M[0], mat.M[4], mat.M[8]);
+  tmp *= offset.x;
+  tmp += xMin;
+  xBV.AddPoint(tmp);
+
+  // Find min + y
+  tmp.Set(mat.M[1], mat.M[5], mat.M[9]);
+  tmp *= offset.y;
+  tmp += xMin;
+  xBV.AddPoint(tmp);
+
+  // Find min + z
+  tmp.Set(mat.M[3], mat.M[6], mat.M[10]);
+  tmp *= offset.z;
+  tmp += xMin;
+  xBV.AddPoint(tmp);
+  
+  // Second find the new maximum x,y,z
+  // Find max - x
+  tmp.Set(mat.M[0], mat.M[4], mat.M[8]);
+  tmp *= -offset.x;
+  tmp += xMax;
+  xBV.AddPoint(tmp);
+  
+  // Find max - y
+  tmp.Set(mat.M[1], mat.M[5], mat.M[9]);
+  tmp *= -offset.y;
+  tmp += xMax;
+  xBV.AddPoint(tmp);
+  
+  // Find max - z
+  tmp.Set(mat.M[3], mat.M[6], mat.M[10]);
+  tmp *= -offset.z;
+  tmp += xMax;
+  xBV.AddPoint(tmp);
+  
+  // Use the camera utility function that already exists for minmax boxes
+  return VFC(&cam, xBV.GetMin(), xBV.GetMax());
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::Transform
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::Transform(const Mat44f& mat)
+ * @brief @todo <WRITE BRIEF SkyMinMaxBox::Transform DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyMinMaxBox::Transform FUNCTION DOCUMENTATION>
+ */ 
+void SkyMinMaxBox::Transform(const Mat44f& mat)
+{
+  Vec3f verts[8];
+  _CalcVerts(verts);
+  Clear();
+  for (int i = 0; i < 8; ++i)
+  {
+    AddPoint(mat * verts[i]);
+  }
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::_UpdateSphere
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyMinMaxBox::_UpdateSphere()
+* @brief Updates the bounding sphere based on min and max.
+*/ 
+void SkyMinMaxBox::_UpdateSphere()
+{
+  _vecCenter =  _min;
+  _vecCenter += _max;
+  _vecCenter *= 0.5f;
+  
+  Vec3f rad  =  _max;
+  rad        -= _vecCenter;
+  _rRadius   =  rad.Length();
+}
+
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::Display() const
+ * @brief @todo <WRITE BRIEF SkyMinMaxBox::Display DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyMinMaxBox::Display FUNCTION DOCUMENTATION>
+ */ 
+void SkyMinMaxBox::Display() const
+{
+  Vec3f V[8];
+  _CalcVerts(V);
+  
+  glPushAttrib(GL_LINE_BIT);
+  glLineWidth(1.0);
+  
+  glBegin(GL_LINE_LOOP);  // TOP FACE
+  glVertex3fv(V[4]); glVertex3fv(V[5]); glVertex3fv(V[1]); glVertex3fv(V[0]);
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // BOTTOM FACE
+  glVertex3fv(V[3]); glVertex3fv(V[2]); glVertex3fv(V[6]); glVertex3fv(V[7]); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // LEFT FACE
+  glVertex3fv(V[1]); glVertex3fv(V[5]); glVertex3fv(V[6]); glVertex3fv(V[2]); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // RIGHT FACE
+  glVertex3fv(V[0]); glVertex3fv(V[3]); glVertex3fv(V[7]); glVertex3fv(V[4]); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // NEAR FACE
+  glVertex3fv(V[1]); glVertex3fv(V[2]); glVertex3fv(V[3]); glVertex3fv(V[0]); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // FAR FACE
+  glVertex3fv(V[4]); glVertex3fv(V[7]); glVertex3fv(V[6]); glVertex3fv(V[5]); 
+  glEnd();
+  
+  glPopAttrib();
+}
+
+//-----------------------------------------------------------------------------
+// Calculates the eight corner vertices of the MinMaxBox.
+// V must be prealloced.
+//       5---4
+//      /   /|
+//     1---0 |   VERTS : 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
+//     |   | 7   (L,R, B,T, N,F) = (Left,Right, Bottom,Top, Near,Far)
+//     |   |/
+//     2---3
+//-----------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Function              : SkyMinMaxBox::_CalcVerts
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyMinMaxBox::_CalcVerts(Vec3f pVerts[8]) const
+ * @brief @todo <WRITE BRIEF SkyMinMaxBox::_CalcVerts DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyMinMaxBox::_CalcVerts FUNCTION DOCUMENTATION>
+ */ 
+void SkyMinMaxBox::_CalcVerts(Vec3f pVerts[8]) const
+{
+  pVerts[0].Set(_max); pVerts[4].Set(_max.x, _max.y, _min.z);
+  pVerts[1].Set(_min.x, _max.y, _max.z); pVerts[5].Set(_min.x, _max.y, _min.z);
+  pVerts[2].Set(_min.x, _min.y, _max.z); pVerts[6].Set(_min);
+  pVerts[3].Set(_max.x, _min.y, _max.z); pVerts[7].Set(_max.x, _min.y, _min.z);
+}
\ 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 (file)
index 0000000..6a38519
--- /dev/null
@@ -0,0 +1,85 @@
+//------------------------------------------------------------------------------
+// File : SkyMinMaxBox.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+* @file SkyMinMaxBox.hpp
+* 
+* Interface definition for a min-max bounding box class for bounding volume hierarchies.
+*/
+#ifndef __SKYMINMAXBOX_HPP__
+#define __SKYMINMAXBOX_HPP__
+
+#include "SkyBoundingVolume.hpp"
+
+//------------------------------------------------------------------------------
+/**
+* @class SkyMinMaxBox
+* @brief An AABB class that can be used in bounding volume hierarchies.
+* 
+* @todo <WRITE EXTENDED CLASS DESCRIPTION>
+*/
+class SkyMinMaxBox : public SkyBoundingVolume
+{
+public:
+  SkyMinMaxBox();
+  //! Destructor
+  virtual ~SkyMinMaxBox() {}
+  
+  void  AddPoint( const Vec3f &pt );
+  void  AddPoint( float x , float y , float z );
+  
+  //! Expand this box to contain @a box.
+  void  Union(const SkyMinMaxBox& box)           { AddPoint(box.GetMin()); AddPoint(box.GetMax()); }
+
+  //! Returns the minimum corner of the bounding box.
+  const Vec3f &GetMin() const                   { return _min; }
+  //! Returns the maximum corner of the bounding box.
+  const Vec3f &GetMax() const                   { return _max; }
+  
+  //! Sets the minimum corner of the bounding box.
+  void  SetMin(const Vec3f &min)                { _min = min; _UpdateSphere(); }
+  //! Sets the maximum corner of the bounding box.
+  void  SetMax(const Vec3f &max)                { _max = max; _UpdateSphere(); }
+  
+  //! Returns the X width of the bounding box.
+  float GetWidthInX() const                     { return _max.x - _min.x;}
+  //! Returns the Y width of the bounding box.
+  float GetWidthInY() const                     { return _max.y - _min.y;}
+  //! Returns the Z width of the bounding box.
+  float GetWidthInZ() const                     { return _max.z - _min.z;}
+  
+  bool  PointInBBox( const Vec3f &pt ) const;
+  
+  bool  ViewFrustumCull( const Camera &cam, const Mat44f &mat );
+
+  void  Transform(const Mat44f& mat);
+  
+  // Reset the bounding box
+  void  Clear();
+  
+  void  Display() const;
+  
+protected:
+  void _UpdateSphere();
+  void _CalcVerts(Vec3f pVerts[8]) const;
+
+private:
+       Vec3f _min;   // Original object space BV
+       Vec3f _max;
+};
+
+#endif //__SKYMINMAXBOX_HPP__
\ 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 (file)
index 0000000..8364095
--- /dev/null
@@ -0,0 +1,116 @@
+//------------------------------------------------------------------------------
+// File : SkyRenderable.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+//------------------------------------------------------------------------------
+// File : SkyRenderable.hpp
+//------------------------------------------------------------------------------
+// Sky  : Copyright 2002 Mark J. Harris and Andrew Zaferakis
+//------------------------------------------------------------------------------
+/**
+ * @file SkyRenderable.hpp
+ *
+ * Abstract base class definition for SkyRenderable, a renderable object class.
+ */ 
+#ifndef __SKYRENDERABLE_HPP__
+#define __SKYRENDERABLE_HPP__
+
+#pragma warning( disable : 4786)
+
+#include <string>
+
+#include "SkyUtil.hpp"
+
+// forward to reduce unnecessary dependencies
+class SkyMinMaxBox;
+class SkyRenderableInstance;
+class Camera;
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyRenderable
+ * @brief An base class for renderable objects.
+ * 
+ * Each SkyRenderable object should know how to Display itself, however some
+ * objects may not have a bounding volume that is useful (skybox, etc.)
+ */
+class SkyRenderable
+{
+public:
+  //! Constructor
+  SkyRenderable() {}
+  //! Destructor
+  virtual ~SkyRenderable() { }
+
+  //------------------------------------------------------------------------------
+  // Function            :                      SetName
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+  * @fn                      SetName(const std::string &name)
+  * @brief Set a name for this renderable.
+  */ 
+  void                        SetName(const std::string &name) { _name = name; }
+
+  //------------------------------------------------------------------------------
+  // Function            :         GetName
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+  * @fn         GetName() const
+  * @brief Get the name of this renderable.
+  */ 
+  const std::string&          GetName() const                  { return _name; }
+  
+  //------------------------------------------------------------------------------
+  // Function            : Update
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Update(const Camera &cam, SkyRenderableInstance *pInstance)
+   * @brief Update the state of the renderable.
+   * 
+   * This method is optional, as some renderables will need periodic updates
+   * (i.e. for animation) and others will not.
+   */ 
+  virtual SKYRESULT           Update(const Camera &cam, SkyRenderableInstance *pInstance = NULL)
+                              { return SKYRESULT_OK;  }
+  
+  //------------------------------------------------------------------------------
+  // Function            : Display
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Display(const Camera &cam, SkyRenderableInstance *pInstance)
+   * @brief Display the object.
+   */ 
+  virtual SKYRESULT           Display(const Camera &cam, SkyRenderableInstance *pInstance = NULL) = 0;
+
+  //------------------------------------------------------------------------------
+  // Function            : CopyBoundingVolume
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn CopyBoundingVolume() const
+   * @brief Create a copy of the object's bounding volume, useful for collision, VFC, etc.
+   */ 
+  virtual SkyMinMaxBox*       CopyBoundingVolume() const = 0;// { return 0; }
+
+protected:
+  std::string         _name; // the name of this renderable.
+};
+
+#endif //__SKYRENDERABLE_HPP__
\ 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 (file)
index 0000000..c483999
--- /dev/null
@@ -0,0 +1,202 @@
+//------------------------------------------------------------------------------
+// File : SkyRenderableInstance.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyRenderableInstance.hpp
+ * 
+ * Interface definition for SkyRenderableInstance, an instance of a renderable object.
+ */
+#ifndef __SKYRENDERABLEINSTANCE_HPP__
+#define __SKYRENDERABLEINSTANCE_HPP__
+
+#include <vector>
+#include <mat33.hpp>
+#include <mat44.hpp>
+#include "SkyUtil.hpp"
+
+// forward to reduce unnecessary dependencies
+class Camera;
+class SkyMinMaxBox;
+
+// forward so we can make the following typedefs easily visible in the header.
+// rather than buried under the class definition.
+class SkyRenderableInstance;
+
+//! A dynamic array of SkyRenderableInstance pointers.
+typedef std::vector<SkyRenderableInstance*>       InstanceArray;
+//! An instance array iterator.
+typedef InstanceArray::iterator                   InstanceIterator;
+
+//------------------------------------------------------------------------------
+/**
+* @class SkyRenderableInstance
+* @brief An instance of a SkyRenderable object.
+* 
+* An instance contains a pointer to a SkyRenderable object.  The
+* instance contains attributes such as position, orientation,
+* scale, etc. that vary between instances.
+*/
+class SkyRenderableInstance
+{
+public:
+  //! Constructor.
+  SkyRenderableInstance() 
+  : _bCulled(false), _bAlive(true), _vecPosition(0, 0, 0), _rScale(1), _rSquareSortDistance(0)
+  { 
+    _matRotation.Identity(); _matInvRotation.Identity(); 
+  }
+
+  //! Constructor.
+  SkyRenderableInstance(const Vec3f   &position, 
+                        const Mat33f  &rotation, 
+                        const float   scale)
+  : _bCulled(false), _bAlive(true), _vecPosition(position), 
+    _matRotation(rotation), _rScale(scale), _rSquareSortDistance(0)
+  {
+    _matInvRotation = _matRotation;
+    _matInvRotation.Transpose();
+  }
+
+  //! Destructor
+  virtual ~SkyRenderableInstance() {}
+   
+  // Setters / Getters                                                      
+  //! Set the world space position of the instance.
+  virtual void SetPosition(const Vec3f  &position)     { _vecPosition = position; }
+  //! Set the world space rotation of the instance.
+  virtual void SetRotation(const Mat33f &rotation)     { _matRotation    = rotation;  
+                                                         _matInvRotation = rotation; 
+                                                         _matInvRotation.Transpose(); }
+  //! Set the world space scale of the instance.
+  virtual void SetScale(     const float  &scale)      { _rScale    = scale;  }
+  
+  //! Returns the world space position of the instance.
+  virtual const Vec3f&   GetPosition() const           { return _vecPosition; }
+  //! Returns the world space rotation matrix of the instance.
+  virtual const Mat33f&  GetRotation() const           { return _matRotation; }
+  //!  Returns the inverse of the world space rotation matrix of the instance.
+  virtual const Mat33f&  GetInverseRotation() const    { return _matInvRotation; }
+  //! Returns the world space scale of the instance.
+  virtual float          GetScale() const              { return _rScale;      }
+  
+  //! Update the instance based on the given camera, @a cam.
+  virtual SKYRESULT Update(const Camera &cam)          { return SKYRESULT_OK; }
+  //! Render the instance.
+  virtual SKYRESULT Display()                          { return SKYRESULT_OK; }
+  
+  //! Returns the transform matrix from model space to world space.
+  inline virtual void  GetModelToWorldTransform(Mat44f &mat) const;
+  
+  //! Returns the transform matrix from world space to model space.
+
+  inline virtual void  GetWorldToModelTransform(Mat44f &mat) const;
+
+  //! Returns the object-space bounding volume for this instance, or NULL if none is available.
+  virtual SkyMinMaxBox* GetBoundingVolume() const      { return NULL;         }
+   
+  //! Returns true if and only if the bounding volume of this instance lies entirely outside @a cam.  
+  virtual bool  ViewFrustumCull(const Camera &cam)     { return false;        }
+  //! Returns true if the instance was culled.
+  virtual bool  IsCulled()                             { return _bCulled;     }
+  //! Sets the culled state of the instance.
+  virtual void  SetCulled(bool bCulled)                { _bCulled = bCulled;  }
+  
+  //! Returns true if the instance is currently active.
+  virtual bool  IsAlive()                              { return _bAlive;      }
+  //! Activates or deactivates the instance.
+  virtual void  SetIsAlive(bool bAlive)                { _bAlive = bAlive;    }
+
+  //! Sets the distance of this object from the sort position.  Used to sort instances.
+  virtual void  SetSquareSortDistance(float rSqrDist)  { _rSquareSortDistance = rSqrDist; }
+  //! Returns the distance of this object from the sort position. (Set with SetSquareSortDistance())
+  virtual float GetSquareSortDistace() const           { return _rSquareSortDistance;     }
+  
+  //! This operator is used to sort instance arrays. 
+  bool operator<(const SkyRenderableInstance& instance) const
+  {
+    return (_rSquareSortDistance > instance._rSquareSortDistance);
+  }
+
+protected:
+  bool          _bCulled;        // Culled flag
+  bool          _bAlive;         // Alive object flag  
+
+  Vec3f         _vecPosition;    // Position
+  Mat33f        _matRotation;    // Rotation
+  Mat33f        _matInvRotation; // inverse rotation
+  float         _rScale;         // Scale
+
+  // for sorting particles during shading
+  float         _rSquareSortDistance;
+};
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstance::GetModelToWorldTransform
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstance::GetModelToWorldTransform(Mat44f &mat) const
+ * @brief Returns the 4x4 transformation matrix from world to model space.
+ */ 
+inline void SkyRenderableInstance::GetModelToWorldTransform(Mat44f &mat) const
+{
+  mat[0]  = _matRotation.M[0]; mat[4]  = _matRotation.M[3]; 
+  mat[8]  = _matRotation.M[6]; mat[12] = 0;
+  mat[1]  = _matRotation.M[1]; mat[5]  = _matRotation.M[4]; 
+  mat[9]  = _matRotation.M[7]; mat[13] = 0;
+  mat[2]  = _matRotation.M[2]; mat[6]  = _matRotation.M[5]; 
+  mat[10] = _matRotation.M[8]; mat[14] = 0;
+  mat[3]  = 0; mat[7] = 0; mat[11] = 0; mat[15] = 0;
+
+  // Scale the matrix (we don't want to scale translation or mat[15] which is 1)
+  if (_rScale != 1)
+    mat *= _rScale;
+
+  // Set the translation and w coordinate after the potential scaling
+  mat[12] = _vecPosition.x; mat[13] = _vecPosition.y; mat[14] = _vecPosition.z;    
+  mat[15] = 1;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : Mat44f& SkyRenderableInstance::GetWorldToModelTransform
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstance::GetWorldToModelTransform(Mat44f &mat) const
+ * @brief Returns the 4x4 transformation matrix from world to model space.
+ */ 
+inline void SkyRenderableInstance::GetWorldToModelTransform(Mat44f &mat) const
+{
+  mat[0]  = _matRotation.M[0]; mat[4]  = _matRotation.M[1]; 
+  mat[8]  = _matRotation.M[2]; mat[12] = 0;
+  mat[1]  = _matRotation.M[3]; mat[5]  = _matRotation.M[4]; 
+  mat[9]  = _matRotation.M[5]; mat[13] = 0;
+  mat[2]  = _matRotation.M[6]; mat[6]  = _matRotation.M[7]; 
+  mat[10] = _matRotation.M[8]; mat[14] = 0;
+  mat[3]  = 0; mat[7] = 0; mat[11] = 0; mat[15] = 0;
+
+  // Scale the matrix (we don't want to scale translation or mat[15] which is 1)
+  if (_rScale != 1)
+    mat *= (1 / _rScale);
+
+  // Set the translation and w coordinate after the potential scaling
+  mat[12] = -_vecPosition.x; mat[13] = -_vecPosition.y; mat[14] = -_vecPosition.z;    
+  mat[15] = 1;
+}
+
+#endif //__SKYRENDERABLEINSTANCE_HPP__
\ 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 (file)
index 0000000..2f40403
--- /dev/null
@@ -0,0 +1,705 @@
+//------------------------------------------------------------------------------
+// File : SkyRenderableInstanceCloud.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyRenderableInstanceCloud.cpp
+ * 
+ * Implementation of class SkyRenderableInstanceCloud.
+ */
+#include "SkyUtil.hpp"
+#include "SkyCloud.hpp"
+#include "SkyMaterial.hpp"
+#include "SkyBoundingVolume.hpp"
+#include "SkyRenderableInstanceCloud.hpp"
+#include "SkyDynamicTextureManager.hpp"
+
+//! Set this to 1 to see verbose messages about impostor updates.
+#define SKYCLOUD_VERBOSE 0
+
+//! Set this to control the number of frames a cloud has to be culled before its textures are released.
+#define SKYCLOUD_CULL_RELEASE_COUNT 100
+
+//------------------------------------------------------------------------------
+// Static declarations.
+//------------------------------------------------------------------------------
+unsigned int        SkyRenderableInstanceCloud::s_iCount               = 0;
+float               SkyRenderableInstanceCloud::s_rErrorToleranceAngle = SKYDEGREESTORADS * 0.125f;
+SkyMaterial*        SkyRenderableInstanceCloud::s_pMaterial            = NULL;
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, bool bUseOffScreenBuffer)
+ * @brief Constructor.
+ */ 
+SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, 
+                                                       bool bUseOffScreenBuffer /* = true */)
+: SkyRenderableInstance(),
+  _iCloudID(-1),
+  _pCloud(pCloud),
+  _pWorldSpaceBV(NULL),
+  _rRadius(0),
+  _bScreenImpostor(false),
+  _bImageExists(false),
+  _bEnabled(true),
+  _bUseOffScreenBuffer(bUseOffScreenBuffer),
+  _bSplit(false),
+  _vecSplit(0, 0, 0),
+  _vecNearPoint(0, 0, 0),
+  _vecFarPoint(0, 0, 0), 
+  _iLogResolution(0),
+  _pBackTexture(NULL),
+  _pFrontTexture(NULL),
+  _iCulledCount(0)
+{
+  _Initialize();
+  cout << "Cloud Instance created" << endl;
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::SkyRenderableInstanceCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud *pCloud, const Vec3f &position, const Mat33f &rotation, const float scale, bool bUseOffScreenBuffer)
+ * @brief Constructor.
+ */ 
+SkyRenderableInstanceCloud::SkyRenderableInstanceCloud(SkyCloud     *pCloud, 
+                                                       const Vec3f  &position, 
+                                                       const Mat33f &rotation, 
+                                                       const float  scale,
+                                                       bool         bUseOffScreenBuffer /* = true */)
+: SkyRenderableInstance(position, rotation, scale),
+  _iCloudID(-1),
+  _pCloud(pCloud),
+  _pWorldSpaceBV(NULL),
+  _rRadius(0),
+  _bScreenImpostor(false),
+  _bImageExists(false),
+  _bEnabled(true),
+  _bUseOffScreenBuffer(false),
+  _bSplit(false),
+  _vecSplit(0, 0, 0),
+  _vecNearPoint(0, 0, 0),
+  _vecFarPoint(0, 0, 0), 
+  _iLogResolution(0),
+  _pBackTexture(NULL),
+  _pFrontTexture(NULL)
+{
+  _Initialize();
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
+ * @brief Destructor
+ */ 
+SkyRenderableInstanceCloud::~SkyRenderableInstanceCloud()
+{
+  _pCloud = NULL;
+  SAFE_DELETE(_pWorldSpaceBV);
+
+  s_iCount--;
+  // delete the offscreen buffer when no one else is using it.
+  if (0 == s_iCount)
+  {
+//JW??    SAFE_DELETE(s_pRenderBuffer);
+    SAFE_DELETE(s_pMaterial);
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::SetPosition
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::SetPosition(const Vec3f  &position)
+ * @brief Set the world space position of the instance.
+ * 
+ * @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetPosition FUNCTION DOCUMENTATION>
+ */ 
+void SkyRenderableInstanceCloud::SetPosition(const Vec3f  &position)
+{ 
+  if (_pCloud)
+  {
+    _pCloud->Translate(position - _vecPosition);
+  }
+  _vecPosition = position; 
+   
+  _UpdateWorldSpaceBounds(); 
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::SetRotation
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
+ * @brief Set the world space rotation of the instance.
+ * 
+ * @todo <WRITE EXTENDED SkyRenderableInstanceCloud::SetRotation FUNCTION DOCUMENTATION>
+ */ 
+void SkyRenderableInstanceCloud::SetRotation(const Mat33f &rotation)
+{ 
+  if (_pCloud)
+  {
+    _pCloud->Translate(-_vecPosition);
+    _pCloud->Rotate(_matInvRotation * rotation);
+    _pCloud->Translate(_vecPosition);
+  }
+  _matRotation    = rotation;
+  _matInvRotation = rotation; 
+  _matInvRotation.Transpose();  
+  _UpdateWorldSpaceBounds(); 
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::SetScale
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::SetScale(const float  &scale)
+ * @brief Set the world space scale of the instance. 
+ */ 
+void SkyRenderableInstanceCloud::SetScale(const float  &scale)
+{ 
+  if (_pCloud)
+  {
+    _pCloud->Translate(-_vecPosition);
+    _pCloud->Scale(scale);
+    _pCloud->Translate(_vecPosition);
+  }
+  _rScale = scale; 
+  _UpdateWorldSpaceBounds(); 
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : DrawQuad
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
+ * @brief Simply draws an OpenGL quad at @a pos.
+ *
+ * The quad's size and orientation are determined by the (non-unit) vectors @a x
+ * and @a y.  Its color is given by @a color.
+ */ 
+inline void DrawQuad(Vec3f pos, Vec3f x, Vec3f y, Vec4f color)
+{
+  glColor4fv(&(color.x));
+  Vec3f left  = pos;  left   -= y; 
+  Vec3f right = left; right  += x; 
+  left  -= x;
+  glTexCoord2f(0, 0); glVertex3fv(&(left.x));
+  glTexCoord2f(1, 0); glVertex3fv(&(right.x));
+  left  += y;  left  += y;
+  right += y;  right += y;
+  glTexCoord2f(1, 1); glVertex3fv(&(right.x));
+  glTexCoord2f(0, 1); glVertex3fv(&(left.x));
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit)
+ * @brief Display the instance of the cloud using the impostor image.
+ */ 
+SKYRESULT SkyRenderableInstanceCloud::Display(bool bDisplayFrontOfSplit /* = false */)
+{
+       
+  if (!_bImageExists || !_bEnabled)
+  {
+    //FAIL_RETURN(DisplayWithoutImpostor(*(GLVU::GetCurrent()->GetCurrentCam())));
+    FAIL_RETURN(DisplayWithoutImpostor(Camera::Camera()));
+  }
+  else
+  {\r//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)
+    {\r//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 (file)
index 0000000..e7bac3d
--- /dev/null
@@ -0,0 +1,273 @@
+//------------------------------------------------------------------------------
+// File : SkyRenderableInstanceCloud.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyRenderableInstanceCloud.hpp
+ * 
+ * Interface for class SkyRenderableInstanceCloud, an instance of a SkyCloud object.
+ */
+#ifndef __SKYRENDERABLEINSTANCECLOUD_HPP__
+#define __SKYRENDERABLEINSTANCECLOUD_HPP__
+
+class  SkyCloud;
+class  SkyTexture;
+//class  SkyOffScreenBuffer;
+
+#include <vector>
+#include "camera.hpp"
+#include "SkyContext.hpp"
+#include "SkyRenderableInstance.hpp"
+#include "SkyRenderableInstanceGeneric.hpp"
+#include "SkyCloud.hpp"
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyRenderableInstanceCloud
+ * @brief An instance of a cloud.  Renders using an impostor.
+ * 
+ * @todo <WRITE EXTENDED CLASS DESCRIPTION>
+ */
+class SkyRenderableInstanceCloud : public SkyRenderableInstance
+{
+public:
+  SkyRenderableInstanceCloud( SkyCloud      *pCloud, bool bUseOffScreenBuffer = false);
+  SkyRenderableInstanceCloud( SkyCloud      *pCloud, 
+                              const Vec3f   &position, 
+                              const Mat33f  &rotation, 
+                              const float   scale,
+                              bool          bUseOffScreenBuffer = false);
+  virtual ~SkyRenderableInstanceCloud();
+  
+  // Setters / Getters
+    //! Sets the identifier for this cloud (used by SkySceneManager.)
+  void                   SetID(int id)                        { _iCloudID = id;               }
+  
+  virtual void           SetPosition(const Vec3f  &position);
+  
+  virtual void           SetRotation(const Mat33f &rotation);
+  
+  virtual void           SetScale(const float  &scale);
+
+  //! Returns SkySceneManager's id for this cloud.
+  int                    GetID() const                        { return _iCloudID;             }
+  //! Returns a pointer to the renderable that this instance represents.
+  virtual SkyCloud*      GetCloud() const                     { return _pCloud;               }
+  
+  //! Returns the world space bounding box of the cloud instance.
+  const SkyMinMaxBox&    GetWorldSpaceBounds()                { return *_pWorldSpaceBV;      }
+
+  //! Make this into a split impostor.  Will be rendered as two halves, around the split point.
+  void                   SetSplit(bool bSplit)                { _bSplit = bSplit;             }
+  
+  //! Set the distance at which the cloud will be split (from the camera position).
+  void                   SetSplitPoint(const Vec3f& vecSplit) { _vecSplit = vecSplit;         }
+
+  //! Returns true if this is a split impostor (cloud contains objects)
+  bool                   IsSplit() const                      { return _bSplit;               }
+
+  //! Returns true if the camera is inside this clouds bounding volume.
+  bool                   IsScreenImpostor() const             { return _bScreenImpostor;      }
+  
+  virtual SKYRESULT      Update(const Camera& cam);
+  virtual SKYRESULT      Display(bool bDisplayFrontOfSplit = false);
+  SKYRESULT              DisplayWithoutImpostor(const Camera& cam);
+    
+  virtual bool           ViewFrustumCull( const Camera &cam );
+
+  void                   ReleaseImpostorTextures();
+
+  
+  virtual SkyMinMaxBox*  GetBoundingVolume() const            { return _pWorldSpaceBV;        }
+  
+  //----------------------------------------------------------------------------
+  // Determine if the current impostor image is valid for the given viewpoint
+  //----------------------------------------------------------------------------
+  bool                   IsImpostorValid(const Camera &cam);
+  
+  //------------------------------------------------------------------------------
+  // Function            : Enable
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+  * @fn Enable(bool bEnable)
+  * @brief Enable / Disable the use of impostor images (if disabled, displays geometry).
+  */ 
+  void                   Enable(bool bEnable)                 { _bEnabled = bEnable;          }
+  
+  static void            SetErrorToleranceAngle(float rDegrees);  
+
+protected: // methods
+  void        _Initialize();
+  inline int  _GetRequiredLogResolution(float rObjectDistance, float rObjectRadius, float rCamRadius);
+  
+  inline void _UpdateWorldSpaceBounds();
+
+protected: // data
+  int               _iCloudID;        // used by the scene manager to identify clouds.
+
+  SkyCloud          *_pCloud;         // Pointer to the cloud object
+  SkyMinMaxBox      *_pWorldSpaceBV; // Pointer to bounding volume in object space
+  
+  float             _rRadius;         // Radius of the impostor.
+  bool              _bScreenImpostor; // Is this a screen space or world space impostor?
+  bool              _bImageExists;    // The impostor image exists and is ready to use.
+  bool              _bEnabled;        // if disabled, draw geometry -- otherwise, draw impostor.
+  bool              _bUseOffScreenBuffer;  // if enabled, uses off-screen rendering to create impostor images.
+  
+  bool              _bSplit;          // true if the cloud contains other object instances.
+  Vec3f             _vecSplit;        // the point about which this cloud is split.
+
+  Vec3f             _vecNearPoint;    // Nearest point on bounding sphere to viewpoint.
+  Vec3f             _vecFarPoint;     // Farthest point on bounding sphere from viewpoint.
+  
+  Camera            _impostorCam;     // camera used to generate this impostor
+  
+  unsigned int      _iLogResolution;  // Log base 2 of current impostor image resolution.
+
+  SkyTexture        *_pBackTexture;   // Back texture for split clouds or main texture for unsplit.
+  SkyTexture        *_pFrontTexture;  // Front texture for split clouds.
+
+  unsigned int      _iCulledCount;    // used to determine when to release textures
+  
+  static unsigned int        s_iCount;  // keep track of number of impostors using the render buffer.
+//JW??  static SkyOffScreenBuffer* s_pRenderBuffer;
+  static float               s_rErrorToleranceAngle;
+  static SkyMaterial        *s_pMaterial; // shared material for cloud impostors. 
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyContainerCloud
+ * @brief A class used to organize the rendering order of cloud impostors and the objects in the clouds
+ * 
+ * @todo <WRITE EXTENDED CLASS DESCRIPTION>
+ */
+class SkyContainerCloud : public SkyRenderableInstance
+{
+public: // methods
+  //! Constructor.
+  SkyContainerCloud(SkyRenderableInstanceCloud *cloud) : SkyRenderableInstance(), pCloud(cloud) {}
+  //! Destructor.
+  ~SkyContainerCloud() 
+  { pCloud = NULL; containedOpaqueInstances.clear(); containedTransparentInstances.clear(); }
+
+  virtual SKYRESULT Display()                      
+  {
+    // display the back half of the split impostor.
+    FAIL_RETURN_MSG(pCloud->Display(false),
+                    "SkySceneManager::Display(): cloud instance display failed.");
+
+    if (pCloud->IsSplit())
+    {
+      // display contained instances -- first opaque, then transparent.
+      InstanceIterator ii;
+      for (ii = containedOpaqueInstances.begin(); ii != containedOpaqueInstances.end(); ++ii)
+        FAIL_RETURN((*ii)->Display());
+      for (ii = containedTransparentInstances.begin(); ii != containedTransparentInstances.end(); ++ii)
+        FAIL_RETURN((*ii)->Display());
+
+      // now display the front half of the split impostor.
+      FAIL_RETURN_MSG(pCloud->Display(true),
+                      "SkySceneManager::Display(): cloud instance display failed.");
+    }  
+
+    return SKYRESULT_OK;
+  }
+
+  virtual const Vec3f& GetPosition() const { return pCloud->GetPosition(); }
+
+public: //data -- here the data are public because the interface is minimal.
+  SkyRenderableInstanceCloud *pCloud;
+
+  InstanceArray               containedOpaqueInstances;
+  InstanceArray               containedTransparentInstances;
+
+  // This operator is used to sort ContainerCloud arrays. 
+  bool operator<(const SkyContainerCloud& container) const
+  {
+    return (*((SkyRenderableInstance*)pCloud) < *((SkyRenderableInstance*)container.pCloud));
+  }
+};
+
+
+//------------------------------------------------------------------------------
+// Function              : _GetRequiredLogResolution
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::_GetRequiredLogResolution(float rObjectDistance, float rObjectRadius, float rCamRadius)
+ * @brief Returns the integer logarithm base two of the expected impostor resolution.
+ * 
+ * Impostor resolution is based on object size, distance, and the FOV of the camera (stored as the
+ * radius of a sphere centered at the camera position and passing through the corners of the 
+ * projection plane. 
+ */ 
+inline int SkyRenderableInstanceCloud::_GetRequiredLogResolution(float rObjectDistance, 
+                                                                 float rObjectRadius, 
+                                                                 float rCamRadius)
+{
+  int iScreenWidth, iScreenHeight;
+  GraphicsContext::InstancePtr()->GetWindowSize(iScreenWidth, iScreenHeight);
+  //cout << "SkyRes: w=" << iScreenWidth << "h=" << iScreenHeight << endl; char ff; cin >> ff;
+  int iScreenResolution = (iScreenWidth > iScreenHeight) ? iScreenWidth : iScreenHeight;
+  int iLogMinScreenResolution = (iScreenWidth > iScreenHeight) ? iScreenHeight : iScreenWidth;
+  iLogMinScreenResolution = SkyGetLogBaseTwo(iLogMinScreenResolution) - 1;
+
+  int iRes = 2 * iScreenResolution * _pWorldSpaceBV->GetRadius() / rObjectDistance;
+  int iLogResolution;
+  
+  if (rObjectDistance - (0.5f * rObjectRadius) < rCamRadius) 
+  {
+    iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 8);
+  }
+  else if (rObjectDistance - rObjectRadius < rCamRadius) 
+  {
+    iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 4);
+  }
+  else if (iRes > iScreenResolution) 
+  {
+    iLogResolution = SkyGetLogBaseTwo(iScreenResolution / 2);
+  }
+  else
+  {
+    iLogResolution = SkyGetLogBaseTwo(iRes);
+  }
+
+  // if not rendering to an off screen buffer, make sure the resolution fits in the window!
+  if (!_bUseOffScreenBuffer && (iLogMinScreenResolution < iLogResolution))
+    iLogResolution = iLogMinScreenResolution;
+
+  return iLogResolution;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds()
+ * @brief Updates the world space bounding box of the cloud.
+ */ 
+inline void SkyRenderableInstanceCloud::_UpdateWorldSpaceBounds()
+{
+  SAFE_DELETE(_pWorldSpaceBV);
+  _pWorldSpaceBV = _pCloud->CopyBoundingVolume();
+  _vecPosition = _pCloud->CopyBoundingVolume()->GetCenter();
+}
+
+#endif //__SKYRENDERABLEINSTANCECLOUD_HPP__
\ 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 (file)
index 0000000..7a9c3bb
--- /dev/null
@@ -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 (file)
index 0000000..b69d26a
--- /dev/null
@@ -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 (file)
index 0000000..dbd8871
--- /dev/null
@@ -0,0 +1,178 @@
+//------------------------------------------------------------------------------
+// File : SkyRenderableInstanceGroup.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyRenderableInstanceGroup.cpp
+ * 
+ * Implementation of class SkyRenderableInstanceGroup, an instance that groups
+ * other instances.
+ */
+
+#include <GL/glut.h>
+#include "SkyRenderableInstanceGroup.hpp"
+#include "SkySceneManager.hpp"
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::SkyRenderableInstanceGroup
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::SkyRenderableInstanceGroup()
+ * @brief Constructor.
+ */ 
+SkyRenderableInstanceGroup::SkyRenderableInstanceGroup()
+: SkyRenderableInstance(),
+  _pObjectSpaceBV(NULL) 
+{
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup()
+ * @brief Destructor.
+ */ 
+SkyRenderableInstanceGroup::~SkyRenderableInstanceGroup()
+{
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::Update
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::Update(const Camera &cam)
+ * @brief Processes any per frame updates the instance requires.
+ * 
+ * This method simply calls the SkyRenderableInstance::Update() method of each of
+ * its sub-instances.
+ */ 
+SKYRESULT SkyRenderableInstanceGroup::Update(const Camera &cam)
+{
+  InstanceIterator ii;
+  for (ii = _opaqueSubInstances.begin(); ii != _opaqueSubInstances.end(); ++ii)
+  {
+    FAIL_RETURN((*ii)->Update(cam));
+  }
+  for (ii = _transparentSubInstances.begin(); ii != _transparentSubInstances.end(); ++ii)
+  {
+    FAIL_RETURN((*ii)->Update(cam));
+  }
+
+  SkySceneManager::SortInstances(_transparentSubInstances, cam.Orig);
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::Display()
+ * @brief Displays all sub-instances of this instance.
+ * 
+ * The object-to-world transform of this instance group will be applied to all sub-instances before
+ * their own object-to-world transforms are applied.
+ */ 
+SKYRESULT SkyRenderableInstanceGroup::Display()
+{
+  // Get and set the world space transformation
+  Mat44f mat;
+  GetModelToWorldTransform(mat);
+
+  glMatrixMode(GL_MODELVIEW);
+  glPushMatrix();
+  glMultMatrixf(mat.M);
+
+  InstanceIterator ii;
+  /***
+  for (ii = _opaqueSubInstances.begin(); ii != _opaqueSubInstances.end(); ++ii)
+  {
+    FAIL_RETURN((*ii)->Display());
+  }
+
+  for (ii = _transparentSubInstances.begin(); ii != _transparentSubInstances.end(); ++ii)
+  {
+    FAIL_RETURN((*ii)->Display());
+  }
+\r***/
+  _pObjectSpaceBV->Display();
+
+  glMatrixMode(GL_MODELVIEW);
+  glPopMatrix();
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::ViewFrustumCull
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::ViewFrustumCull(const Camera& cam)
+ * @brief @todo <WRITE BRIEF SkyRenderableInstanceGroup::ViewFrustumCull DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyRenderableInstanceGroup::ViewFrustumCull FUNCTION DOCUMENTATION>
+ */ 
+bool SkyRenderableInstanceGroup::ViewFrustumCull(const Camera& cam)
+{
+  Mat44f xform;
+  GetModelToWorldTransform(xform);
+  _bCulled = (_pObjectSpaceBV == NULL) ? false : _pObjectSpaceBV->ViewFrustumCull(cam, xform);
+  return _bCulled;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyRenderableInstanceGroup::AddSubInstance
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyRenderableInstanceGroup::AddSubInstance(SkyRenderableInstance *pInstance, bool bTransparent)
+ * @brief Adds a sub-instance to the group.
+ */ 
+void SkyRenderableInstanceGroup::AddSubInstance(SkyRenderableInstance *pInstance, bool bTransparent)
+{
+  if (!bTransparent)
+    _opaqueSubInstances.push_back(pInstance);
+  else
+    _transparentSubInstances.push_back(pInstance);
+
+  // update the bounds...
+  Mat44f xform;
+  pInstance->GetModelToWorldTransform(xform);
+
+  SkyMinMaxBox *pBV = pInstance->GetBoundingVolume();
+  if (pBV)
+  {
+    Vec3f min = pInstance->GetBoundingVolume()->GetMin();
+    Vec3f max = pInstance->GetBoundingVolume()->GetMax();
+
+    if (!_pObjectSpaceBV)
+      _pObjectSpaceBV = new SkyMinMaxBox;
+
+    _pObjectSpaceBV->AddPoint(xform * min);
+    _pObjectSpaceBV->AddPoint(xform * max);
+  } 
+}
\ 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 (file)
index 0000000..1557003
--- /dev/null
@@ -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 (file)
index 0000000..6ccfe80
--- /dev/null
@@ -0,0 +1,232 @@
+//------------------------------------------------------------------------------
+// File : SkySceneLoader.cpp
+//------------------------------------------------------------------------------
+// Adapted from SkyWorks for FlightGear by J. Wojnaroski -- castle@mminternet.com
+// Copywrite July 2002
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+/**
+ * @file SkySceneLoader.cpp
+ * 
+ * Implementation of class SkySceneLoader.
+ */
+
+#include <plib/ssg.h>
+#include <simgear/math/point3d.hxx>
+
+#include "SkySceneLoader.hpp"
+#include "SkySceneManager.hpp"
+#include "SkyTextureManager.hpp"
+#include "SkySceneManager.hpp"
+#include "SkyDynamicTextureManager.hpp"
+#include "SkyContext.hpp"
+//#include "SkyViewManager.hpp"
+//#include "SkyRenderableInstanceGroup.hpp" 
+#include "SkyLight.hpp"
+#include "camera.hpp"
+
+ssgLight _sky_ssgLights [ 8 ] ;
+static Point3D origin;
+Point3D offset;
+//int      _ssgFrameCounter = 0 ;
+Camera *pCam = new Camera();
+// Need to add a light here until we figure out how to use the sun position and color
+SkyLight::SkyLightType eType = SkyLight::SKY_LIGHT_DIRECTIONAL;
+SkyLight *pLight = new SkyLight(eType);
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneLoader::SkySceneLoader
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneLoader::SkySceneLoader()
+ * @brief Constructor.
+ */ 
+SkySceneLoader::SkySceneLoader()
+{
+
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneLoader::~SkySceneLoader
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneLoader::~SkySceneLoader()
+ * @brief Destructor.
+ */ 
+SkySceneLoader::~SkySceneLoader()
+{
+       SceneManager::Destroy();
+       DynamicTextureManager::Destroy();
+       TextureManager::Destroy();
+       GraphicsContext::Destroy();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneLoader::Load
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneLoader::Load(std::string filename)
+ * @brief Loads a SkyWorks scene.
+ * 
+ * This is a temporary fix, as it loads only limited scenes
+ *  It can however, load any number of Cloud
+ +
+ */ 
+bool SkySceneLoader::Load(std::string filename)
+{ 
+  SkyArchive archive;
+  if (SKYFAILED(archive.Load(filename.c_str()))) {
+       cout << "Archive file not found\n";
+    return false; }
+  char *pFilename;
+  
+  // Need to create the managers
+  GraphicsContext::Instantiate();
+  TextureManager::Instantiate();
+  DynamicTextureManager::Instantiate();
+  SceneManager::Instantiate();
+
+  unsigned int iNumFiles;
+  if (!SKYFAILED(archive.GetInfo("CloudFile", STRING_TYPE, &iNumFiles)))
+  {
+    for (unsigned int i = 0; i < iNumFiles; ++i)
+    {
+      FAIL_RETURN(archive.FindString("CloudFile", &pFilename, i));\r  
+      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 (file)
index 0000000..7e9cf44
--- /dev/null
@@ -0,0 +1,58 @@
+//------------------------------------------------------------------------------
+// File : SkySceneLoader.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkySceneLoader.hpp
+ * 
+ * Definition of a simple class for loading scenes into SkyWorks.
+ */
+#ifndef __SKYSCENELOADER_HPP__
+#define __SKYSCENELOADER_HPP__
+
+#include <string>
+#include "SkyUtil.hpp"
+
+#include <simgear/math/point3d.hxx>
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkySceneLoader
+ * @brief A simple scene loader for SkyWorks scenes.
+ * 
+ * Loads a scene using the Load() method, which is passed the filename of a 
+ * file containing a SkyArchive describing the scene. 
+ */
+class SkySceneLoader
+{
+public:
+  SkySceneLoader();
+  ~SkySceneLoader();
+
+  bool Load(std::string filename);
+  
+  void Set_Cloud_Orig( Point3D *posit );
+  
+  //void Update();
+  void Update( sgMat4 viewmat, Point3D *posit );
+  
+  void Resize( double w, double h);
+  
+  void Draw();
+  
+};
+
+#endif //__SKYSCENELOADER_HPP__
\ 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 (file)
index 0000000..726eed3
--- /dev/null
@@ -0,0 +1,919 @@
+//------------------------------------------------------------------------------
+// File : SkySceneManager.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+
+/**
+ * @file SkySceneManager.cpp
+ * 
+ * Implementation of the singleton class SkySceneManager, which manages objects,
+ * instances, scene update, visibility, culling, and rendering.
+ */
+
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+#include "SkySceneManager.hpp"
+#include "SkyMaterial.hpp"
+#include "SkyLight.hpp"
+#include "SkyCloud.hpp"
+#include "SkyRenderable.hpp"
+#include "SkyRenderableInstance.hpp"
+#include "SkyRenderableInstanceCloud.hpp"
+//#include "SkyHeavens.hpp"
+//#include "SkyHeightField.hpp"
+
+#include "camutils.hpp"
+#include <algorithm>
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::SkySceneManager
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::SkySceneManager()
+ * @brief Constructor
+ */ 
+SkySceneManager::SkySceneManager()
+: /*_pSkyBox(NULL),
+  _pTerrain(NULL),\r*/
+  _bDrawLights(false),
+  _bDrawTree(false),
+  _bReshadeClouds(true)
+{
+  _wireframeMaterial.SetColorMaterialMode(GL_DIFFUSE);
+  _wireframeMaterial.EnableColorMaterial(true);
+  _wireframeMaterial.EnableLighting(false);
+
+  // add the default material with ID -1 
+  // this should avoid errors caused by models without materials exported from MAX
+  // (because flexporter gives them the ID -1).
+  SkyMaterial *pDefaultMaterial = new SkyMaterial;
+  pDefaultMaterial->SetMaterialID(-1);
+  AddMaterial(pDefaultMaterial);
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::~SkySceneManager
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::~SkySceneManager()
+ * @brief Destructor.
+ *
+ * This destructor deletes all renderables, instances (renderable instances, cloud instances, 
+ * and otherwise), materials, and lights that were added to the scene using the Add*() functions.
+ * In other words, the scene manager owns all entities added to the scene.  This eases cleanup 
+ * and shutdown.
+ */ 
+SkySceneManager::~SkySceneManager()
+{
+  ObjectIterator oi;
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi)
+    SAFE_DELETE(*oi);
+  _objects.clear();
+
+  CloudIterator ci;
+  for (ci = _clouds.begin(); ci != _clouds.end(); ++ci)
+    SAFE_DELETE(*ci);
+  _clouds.clear();
+
+  InstanceIterator ii;
+  for (ii = _instances.begin(); ii != _instances.end(); ++ii)
+    SAFE_DELETE(*ii);
+  _instances.clear();
+
+  CloudInstanceIterator cii;
+  for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
+    SAFE_DELETE(*cii);
+  _cloudInstances.clear();
+
+  ContainerSetIterator cni;
+  for (cni = _containerClouds.begin(); cni != _containerClouds.end(); ++cni)
+    SAFE_DELETE(cni->second);
+  _containerClouds.clear();
+
+  MaterialIterator mi;
+  for (mi = _materials.begin(); mi != _materials.end(); ++mi)
+    SAFE_DELETE(mi->second);
+  _materials.clear();
+
+  LightIterator li;
+  for (li = _lights.begin(); li!= _lights.end(); ++li)
+    SAFE_DELETE(li->second);
+  _lights.clear();
+
+  //SAFE_DELETE(_pSkyBox);
+  //SAFE_DELETE(_pTerrain);
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddObject
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::AddObject(SkyRenderable *pObject)
+ * @brief Add a new SkyRenderable object to the manager.
+ */ 
+SKYRESULT SkySceneManager::AddObject(SkyRenderable *pObject)
+{
+  // Check for null object
+  if (NULL == pObject)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+                    "SkySceneManager::AddObject(): Attempting to add NULL Renderable Object.");
+  }
+
+  _objects.push_back(pObject);
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddInstance
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent)
+* @brief Add a new SkyRenderableInstance to the manager.
+*/ 
+SKYRESULT SkySceneManager::AddInstance(SkyRenderableInstance *pInstance, bool bTransparent /* = false */)
+{
+  // Check for null instance
+  if (NULL == pInstance)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+      "SkySceneManager::AddObject(): Attempting to add NULL Renderable Instance.");
+  }
+  
+  if (!bTransparent)
+    _instances.push_back(pInstance);
+  else
+    _transparentInstances.push_back(pInstance);
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddCloud
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::AddCloud(SkyCloud *pCloud)
+ * @brief Add a new cloud object to the manager.
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::AddCloud FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::AddCloud(SkyCloud *pCloud)
+{
+  if (NULL == pCloud)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+      "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Object.");
+  }
+  
+  _clouds.push_back(pCloud);
+  
+  return SKYRESULT_OK;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddCloudInstance
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
+ * @brief Add a new instance of a cloud to the manager.
+ * 
+ * @todo Note that since cloud instances share shading information, if two instances
+ * of a cloud have different orientations, one of the instances will have incorrect
+ * lighting for the scene.  For this reason, I recommend that the number of clouds and 
+ * cloud instances is equal.
+ */ 
+SKYRESULT SkySceneManager::AddCloudInstance(SkyRenderableInstanceCloud *pInstance)
+{
+  // Check for null instance
+  if (NULL == pInstance)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+      "SkySceneManager::AddObject(): Attempting to add NULL SkyCloud Instance.");
+  }
+  
+  pInstance->SetID(_cloudInstances.size());
+
+  _cloudInstances.push_back(pInstance);
+
+  SkyContainerCloud *pContainer = new SkyContainerCloud(pInstance);
+  _containerClouds.insert(std::make_pair(pInstance->GetID(), pContainer));
+
+  RebuildCloudBVTree();
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
+* @brief Adds a material to the scene.
+* 
+* Materials are kept in a map with their ID as key.  A material can be retrieved
+* from the scene manager by passing its ID to GetMaterial.
+*
+* @see GetMaterial, SkyMaterial
+*/ 
+SKYRESULT SkySceneManager::AddMaterial(SkyMaterial *pMaterial)
+{
+  // Check for null instance
+  if (NULL == pMaterial)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+      "SkySceneMananger::AddMaterial(): Attempting to add NULL Material to Scene Manager");
+  }
+  
+  _materials.insert(std::make_pair(pMaterial->GetMaterialID(), pMaterial));
+  return SKYRESULT_OK;
+}
+
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::GetMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::GetMaterial(int iMaterialID)
+ * @brief Returns the material with ID @a iMaterialID.
+ * 
+ * If the material is not found, returns NULL.
+ *
+ * @see AddMaterial, SkyMaterial
+ */ 
+SkyMaterial* SkySceneManager::GetMaterial(int iMaterialID)
+{
+  MaterialIterator mi = _materials.find(iMaterialID);
+  if (_materials.end() == mi)
+  {
+    SkyTrace("SkySceneManager::GetMaterial: Error: invalid material ID");
+    return NULL;
+  }
+  else
+    return mi->second;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::ActivateMaterial
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::ActivateMaterial(int iMaterialID)
+ * @brief Makes the specified material active, setting the appropriate rendering state.
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::ActivateMaterial FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::ActivateMaterial(int iMaterialID)
+{\rcout  << "Activating material\n"; char mm; cin >> mm;
+  MaterialIterator mi = _materials.find(iMaterialID);
+  if (_materials.end() == mi)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+                    "SkySceneManager::ActivateMaterial: Error: invalid material ID.");
+  }
+  else
+  {
+    FAIL_RETURN_MSG(mi->second->Activate(), 
+                    "SkySceneManager::ActivateMaterial: Error: failed to activate.");
+  }
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::AddLight
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::AddLight(SkyLight *pLight)
+ * @brief @todo <WRITE BRIEF SkySceneManager::AddLight DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::AddLight FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::AddLight(SkyLight *pLight)
+{
+  // Check for null instance
+  if (NULL == pLight)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+                    "SkySceneMananger::AddLight(): Attempting to add NULL Light to Scene Manager");
+  }
+  
+  _lights.insert(std::make_pair(_lights.size(), pLight));
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::GetLight
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::GetLight(int iLightID)
+ * @brief @todo <WRITE BRIEF SkySceneManager::GetLight DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::GetLight FUNCTION DOCUMENTATION>
+ */ 
+SkyLight* SkySceneManager::GetLight(int iLightID)
+{
+  LightIterator li = _lights.find(iLightID);
+  if (_lights.end() == li)
+  {
+    SkyTrace("SkySceneManager::GetLight: Error: Invalid light ID");
+    return NULL;
+  }
+  else
+    return li->second;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : Alive
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn Alive(SkyRenderableInstance* pInstance)
+ * @brief A predicate to determine if an object is dead or not.
+ */ 
+bool Alive(SkyRenderableInstance* pInstance)
+{
+  return (pInstance->IsAlive());
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::Update
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkySceneManager::Update(const Camera &cam)
+* @brief Iterate through all SkyRenderableInstances and update them.
+*/ 
+SKYRESULT SkySceneManager::Update(const Camera &cam)
+{
+  _ResolveVisibility(cam);
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::Display
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkySceneManager::Display(const Camera &cam)
+* @brief Iterate through all SkyRenderableInstances and display them.
+*/ 
+SKYRESULT SkySceneManager::Display( const Camera &cam )
+
+{
+  _clearMaterial.Activate();
+  //glClear(GL_DEPTH_BUFFER_BIT);
+
+  // set lights (only lights that have changed will be passed to GL).
+  for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
+  {
+    li->second->Activate(li->first);
+    //if (_bDrawLights)
+    //li->second->Display();
+  }
+  //if (_bDrawTree)\r// force the issue and draw
+    _VisualizeCloudBVTree(cam, _cloudBVTree.GetRoot());
+    
+  glLineWidth(2.0);
+  glBegin(GL_LINES);
+  //  red is Cartesian y-axis
+  glColor3ub( 255, 0, 0 );
+  glVertex3f( 0.0,0.0,0.0 );
+  glVertex3f( 0.0, -104000.0, 0.0);
+  // yellow is Cartesian z-axis
+  glColor3ub( 255, 255, 0 );
+  glVertex3f( 0.0, 0.0, 0.0);
+  glVertex3f( 0.0, 0.0, 104000.0);
+  // blue is Cartesian x-axis
+  glColor3ub( 0, 0, 255 );
+  glVertex3f( 0.0, 0.0, 0.0);
+  glVertex3f( -104000.0, 0.0, 0.0);
+  glEnd();
+
+  // draw all container clouds and "free" objects not in clouds.
+  int i = 0;
+  for (InstanceIterator iter = _visibleInstances.begin(); iter != _visibleInstances.end(); ++iter)
+  {
+    FAIL_RETURN_MSG((*iter)->Display(),
+                  "SkySceneManager::Display(): instance display failed.");
+    i++;
+  }
+  //cout << "There are " << i << " visible clouds\n";
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::RebuildCloudBVTree
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::RebuildCloudBVTree()
+ * @brief Builds an AABB tree of the cloud bounding volumes.  
+ */ 
+SKYRESULT SkySceneManager::RebuildCloudBVTree()
+{
+  CloudInstanceIterator cii;
+  SkyMinMaxBox bbox;
+
+  _cloudBVTree.BeginTree();
+  for (cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
+  {
+    bbox = (*cii)->GetWorldSpaceBounds();
+    _cloudBVTree.AddObject(*cii, bbox);
+  }
+  _cloudBVTree.EndTree();
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::ShadeClouds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::ShadeClouds()
+ * @brief @todo <WRITE BRIEF SkySceneManager::ShadeClouds DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::ShadeClouds FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::ShadeClouds()
+{\rcout  <<  "SkySceneManager::ShadeClouds()\n";
+  int i=0;
+  
+  for (CloudInstanceIterator cii = _cloudInstances.begin(); cii != _cloudInstances.end(); ++cii)
+  {
+    for (LightIterator li = _lights.begin(); li != _lights.end(); ++li)
+    {
+      
+      if (SkyLight::SKY_LIGHT_DIRECTIONAL == li->second->GetType())
+      {
+        (*cii)->GetCloud()->Illuminate(li->second, *cii, li == _lights.begin());
+        printf("Shading Cloud %d of %d with light %d \n", i++, _cloudInstances.size(), *li );
+      }
+    }
+  }
+  _bReshadeClouds = false;
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::LoadClouds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale)
+ * @brief @todo <WRITE BRIEF SkySceneManager::LoadClouds DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::LoadClouds FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::LoadClouds(SkyArchive& cloudArchive, float rScale /* = 1.0f */)
+{
+  unsigned int iNumClouds = 0;
+  cloudArchive.FindUInt32("CldNumClouds", &iNumClouds);
+  SkyArchive subArchive;
+       //iNumClouds = 5;  //set this value to reduce cloud field for debugging
+  for (int i = 0; i < iNumClouds; ++i)
+  {\rprintf("Loading # %d of %d clouds\n", i, iNumClouds);
+    cloudArchive.FindArchive("Cloud", &subArchive, i);
+    SkyCloud *pCloud = new SkyCloud();
+    pCloud->Load(subArchive, rScale);
+    SkyRenderableInstanceCloud *pInstance = new SkyRenderableInstanceCloud(pCloud, false);
+    AddCloud(pCloud);
+    AddCloudInstance(pInstance);
+  }
+  RebuildCloudBVTree();
+  return SKYRESULT_OK;
+}
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_SortClouds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_SortClouds DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_SortClouds FUNCTION DOCUMENTATION>
+ */ 
+void SkySceneManager::_SortClouds(CloudInstanceArray& clouds, const Vec3f& vecSortPoint)
+{
+  static InstanceComparator comparator;
+
+  for (CloudInstanceIterator cii = clouds.begin(); cii != clouds.end(); ++cii)
+  {
+    Vec3f vecPos = (*cii)->GetPosition();
+    vecPos -= vecSortPoint;
+    (*cii)->SetSquareSortDistance(vecPos.LengthSqr());
+  }
+
+  std::sort(clouds.begin(), clouds.end(), comparator);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_SortInstances
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_SortInstances DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_SortInstances FUNCTION DOCUMENTATION>
+ */ 
+void SkySceneManager::SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint)
+{
+  static InstanceComparator comparator;
+
+  for (InstanceIterator ii = instances.begin(); ii != instances.end(); ++ii)
+  {
+    Vec3f vecPos = (*ii)->GetPosition();
+    vecPos -= vecSortPoint;
+    (*ii)->SetSquareSortDistance(vecPos.LengthSqr());
+  }
+  
+  std::sort(instances.begin(), instances.end(), comparator);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_ViewFrustumCullClouds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_ViewFrustumCullClouds DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_ViewFrustumCullClouds FUNCTION DOCUMENTATION>
+ */ 
+void SkySceneManager::_ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode)
+{ 
+  if (!pNode)
+    return;
+
+  int i;
+  int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
+  
+\r //iResult = COMPLETEIN; // just a hack to force the issue
+  if (COMPLETEIN == iResult)
+  {
+    // trivially add all instances 
+    for (i = 0; i < pNode->GetNumObjs(); ++i)
+    {
+      SkyRenderableInstanceCloud* pInstance = 
+        const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
+      _visibleCloudInstances.push_back(pInstance);
+    }
+  }
+  else if ((PARTIAL == iResult) && pNode->IsLeaf())
+  {
+    SkyMinMaxBox bbox;
+    
+    // check each instance in this node against camera
+    for (i = 0; i < pNode->GetNumObjs(); ++i)
+    {
+      SkyRenderableInstanceCloud* pInstance = 
+        const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
+      bbox = pInstance->GetWorldSpaceBounds();
+      iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
+      if (COMPLETEOUT != iResult)
+        _visibleCloudInstances.push_back(pInstance);
+      else
+        pInstance->ReleaseImpostorTextures();
+    }
+  }
+  else if (PARTIAL == iResult)
+  {
+    _ViewFrustumCullClouds(cam, pNode->GetLeftChild());
+    _ViewFrustumCullClouds(cam, pNode->GetRightChild());
+  }
+  else // the node is completely out.  All of its child clouds should release their textures.
+  {
+    for (i = 0; i < pNode->GetNumObjs(); ++i)
+    {
+      SkyRenderableInstanceCloud* pInstance = 
+        const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
+      pInstance->ReleaseImpostorTextures();
+    }
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_VisualizeCloudBVTree
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_VisualizeCloudBVTree DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_VisualizeCloudBVTree FUNCTION DOCUMENTATION>
+ */ 
+void SkySceneManager::_VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode)
+{
+  // set display state.
+  _wireframeMaterial.Activate();
+
+  int iResult = CamMinMaxBoxOverlap(&cam, pNode->GetNodeBV().GetMin(), pNode->GetNodeBV().GetMax());
+
+  if (COMPLETEIN == iResult)
+  {
+    // draw this node's bounding box in green.
+    glColor3f(0, 1, 0);
+    pNode->GetNodeBV().Display();
+  }
+  else if (PARTIAL == iResult)
+  {
+    SkyMinMaxBox bbox;
+
+    if (pNode->IsLeaf())
+    {
+      // draw this node's bounding box and the boxes of all of its objects that are visible.
+      // draw this node's bbox in orange.
+      glColor3f(1, 0.5, 0);
+      pNode->GetNodeBV().Display();
+
+      int i;
+      for (i = 0; i < pNode->GetNumObjs(); ++i)
+      {
+        SkyRenderableInstanceCloud* pInstance = 
+          const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
+        bbox = pInstance->GetWorldSpaceBounds();
+        iResult = CamMinMaxBoxOverlap(&cam, bbox.GetMin(), bbox.GetMax());
+
+        if (COMPLETEIN == iResult)
+        {
+          // draw the box in green
+          glColor3f(0, 1, 0);
+          bbox.Display();
+        }
+        else if (PARTIAL == iResult)
+        {
+          // draw the box in yellow
+          glColor3f(1, 1, 0);
+          bbox.Display();          
+        }
+      }
+    }
+    else
+    {
+      _VisualizeCloudBVTree(cam, pNode->GetLeftChild());
+      _VisualizeCloudBVTree(cam, pNode->GetRightChild());
+    }
+  }
+  else
+  {
+    // draw the node's bbox in red.  
+    // This should NEVER be visible from the camera from which it was culled!
+    glColor3f(1, 0, 0);
+    pNode->GetNodeBV().Display();
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_ResolveVisibility
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::_ResolveVisibility(const Camera &cam)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_ResolveRenderingOrder DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_ResolveRenderingOrder FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkySceneManager::_ResolveVisibility(const Camera &cam)
+{
+  InstanceIterator ii;
+
+  // clear the free instance array
+  _visibleInstances.clear();
+
+  // clear the contained instance arrays
+  ContainerSetIterator csi;
+  for (csi = _containerClouds.begin(); csi != _containerClouds.end(); ++csi)
+  {
+    csi->second->containedOpaqueInstances.clear();
+    csi->second->containedTransparentInstances.clear();
+  }
+
+  // clear the visible cloud array.
+  _visibleCloudInstances.clear();
+  
+  // Test each instance for containment inside a cloud's bounding volume.
+  // If the instance is inside a cloud, it is considered a "contained" instance, and will be 
+  // rendered with the cloud in which it is contained for correct visibility.  If the instance is
+  // not inside any cloud, then it is a "free" instance, and will be rendered after all contained
+  // instances.  Transparent instances of each type are rendered after opaque instances of each 
+  // type.
+
+  // opaque instances
+  for (ii = _instances.begin(); ii != _instances.end(); ++ii)
+  {\rcout <<  "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)
+  {\rcout << "Transparent instance\n"; char tt; cin >> tt;
+    (*ii)->ViewFrustumCull(cam);  // First VFC then check if culled, some instances may
+    // manually set the culled flag, instead of using VFC  
+    if (!(*ii)->IsCulled())
+    {
+      // first update this instance.
+      FAIL_RETURN_MSG((*ii)->Update(cam), "SkySceneManager::Update(): instance update failed.");
+      
+      if (!_TestInsertInstanceIntoClouds(cam, _cloudBVTree.GetRoot(), *ii, true))
+        _visibleInstances.push_back(*ii);
+    }
+  }
+
+  // view frustum cull the clouds
+  _ViewFrustumCullClouds(cam, _cloudBVTree.GetRoot());  
+
+  // Clouds must be rendered in sorted order.
+  //_SortClouds(_visibleCloudInstances, cam.Orig);
+
+  // reshade the clouds if necessary.
+  if (_bReshadeClouds)
+  {
+  printf("ReShading clouds\n");
+    FAIL_RETURN(ShadeClouds());
+  }
+
+  // Now process the visible clouds.  First, go through the container clouds corresponding to the
+  // clouds, calculate their split points, and update their impostors.
+  for (CloudInstanceIterator cii = _visibleCloudInstances.begin(); 
+       cii != _visibleCloudInstances.end(); 
+       ++cii)
+  {
+    // get the container corresponding to this cloud
+    ContainerSetIterator csi = _containerClouds.find((*cii)->GetID());
+   
+    if (csi == _containerClouds.end())
+    {
+      SkyTrace("Error: SkySceneManager::_ResolveVisibility(): Invalid cloud instance %d.", 
+               (*cii)->GetID());
+      return SKYRESULT_FAIL;
+    }
+    
+    if (csi->second->containedOpaqueInstances.size() > 0 ||
+        csi->second->containedTransparentInstances.size() > 0)
+    {
+      SortInstances(csi->second->containedOpaqueInstances, cam.Orig);
+      SortInstances(csi->second->containedTransparentInstances, cam.Orig);
+    
+    
+      SkyRenderableInstance *pOpaque = (csi->second->containedOpaqueInstances.size() > 0) ? 
+                                        csi->second->containedOpaqueInstances.back() : NULL;
+      SkyRenderableInstance *pTransparent = (csi->second->containedTransparentInstances.size() > 0) ? 
+                                             csi->second->containedTransparentInstances.back() : NULL;
+    
+      // find the closest contained instance to the camera
+      if (pOpaque && pTransparent)
+      {
+        if (*pOpaque < *pTransparent)
+          (*cii)->SetSplitPoint(pOpaque->GetPosition());
+        else
+          (*cii)->SetSplitPoint(pTransparent->GetPosition());
+      }
+      else if (pOpaque)
+        (*cii)->SetSplitPoint(pOpaque->GetPosition());
+      else if (pTransparent)
+        (*cii)->SetSplitPoint(pTransparent->GetPosition());
+      else
+        (*cii)->SetSplit(false);
+    }
+    else
+      (*cii)->SetSplit(false);
+    
+    // add the container to the list of visiblie clouds to be rendered this frame.
+    _visibleInstances.push_back(csi->second);
+
+    // now update the impostors
+    FAIL_RETURN_MSG((*cii)->Update(cam),
+      "SkySceneManager::_ResolveVisibility(): cloud instance update failed.");
+  } 
+
+  SortInstances(_visibleInstances, cam.Orig);
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkySceneManager::_TestInsertInstanceIntoClouds
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkySceneManager::_TestInsertInstanceIntoClouds(const Camera &cam, const CloudBVTree::Node *pNode, SkyRenderableInstance *pInstanceToInsert, bool bTransparent)
+ * @brief @todo <WRITE BRIEF SkySceneManager::_TestInsertInstanceIntoClouds DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkySceneManager::_TestInsertInstanceIntoClouds FUNCTION DOCUMENTATION>
+ */ 
+bool SkySceneManager::_TestInsertInstanceIntoClouds(const Camera            &cam,
+                                                    const CloudBVTree::Node *pNode, 
+                                                    SkyRenderableInstance   *pInstanceToInsert,
+                                                    bool                    bTransparent)
+{
+  if (_clouds.size() <= 0)
+    return false;
+
+  if (pNode->GetNodeBV().PointInBBox(pInstanceToInsert->GetPosition()))
+  {
+    if (pNode->IsLeaf())
+    {
+      SkyMinMaxBox bbox;
+      int i;
+
+      // check the instance against each cloud in this leaf node.
+      for (i = 0; i < pNode->GetNumObjs(); ++i)
+      {
+        SkyRenderableInstanceCloud* pCloud = 
+          const_cast<SkyRenderableInstanceCloud*>(pNode->GetObj(i));
+        bbox = pCloud->GetWorldSpaceBounds();
+        if (bbox.PointInBBox(pInstanceToInsert->GetPosition()))
+        {
+          // get the container cloud struct for this cloud instance, and add this instance.
+          ContainerSetIterator csi = _containerClouds.find(pCloud->GetID());
+          if (csi == _containerClouds.end())
+          {
+            SkyTrace(
+              "Error: SkySceneManager::_TestInsertInstanceIntoClouds(): Invalid cloud instance %d.", 
+              pCloud->GetID());
+            return false;
+          }
+          else // this instance is inside a cloud.  Set up for split cloud rendering.
+          {
+            if (!bTransparent)
+              csi->second->containedOpaqueInstances.push_back(pInstanceToInsert);
+            else
+              csi->second->containedTransparentInstances.push_back(pInstanceToInsert);
+            csi->second->pCloud->SetSplit(true);
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+    else
+    {
+      if (!_TestInsertInstanceIntoClouds(cam, pNode->GetLeftChild(), pInstanceToInsert, bTransparent))
+        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 (file)
index 0000000..054c517
--- /dev/null
@@ -0,0 +1,188 @@
+//------------------------------------------------------------------------------
+// File : SkySceneManager.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkySceneManager.hpp
+ * 
+ * The SkySceneManager class manages all of the renderable objects and
+ * instances.  This class maintains lists of each object and instance.
+ * The scene manager decides what to display, it can make use of various
+ * techniques such as view frustum culling, material grouping, etc.
+ */
+#ifndef __SKYSCENEMANAGER_HPP__
+#define __SKYSCENEMANAGER_HPP__
+
+// warning for truncation of template name for browse info
+#pragma warning( disable : 4786)
+
+#include "vec3f.hpp"
+#include <vector>
+#include <map>
+
+#include "SkyUtil.hpp"
+#include "SkySingleton.hpp"
+#include "SkyRenderableInstance.hpp"
+#include "SkyMaterial.hpp"
+#include "SkyAABBTree.hpp"
+#include "SkyRenderableInstanceCloud.hpp"
+
+// forward to reduce unnecessary dependencies
+class Camera;
+class SkyRenderable;
+class SkyRenderableInstance;
+class SkyMaterial;
+class SkyLight;
+class SkyCloud;
+//class SkyHeavens;
+//class SkyHeightField;
+
+//------------------------------------------------------------------------------
+/**
+* @class SkySceneManager
+* @brief Manages all of the renderable objects and instances.
+*/
+class SkySceneManager;  // Forward declaration
+
+//! A singleton of the SkySceneManager.  Can only create the SceneManager with SceneManager::Instantiate();
+typedef SkySingleton<SkySceneManager> SceneManager;
+
+class SkySceneManager
+{
+public:
+  SKYRESULT     AddObject(   SkyRenderable *pObject);
+  SKYRESULT     AddInstance( SkyRenderableInstance *pInstance, bool bTransparent = false);
+  
+  SKYRESULT     AddCloud(    SkyCloud *pCloud);
+  SKYRESULT     AddCloudInstance(SkyRenderableInstanceCloud *pInstance);
+  
+  SKYRESULT     AddMaterial( SkyMaterial *pMaterial);
+  SkyMaterial*  GetMaterial( int iMaterialID);
+  SKYRESULT     ActivateMaterial(int iMaterialID);
+  
+  SKYRESULT     AddLight(    SkyLight *pLight);
+  SkyLight*     GetLight(    int iLightID);
+
+  //! Set the sky box for this scene.
+ // void          SetSkyBox(   SkyHeavens *pSkyBox)       { _pSkyBox = pSkyBox;   }
+  //! Set the terrain for this scene.
+  //void          SetTerrain(  SkyHeightField *pTerrain)  { _pTerrain = pTerrain; }
+
+  //! Enable wireframe display of lights (for debugging).
+  void          EnableDrawLights(bool bEnable)          { _bDrawLights = bEnable; }
+  //! Enable wireframe display of bounding volume tree of clouds.
+  void          EnableDrawBVTree(bool bEnable)          { _bDrawTree   = bEnable; }
+
+  //! Returns true if wireframe display of lights is enabled.
+  bool          IsDrawLightsEnabled() const             { return _bDrawLights;  }
+  //! Returns true if wireframe display of the cloud bounding volume tree is enabled.
+  bool          IsDrawBVTreeEnabled() const             { return _bDrawTree;    }
+  
+  SKYRESULT     Update( const Camera &cam);
+  SKYRESULT     Display( const Camera &cam);
+
+  SKYRESULT     RebuildCloudBVTree();
+  SKYRESULT     ShadeClouds();
+
+  //! Force the illumination of all clouds to be recomputed in the next update.
+  void          ForceReshadeClouds()                    { _bReshadeClouds = true; }
+
+  // sort instances in @a instances from back to front.
+  static void          SortInstances(InstanceArray& instances, const Vec3f& vecSortPoint);
+
+  // load a set of clouds from an archive file.
+  SKYRESULT     LoadClouds(SkyArchive& cloudArchive, float rScale = 1.0f);
+  
+protected: // datatypes
+  // Typedef the vectors into cleaner names
+  typedef std::vector<SkyRenderable*>               ObjectArray;
+  
+  typedef std::map<int, SkyMaterial*>               MaterialSet;
+  typedef std::map<int, SkyLight*>                  LightSet;
+
+  typedef std::vector<SkyRenderableInstanceCloud*>  CloudInstanceArray;
+  typedef std::vector<SkyCloud*>                    CloudArray;
+  typedef std::map<int, SkyContainerCloud*>         ContainerCloudSet;
+  
+  typedef SkyAABBTree<SkyRenderableInstanceCloud*>  CloudBVTree;
+  
+  typedef ObjectArray::iterator                     ObjectIterator;
+  typedef CloudArray::iterator                      CloudIterator;
+  typedef CloudInstanceArray::iterator              CloudInstanceIterator;
+  typedef MaterialSet::iterator                     MaterialIterator;
+  typedef LightSet::iterator                        LightIterator;
+  typedef ContainerCloudSet::iterator               ContainerSetIterator;
+  
+  class InstanceComparator
+  {
+  public:
+    bool operator()(SkyRenderableInstance* pA, SkyRenderableInstance *pB)
+    {
+      return ((*pA) < (*pB));
+    }
+  };
+
+  class ContainerComparator
+  {
+  public:
+    bool operator()(SkyContainerCloud* pA, SkyContainerCloud *pB)
+    {
+      return ((*pA) < (*pB));
+    }
+  };
+  
+
+protected: // methods
+  SkySceneManager();
+  ~SkySceneManager();
+  
+  void                                 _SortClouds(CloudInstanceArray& clouds,  const Vec3f& vecSortPoint);
+
+  void          _ViewFrustumCullClouds(const Camera& cam, const CloudBVTree::Node *pNode);
+  void          _VisualizeCloudBVTree(const Camera& cam, const CloudBVTree::Node *pNode);
+  
+  SKYRESULT     _ResolveVisibility(const Camera &cam);
+  bool          _TestInsertInstanceIntoClouds(const Camera              &cam,
+                                              const CloudBVTree::Node   *pNode,
+                                              SkyRenderableInstance     *pInstanceToInsert,
+                                              bool                      bTransparent);
+  
+private: // data
+  ObjectArray         _objects;
+  CloudArray          _clouds;
+  InstanceArray       _instances;
+  InstanceArray       _transparentInstances;
+  InstanceArray       _visibleInstances;      //! @TODO: change this to "_freeInstances"
+  CloudInstanceArray  _cloudInstances;
+  CloudInstanceArray  _visibleCloudInstances;
+  ContainerCloudSet   _containerClouds;
+
+  MaterialSet         _materials;
+  LightSet            _lights;
+
+  SkyMaterial         _wireframeMaterial;  // used for rendering the wireframes for debugging
+  SkyMaterial         _clearMaterial;      // used to maintain state consistency when clearing.
+  CloudBVTree         _cloudBVTree;
+
+  //SkyHeavens          *_pSkyBox;
+  //SkyHeightField      *_pTerrain;
+
+  bool                _bDrawLights;
+  bool                _bDrawTree;
+  bool                _bReshadeClouds;
+};
+
+#endif //__SKYSCENEMANAGER_HPP__  
\ 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 (file)
index 0000000..e8aeaf6
--- /dev/null
@@ -0,0 +1,292 @@
+//------------------------------------------------------------------------------
+// File : SkySingleton.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkySingleton.hpp
+ * 
+ * A generic singleton template wrapper to make classes into singletons
+ */
+#ifndef __SKYSINGLETON_HPP__
+#define __SKYSINGLETON_HPP__
+
+#include "SkyUtil.hpp"
+#include <assert.h>
+#include <stdlib.h>
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkySingleton
+ * @brief A singleton template class.
+ * 
+ * Usage : Use this template container class to make any class into a
+ *         singleton.  I usually do this:
+ *
+ * @code   
+ * class MyClass       
+ * {       
+ * public:       
+ *   // normal class stuff, but don't put ctor/dtor here.       
+ *   int GetData() { return _someData; }       
+ * protected:       
+ *   // Make the ctor(s)/dtor protected, so this can only be       
+ *   // instantiated as a singleton.  Note: singleton will still       
+ *   // work on classes that do not follow this (public ctors)       
+ *   // but violation of the singleton is possible then, since non-       
+ *   // singleton versions of the class can be instantiated.       
+ *   MyClass() : _someData(5) {}       
+ *   MyClass(int arg) : _someData(arg) {} // etc...       
+ *   // don't implement the copy constructor, because singletons       
+ *   // shouldn't be copied!       
+ *   MyClass(const MyClass& mc) {}       
+ *   ~MyClass() {}       
+ * private:       
+ *   int _someData;       
+ * };
+ *
+ * // now create a singleton of MyClass       
+ * typedef SkySingleton<MyClass> MyClassSingleton;
+ *
+ * @endcode
+ * Later, in your program code, you can instantiate the singleton and access
+ * its members like so:
+ *
+ * @code   
+ * void somefunc()        
+ * {        
+ *   // instantiate the MyClassSingleton        
+ *   MyClassSingleton::Instantiate();        
+ *   // could also call MyClassSingleton::Instantiate(10);        
+ *   // since we have a constructor of that form in MyClass.
+ *         
+ *   // access the methods in MyClass:        
+ *   int data1 = MyClassSingleton::InstancePtr()->GetData();        
+ *   // or...        
+ *   int data2 = MyClassSingleton::InstanceRef().GetData();
+ *         
+ *   // now destroy the singleton        
+ *   MyClassSingleton::Destroy();        
+ * }
+ * @endcode
+ */
+template <class T>
+class SkySingleton : protected T
+{
+public:
+  
+  //------------------------------------------------------------------------------
+  // Function            : Instantiate
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Instantiate()
+   * @brief Creates the singleton instance for class T.
+   *
+   * Assures (by assertion) that the instance will only be created once.
+   * This works for default constructors.
+   */ 
+  static void Instantiate()
+  {
+    assert(!s_pInstance);
+    s_pInstance = new SkySingleton();
+  }
+  
+  //------------------------------------------------------------------------------
+  // Function            : Destroy
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Destroy()           { SAFE_DELETE(s_pInstance);                 }
+   * @brief Destructor, deletes the instance
+   */ 
+  static void Destroy()           { SAFE_DELETE(s_pInstance);                 }
+  
+  //------------------------------------------------------------------------------
+  // Function            : InstancePtr
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn InstancePtr()         { assert(s_pInstance); return s_pInstance;  }
+   * @brief Returns a pointer to the instance
+   */ 
+  static T* InstancePtr()         { assert(s_pInstance); return s_pInstance;  }
+
+  //------------------------------------------------------------------------------
+  // Function            : InstanceRef
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn InstanceRef()         { assert(s_pInstance); return *s_pInstance; }
+   * @brief Returns a reference to the instance
+   */ 
+  static T& InstanceRef()         { assert(s_pInstance); return *s_pInstance; }
+
+  //------------------------------------------------------------------------------
+  // Function            :  static void Instantiate
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn  static void Instantiate(const A& a)
+   * @brief Instantiates class of type T that have constructors with an argument
+   *
+   * This might be a source of confusion.  These templatized
+   * functions are used to instantiate classes of type T that
+   * have constructors with arguments.  For n arguments, you
+   * to add a function below with n arguments.  Note, these will
+   * only be created if they are used, since they are templates.
+   * I've added 4 below, for 1-4 arguments.  If you get a
+   * compilation error, add one for the number of arguments you
+   * need.  Also need a SkySingleton protected constructor with
+   * the same number of arguments.
+   */ 
+  template<class A>
+  static void Instantiate(const A& a)
+  {
+    assert(!s_pInstance);
+    s_pInstance = new SkySingleton(a);
+  }
+
+  //------------------------------------------------------------------------------
+  // Function            : Instantiate
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Instantiate(const A& a, const B& b)
+   * @brief Instantiates class of type T that have constructors with 2 args
+   */ 
+  template<class A, class B>
+  static void Instantiate(const A& a, const B& b)
+  {
+    assert(!s_pInstance);
+    s_pInstance = new SkySingleton(a, b);
+  }
+
+  //------------------------------------------------------------------------------
+  // Function            : Instantiate
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Instantiate(const A& a, const B& b, const C& c)
+   * @brief Instantiates class of type T that have constructors with 3 args
+   */ 
+  template<class A, class B, class C>
+  static void Instantiate(const A& a, const B& b, const C& c)
+  {
+    assert(!s_pInstance);
+    s_pInstance = new SkySingleton(a, b, c);
+  }
+
+  //------------------------------------------------------------------------------
+  // Function            : Instantiate
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Instantiate(const A& a, const B& b, const C& c, const D& d)
+   * @brief Instantiates class of type T that have constructors with 4 args
+   */ 
+  template<class A, class B, class C, class D> 
+  static void Instantiate(const A& a, const B& b, const C& c, const D& d)
+  {
+    assert(!s_pInstance);
+    s_pInstance = new SkySingleton(a, b, c, d);
+  }
+  
+protected:
+  // although the instance is of type SkySingleton<T>, the Instance***() funcs 
+  // above implicitly cast it to type T.
+  static SkySingleton* s_pInstance;
+  
+private:
+
+  //------------------------------------------------------------------------------
+  // Function            : SkySingleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn SkySingleton()
+   * @brief Hidden so that the singleton can only be instantiated via public static Instantiate function.
+   */ 
+  SkySingleton() : T() {}
+  
+  //------------------------------------------------------------------------------
+  // Function            : Singleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Singleton(const A& a)
+   * @brief Used by the templatized public Instantiate() functions.
+   */ 
+  template<class A> 
+  SkySingleton(const A& a) : T(a) {}
+
+  //------------------------------------------------------------------------------
+  // Function            : Singleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Singleton(const A& a, const B& b)
+   * @brief Used by the templatized public Instantiate() functions.
+   */ 
+  template<class A, class B> 
+  SkySingleton(const A& a, const B& b) : T(a, b) {}
+
+  //------------------------------------------------------------------------------
+  // Function            : Singleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Singleton(const A& a, const B& b, const C& c)
+   * @brief Used by the templatized public Instantiate() functions.
+   */ 
+  template<class A, class B, class C> 
+  SkySingleton(const A& a, const B& b, const C& c) : T(a, b, c) {}
+
+  //------------------------------------------------------------------------------
+  // Function            : Singleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn Singleton(const A& a, const B& b, const C &c, const D& d)
+   * @brief Used by the templatized public Instantiate() functions.
+   */ 
+  template<class A, class B, class C, class D> 
+  SkySingleton(const A& a, const B& b, const C &c, const D& d) : T(a, b, c, d) {}
+
+  //------------------------------------------------------------------------------
+  // Function            : SkySingleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn SkySingleton(const SkySingleton&)
+   * @brief Hidden because you can't copy a singleton!
+   */ 
+  SkySingleton(const SkySingleton&) {}  // hide the copy ctor: singletons can'
+
+  //------------------------------------------------------------------------------
+  // Function            : ~SkySingleton
+  // Description           : 
+  //------------------------------------------------------------------------------
+  /**
+   * @fn ~SkySingleton()
+   * @brief Destructor, hidden, destroy via the public static Destroy() method.
+   */ 
+  ~SkySingleton()                  {}  // hide the dtor: 
+};
+
+// declare the static instance pointer
+template<class T> SkySingleton<T>* SkySingleton<T>::s_pInstance = NULL;
+
+#endif //__SKYSINGLETON_HPP__
\ 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 (file)
index 0000000..5079011
--- /dev/null
@@ -0,0 +1,96 @@
+//------------------------------------------------------------------------------
+// File : SkyTexture.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyTexture.hpp
+ * 
+ * Interface definition for class SkyTexture, a texture class.
+ */
+#ifndef __SKYTEXTURE_HPP__
+#define __SKYTEXTURE_HPP__
+
+#pragma warning( disable : 4786 )
+
+#include <GL/glut.h>
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyTexture
+ * @brief A basic texture class.
+ * 
+ * @todo <WRITE EXTENDED CLASS DESCRIPTION>
+ */
+class SkyTexture
+{
+public:
+  //! Default Constructor.
+  SkyTexture() : _iID(0), _iWidth(0), _iHeight(0) {}
+  //! Constructor.
+  SkyTexture(unsigned int iWidth, unsigned int iHeight, unsigned int iTextureID)
+    : _iID(iTextureID), _iWidth(iWidth), _iHeight(iHeight) {}
+  //! Destructor.
+  ~SkyTexture() {}
+
+  //! Sets the texture width in texels.
+  void              SetWidth(unsigned int iWidth)   { _iWidth  = iWidth;      }
+  //! Sets the texture height in texels.
+  void              SetHeight(unsigned int iHeight) { _iHeight = iHeight;     }
+  //! Sets the texture ID as created by OpenGL.
+  void              SetID(unsigned int iTextureID)  { _iID     = iTextureID;  }
+                    
+  //! Returns the texture width in texels.
+  unsigned int      GetWidth() const                { return _iWidth;         }
+  //! Returns the texture height in texels.
+  unsigned int      GetHeight() const               { return _iHeight;        }
+  //! Returns the texture ID as created by OpenGL.
+  unsigned int      GetID() const                   { return _iID;            }
+
+  inline SKYRESULT  Destroy();
+
+protected:
+  unsigned int _iID;
+  unsigned int _iWidth;
+  unsigned int _iHeight;
+};
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTexture::Destroy
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTexture::Destroy()
+ * @brief Destroys the OpenGL texture object represented by this SkyTexture object.
+ * 
+ * Fails if the GL texture has not been created (i.e. its ID is zero).
+ */ 
+inline SKYRESULT SkyTexture::Destroy()
+{
+  if (0 == _iID)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, 
+                    "SkyTexture::Destroy(): Error: attempt to destroy unallocated texture.");
+  }
+  else
+  {
+    glDeleteTextures(1, &_iID);
+    _iID = 0;
+  }
+  return SKYRESULT_OK;
+}
+
+#endif //__SKYTEXTURE_HPP__
\ 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 (file)
index 0000000..715971b
--- /dev/null
@@ -0,0 +1,883 @@
+//------------------------------------------------------------------------------
+// File : SkyTextureManager.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyTextureManager.cpp
+ * 
+ * Implementation of a manager that keeps track of texture resource locations and sharing.
+ */
+
+#pragma warning( disable : 4786)
+
+#include "SkyTextureManager.hpp"
+#include "SkyContext.hpp"
+//#include "glvu.hpp"
+//#include "ppm.hpp"
+//#include "tga.hpp"
+//#include "fileutils.hpp"
+
+bool SkyTextureManager::s_bSlice3DTextures = false;
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::SkyTextureManager
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::SkyTextureManager(bool bSlice3DTextures)
+ * @brief Constructor.
+ * 
+ */ 
+SkyTextureManager::SkyTextureManager(bool bSlice3DTextures /* = false */)
+{
+  s_bSlice3DTextures = bSlice3DTextures;
+
+  // this should be put somewhere more safe -- like done once in the functions that actually
+  // use these extensions.
+  /*GraphicsContext::InstancePtr()->InitializeExtensions("GL_ARB_texture_cube_map "
+                                                         "GL_VERSION_1_2");*/
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::~SkyTextureManager
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::~SkyTextureManager()
+ * @brief destructor.
+ * 
+ * @todo <WRITE EXTENDED SkyTextureManager::~SkyTextureManager FUNCTION DOCUMENTATION>
+ */ 
+SkyTextureManager::~SkyTextureManager()
+{
+  _texturePaths.clear();
+  for ( TextureIterator iter = _textures.begin(); 
+        iter != _textures.end(); 
+        ++iter)
+  {
+    DestroyTextureObject(iter->second);
+  }
+  _textures.clear();
+
+  for ( TextureList::iterator uncachedIter = _uncachedTextures.begin(); 
+        uncachedIter != _uncachedTextures.end();
+        ++uncachedIter)
+  {
+    DestroyTextureObject(*uncachedIter);
+  }
+  _uncachedTextures.clear();
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::AddPath
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::AddPath(const string &path)
+ * @brief Adds a texture path to the list of active search paths. 
+ * 
+ */ 
+void  SkyTextureManager::AddPath(const string &path)
+{
+  _texturePaths.push_back(path);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::Get2DTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::Get2DTexture(const string& filename, SkyTexture& texture, bool bMipmap)
+ * @brief Returns a 2D texture object from the texture set.
+ * 
+ * If the texture is already loaded, it is returned.  If it is not, the texture is loaded from 
+ * file, added to the texture set, and returned.
+ * 
+ * If the image cannot be loaded, returns an error.  Otherwise returns success.
+ */ 
+SKYRESULT SkyTextureManager::Get2DTexture(const string& filename, 
+                                          SkyTexture& texture,
+                                          bool bMipmap /* = false */)
+{
+  TextureIterator iter = _textures.find(filename);
+  
+  if (iter != _textures.end())
+  { // the texture is already loaded, just return it.
+    texture = iter->second;
+  }
+  else
+  { // the texture is being requested for the first time, load and return it
+    FAIL_RETURN(Clone2DTexture(filename, texture, bMipmap));
+
+    _textures.insert(make_pair(filename, texture));  
+  }
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::Get3DTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::Get3DTexture(const string& filename, SkyTexture& texture, unsigned int iDepth, bool bMipmap, bool bLoadFromSliceFiles)
+ * @brief Returns a 3D texture object from the texture set.
+ * 
+ * If the texture is already loaded, it is returned.  If it is not, the texture is loaded from 
+ * file, added to the texture set, and returned.  If the image cannot be loaded, returns an error.  
+ * Otherwise returns success. 
+ *
+ * For 3D textures, this simply loads a 2D image file, and duplicates it across each slice.  The 
+ * parameter iDepth must be set in order to use a 2D texture image for a 3D texture. 
+ */ 
+SKYRESULT SkyTextureManager::Get3DTexture(const string& filename, 
+                                       SkyTexture& texture,
+                                       unsigned int iDepth,
+                                       bool bMipmap /* = false */,
+                                       bool bLoadFromSliceFiles /* = false */)
+{
+  TextureIterator iter = _textures.find(filename);
+  
+  if (iter != _textures.end())
+  { // the texture is already loaded, just return it.
+    texture = iter->second;
+  }
+  else
+  { // the texture is being requested for the first time, load and return it
+    FAIL_RETURN(Clone3DTexture(filename, texture, iDepth, bMipmap, bLoadFromSliceFiles));
+
+    _textures.insert(make_pair(filename, texture));  
+  }
+
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : roundPowerOf2
+// Description     : 
+//------------------------------------------------------------------------------
+static int roundPowerOf2(int n)
+{
+  int m;
+  for (m = 1; m < n; m *= 2);
+
+  // m >= n
+  if (m - n <= n - m/2) 
+    return m;
+  else
+    return m/2;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::Clone2DTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::Clone2DTexture( const string &filename, SkyTexture& texture, bool bMipmap)
+ * @brief Returns a 2D texture object.
+ * 
+ * Ignores texture set.  This always loads the file, if it exists, and creates and returns the texture.
+ *
+ * If the image cannot be loaded, returns an error.  Otherwise returns success.
+ */ 
+SKYRESULT SkyTextureManager::Clone2DTexture(const string &filename, 
+                                            SkyTexture& texture,
+                                            bool bMipmap /* = false */)
+{
+  string pathFilename;
+  unsigned char *pImageData = NULL;
+  int iWidth       = 0;
+  int iHeight      = 0;
+  int iChannels    = 0;
+
+  enum ImageType
+  {
+    IMAGE_PPM,
+    IMAGE_TGA
+  };
+  ImageType eType;
+\r/****
+  // 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");
+  \r****/
+  // 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;
+    }\r*/
+    
+  //}
+  
+  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;
+        }\r*/
+        
+        //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 (file)
index 0000000..0bda600
--- /dev/null
@@ -0,0 +1,208 @@
+//------------------------------------------------------------------------------
+// File : SkyTextureManager.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or implied warranty.
+/**
+ * @file SkyTextureManager.hpp
+ * 
+ * Definition of a manager that keeps track of texture locations and sharing of texture files.                                          |
+ */
+#ifndef SKYTEXTUREMANAGER_HPP
+#define SKYTEXTUREMANAGER_HPP
+
+#pragma warning( disable : 4786)
+
+#include "SkySingleton.hpp"
+#include "SkyTexture.hpp"
+#include <string>
+#include <list>
+#include <map>
+
+using namespace std;
+
+// forward declaration for singleton
+class SkyTextureManager;
+
+//! A singleton of the SkyTextureManager.  Can only create the TextureManager with TextureManager::Instantiate();
+typedef SkySingleton<SkyTextureManager> TextureManager;
+
+//------------------------------------------------------------------------------
+/**
+ * @class SkyTextureManager
+ * @brief A resource manager for textures.
+ * 
+ * This manager allows textures to be shared.  It keeps a mapping of 
+ * filenames to texture objects, and makes it easy to use the same texture
+ * for multiple objects without the objects having to be aware of the 
+ * sharing.  Supports cube map textures, and 2D textures.  Can also be used
+ * to "clone textures", which creates unmanaged texture objects from files 
+ * that are not kept in the mapping, and thus are not shared.
+ */
+class SkyTextureManager
+{
+public: // types
+  typedef list<string> StringList;
+
+public: // methods
+  //.-------------------------------------------------------------------------.
+  //|  Paths to texture directories
+  //.-------------------------------------------------------------------------.
+  void              AddPath(const string& path);
+  //! Return the list of texture paths that will be searched by Get2DTexture() and Get3DTexture().
+  const StringList& GetPaths() const                    { return _texturePaths;  }
+  //! Clear the list of texture paths that will be searched by Get2DTexture() and Get3DTexture().
+  void              ClearPaths()                        { _texturePaths.clear(); }
+  
+  //.-------------------------------------------------------------------------.
+  //|  Texture loading
+  //.-------------------------------------------------------------------------.
+  SKYRESULT         Get2DTexture(         const string  &filename, 
+                                          SkyTexture&   texture,
+                                          bool          bMipmap             = false); 
+  SKYRESULT         Get3DTexture(         const string  &filename, 
+                                          SkyTexture&   texture,
+                                          unsigned int  iDepth,
+                                          bool          bMipmap             = false,
+                                          bool          bLoadFromSliceFiles = false);
+  SKYRESULT         GetCubeMapTexture(    const string  &filename, 
+                                          SkyTexture&   texture,
+                                          bool          bMipmap             = false);
+
+  //.-------------------------------------------------------------------------.
+  //|  Texture cloning: create a duplicate texture object: not added to set!
+  //.-------------------------------------------------------------------------.
+  SKYRESULT         Clone2DTexture(       const string  &filename, 
+                                          SkyTexture&   texture,
+                                          bool          bMipmap             = false);
+  SKYRESULT         Clone3DTexture(       const string  &filename, 
+                                          SkyTexture&   texture,
+                                          unsigned int  iDepth,
+                                          bool          bMipmap             = false,
+                                          bool          bLoadFromSliceFiles = false );
+  SKYRESULT         CloneCubeMapTexture(  const string  &filename, 
+                                          SkyTexture&   texture,
+                                          bool          bMipmap             = false);
+
+  //.-------------------------------------------------------------------------.
+  //|  Texture Object Creation: not added to the texture set (no filename!)
+  //.-------------------------------------------------------------------------.
+  inline SKYRESULT  Create2DTextureObject(SkyTexture    &texture, 
+                                          unsigned int  iWidth, 
+                                          unsigned int  iHeight,
+                                          unsigned int  iFormat,
+                                          unsigned char *pData);
+  inline SKYRESULT  Create3DTextureObject(SkyTexture    &texture, 
+                                          unsigned int  iWidth, 
+                                          unsigned int  iHeight,
+                                          unsigned int  iDepth,
+                                          unsigned int  iFormat,
+                                          unsigned char *pData);
+
+  //.-------------------------------------------------------------------------.
+  //|  Texture Object Destruction: use this because texture objects are structs
+  //|  that use shallow copies!
+  //.-------------------------------------------------------------------------.
+  static void       DestroyTextureObject( SkyTexture &texture);
+
+  
+protected:
+  SkyTextureManager(bool bSlice3DTextures = false);
+  ~SkyTextureManager();
+
+  SKYRESULT  _Create2DTextureObject(      SkyTexture    &texture, 
+                                          unsigned int  iWidth, 
+                                          unsigned int  iHeight,
+                                          unsigned int  iFormat,
+                                          unsigned char *pData);
+  SKYRESULT  _Create3DTextureObject(      SkyTexture    &texture, 
+                                          unsigned int  iWidth, 
+                                          unsigned int  iHeight,
+                                          unsigned int  iDepth,
+                                          unsigned int  iFormat,
+                                          unsigned char *pData);
+private:
+  typedef list<SkyTexture>        TextureList;
+  typedef map<string, SkyTexture> TextureSet;
+  typedef TextureSet::iterator    TextureIterator;
+  
+  //.-------------------------------------------------------------------------.
+  //|  Data
+  //.-------------------------------------------------------------------------.
+  
+  // paths searched for textures specified by filename.
+  StringList  _texturePaths;
+  
+  // cached textures
+  TextureSet  _textures;        // loaded textures
+  // textures created directly, not loaded from file and cached.
+  TextureList _uncachedTextures;
+  
+  // if this is true, then 3D textures will be represented as a set of 2D slices.
+  static bool s_bSlice3DTextures;
+};
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::Create2DTextureObject
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::Create2DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iFormat, unsigned char *pData)
+ * @brief Creates a 2D texture.
+ * 
+ * Creates an OpenGL texture object and returns its ID and dimensions in a SkyTexture structure.
+ * This texture will be deleted by the texture manager at shutdown.
+ *
+ */ 
+inline SKYRESULT SkyTextureManager::Create2DTextureObject(SkyTexture &texture, 
+                                                          unsigned int iWidth, 
+                                                          unsigned int iHeight, 
+                                                          unsigned int iFormat, 
+                                                          unsigned char *pData)
+{
+  SKYRESULT retval = _Create2DTextureObject(texture, iWidth, iHeight, iFormat, pData);
+  if SKYSUCCEEDED(retval)
+    _uncachedTextures.push_back(texture);
+  return retval;
+}
+  
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureManager::Create3DTextureObject
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureManager::Create3DTextureObject(SkyTexture &texture, unsigned int iWidth, unsigned int iHeight, unsigned int iDepth, unsigned int iFormat, unsigned char *pData)
+ * @brief Creates a 3D texture.
+ * 
+ * Creates an OpenGL texture object and returns its ID and dimensions in a SkyTexture structure.
+ * This texture will be deleted by the texture manager at shutdown, and should not be destroyed 
+ * by the user.
+ *
+ */ 
+inline SKYRESULT SkyTextureManager::Create3DTextureObject(SkyTexture &texture, 
+                                                          unsigned int iWidth, 
+                                                          unsigned int iHeight, 
+                                                          unsigned int iDepth, 
+                                                          unsigned int iFormat, 
+                                                          unsigned char *pData)
+{
+  SKYRESULT retval = _Create3DTextureObject(texture, iWidth, iHeight, iDepth, iFormat, pData);
+  if SKYSUCCEEDED(retval)
+    _uncachedTextures.push_back(texture);
+  return retval;
+}
+
+#endif //QGLVUTEXTUREMANAGER_HPP
diff --git a/simgear/scene/sky/clouds3d/SkyTextureState.cpp b/simgear/scene/sky/clouds3d/SkyTextureState.cpp
new file mode 100644 (file)
index 0000000..5495ce1
--- /dev/null
@@ -0,0 +1,271 @@
+//------------------------------------------------------------------------------
+// File : SkyTextureState.cpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file SkyTextureState.cpp
+ * 
+ * Implementation of class SkyTextureState, which encapsulates OpenGL texture state.
+ */
+#include "SkyTextureState.hpp"
+//#include "glvu.hpp"
+
+//------------------------------------------------------------------------------
+// Static initializations.
+//------------------------------------------------------------------------------
+unsigned int SkyTextureState::s_iNumTextureUnits = 0;
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::SkyTextureState
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyTextureState::SkyTextureState()
+* @brief Constructor.
+*/ 
+SkyTextureState::SkyTextureState()
+{
+  if (0 == s_iNumTextureUnits)
+  {
+    int iNumTextureUnits = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &iNumTextureUnits);
+    if (iNumTextureUnits > 0)
+      s_iNumTextureUnits = iNumTextureUnits;
+    else
+      s_iNumTextureUnits = 1;
+  }
+  
+  _pTextureUnitState = new TexState[s_iNumTextureUnits];
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::~SkyTextureState
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyTextureState::~SkyTextureState()
+* @brief Destructor.
+*/ 
+SkyTextureState::~SkyTextureState()
+{
+  SAFE_DELETE(_pTextureUnitState);
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::Activate
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::Activate()
+ * @brief @todo <WRITE BRIEF SkyTextureState::Activate DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyTextureState::Activate FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyTextureState::Activate()
+{
+  SkyTextureState *pCurrent = GraphicsContext::InstancePtr()->GetCurrentTextureState();
+  assert(NULL != pCurrent);
+  //GLVU::CheckForGLError("SkyTextureState::Activate(8)");
+  for (unsigned int i = 0; i < s_iNumTextureUnits; ++i)
+  {
+    if (s_iNumTextureUnits > 1)
+      glActiveTextureARB(GL_TEXTURE0_ARB + i);
+    bool bEnabled = IsTextureEnabled(i);
+    if (pCurrent->IsTextureEnabled(i) != bEnabled)
+    {
+      FAIL_RETURN(pCurrent->EnableTexture(i, bEnabled));
+      //GLVU::CheckForGLError("SkyTextureState::Activate(7)");
+      if (bEnabled)
+        glEnable(GetActiveTarget(i));
+      else
+        glDisable(GetActiveTarget(i));
+    }
+    //GLVU::CheckForGLError("SkyTextureState::Activate(6)");
+    if (bEnabled)
+    {
+      GLenum eTarget    = GetActiveTarget(i);
+      unsigned int iID  = GetTextureID(i);
+      if ((pCurrent->GetActiveTarget(i) != eTarget) ||
+          (pCurrent->GetTextureID(i)    != iID))
+      {
+        FAIL_RETURN(pCurrent->SetTexture(i, eTarget, iID));
+        glBindTexture(eTarget, iID);
+      }
+      //GLVU::CheckForGLError("SkyTextureState::Activate(5)");
+      GLenum paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_S);
+      if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_S) != paramValue) 
+      {
+        FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_S, paramValue));
+        glTexParameteri(eTarget, GL_TEXTURE_WRAP_S, paramValue);
+      }
+      //GLVU::CheckForGLError("SkyTextureState::Activate(4)");
+      paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_T);
+      if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_T) != paramValue) 
+      {
+        FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_T, paramValue));
+        glTexParameteri(eTarget, GL_TEXTURE_WRAP_T, paramValue);
+      }
+      //GLVU::CheckForGLError("SkyTextureState::Activate(3)");
+      paramValue = GetTextureParameter(i, GL_TEXTURE_WRAP_R);
+      if (pCurrent->GetTextureParameter(i, GL_TEXTURE_WRAP_R) != paramValue) 
+      {
+        FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_WRAP_R, paramValue));
+        //glTexParameteri(eTarget, GL_TEXTURE_WRAP_R, paramValue);
+      }
+      //GLVU::CheckForGLError("SkyTextureState::Activate(2)");
+      paramValue = GetTextureParameter(i, GL_TEXTURE_MIN_FILTER);
+      if (pCurrent->GetTextureParameter(i, GL_TEXTURE_MIN_FILTER) != paramValue) 
+      {
+        FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_MIN_FILTER, paramValue));
+        glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, paramValue);
+      }
+       //GLVU::CheckForGLError("SkyTextureState::Activate(1)");
+      paramValue = GetTextureParameter(i, GL_TEXTURE_MAG_FILTER);
+      if (pCurrent->GetTextureParameter(i, GL_TEXTURE_MAG_FILTER) != paramValue) 
+      {
+        FAIL_RETURN(pCurrent->SetTextureParameter(i, GL_TEXTURE_MAG_FILTER, paramValue));
+        glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, paramValue);
+      }
+      //GLVU::CheckForGLError("SkyTextureState::Activate()");
+    }
+    if (s_iNumTextureUnits > 1)
+      glActiveTextureARB(GL_TEXTURE0_ARB);
+  }
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::SetTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture&  texture)
+ * @brief @todo <WRITE BRIEF SkyTextureState::BindTexture DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyTextureState::BindTexture FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyTextureState::SetTexture(unsigned int iTextureUnit, 
+                                      GLenum       eTarget, 
+                                      SkyTexture&  texture)
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::BindTexture(): Invalid texture unit.");
+  }
+  
+  _pTextureUnitState[iTextureUnit].eActiveTarget = eTarget;
+  _pTextureUnitState[iTextureUnit].iBoundTexture = texture.GetID();
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::SetTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID)
+ * @brief @todo <WRITE BRIEF SkyTextureState::SetTexture DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyTextureState::SetTexture FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyTextureState::SetTexture(unsigned int iTextureUnit, 
+                                      GLenum       eTarget, 
+                                      unsigned int iTextureID)
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::BindTexture(): Invalid texture unit.");
+  }
+  
+  _pTextureUnitState[iTextureUnit].eActiveTarget = eTarget;
+  _pTextureUnitState[iTextureUnit].iBoundTexture = iTextureID;
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::EnableTexture
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::EnableTexture(unsigned int iTextureUnit, bool bEnable)
+ * @brief @todo <WRITE BRIEF SkyTextureState::EnableTexture DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyTextureState::EnableTexture FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyTextureState::EnableTexture(unsigned int iTextureUnit, bool bEnable)
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::EnableTexture(): Invalid texture unit.");
+  }  
+  
+  _pTextureUnitState[iTextureUnit].bEnabled = bEnable;
+  
+  return SKYRESULT_OK;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::SetTextureParameter
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::SetTextureParameter(unsigned int iTextureUnit, GLenum eParameter, GLenum eMode)
+ * @brief @todo <WRITE BRIEF SkyTextureState::SetTextureParameter DOCUMENTATION>
+ * 
+ * @todo <WRITE EXTENDED SkyTextureState::SetTextureParameter FUNCTION DOCUMENTATION>
+ */ 
+SKYRESULT SkyTextureState::SetTextureParameter(unsigned int iTextureUnit, 
+                                               GLenum       eParameter, 
+                                               GLenum       eMode)
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTextureState::SetTextureParameter(): Invalid texture unit.");
+  }  
+
+  switch (eParameter)
+  {
+  case GL_TEXTURE_WRAP_S:
+    _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_S] = eMode;
+    break;
+  case GL_TEXTURE_WRAP_T:
+    _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_T] = eMode;
+    break;
+  case GL_TEXTURE_WRAP_R:
+    _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_R] = eMode;
+    break;
+  case GL_TEXTURE_MIN_FILTER:
+    _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MIN] = eMode;
+    break;
+  case GL_TEXTURE_MAG_FILTER:
+    _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MAG] = eMode;
+    break;
+  default:
+    FAIL_RETURN_MSG(SKYRESULT_FAIL, "SkyTExtureState::SetTextureParameter(): Invalid parameter.");
+    break;
+  }
+  
+  return SKYRESULT_OK;
+}
\ 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 (file)
index 0000000..1df2d39
--- /dev/null
@@ -0,0 +1,205 @@
+//------------------------------------------------------------------------------
+// File : SkyTextureState.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+* @file SkyTextureState.hpp
+* 
+* Interface Definition for class SkyTextureState, which encapsulates OpenGL texture state.
+*/
+#ifndef __SKYTEXTURESTATE_HPP__
+#define __SKYTEXTURESTATE_HPP__
+
+#include "SkyUtil.hpp"
+#include "SkyTexture.hpp"
+#include "SkyContext.hpp"
+#include <map>
+
+//------------------------------------------------------------------------------
+/**
+* @class SkyTextureState
+* @brief A wrapper for texture unit state.
+* 
+* @todo <WRITE EXTENDED CLASS DESCRIPTION>
+*/
+class SkyTextureState
+{
+public: // methods
+       SkyTextureState();
+       ~SkyTextureState();
+
+  SKYRESULT Activate();
+
+  SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, SkyTexture& texture);
+  SKYRESULT SetTexture(unsigned int iTextureUnit, GLenum eTarget, unsigned int iTextureID);
+  SKYRESULT EnableTexture(unsigned int iTextureUnit, bool bEnable);
+  SKYRESULT SetTextureParameter(unsigned int  iTextureUnit, 
+                                GLenum        eParameter, 
+                                GLenum        eMode);
+
+  inline GLenum       GetActiveTarget(unsigned int iTextureUnit) const;
+  inline unsigned int GetTextureID(unsigned int iTextureUnit) const;
+  inline bool         IsTextureEnabled(unsigned int iTextureUnit) const;
+  inline GLenum       GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const;
+
+protected: // datatypes    
+  struct TexState
+  {
+    TexState() : eActiveTarget(GL_TEXTURE_2D), iBoundTexture(0), bEnabled(false)
+    {
+      // set state to GL defaults.
+      int i;
+      for (i = 0; i < SKY_TEXCOORD_COUNT; ++i) { eWrapMode[i] = GL_REPEAT; }
+      eFilterMode[SKY_FILTER_MIN] = GL_NEAREST_MIPMAP_LINEAR;
+      eFilterMode[SKY_FILTER_MAG] = GL_LINEAR;
+    }
+
+    enum TexCoord
+    {
+      SKY_TEXCOORD_S,
+      SKY_TEXCOORD_T,
+      SKY_TEXCOORD_R,
+      SKY_TEXCOORD_COUNT
+    };
+    
+    enum TexFilter
+    {
+      SKY_FILTER_MIN,
+      SKY_FILTER_MAG,
+      SKY_FILTER_COUNT
+    };
+    
+    GLenum        eActiveTarget;
+    unsigned int  iBoundTexture; 
+    bool          bEnabled;
+    GLenum        eWrapMode[SKY_TEXCOORD_COUNT];       
+    GLenum        eFilterMode[SKY_FILTER_COUNT];  
+  };
+
+protected: // data
+
+  TexState        *_pTextureUnitState;  // one per texture unit
+    
+  static unsigned int  s_iNumTextureUnits;
+};
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::GetActiveTarget
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::GetActiveTarget(unsigned int iTextureUnit) const
+ * @brief Returns the active texture target for the specified texture unit.
+ * 
+ * If an invalid texture unit is specifed, returns GL_NONE.
+ */ 
+inline GLenum SkyTextureState::GetActiveTarget(unsigned int iTextureUnit) const
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    SkyTrace("SkyTextureState::GetActiveTexture(): Invalid texture unit.");
+    return GL_NONE;
+  }
+  return _pTextureUnitState[iTextureUnit].eActiveTarget;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : int SkyTextureState::GetTextureID
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn int SkyTextureState::GetTextureID(unsigned int iTextureUnit) const
+* @brief Returns the texture ID associated with the specified texture unit.
+* 
+* If an invalid texture unit is specifed, returns GL_NONE.
+*/ 
+inline unsigned int SkyTextureState::GetTextureID(unsigned int iTextureUnit) const
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    SkyTrace("SkyTextureState::GetTextureID(): Invalid texture unit.");
+    return GL_NONE;
+  }
+  return _pTextureUnitState[iTextureUnit].iBoundTexture;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::IsTextureEnabled
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+* @fn SkyTextureState::IsTextureEnabled(unsigned int iTextureUnit) const
+* @brief Returns the status (enabled or disabled) of the specified texture unit.
+* 
+* If an invalid texture unit is specifed, returns false.
+*/ 
+inline bool SkyTextureState::IsTextureEnabled(unsigned int iTextureUnit) const
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    SkyTrace("SkyTextureState::IsTextureEnabled(): Invalid texture unit.");
+    return false;
+  }
+  return _pTextureUnitState[iTextureUnit].bEnabled;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTextureState::GetTextureParameter
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyTextureState::GetTextureParameter(unsigned int iTextureUnit, GLenum eParamter) const
+ * @brief Returns the current value of @eParameter on the specified texture unit.
+ * 
+ * If an invalid texture unit or parameter is specified, returns GL_NONE.
+ */ 
+inline GLenum SkyTextureState::GetTextureParameter(unsigned int iTextureUnit, GLenum eParameter) const
+{
+  if (iTextureUnit >= s_iNumTextureUnits)
+  {
+    SkyTrace("SkyTextureState::GetTextureParamter(): Invalid texture unit.");
+    return GL_NONE;
+  }
+
+  switch (eParameter)
+  {
+  case GL_TEXTURE_WRAP_S:
+    return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_S];
+    break;
+  case GL_TEXTURE_WRAP_T:
+    return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_T];
+    break;
+  case GL_TEXTURE_WRAP_R:
+    return _pTextureUnitState[iTextureUnit].eWrapMode[TexState::SKY_TEXCOORD_R];
+    break;
+  case GL_TEXTURE_MIN_FILTER:
+    return _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MIN];
+    break;
+  case GL_TEXTURE_MAG_FILTER:
+    return _pTextureUnitState[iTextureUnit].eFilterMode[TexState::SKY_FILTER_MAG];
+    break;
+  default:
+    SkyTrace("SkyTExtureState::SetTextureParameter(): Invalid parameter.");
+    break;
+  }
+  return GL_NONE;
+}
+
+#endif //__SKYTEXTURESTATE_HPP__
\ 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 (file)
index 0000000..ceeeab1
--- /dev/null
@@ -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 (file)
index 0000000..9e020f6
--- /dev/null
@@ -0,0 +1,192 @@
+//------------------------------------------------------------------------------
+// File : SkyUtil.hpp
+//------------------------------------------------------------------------------
+// SkyWorks : Copyright 2002 Mark J. Harris and
+//                                             The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The author(s) and The University of North Carolina at Chapel Hill make no 
+// representations about the suitability of this software for any purpose. 
+// It is provided "as is" without express or 
+// implied warranty.
+/**
+ * @file  SkyUtil.hpp
+ * @brief Safe deallocation functions, result codes, trace functions, and macros.
+ */
+#ifndef __SKYUTIL_HPP__
+#define __SKYUTIL_HPP__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+
+//-----------------------------------------------------------------------------
+// Useful constants
+//-----------------------------------------------------------------------------
+//! Pi.
+const float SKY_PI      = 4.0f * (float) atan(1.0f);
+//! 1.0 / Pi
+const float SKY_INV_PI  = 1.0f / SKY_PI;
+//! 1.0 / (4.0 * Pi)
+const float SKY_INV_4PI = 1.0f / (4.0f * SKY_PI);
+
+//-----------------------------------------------------------------------------
+// Safe deallocation
+//-----------------------------------------------------------------------------
+//! Delete and set pointer to NULL.
+#define SAFE_DELETE(p)       { delete   (p); (p)=NULL; }
+//! Delete an array and set pointer to NULL.
+#define SAFE_DELETE_ARRAY(p) { delete[] (p); (p)=NULL; }
+//#define SAFE_RELEASE(p)      { (p) = NULL; } 
+//{ if(p) {  (p)->Release(); (p)=NULL; } }
+
+//------------------------------------------------------------------------------
+// Useful Macros
+//------------------------------------------------------------------------------
+//! Convert Degrees to Radians
+#define SKYDEGREESTORADS 0.01745329252f
+//! Convert Radians to Degrees
+#define SKYRADSTODEGREES 57.2957795131f
+
+//------------------------------------------------------------------------------
+// Function              : SkyGetLogBaseTwo
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn SkyGetLogBaseTwo(int iNum)
+ * @brief Returns the integer base two logarithm of the integer input.
+ */ 
+inline int SkyGetLogBaseTwo(int iNum)
+{
+  int i, n;
+  for(i = iNum-1, n = 0; i > 0; i >>= 1, n++ );
+  return n;
+}
+
+
+//------------------------------------------------------------------------------
+// Function              : SkyTrace
+// Description     : 
+//------------------------------------------------------------------------------
+void SkyTrace( char* strMsg, ... );
+
+
+//.----------------------------------------------------------------------------.
+//|   Result Codes                                                             |
+//.----------------------------------------------------------------------------.
+//! SKYRESULTs are used for returning error information that can be used to trace bugs.
+typedef int SKYRESULT;
+
+//! Returns true if the SKYRESULT is a success result.
+#define SKYSUCCEEDED(Status) ((SKYRESULT)(Status) >= 0)
+//! Returns true if the SKYRESULT is a failure result.
+#define SKYFAILED(Status) ((SKYRESULT)(Status) < 0)
+
+//! SKYRESULTs are used for returning error information that can be used to trace bugs.
+enum SKYRESULT_CODES
+{
+    // SUCCESS CODES: non-negative
+    SKYRESULT_OK = 1,
+    // FAILURE CODES: negative
+    SKYRESULT_FAIL = -1
+};
+
+
+//-----------------------------------------------------------------------------
+// FAIL_RETURN
+//-----------------------------------------------------------------------------
+// Print debug messages to the WIN32 debug window 
+//-----------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Function              : FAIL_RETURN
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn FAIL_RETURN(p)
+ * @brief Prints a trace message if @a p failed, and returns the failure code.
+ *
+ * Outputs in a format that can be double-clicked in DevStudio to open the 
+ * appropriate file and location.
+ */ 
+#if defined(DEBUG) | defined(_DEBUG)
+       #define FAIL_RETURN(p) \
+       { \
+               SKYRESULT __SKYUTIL__result__; \
+                       if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
+                               fprintf(stderr, "!!!! FAIL_RETURN TRAP !!!! %s: %d: %d\n",__FILE__, __LINE__, __SKYUTIL__result__); \
+                               return __SKYUTIL__result__; \
+                       } \
+       }
+#else
+       #define FAIL_RETURN(p) p
+#endif
+
+
+//------------------------------------------------------------------------------
+// Function              : FAIL_RETURN_MSG
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn FAIL_RETURN_MSG(p,str)
+ * @brief Similar to FAIL_RETURN, but also appends a user-supplied message.
+ * 
+ * @see FAIL_RETURN, FAIL_RETURN_MSG
+ */ 
+#if defined(DEBUG) | defined(_DEBUG)
+       #define FAIL_RETURN_MSG(p,str) \
+       { \
+               SKYRESULT __SKYUTIL__result__; \
+                       if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
+                               fprintf(stderr, "!!!! FAIL_RETURN_MSG TRAP !!!! %s: %d: %d: %s\n",__FILE__,__LINE__,__SKYUTIL__result__,str); \
+                               return __SKYUTIL__result__; \
+                       } \
+       }
+#else
+       #define FAIL_RETURN_MSG(p,str) p
+#endif
+
+
+//------------------------------------------------------------------------------
+// Function              : FAIL_RETURN_MSGBOX
+// Description     : 
+//------------------------------------------------------------------------------
+/**
+ * @fn FAIL_RETURN_MSGBOX(p,str)
+ * @brief Similar to FAIL_RETURN_MSG, but also displays the error in a message box (in Windows).
+ * 
+ * @see FAIL_RETURN_MSG, FAIL_RETURN
+ */ 
+#if defined(DEBUG) | defined(_DEBUG)
+#ifdef USEWINDOWSOUTPUT
+       #define FAIL_RETURN_MSGBOX(p,str) \
+       { \
+               SKYRESULT __SKYUTIL__result__; \
+                       if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
+                char msg[512]; \
+                sprintf(msg, "%s: %d: %d: %s\n",__FILE__,__LINE__,__SKYUTIL__result__,str); \
+                MessageBox(NULL, msg, "!!!! FAIL_RETURN_MSG TRAP !!!!", MB_OK); \
+                               return __SKYUTIL__result__; \
+                       } \
+       }
+#else
+    #define FAIL_RETURN_MSGBOX(p,str) \
+       { \
+               SKYRESULT __SKYUTIL__result__; \
+                       if ( SKYFAILED( __SKYUTIL__result__ = (p) ) ) { \
+                fprintf(stderr, "!!!! FAIL_RETURN_MSG TRAP !!!! %s: %d: %d: %s\n",__FILE__,__LINE__,__D3DUTIL__hres__,str); \
+                               return __SKYUTIL__result__; \
+                       } \
+       }
+#endif
+#else
+       #define FAIL_RETURN_MSGBOX(p,str) p
+#endif
+
+#endif //__SKYUTIL_HPP__
\ 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 (file)
index 0000000..736305a
--- /dev/null
@@ -0,0 +1,84 @@
+//------------------------------------------------------------------------------
+// File : camdisplay.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// camdisplay.cpp
+//============================================================================
+
+#include <GL/glut.h>
+#include "camera.hpp"
+
+//----------------------------------------------------------------------------
+// OPENGL CAMERA FRUSTUM DRAWING ROUTINES
+//----------------------------------------------------------------------------
+void Camera::Display() const
+{
+  // CALC EIGHT CORNERS OF FRUSTUM (NEAR PTS AND FAR PTS)
+  Vec3f V[8];
+  CalcVerts(V);
+
+
+  // DRAW THE FRUSTUM IN WIREFRAME
+  glBegin(GL_LINE_LOOP);  // TOP FACE
+    glVertex3fv(&(V[4].x)); glVertex3fv(&(V[5].x)); 
+    glVertex3fv(&(V[1].x)); glVertex3fv(&(V[0].x));
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // BOTTOM FACE
+    glVertex3fv(&(V[3].x)); glVertex3fv(&(V[2].x));
+    glVertex3fv(&(V[6].x)); glVertex3fv(&(V[7].x)); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // LEFT FACE
+    glVertex3fv(&(V[1].x)); glVertex3fv(&(V[5].x));
+    glVertex3fv(&(V[6].x)); glVertex3fv(&(V[2].x)); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // RIGHT FACE
+    glVertex3fv(&(V[0].x)); glVertex3fv(&(V[3].x));
+    glVertex3fv(&(V[7].x)); glVertex3fv(&(V[4].x)); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // NEAR FACE
+    glVertex3fv(&(V[1].x)); glVertex3fv(&(V[2].x));
+    glVertex3fv(&(V[3].x)); glVertex3fv(&(V[0].x)); 
+  glEnd();
+  glBegin(GL_LINE_LOOP);  // FAR FACE
+    glVertex3fv(&(V[4].x)); glVertex3fv(&(V[7].x));
+    glVertex3fv(&(V[6].x)); glVertex3fv(&(V[5].x)); 
+  glEnd();
+
+  // DRAW PROJECTOR LINES FROM EYE TO CORNERS OF VIEWPLANE WINDOW
+  glBegin(GL_LINES);
+    glVertex3fv(&(Orig.x)); glVertex3fv(&(V[1].x));
+    glVertex3fv(&(Orig.x)); glVertex3fv(&(V[2].x));
+    glVertex3fv(&(Orig.x)); glVertex3fv(&(V[3].x));
+    glVertex3fv(&(Orig.x)); glVertex3fv(&(V[0].x));
+  glEnd();
+
+}
+void Camera::DisplayInGreen() const
+{
+  //draws the camera in unlit green lines, then restores the GL state
+  glPushAttrib(GL_LIGHTING_BIT);
+  glDisable(GL_LIGHTING);
+  glPushAttrib(GL_LINE_BIT);
+  glLineWidth(1.0);
+  glColor3f(0,1,0);
+
+  Display();
+
+  glPopAttrib();
+  glPopAttrib();
+  
+}
diff --git a/simgear/scene/sky/clouds3d/camera.cpp b/simgear/scene/sky/clouds3d/camera.cpp
new file mode 100644 (file)
index 0000000..c5b89fa
--- /dev/null
@@ -0,0 +1,409 @@
+//------------------------------------------------------------------------------
+// File : camera.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// camera.cpp : camera class implementation
+//----------------------------------------------------------------------------
+// $Id$
+//============================================================================
+#include "camera.hpp"
+#include <iostream.h>
+
+//----------------------------------------------------------------------------
+// CONSTRUCTOR: defines a default camera system defined as (45 DEG FOV)
+//----------------------------------------------------------------------------
+Camera::Camera()
+{
+  X.Set(1,0,0); Y.Set(0,1,0); Z.Set(0,0,1);
+  Orig.Set(0,0,0);
+  Near=0.5f; Far=140.0f; wL=-1; wR=1; wT=1; wB=-1;
+}
+
+Camera::Camera(const Camera &Cam)
+{
+  Copy(Cam);
+}
+
+void Camera::Copy(const Camera &Cam)
+{
+  X=Cam.X;  Y=Cam.Y;  Z=Cam.Z;  Orig=Cam.Orig;
+  Near=Cam.Near;  Far=Cam.Far;
+  wL=Cam.wL;  wR=Cam.wR;  wT=Cam.wT;  wB=Cam.wB;
+}
+
+//----------------------------------------------------------------------------
+// OpenGL CAMERA ORIENTATION ROUTINE (glLookAt)
+//----------------------------------------------------------------------------
+void Camera::LookAt(
+  const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp)
+{
+  Z = Eye-ViewRefPt;  Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
+  X = ViewUp/Z;       X.Normalize();
+  Y = Z/X;            Y.Normalize();
+  Orig = Eye;
+}
+
+//----------------------------------------------------------------------------
+// OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (gluPerspective)
+// Aspect = Width/Height; Yfov in degrees
+//----------------------------------------------------------------------------
+void Camera::Perspective(float Yfov, float Aspect, float Ndist, float Fdist)
+{
+  Yfov *= 0.0174532f;  // CONVERT TO RADIANS
+  Near=Ndist;  Far=Fdist;
+  wT=(float)tan(Yfov*0.5f)*Near;  wB=-wT;
+  wR=wT*Aspect; wL=-wR;
+}
+
+//----------------------------------------------------------------------------
+// OpenGL PERSPECTIVE FRUSTUM DEFINITION ROUTINE (glFrustum). Window extents
+// are defined on the viewplane at z=-Ndist.
+//----------------------------------------------------------------------------
+void Camera::Frustum(float l, float r, float b, float t, float Ndist, float Fdist)
+{
+  Near=Ndist;  Far=Fdist;
+  wR=r;  wL=l;  wB=b;  wT=t;
+}
+
+//----------------------------------------------------------------------------
+// Completely defines a camera as a tight fitting frustum surrounding the
+// given bounding sphere. This is useful when most precision
+// is required in pixel and depth resolution (for example, shadow-maps).
+// The resulting camera is not skewed!
+//----------------------------------------------------------------------------
+void Camera::TightlyFitToSphere(
+  const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad)
+{
+  // FIRST DEFINE COORDINATE FRAME
+  LookAt(Eye,Cntr,ViewUp);
+
+  // PROJECTED DIST TO CNTR ALONG VIEWDIR
+  float DistToCntr = (Cntr-Orig) * ViewDir();
+
+  // CALC TIGHT-FITTING NEAR AND FAR PLANES
+  Near = DistToCntr-Rad;
+  Far = DistToCntr+Rad;
+
+  //x = n*R / sqrt(d2 - r2)
+
+  if (Near<=0 || Far<=0) 
+    printf("ERROR (Camera::TightlyFitToSphere) Eye is inside the sphere!\n");
+
+  // CALC TIGHT-FITTING SIDES
+  wT = (Near * Rad) / (float)sqrt(DistToCntr*DistToCntr - Rad*Rad);//(Near * Rad) / DistToCntr;
+  wB = -wT;
+  wL = wB;
+  wR = wT;
+}
+
+//----------------------------------------------------------------------------
+// Routines to return the Lookat, Perspective, and Frustum params.
+// NOTE: Perspective is designed for non-skewed cameras: the viewing
+//       direction must be centered on the viewplane window. Use frustum
+//       for off-axis cameras.
+//----------------------------------------------------------------------------
+void Camera::GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const
+{
+  *Eye = Orig;
+  *ViewRefPt = Orig - Z;
+  *ViewUp = Y;
+}
+
+void Camera::GetPerspectiveParams(float *Yfov, float *Aspect, 
+                                  float *Ndist, float *Fdist) const
+{
+  *Yfov = (float)atan(wT/Near) * 57.29578f * 2.0f;  // CONVERT TO DEGREES
+  *Aspect = wR/wT;
+  *Ndist = Near;
+  *Fdist = Far;
+}
+
+void Camera::GetFrustumParams(float *l, float *r, float *b, float *t, 
+                              float *Ndist, float *Fdist) const
+{
+  *l = wL;
+  *r = wR;
+  *b = wB;
+  *t = wT;
+  *Ndist = Near;
+  *Fdist = Far;
+}
+
+//----------------------------------------------------------------------------
+// RETURNS THE COP OR EYE IN WORLD COORDS (ORIG OF CAMERA SYSTEM)
+//----------------------------------------------------------------------------
+const Vec3f& Camera::wCOP() const
+{
+   return( Orig );
+}
+
+//----------------------------------------------------------------------------
+// RETURNS THE VIEWING DIRECTION
+//----------------------------------------------------------------------------
+Vec3f Camera::ViewDir() const
+{
+   return( -Z );
+}
+
+Vec3f Camera::ViewDirOffAxis() const
+{
+  float x=(wL+wR)*0.5f, y=(wT+wB)*0.5f;  // MIDPOINT ON VIEWPLANE WINDOW
+  Vec3f ViewDir = X*x + Y*y - Z*Near;
+  ViewDir.Normalize();
+  return( ViewDir );
+}
+
+//----------------------------------------------------------------------------
+// Vec3f WORLD-TO-CAM AND CAM-TO-WORLD ROUTINES
+//----------------------------------------------------------------------------
+Vec3f Camera::WorldToCam(const Vec3f& wP) const
+{
+  Vec3f sP(wP-Orig);
+  Vec3f cP(X*sP,Y*sP,Z*sP);  return(cP);
+}
+
+// Return the z-value of the world point in camera space
+float Camera::WorldToCamZ(const Vec3f& wP) const
+{
+  Vec3f sP(wP-Orig);
+  float zdist = Z*sP;
+  return(zdist);
+}
+
+
+Vec3f Camera::CamToWorld(const Vec3f& cP) const
+{
+  Vec3f wP(X*cP.x + Y*cP.y + Z*cP.z + Orig);  return(wP);
+}
+
+//----------------------------------------------------------------------------
+// Makes the camera pose be the identity. World and camera space will be the
+// same. Window extents and near/far planes are unaffected.
+//----------------------------------------------------------------------------
+void Camera::LoadIdentityXform()
+{
+  X.Set(1,0,0);
+  Y.Set(0,1,0);
+  Z.Set(0,0,1);
+  Orig.Set(0,0,0);
+}
+
+//----------------------------------------------------------------------------
+// Applies an OpenGL style premult/col vector xform to the coordinate frame.
+// Only rotates, translates, and uniform scales are allowed.
+// Window extents and near/far planes are affected by scaling.
+//----------------------------------------------------------------------------
+void Camera::Xform(const float M[16])
+{
+  X.Set( X.x*M[0] + X.y*M[4] + X.z*M[8],
+         X.x*M[1] + X.y*M[5] + X.z*M[9],
+         X.x*M[2] + X.y*M[6] + X.z*M[10] );
+  Y.Set( Y.x*M[0] + Y.y*M[4] + Y.z*M[8],
+         Y.x*M[1] + Y.y*M[5] + Y.z*M[9],
+         Y.x*M[2] + Y.y*M[6] + Y.z*M[10] );
+  Z.Set( Z.x*M[0] + Z.y*M[4] + Z.z*M[8],
+         Z.x*M[1] + Z.y*M[5] + Z.z*M[9],
+         Z.x*M[2] + Z.y*M[6] + Z.z*M[10] );
+  Orig.Set( Orig.x*M[0] + Orig.y*M[4] + Orig.z*M[8] + M[12],
+            Orig.x*M[1] + Orig.y*M[5] + Orig.z*M[9] + M[13],
+            Orig.x*M[2] + Orig.y*M[6] + Orig.z*M[10] + M[14] );
+
+  // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
+  float Scale = X.Length();
+  X /= Scale;
+  Y /= Scale;
+  Z /= Scale;
+
+  // SCALE THE WINDOW EXTENTS AND THE NEAR/FAR PLANES
+  wL*=Scale;
+  wR*=Scale;
+  wB*=Scale;
+  wT*=Scale;
+  Near*=Scale;
+  Far*=Scale;
+};
+
+
+//----------------------------------------------------------------------------
+// Translates the camera by the vector amount trans.
+//----------------------------------------------------------------------------
+void Camera::Translate(const Vec3f& trans)
+{
+  Orig += trans;
+}
+
+
+//----------------------------------------------------------------------------
+// Translates the camera about its origin by the rotation matrix M.
+//----------------------------------------------------------------------------
+void Camera::Rotate(const float M[9])
+{
+  X.Set( X.x*M[0] + X.y*M[3] + X.z*M[6],
+         X.x*M[1] + X.y*M[4] + X.z*M[7],
+         X.x*M[2] + X.y*M[5] + X.z*M[8] );
+  Y.Set( Y.x*M[0] + Y.y*M[3] + Y.z*M[6],
+         Y.x*M[1] + Y.y*M[4] + Y.z*M[7],
+         Y.x*M[2] + Y.y*M[5] + Y.z*M[8] );
+  Z.Set( Z.x*M[0] + Z.y*M[3] + Z.z*M[6],
+         Z.x*M[1] + Z.y*M[4] + Z.z*M[7],
+         Z.x*M[2] + Z.y*M[5] + Z.z*M[8] );
+}
+
+
+//----------------------------------------------------------------------------
+// Returns the COMPOSITE xform matrix that takes a point in the object space
+// to a screen space (pixel) point. The inverse is also provided.
+// You have to give the pixel dimensions of the viewport window.
+//----------------------------------------------------------------------------
+float* Camera::GetXform_Screen2Obj(float* M, int WW, int WH) const
+{
+  Screen2WorldXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
+                        wL,wR,wB,wT,Near,Far,WW,WH);
+  return(M);
+}
+
+float* Camera::GetXform_Obj2Screen(float* M, int WW, int WH) const
+{
+  World2ScreenXform16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x),
+                        wL,wR,wB,wT,Near,Far,WW,WH);
+  return(M);
+}
+
+//----------------------------------------------------------------------------
+// OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/COL VECT, 4x4 MATRIX)
+// A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
+// VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
+// WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
+// Modelview XFORM. The associated inverse matrices are also provided.
+//----------------------------------------------------------------------------
+float* Camera::GetModelviewMatrix(float* M) const
+{
+  Viewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
+  return(M);
+}
+
+float* Camera::GetInvModelviewMatrix(float* M) const
+{  
+  invViewing16fv(M,&(X.x),&(Y.x),&(Z.x),&(Orig.x));
+  return(M);
+}
+
+float* Camera::GetProjectionMatrix(float* M) const
+{
+  Frustum16fv(M,wL,wR,wB,wT,Near,Far);
+  return(M);  
+}
+
+void Camera::SetModelviewMatrix(const float* M)
+{
+  Viewing2CoordFrame16fv(M, &(X.x), &(Y.x), &(Z.x), &(Orig.x));
+}
+
+float* Camera::GetInvProjectionMatrix(float* M) const
+{
+  invFrustum16fv(M,wL,wR,wB,wT,Near,Far);
+  return(M);  
+}
+
+float* Camera::GetViewportMatrix(float* M, int WW, int WH) const
+{
+  Viewport16fv(M,WW,WH);
+  return(M);
+}
+
+float* Camera::GetInvViewportMatrix(float* M, int WW, int WH) const
+{
+  invViewport16fv(M,WW,WH);
+  return(M);
+}
+
+//----------------------------------------------------------------------------
+// Given a screen pixel location (sx,sy) w/ (0,0) at the lower-left and the
+// screen dimensions, return the ray (start,dir) of the ray in world coords.
+//----------------------------------------------------------------------------
+void Camera::GetPixelRay(float sx, float sy, int ww, int wh, 
+                         Vec3f *Start, Vec3f *Dir) const
+{
+  Vec3f wTL = Orig + (X*wL) + (Y*wT) - (Z*Near);  // FIND LOWER-LEFT
+  Vec3f dX = (X*(wR-wL))/(float)ww;               // WORLD WIDTH OF PIXEL
+  Vec3f dY = (Y*(wT-wB))/(float)wh;               // WORLD HEIGHT OF PIXEL
+  wTL += (dX*sx - dY*sy);                         // INCR TO WORLD PIXEL
+  wTL += (dX*0.5 - dY*0.5);                       // INCR TO PIXEL CNTR
+  *Start = Orig;
+  *Dir = wTL-Orig;
+}
+
+//----------------------------------------------------------------------------
+// READ AND WRITE CAMERA AXES AND ORIGIN TO AND FROM A FILE GIVEN A FILE PTR.
+//----------------------------------------------------------------------------
+void Camera::WriteToFile(FILE *fp) const
+{
+ if (fp==NULL) { printf("ERROR WRITING CAM TO FILE!\n"); return; }
+ fprintf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f\n",
+  X.x,X.y,X.z, Y.x,Y.y,Y.z, Z.x,Z.y,Z.z, Orig.x,Orig.y,Orig.z);
+}
+
+int Camera::ReadFromFile(FILE *fp)  // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
+{
+ int Cond = fscanf(fp,"%f %f %f %f %f %f %f %f %f %f %f %f",
+                   &X.x,&X.y,&X.z, &Y.x,&Y.y,&Y.z, 
+                   &Z.x,&Z.y,&Z.z, &Orig.x,&Orig.y,&Orig.z);
+ return(Cond!=EOF);
+}
+
+//----------------------------------------------------------------------------
+// 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
+// (Left,Right, Bottom,Top, Near,Far)
+// In order, near pts counter-clockwise starting with right-top-near (RTN) pt
+// and then far pts ccw starting with right-top-far (RTF) pt
+//----------------------------------------------------------------------------
+void Camera::CalcVerts(Vec3f *V)  const // MUST BE PREALLOCED : "Vec3f V[8]"
+{
+  // WINDOW EXTENTS ARE DEFINED ON THE NEAR PLANE, CALC NEAR PTS (IN CAM COORDS)
+  float NearZ = -Near;
+  V[0].Set(wR,wT,NearZ);
+  V[1].Set(wL,wT,NearZ);
+  V[2].Set(wL,wB,NearZ);
+  V[3].Set(wR,wB,NearZ);
+
+  // CALC FAR PTS (IN CAM COORDS)
+  float FarZ=-Far, FN=Far/Near;
+  float fwL=wL*FN, fwR=wR*FN, fwB=wB*FN, fwT=wT*FN;
+  V[4].Set(fwR,fwT,FarZ);
+  V[5].Set(fwL,fwT,FarZ);
+  V[6].Set(fwL,fwB,FarZ);
+  V[7].Set(fwR,fwB,FarZ);
+
+  // XFORM FRUSTUM IN CAM COORDS TO WORLD SPACE
+  for (int i=0; i<8; i++)
+    V[i] = CamToWorld(V[i]); 
+}
+
+//----------------------------------------------------------------------------
+// PRINT ROUTINE
+//----------------------------------------------------------------------------
+void Camera::Print() const
+{
+  printf("Camera System Parameters:\n");
+  printf("       X: (%.3f, %.3f, %.3f)\n", X.x, X.y, X.z);
+  printf("       Y: (%.3f, %.3f, %.3f)\n", Y.x, Y.y, Y.z);
+  printf("       Z: (%.3f, %.3f, %.3f)\n", Z.x, Z.y, Z.z);
+  printf("  Origin: (%.3f, %.3f, %.3f)\n", Orig.x, Orig.y, Orig.z);
+  printf(" NFLRBT: (%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
+               Near,Far,wL,wR,wB,wT);
+};
diff --git a/simgear/scene/sky/clouds3d/camera.hpp b/simgear/scene/sky/clouds3d/camera.hpp
new file mode 100644 (file)
index 0000000..42a24c8
--- /dev/null
@@ -0,0 +1,102 @@
+//------------------------------------------------------------------------------
+// File : camera.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// camera.hpp : OPENGL-style camera class definition
+//  Defines and stores a "camera" composed of 3 coord axes, an origin for
+//  these axes (center-of-projection or eye location), a near and far plane
+//  as distances from the origin projected along the viewing direction, 
+//  the viewplane window extents (projection window defined in cam coords 
+//  on the viewplane - near plane). ViewPlane is defined as the near plane.
+//  Viewing direction is always defined along the -Z axis with eye at origin.
+//----------------------------------------------------------------------------
+// $Id$
+//============================================================================
+
+#ifndef CAMERA
+#define CAMERA
+
+#include <stdio.h>
+#include <vec3f.hpp>
+#include <mat16fv.hpp>
+
+class Camera
+{
+ public:
+
+  Vec3f X, Y, Z;            // NORMALIZED CAMERA COORDINATE-AXIS VECTORS
+  Vec3f Orig;               // LOCATION OF ORIGIN OF CAMERA SYSTEM IN WORLD COORDS
+  float wL,wR,wB,wT;        // WINDOW EXTENTS DEFINED AS A RECT ON NearPlane
+  float Near,Far;           // DISTANCES TO NEAR AND FAR PLANES (IN VIEWING DIR)
+
+  Camera();
+  Camera(const Camera &Cam);
+  void Copy(const Camera &Cam);
+
+  void LookAt(const Vec3f& Eye, const Vec3f& ViewRefPt, const Vec3f& ViewUp);
+  void Perspective(float Yfov, float Aspect, float Ndist, float Fdist);
+  void Frustum(float l, float r, float b, float t, float Ndist, float Fdist);
+
+  void TightlyFitToSphere(
+    const Vec3f& Eye, const Vec3f& ViewUp, const Vec3f& Cntr, float Rad);
+
+  void GetLookAtParams(Vec3f *Eye, Vec3f *ViewRefPt, Vec3f *ViewUp) const;
+  void GetPerspectiveParams(float *Yfov, float *Aspect, 
+                            float *Ndist, float *Fdist) const;
+  void GetFrustumParams(float *l, float *r, float *b, float *t, 
+                        float *Ndist, float *Fdist) const;
+  const Vec3f& wCOP() const; // WORLD COORDINATE CENTER-OF-PROJECTION (EYE)
+  Vec3f ViewDir() const;     // VIEWING DIRECTION
+  Vec3f ViewDirOffAxis() const;
+
+  float* GetXform_Screen2Obj(float* M, int WW, int WH) const;
+  float* GetXform_Obj2Screen(float* M, int WW, int WH) const;
+
+  float* GetModelviewMatrix(float* M) const;
+  float* GetProjectionMatrix(float* M) const;
+  float* GetViewportMatrix(float* M, int WW, int WH) const;
+
+  void SetModelviewMatrix(const float* M);
+
+  float* GetInvModelviewMatrix(float* M) const;
+  float* GetInvProjectionMatrix(float* M) const;
+  float* GetInvViewportMatrix(float* M, int WW, int WH) const;
+
+  Vec3f WorldToCam(const Vec3f &wP) const;
+  float WorldToCamZ(const Vec3f &wP) const;
+  Vec3f CamToWorld(const Vec3f &cP) const;
+
+  void LoadIdentityXform();
+  void Xform(const float M[16]);
+
+  void Translate(const Vec3f& trans);
+  void Rotate(const float M[9]);
+
+  void GetPixelRay(float sx, float sy, int ww, int wh, 
+                   Vec3f *Start, Vec3f *Dir) const;
+
+  void WriteToFile(FILE *fp) const;
+  int ReadFromFile(FILE *fp);  // RETURNS "1" IF SUCCESSFUL, "0" IF EOF
+
+  void CalcVerts(Vec3f *V) const;    // CALCS EIGHT CORNERS OF VIEW-FRUSTUM
+  void Print() const;
+  void Display() const;
+  void DisplaySolid() const;
+  void DisplayInGreen() const;
+};
+
+#endif
diff --git a/simgear/scene/sky/clouds3d/camutils.cpp b/simgear/scene/sky/clouds3d/camutils.cpp
new file mode 100644 (file)
index 0000000..5363406
--- /dev/null
@@ -0,0 +1,324 @@
+//------------------------------------------------------------------------------
+// File : camutils.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// camutils.cpp : a set of camera utility functions
+//============================================================================
+
+#include "camutils.hpp"
+#include <plane.hpp>
+#include <tri.hpp>
+#include <minmaxbox.hpp>
+
+//----------------------------------------------------------------------------
+// Given a camera's 8 corner vertices and its 6 side planes and a triangle ABC, 
+// return whether or not the tri overlaps the camera's frustum.
+//----------------------------------------------------------------------------
+int CamTriOverlap(const Vec3f V[8], const float P[][4], 
+                  const Vec3f& A, const Vec3f& B, const Vec3f& C)
+{
+  // TEST TRIANGLE AGAINST ALL PLANES OF CAMERA, FOR EACH VERTEX CLASSIFY
+  // AS INSIDE OR OUTSIDE OF PLANE (BY SETTING APPROPRIATE BIT IN BITMASK)
+  // FOR EACH VERTEX, WE HAVE A BITMASK INDICATING WHETHER THE VERTEX
+  // IS IN OR OUT OF EACH PLANE (LS 6-BITS, SET MEANS "OUT")
+  unsigned int BitMaskA=0, BitMaskB=0, BitMaskC=0;
+  unsigned int PlaneBitMask=1;  // CURRENT PLANE BEING CHECKED
+  int i;
+  for (i=0; i<6; i++)
+  {
+    if ( PlanePtOutTest(P[i], &(A.x)) ) BitMaskA |= PlaneBitMask;
+    if ( PlanePtOutTest(P[i], &(B.x)) ) BitMaskB |= PlaneBitMask;
+    if ( PlanePtOutTest(P[i], &(C.x)) ) BitMaskC |= PlaneBitMask;
+    PlaneBitMask<<=1;
+  }
+
+  // TRIVIAL ACCEPTANCE: IF ANY VERTEX IS COMPLETELY INSIDE ALL PLANES (=0)
+  if (BitMaskA==0 || BitMaskB==0 || BitMaskC==0) return(1);
+
+  // TRIVIAL REJECTION: IF ALL VERTICES ARE OUTSIDE OF ANY PLANE
+  PlaneBitMask=1;
+  for (i=0; i<6; i++)
+  {
+    if ((BitMaskA & BitMaskB & BitMaskC & PlaneBitMask) > 0) return(0);
+    PlaneBitMask<<=1;
+  }
+
+  // TEST EDGES OF TRIANGLE AGAINST PLANES OF CAMERA
+  float InT, OutT;
+  if ( PlanesEdgeIsect(P,6,&(A.x),&(B.x),&InT,&OutT) ) return(1);
+  if ( PlanesEdgeIsect(P,6,&(B.x),&(C.x),&InT,&OutT) ) return(1);
+  if ( PlanesEdgeIsect(P,6,&(C.x),&(A.x),&InT,&OutT) ) return(1);
+
+  // TEST EDGES OF CAMERA AGAINST TRIANGLE
+  float IsectPt[3];
+  if ( EdgeTriIsect(&(V[0].x),&(V[4].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[1].x),&(V[5].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[2].x),&(V[6].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[3].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[1].x),&(V[0].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[5].x),&(V[4].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[6].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[2].x),&(V[3].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[4].x),&(V[7].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[5].x),&(V[6].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[1].x),&(V[2].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+  if ( EdgeTriIsect(&(V[0].x),&(V[3].x),&(A.x),&(B.x),&(C.x),IsectPt) ) return(1);
+
+  return(0);
+} 
+
+int CamTriOverlap(const Camera *Cam, 
+                  const Vec3f& A, const Vec3f& B, const Vec3f& C)
+{
+  // GET CAMERA VERTICES
+  Vec3f V[8];
+  Cam->CalcVerts(V);
+
+  // CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
+  float P[6][4];
+  CalcCamPlanes(V,P);
+
+  return( CamTriOverlap(V,P,A,B,C) );
+} 
+
+//----------------------------------------------------------------------------
+// Temporary implementation of CamQuadOverlap (uses CamTriOverlap).
+//----------------------------------------------------------------------------
+int CamQuadOverlap(
+  const Camera *Cam, 
+  const Vec3f& A, const Vec3f& B, const Vec3f& C, const Vec3f& D)
+{
+  if ( CamTriOverlap(Cam,A,B,C) ) return(1);
+  if ( CamTriOverlap(Cam,C,D,A) ) return(1);
+  return(0);
+}
+
+int CamQuadOverlap(
+  const Camera *Cam, 
+  const float A[3], const float B[3], const float C[3], const float D[3])
+{
+  Vec3f a(A),b(B),c(C),d(D);
+  return( CamQuadOverlap(Cam,a,b,c,d) );
+}
+
+//----------------------------------------------------------------------------
+// Calculate the six planes for a camera. User must have prealloced an array
+// of 24 floats (6 planes * 4 coeffs each). Two version: 1 that calculates
+// the camera vertices, requires the cam verts to be precomputed
+//----------------------------------------------------------------------------
+void CalcCamPlanes(const Vec3f *V, float P[][4])
+{
+  PlaneEquation(P[0], &(V[2].x),&(V[5].x),&(V[6].x)); // LEFT
+  PlaneEquation(P[1], &(V[0].x),&(V[7].x),&(V[4].x)); // RIGHT
+  PlaneEquation(P[2], &(V[3].x),&(V[6].x),&(V[7].x)); // BOTTOM
+  PlaneEquation(P[3], &(V[1].x),&(V[4].x),&(V[5].x)); // TOP
+  PlaneEquation(P[4], &(V[1].x),&(V[2].x),&(V[0].x)); // NEAR
+  PlaneEquation(P[5], &(V[4].x),&(V[6].x),&(V[5].x)); // FAR
+}
+
+void CalcCamPlanes(const Camera *Cam, float P[][4])
+{
+  Vec3f V[8];
+  Cam->CalcVerts(V);
+  CalcCamPlanes(V,P);
+}
+
+//--------------------------------------------------------------------------
+// Camera view-frustum/MinMaxBox (AABB) overlap test: given the extents of the 
+// AABB returns the type of overlap determined (complete out(1), partial (0), 
+// complete in (-1)) m and M are the min and max extents of the AABB respectively.
+// Version is provided that takes in a precomputed set of camera vertices
+// and planes
+//--------------------------------------------------------------------------
+int CamMinMaxBoxOverlap(
+  const Camera *Cam, const Vec3f V1[8], const float cP[][4], 
+  const Vec3f& m, const Vec3f& M)
+{
+  // GO FOR TRIVIAL REJECTION OR ACCEPTANCE USING "FASTER OVERLAP TEST"
+  int CompletelyIn=1;    // ASSUME COMPLETELY IN UNTIL ONE COUNTEREXAMPLE
+  int R;                 // TEST RETURN VALUE
+  for (int i=0; i<6; i++)
+  {
+    R=PlaneMinMaxBoxOverlap(cP[i],&(m.x),&(M.x));
+    if(R==COMPLETEOUT) return(COMPLETEOUT); 
+    else if(R==PARTIAL) CompletelyIn=0;
+  }
+
+  if (CompletelyIn) return(COMPLETEIN);  // CHECK IF STILL COMPLETELY "IN"
+
+  // TEST IF VIEW-FRUSTUM EDGES PROTRUDE THROUGH AABB
+  float InT, OutT;
+  if ( EdgeMinMaxBoxIsect(&(V1[0].x),&(V1[4].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[1].x),&(V1[5].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[2].x),&(V1[6].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[3].x),&(V1[7].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[0].x),&(V1[1].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[1].x),&(V1[2].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[2].x),&(V1[3].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[3].x),&(V1[0].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[4].x),&(V1[5].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[5].x),&(V1[6].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[6].x),&(V1[7].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+  if ( EdgeMinMaxBoxIsect(&(V1[7].x),&(V1[0].x),&(m.x),&(M.x),&InT,&OutT) ) return(PARTIAL);
+
+  // COMPUTE VERTICES OF AABB
+  float bV[8][3];
+  GetMinMaxBoxVerts(&(m.x),&(M.x),bV);
+
+  // TEST FOR PROTRUSION OF AABB EDGES THROUGH VIEW-FRUSTUM
+  if ( PlanesEdgeIsect(cP,6,bV[0],bV[4],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[1],bV[5],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[2],bV[6],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[3],bV[7],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[0],bV[1],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[1],bV[2],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[2],bV[3],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[3],bV[0],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[4],bV[5],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[5],bV[6],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[6],bV[7],&InT,&OutT) ) return(PARTIAL);
+  if ( PlanesEdgeIsect(cP,6,bV[7],bV[0],&InT,&OutT) ) return(PARTIAL);
+
+  // VF MUST BE COMPLETELY ENCLOSED SINCE PT IS NOT "OUT "OF ANY AABB PLANE.
+  //return(COMPLETEOUT);
+       return (PARTIAL);
+};
+
+int CamMinMaxBoxOverlap(
+  const Camera *Cam, const float m[3], const float M[3])
+{
+  // GET CAMERA VERTICES
+  Vec3f V1[8];
+  Cam->CalcVerts(V1);
+
+  // CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
+  float cP[6][4];
+  CalcCamPlanes(V1,cP);
+
+  return( CamMinMaxBoxOverlap(Cam,V1,cP,m,M) );
+};
+
+// ---------------------------------------------------------------------- 
+// Returns 1 if and only if the specified box is completely culled away.
+bool VFC(const Camera *Cam, const float m[3], const float M[3])
+{
+  return (CamMinMaxBoxOverlap(Cam, m, M) == COMPLETEOUT);
+}
+
+//----------------------------------------------------------------------------
+// Given the 8 corner vertices and the 6 side planes for two cameras,
+// returns the type of overlap (complete out(1), partial (0), complete in (-1))
+// with respect to the first camera.
+//----------------------------------------------------------------------------
+int CamCamOverlap(
+  const Vec3f V1[8], const float P1[][4], 
+  const Vec3f V2[8], const float P2[][4])
+{
+  int i, NumVertsOutAllPlanes, NumVertsOutOnePlane;
+  float InT, OutT;
+
+  // TEST ALL CAM1 VERTICES AGAINST PLANES OF CAM2
+  NumVertsOutAllPlanes=0;
+  for (i=0; i<6; i++)
+  {
+    NumVertsOutOnePlane=0;
+    for (int j=0; j<8; j++)
+      NumVertsOutOnePlane += PlanePtOutTest(P2[i],&(V1[i].x));
+    if (NumVertsOutOnePlane==8) return(1);  // TRIVIAL REJECT, COMPLETELY OUT!
+    NumVertsOutAllPlanes+=NumVertsOutOnePlane;
+  }
+  if (NumVertsOutAllPlanes==0) return(0); // TRIVIAL ACCEPT, PARTIAL!
+
+  // TEST ALL CAM2 VERTICES AGAINST PLANES OF CAM1
+  NumVertsOutAllPlanes=0;
+  for (i=0; i<6; i++)
+  {
+    NumVertsOutOnePlane=0;
+    for (int j=0; j<8; j++)
+      NumVertsOutOnePlane += PlanePtOutTest(P1[i],&(V2[i].x));
+    if (NumVertsOutOnePlane==8) return(1);  // TRIVIAL REJECT, COMPLETELY OUT!
+    NumVertsOutAllPlanes+=NumVertsOutOnePlane;
+  }
+  if (NumVertsOutAllPlanes==0) return(-1); // TRIVIAL ACCEPT, COMPLETELY IN!
+
+  // TEST ALL CAM1 EDGES AGAINST SET OF CAM2 PLANES
+  if ( PlanesEdgeIsect(P2,6,&(V1[0].x),&(V1[4].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[1].x),&(V1[5].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[2].x),&(V1[6].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[3].x),&(V1[7].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[0].x),&(V1[1].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[1].x),&(V1[2].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[2].x),&(V1[3].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[3].x),&(V1[0].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[4].x),&(V1[5].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[5].x),&(V1[6].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[6].x),&(V1[7].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P2,6,&(V1[7].x),&(V1[0].x),&InT,&OutT) ) return(0);
+
+  // TEST ALL CAM2 EDGES AGAINST SET OF CAM1 PLANES
+  if ( PlanesEdgeIsect(P1,6,&(V2[0].x),&(V2[4].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[1].x),&(V2[5].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[2].x),&(V2[6].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[3].x),&(V2[7].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[0].x),&(V2[1].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[1].x),&(V2[2].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[2].x),&(V2[3].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[3].x),&(V2[0].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[4].x),&(V2[5].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[5].x),&(V2[6].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[6].x),&(V2[7].x),&InT,&OutT) ) return(0);
+  if ( PlanesEdgeIsect(P1,6,&(V2[7].x),&(V2[0].x),&InT,&OutT) ) return(0);
+
+  return(1);
+} 
+
+int CamCamOverlap(const Camera *Cam1, const Camera *Cam2)
+{
+  // GET CAMERA VERTICES
+  Vec3f V1[8], V2[8];
+  Cam1->CalcVerts(V1);
+  Cam2->CalcVerts(V2);
+
+  // CALCULATE SIX CAMERA PLANES FROM CAMERA VERTICES
+  float P1[6][4], P2[6][4];
+  CalcCamPlanes(V1,P1);
+  CalcCamPlanes(V2,P2);
+
+  return( CamCamOverlap(V1,P1,V2,P2) );
+}
+
+//--------------------------------------------------------------------------
+// Given a camera and a plane (defined by four coefficient of implicit
+// form: Ax+By+Cz+D=0), reflect the camera about the plane and invert
+// back into right-handed system (reflection inverts the space, so we
+// have to invert the X-axis and flip the window boundaries).
+//--------------------------------------------------------------------------
+void CamReflectAboutPlane(Camera *Cam, const float Plane[4])
+{
+  // CREATE PLANAR REFLECTION MATRIX
+  float M[16];
+  PlanarReflection16fv(M,Plane);
+
+  // XFORM CAMERA
+  Cam->Xform(M);
+
+  // RESULTING CAM IS LEFT-HANDED, FLIP THE X-AXIS, FLIP X WINDOW BOUNDS
+  Cam->X = -(Cam->X);
+  float t = -(Cam->wL);
+  Cam->wL = -(Cam->wR);
+  Cam->wR = t;
+}
diff --git a/simgear/scene/sky/clouds3d/camutils.hpp b/simgear/scene/sky/clouds3d/camutils.hpp
new file mode 100644 (file)
index 0000000..8f1e34d
--- /dev/null
@@ -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 (file)
index 0000000..334a056
--- /dev/null
@@ -0,0 +1,475 @@
+//------------------------------------------------------------------------------
+// File : mat16fv.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// $Id$
+//----------------------------------------------------------------------------
+// mat16fv.cpp : opengl-style float[16] matrix routines.
+//
+// OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/ROW VECT, 4x4 MATRIX)
+// A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
+// VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
+// WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
+// Modelview XFORM. The associated inverse matrices are also provided.
+// Matrices are of the following form:
+//   M[16] : 0  4  8 12
+//           1  5  9 13
+//           2  6 10 14
+//           3  7 11 15
+//============================================================================
+
+#include <stdio.h>
+#include <math.h>
+#include "vec3fv.hpp"
+
+
+float* Copy16fv(float* A, const float* B) // A=B
+{
+  A[0]=B[0];   A[1]=B[1];   A[2]=B[2];   A[3]=B[3]; 
+  A[4]=B[4];   A[5]=B[5];   A[6]=B[6];   A[7]=B[7]; 
+  A[8]=B[8];   A[9]=B[9];   A[10]=B[10]; A[11]=B[11]; 
+  A[12]=B[12]; A[13]=B[13]; A[14]=B[14]; A[15]=B[15]; 
+  return A;
+}
+
+float* Mult16fv(float* C, const float* A, const float* B) // C=A*B
+{
+  float tC[16];
+
+  tC[0]  = A[0]*B[0] + A[4]*B[1] + A[8]*B[2] + A[12]*B[3];
+  tC[1]  = A[1]*B[0] + A[5]*B[1] + A[9]*B[2] + A[13]*B[3];
+  tC[2]  = A[2]*B[0] + A[6]*B[1] + A[10]*B[2] + A[14]*B[3];
+  tC[3]  = A[3]*B[0] + A[7]*B[1] + A[11]*B[2] + A[15]*B[3];
+
+  tC[4]  = A[0]*B[4] + A[4]*B[5] + A[8]*B[6] + A[12]*B[7];
+  tC[5]  = A[1]*B[4] + A[5]*B[5] + A[9]*B[6] + A[13]*B[7];
+  tC[6]  = A[2]*B[4] + A[6]*B[5] + A[10]*B[6] + A[14]*B[7];
+  tC[7]  = A[3]*B[4] + A[7]*B[5] + A[11]*B[6] + A[15]*B[7];
+
+  tC[8]  = A[0]*B[8] + A[4]*B[9] + A[8]*B[10] + A[12]*B[11];
+  tC[9]  = A[1]*B[8] + A[5]*B[9] + A[9]*B[10] + A[13]*B[11];
+  tC[10] = A[2]*B[8] + A[6]*B[9] + A[10]*B[10] + A[14]*B[11];
+  tC[11] = A[3]*B[8] + A[7]*B[9] + A[11]*B[10] + A[15]*B[11];
+
+  tC[12] = A[0]*B[12] + A[4]*B[13] + A[8]*B[14] + A[12]*B[15];
+  tC[13] = A[1]*B[12] + A[5]*B[13] + A[9]*B[14] + A[13]*B[15];
+  tC[14] = A[2]*B[12] + A[6]*B[13] + A[10]*B[14] + A[14]*B[15];
+  tC[15] = A[3]*B[12] + A[7]*B[13] + A[11]*B[14] + A[15]*B[15];
+
+  Copy16fv(C,tC);
+
+  return(C);
+}
+
+float* Mult16fv3fv(float *NewV, const float* M, const float *V)
+{
+  NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2];
+  NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2];
+  NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2];
+  return(NewV);
+}
+
+float* Mult16fv3fvPerspDiv(float *NewV, const float* M, const float *V)
+{
+  float W = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15];
+  NewV[0] = (M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]) / W;
+  NewV[1] = (M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]) / W;
+  NewV[2] = (M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]) / W;
+  return(NewV);
+}
+
+float* Mult16fv4fv(float *NewV, const float* M, const float *V)
+{
+  NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]*V[3];
+  NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]*V[3];
+  NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]*V[3];
+  NewV[3] = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15]*V[3];
+  return(NewV);
+}
+
+float* Identity16fv(float* M)
+{
+  M[0]=M[5]=M[10]=M[15]=1;
+  M[1]=M[2]=M[3]=M[4]=M[6]=M[7]=M[8]=M[9]=M[11]=M[12]=M[13]=M[14]=0;
+  return(M);
+}
+
+float* Transpose16fv(float* M)
+{
+  #define SWAP(a,b,t) (t)=(a);(a)=(b);(b)=(t);
+  float t;
+  SWAP(M[1],M[4],t);
+  SWAP(M[2],M[8],t);
+  SWAP(M[6],M[9],t);
+  SWAP(M[3],M[12],t);
+  SWAP(M[7],M[13],t);
+  SWAP(M[11],M[14],t);
+  return(M);
+}
+
+float* Rotate16fv(float *M, float DegAng, const float Axis[3])
+{
+  float RadAng = DegAng * 0.0174532f;
+  float ca=(float)cos(RadAng),
+        sa=(float)sin(RadAng);
+  if (Axis[0]==1 && Axis[1]==0 && Axis[2]==0)  // ABOUT X-AXIS
+  {
+   M[0]=1; M[4]=0;  M[8]=0;   M[12]=0;
+   M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
+   M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
+   M[3]=0; M[7]=0;  M[11]=0;  M[15]=1;
+  }
+  if (Axis[0]==0 && Axis[1]==1 && Axis[2]==0)  // ABOUT Y-AXIS
+  {
+   M[0]=ca;  M[4]=0; M[8]=sa;  M[12]=0;
+   M[1]=0;   M[5]=1; M[9]=0;   M[13]=0;
+   M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
+   M[3]=0;   M[7]=0; M[11]=0;  M[15]=1;
+  }
+  if (Axis[0]==0 && Axis[1]==0 && Axis[2]==1)  // ABOUT Z-AXIS
+  {
+   M[0]=ca; M[4]=-sa; M[8]=0;  M[12]=0;
+   M[1]=sa; M[5]=ca;  M[9]=0;  M[13]=0;
+   M[2]=0;  M[6]=0;   M[10]=1; M[14]=0;
+   M[3]=0;  M[7]=0;   M[11]=0; M[15]=1;
+  }
+  else                                      // ARBITRARY AXIS
+  {
+   float l = Axis[0]*Axis[0]+Axis[1]*Axis[1]+Axis[2]*Axis[2];
+   float x, y, z;
+   x=Axis[0],y=Axis[1],z=Axis[2];
+   if (l > 1.0001f || l < 0.9999f && l!=0)
+   {
+     // needs normalization
+     l=1.0f/(float)sqrt(l);
+     x*=l; y*=l; z*=l;
+   }
+   float x2=x*x, y2=y*y, z2=z*z;
+   M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
+   M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
+   M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
+   M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
+   M[15]=1;
+  }
+  return(M);
+}
+
+float* invRotate16fv(float *M, float DegAng, const float Axis[3])
+{
+  Rotate16fv(M,DegAng,Axis);
+  Transpose16fv(M);
+  return(M);
+}
+
+float* Scale16fv(float* M, float sx, float sy, float sz)
+{
+  M[0]=sx; M[4]=0;  M[8]=0;   M[12]=0;
+  M[1]=0;  M[5]=sy; M[9]=0;   M[13]=0;
+  M[2]=0;  M[6]=0;  M[10]=sz; M[14]=0;
+  M[3]=0;  M[7]=0;  M[11]=0;  M[15]=1;
+  return(M);
+}
+
+float* invScale16fv(float* M, float sx, float sy, float sz)
+{
+  M[0]=1/sx; M[4]=0;    M[8]=0;     M[12]=0;
+  M[1]=0;    M[5]=1/sy; M[9]=0;     M[13]=0;
+  M[2]=0;    M[6]=0;    M[10]=1/sz; M[14]=0;
+  M[3]=0;    M[7]=0;    M[11]=0;    M[15]=1;
+  return(M);
+}
+
+float* Translate16fv(float* M, float tx, float ty, float tz)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=tx;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=ty;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=tz;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+  return(M);
+}
+
+float* invTranslate16fv(float* M, float tx, float ty, float tz)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=-tx;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=-ty;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=-tz;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+  return(M);
+}
+
+float* LookAt(float* M,
+              const float Eye[3], 
+              const float LookAtPt[3],
+              const float ViewUp[3])
+{
+  float X[3], Y[3], Z[3];
+  Subtract3fv(Z,Eye,LookAtPt);  Normalize3fv(Z);
+  CrossProd3fv(X,ViewUp,Z);     Normalize3fv(X);
+  CrossProd3fv(Y,Z,X);          Normalize3fv(Y);
+  M[0]=X[0];  M[4]=X[1];  M[8]=X[2];  M[12]=-DotProd3fv(X,Eye);  // TRANS->ROT
+  M[1]=Y[0];  M[5]=Y[1];  M[9]=Y[2];  M[13]=-DotProd3fv(Y,Eye);
+  M[2]=Z[0];  M[6]=Z[1];  M[10]=Z[2]; M[14]=-DotProd3fv(Z,Eye);
+  M[3]=0;     M[7]=0;     M[11]=0;    M[15]=1;
+  return(M);
+}
+
+float* invLookAt(float* M, 
+                 const float Eye[3], 
+                 const float LookAtPt[3], 
+                 const float ViewUp[3])
+{
+  float X[3], Y[3], Z[3];
+  Subtract3fv(Z,Eye,LookAtPt);  Normalize3fv(Z);
+  CrossProd3fv(X,ViewUp,Z);     Normalize3fv(X);
+  CrossProd3fv(Y,Z,X);          Normalize3fv(Y);
+  M[0]=X[0];  M[4]=Y[0];  M[8]=Z[0];  M[12]=Eye[0];  // ROT->TRANS
+  M[1]=X[1];  M[5]=Y[1];  M[9]=Z[1];  M[13]=Eye[1];
+  M[2]=X[2];  M[6]=Y[2];  M[10]=Z[2]; M[14]=Eye[2];
+  M[3]=0;     M[7]=0;     M[11]=0;    M[15]=1;
+  return(M);
+}
+
+float* Frustum16fv(float* M, float l, float r, float b, float t, 
+                   float n, float f)
+{
+  M[0]=(2*n)/(r-l); M[4]=0;           M[8]=(r+l)/(r-l);   M[12]=0;
+  M[1]=0;           M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b);   M[13]=0;
+  M[2]=0;           M[6]=0;           M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
+  M[3]=0;           M[7]=0;           M[11]=-1;           M[15]=0;
+  return(M);  
+}
+
+float* invFrustum16fv(float* M, float l, float r, float b, float t, 
+                      float n, float f)
+{
+  M[0]=(r-l)/(2*n); M[4]=0;           M[8]=0;               M[12]=(r+l)/(2*n);
+  M[1]=0;           M[5]=(t-b)/(2*n); M[9]=0;               M[13]=(t+b)/(2*n);
+  M[2]=0;           M[6]=0;           M[10]=0;              M[14]=-1;
+  M[3]=0;           M[7]=0;           M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
+  return(M);  
+}
+
+float* Perspective(float* M, float Yfov, float Aspect, 
+                   float Ndist, float Fdist)
+{
+  Yfov *= 0.0174532f;  // CONVERT TO RADIANS
+  float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
+  float wR=wT*Aspect, wL=-wR;
+  Frustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
+  return(M);
+}
+
+float* invPerspective(float* M, float Yfov, float Aspect, 
+                      float Ndist, float Fdist)
+{
+  Yfov *= 0.0174532f;  // CONVERT TO RADIANS
+  float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
+  float wR=wT*Aspect, wL=-wR;
+  invFrustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
+  return(M);
+}
+
+float* Viewing16fv(
+  float* M,
+  const float X[3], const float Y[3], const float Z[3], const float O[3])
+{
+  M[0]=X[0];  M[4]=X[1];   M[8]=X[2]; M[12]=-DotProd3fv(X,O);
+  M[1]=Y[0];  M[5]=Y[1];   M[9]=Y[2]; M[13]=-DotProd3fv(Y,O);
+  M[2]=Z[0];  M[6]=Z[1];  M[10]=Z[2]; M[14]=-DotProd3fv(Z,O);
+  M[3]=0;    M[7]=0;    M[11]=0;   M[15]=1;
+  return(M);
+}
+
+// THE INVERSE OF Viewing16fv,
+// THIS TAKES A VIEW MATRIX AND RETURNS VIEWING AXES.  
+// MATRIX ASSUMED TO BE ORTHONORMAL
+void Viewing2CoordFrame16fv(
+  const float *M, float X[3], float Y[3], float Z[3], float O[3])
+{
+  X[0]=M[0];  X[1]=M[4];   X[2]=M[8]; O[0]=-DotProd3fv(M,M+12);
+  Y[0]=M[1];  Y[1]=M[5];   Y[2]=M[9]; O[1]=-DotProd3fv(M+4,M+12);
+  Z[0]=M[2];  Z[1]=M[6];  Z[2]=M[10]; O[2]=-DotProd3fv(M+8,M+12);
+};
+
+float* invViewing16fv(
+  float* M, 
+  const float X[3], const float Y[3], const float Z[3], const float O[3])
+{  
+  M[0]=X[0];  M[4]=Y[0];   M[8]=Z[0]; M[12]=O[0];
+  M[1]=X[1];  M[5]=Y[1];   M[9]=Z[1]; M[13]=O[1];
+  M[2]=X[2];  M[6]=Y[2];  M[10]=Z[2]; M[14]=O[2];
+  M[3]=0;    M[7]=0;    M[11]=0;   M[15]=1;
+  return(M);
+}
+
+float* Viewport16fv(float* M, int WW, int WH)
+{
+  float WW2=(float)WW*0.5f, WH2=(float)WH*0.5f;
+  M[0]=WW2;  M[4]=0;     M[8]=0;     M[12]=WW2;
+  M[1]=0;    M[5]=WH2;   M[9]=0;     M[13]=WH2;
+  M[2]=0;    M[6]=0;     M[10]=0.5f; M[14]=0.5f;
+  M[3]=0;    M[7]=0;     M[11]=0;    M[15]=1;
+  return(M);
+}
+
+float* invViewport16fv(float* M, int WW, int WH)
+{
+  float WW2=2.0f/(float)WW, WH2=2.0f/(float)WH;
+  M[0]=WW2;  M[4]=0;     M[8]=0;    M[12]=-1.0;
+  M[1]=0;    M[5]=WH2;   M[9]=0;    M[13]=-1.0;
+  M[2]=0;    M[6]=0;     M[10]=2.0; M[14]=-1.0;
+  M[3]=0;    M[7]=0;     M[11]=0;   M[15]=1;
+  return(M);
+}
+
+//--------------------------------------------------------------------------
+// Given the coefficient [A B C D] of a plane in the implicit form
+// Ax+By+Cz+D=0 (see plane.hpp), this routine generates a reflection matrix
+// that will "reflect" all points/vectors about the given plane.
+// NOTE: the plane is assumed to be normalized: normal vector (A,B,C) is
+// normalized (unit-length), and D is the negative distance from the origin
+// to the plane along the normal.
+//--------------------------------------------------------------------------
+float* PlanarReflection16fv(float M[16], const float P[4])
+{
+  float AA=P[0]*P[0], AB=P[0]*P[1], AC=P[0]*P[2], AD=P[0]*P[3],
+        BB=P[1]*P[1], BC=P[1]*P[2], BD=P[1]*P[3],
+        CC=P[2]*P[2], CD=P[2]*P[3];
+  M[0]=1-2*AA;  M[4]=-2*AB;   M[8]=-2*AC;   M[12]=-2*AD;
+  M[1]=-2*AB;   M[5]=1-2*BB;  M[9]=-2*BC;   M[13]=-2*BD;
+  M[2]=-2*AC;   M[6]=-2*BC;   M[10]=1-2*CC; M[14]=-2*CD;
+  M[3]=0;       M[7]=0;       M[11]=0;      M[15]=1;
+  return(M);
+}
+
+//--------------------------------------------------------------------------
+// Returns a matrix that will xform a point from the given object-space
+// coordinate frame to world space
+//   A composite matrix is formed as follows:
+//   C = Translation * Rotation * Scaling (using column vectors/pre-multiplication)
+//   WorldPt = C * ModelPt
+// The corresponding inverse Xform is also provided (GetWorld2ObjXform)
+//--------------------------------------------------------------------------
+float* Obj2WorldXform16fv(
+  float *M, 
+  const float X[3], const float Y[3], const float Z[3], 
+  const float O[3], float Scale)
+{
+  float sX[3], sY[3], sZ[3]; // CREATE SCALED VERSION OF ROT AXES
+  ScalarMult3fv(sX,X,Scale);
+  ScalarMult3fv(sY,Y,Scale);
+  ScalarMult3fv(sZ,Z,Scale);
+  M[0]=sX[0]; M[4]=sY[0]; M[8]=sZ[0];  M[12]=O[0];
+  M[1]=sX[1]; M[5]=sY[1]; M[9]=sZ[1];  M[13]=O[1];
+  M[2]=sX[2]; M[6]=sY[2]; M[10]=sZ[2]; M[14]=O[2];
+  M[3]=0;     M[7]=0;     M[11]=0;     M[15]=1;
+  return(M);
+}
+
+float* World2ObjXform16fv(
+  float *M,
+  const float X[3], const float Y[3], const float Z[3], 
+  const float O[3], float Scale)
+{
+  if (Scale<=0) { printf("Too small scale!\n"); Scale=1; }
+  float invScale = 1/Scale;
+  float sX[3], sY[3], sZ[3];
+  ScalarMult3fv(sX,X,invScale);
+  ScalarMult3fv(sY,Y,invScale);
+  ScalarMult3fv(sZ,Z,invScale);
+  M[0]=sX[0]; M[4]=sX[1]; M[8]=sX[2];  M[12]=-DotProd3fv(O,sX);
+  M[1]=sY[0]; M[5]=sY[1]; M[9]=sY[2];  M[13]=-DotProd3fv(O,sY);
+  M[2]=sZ[0]; M[6]=sZ[1]; M[10]=sZ[2]; M[14]=-DotProd3fv(O,sZ);
+  M[3]=0;     M[7]=0;     M[11]=0;     M[15]=1;
+  return(M);
+}
+
+// ONLY TRANSLATES, ROTATES, AND SCALES ARE ALLOWED
+float XformCoordFrame16fv(
+  const float *M, float X[3], float Y[3], float Z[3], float O[3])
+{
+  Set3fv(X, X[0]*M[0] + X[1]*M[4] + X[2]*M[8],
+             X[0]*M[1] + X[1]*M[5] + X[2]*M[9],
+             X[0]*M[2] + X[1]*M[6] + X[2]*M[10] );
+  Set3fv(Y, Y[0]*M[0] + Y[1]*M[4] + Y[2]*M[8],
+             Y[0]*M[1] + Y[1]*M[5] + Y[2]*M[9],
+             Y[0]*M[2] + Y[1]*M[6] + Y[2]*M[10] );
+  Set3fv(Z, Z[0]*M[0] + Z[1]*M[4] + Z[2]*M[8],
+             Z[0]*M[1] + Z[1]*M[5] + Z[2]*M[9],
+             Z[0]*M[2] + Z[1]*M[6] + Z[2]*M[10] );
+  Set3fv(O, O[0]*M[0] + O[1]*M[4] + O[2]*M[8] + M[12],
+             O[0]*M[1] + O[1]*M[5] + O[2]*M[9] + M[13],
+             O[0]*M[2] + O[1]*M[6] + O[2]*M[10] + M[14] );
+
+  // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
+  float Scale = Length3fv(X);
+  ScalarDiv3fv(X,Scale);
+  ScalarDiv3fv(Y,Scale);
+  ScalarDiv3fv(Z,Scale);
+
+  // RETURN UNIFORM SCALING OF AXES (how much coordinate frame was scaled)
+  return(Scale);
+};
+
+
+//----------------------------------------------------------------------------
+// Given a complete definition for a particular view (viewing, projection,
+// and viewport), returns the COMPOSITE xform matrix that takes a point in the 
+// world space to a screen space (pixel) point. The inverse is also provided.
+//----------------------------------------------------------------------------
+float* Screen2WorldXform16fv(
+  float* M, 
+  const float X[3], const float Y[3], const float Z[3],  // VIEWING AXES
+  const float O[3], // VIEWING ORIGIN
+  float l, float r, float b, float t, float n, float f, // PROJECTION
+  int WW, int WH) // VIEWPORT
+{
+  // C = InverseModelview * InverseProjection * InverseViewport
+  float N[16];
+  invViewing16fv(M,X,Y,Z,O);
+  invFrustum16fv(N,l,r,b,t,n,f);
+  Mult16fv(M,M,N);  // M=M*N;
+  invViewport16fv(N,WW,WH);
+  Mult16fv(M,M,N);  // M=M*N;
+  return(M);
+}
+
+float* World2ScreenXform16fv(
+  float* M,
+  const float X[3], const float Y[3], const float Z[3], // VIEWING AXES
+  const float O[3], // VIEWING ORIGIN
+  float l, float r, float b, float t, float n, float f, // PROJECTION
+  int WW, int WH) // VIEWPORT
+{
+  // C = Viewport * Projection * Modelview
+  float N[16];
+  Viewport16fv(M,WW,WH);
+  Frustum16fv(N,l,r,b,t,n,f);
+  Mult16fv(M,M,N);  // M=M*N;
+  Viewing16fv(N,X,Y,Z,O);
+  Mult16fv(M,M,N);  // M=M*N;
+  return(M);
+}
+
+void Print16fv(const float* M)
+{
+  printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
+  printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
+  printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
+  printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);
+}
+
diff --git a/simgear/scene/sky/clouds3d/mat16fv.hpp b/simgear/scene/sky/clouds3d/mat16fv.hpp
new file mode 100644 (file)
index 0000000..d278658
--- /dev/null
@@ -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 (file)
index 0000000..ca99782
--- /dev/null
@@ -0,0 +1,113 @@
+//------------------------------------------------------------------------------
+// File : mat33.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// mat33.hpp : 3x3 matrix template.
+//============================================================================
+
+#ifndef _MAT33_
+#define _MAT33_
+
+#include "vec3f.hpp"
+#include "mat44.hpp"
+
+static const float Mat33TORADS = 0.0174532f;
+static const float Mat33VIEWPORT_TOL = 0.001f;
+
+//----------------------------------------------------------------------------
+// M[9] = [ 0  3  6 ]   
+//        [ 1  4  7 ]  
+//        [ 2  5  8 ]  
+//
+//                         
+//
+// [ x' y' z' ] = [ 0  3  6 ]   [ x ]
+//                [ 1  4  7 ] * [ y ] 
+//                [ 2  5  8 ]   [ z ]
+//----------------------------------------------------------------------------
+template<class Type>
+class Mat33
+{ 
+public:
+  Type M[9];  // 0,1,2 = 1st col; 3,4,5 = 2nd col; etc.
+  
+  Mat33();
+  Mat33(const Type *N);
+  Mat33(Type M0, Type M3, Type M6,
+       Type M1, Type M4, Type M7,
+       Type M2, Type M5, Type M8);
+  Mat33<Type>& operator = (const Mat33& A);  // ASSIGNMENT (=)
+  // ASSIGNMENT (=) FROM AN ARRAY OF Type 
+  Mat33<Type>& operator = (const Type* a);
+  Mat33<Type> operator * (const Mat33& A) const; // MULTIPLICATION (*)
+  // MAT-VECTOR MULTIPLICATION (*)
+  Vec3<Type> operator * (const Vec3<Type>& V) const; 
+  // MAT-VECTOR PRE-MULTIPLICATON (*)
+  friend Vec3<Type> operator * (const Vec3<Type>& V, const Mat33<Type>& M);   
+  // SCALAR POST-MULTIPLICATION
+  Mat33<Type> operator * (Type a) const;
+  // SCALAR PRE-MULTIPLICATION
+  friend Mat33<Type> operator * (Type a, const Mat44<Type>& M); 
+
+  Mat33<Type> operator / (Type a) const;      // SCALAR DIVISION
+  Mat33<Type> operator + (Mat33& M) const;    // ADDITION (+)
+  Mat33<Type>& operator += (Mat33& M);        // ACCUMULATE ADD (+=)
+  Mat33<Type>& operator -= (Mat33& M);        // ACCUMULATE SUB (-=)
+  Mat33<Type>& operator *= (Type a);          // ACCUMULATE MULTIPLY (*=)
+  Mat33<Type>& operator /= (Type a);          // ACCUMULATE DIVIDE (/=)
+
+  bool Inverse(Mat33<Type> &inv, Type tolerance) const;// MATRIX INVERSE
+  
+  operator const Type*() const;                     // CAST TO A Type ARRAY
+  operator Type*();                                 // CAST TO A Type ARRAY
+
+  void RowMajor(Type m[9]);                // return array in row-major order
+
+  Type& operator()(int col, int row);               // 2D ARRAY ACCESSOR
+  const Type& operator()(int col, int row) const;   // 2D ARRAY ACCESSOR
+  void Set(const Type* a);    // SAME AS ASSIGNMENT (=) FROM AN ARRAY OF TypeS
+  void Set(Type M0, Type M3, Type M6,
+           Type M1, Type M4, Type M7,
+           Type M2, Type M5, Type M8);
+  
+  void Identity();
+  void Zero();
+  void Transpose();
+  void Scale(Type Sx, Type Sy, Type Sz);
+  void Scale(const Vec3<Type>& S);
+  void invScale(Type Sx, Type Sy, Type Sz);
+  void invScale(const Vec3<Type>& S);
+  void Rotate(Type DegAng, const Vec3<Type>& Axis);
+  void invRotate(Type DegAng, const Vec3<Type>& Axis);
+  void Star(const Vec3<Type>& v);  // SKEW-SYMM MATRIX EQUIV TO CROSS PROD WITH V
+  void OuterProduct(const Vec3<Type>& u, const Vec3<Type>& v);  // SET TO  u * v^t
+  Type Trace() const;
+  void Print() const;
+  void CopyInto(Type *Mat) const;
+  static void SWAP(Type& a, Type& b) {Type t; t=a;a=b;b=t;}
+};
+
+#include "mat33impl.hpp"
+
+typedef Mat33<float> Mat33f;
+typedef Mat33<double> Mat33d;
+
+#endif
+
+
+
+
diff --git a/simgear/scene/sky/clouds3d/mat33impl.hpp b/simgear/scene/sky/clouds3d/mat33impl.hpp
new file mode 100644 (file)
index 0000000..9d7a8f1
--- /dev/null
@@ -0,0 +1,412 @@
+//------------------------------------------------------------------------------
+// File : mat33impl.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// mat33impl.hpp : 3x3 matrix template.
+// This is the template implementation file. It is included by mat33.hpp.
+//============================================================================
+
+//---------------------------------------------------------------------------
+// CONSTRUCTORS
+//---------------------------------------------------------------------------
+template<class Type>
+Mat33<Type>::Mat33()
+{ 
+  Identity(); 
+}
+
+template<class Type>
+Mat33<Type>::Mat33(const Type *N)
+{
+  M[0]=N[0]; M[3]=N[3];  M[6]=N[6];
+  M[1]=N[1]; M[4]=N[4];  M[7]=N[7];
+  M[2]=N[2]; M[5]=N[5];  M[8]=N[8];
+}
+
+template<class Type>
+Mat33<Type>::Mat33(Type M0, Type M3, Type M6,
+                   Type M1, Type M4, Type M7,
+                   Type M2, Type M5, Type M8)
+      
+{
+  M[0]=M0; M[3]=M3; M[6]=M6;
+  M[1]=M1; M[4]=M4; M[7]=M7;
+  M[2]=M2; M[5]=M5; M[8]=M8; 
+}
+
+//---------------------------------------------------------------------------
+// MATRIX/MATRIX AND MATRIX/VECTOR OPERATORS
+//---------------------------------------------------------------------------
+template<class Type>
+Mat33<Type>& Mat33<Type>::operator = (const Mat33& A)      // ASSIGNMENT (=)
+{
+  M[0]=A.M[0]; M[3]=A.M[3]; M[6]=A.M[6]; 
+  M[1]=A.M[1]; M[4]=A.M[4]; M[7]=A.M[7]; 
+  M[2]=A.M[2]; M[5]=A.M[5]; M[8]=A.M[8];
+  return(*this);
+}
+
+template<class Type>
+Mat33<Type>& Mat33<Type>::operator = (const Type* a) {
+  for (int i=0;i<9;i++) {
+    M[i] = a[i];
+  }
+  return *this;
+}
+
+template<class Type>
+Mat33<Type> Mat33<Type>::operator * (const Mat33& A) const  // MULTIPLICATION (*)
+{
+  Mat33<Type> NewM(
+              M[0]*A.M[0] + M[3]*A.M[1] + M[6]*A.M[2],      // ROW 1
+              M[0]*A.M[3] + M[3]*A.M[4] + M[6]*A.M[5],
+              M[0]*A.M[6] + M[3]*A.M[7] + M[6]*A.M[8],
+              
+              M[1]*A.M[0] + M[4]*A.M[1] + M[7]*A.M[2],      // ROW 2
+              M[1]*A.M[3] + M[4]*A.M[4] + M[7]*A.M[5],
+              M[1]*A.M[6] + M[4]*A.M[7] + M[7]*A.M[8],
+              
+              M[2]*A.M[0] + M[5]*A.M[1] + M[8]*A.M[2],      // ROW 3
+              M[2]*A.M[3] + M[5]*A.M[4] + M[8]*A.M[5],
+              M[2]*A.M[6] + M[5]*A.M[7] + M[8]*A.M[8]);              
+  return(NewM);
+}
+
+// MAT-VECTOR MULTIPLICATION (*)
+template<class Type>
+Vec3<Type> Mat33<Type>::operator * (const Vec3<Type>& V) const
+{
+  Vec3<Type> NewV;
+  NewV.x = M[0]*V.x + M[3]*V.y + M[6]*V.z;
+  NewV.y = M[1]*V.x + M[4]*V.y + M[7]*V.z;
+  NewV.z = M[2]*V.x + M[5]*V.y + M[8]*V.z;
+  return(NewV);
+}
+
+// MAT-VECTOR PRE-MULTIPLICATON (*) (non-member)
+// interpreted as V^t M  
+template<class Type>
+Vec3<Type> operator *(const Vec3<Type>& V, const Mat33<Type>& A)
+{
+  Vec3<Type> NewV;
+  NewV.x = A[0]*V.x + A[1]*V.y + A[2]*V.z;
+  NewV.y = A[3]*V.x + A[4]*V.y + A[5]*V.z;
+  NewV.z = A[6]*V.x + A[7]*V.y + A[8]*V.z;
+  return(NewV);
+}
+
+// SCALAR POST-MULTIPLICATION
+template<class Type>
+Mat33<Type> Mat33<Type>::operator * (Type a) const
+{
+  Mat33<Type> NewM;
+  for (int i = 0; i < 9; i++) 
+    NewM[i] = M[i]*a;
+  return(NewM);
+}
+
+// SCALAR PRE-MULTIPLICATION (non-member)
+template <class Type>
+Mat33<Type> operator * (Type a, const Mat44<Type>& M) 
+{
+  Mat33<Type> NewM;
+  for (int i = 0; i < 9; i++) 
+    NewM[i] = a*M[i];
+  return(NewM);
+}
+
+template <class Type>
+Mat33<Type> Mat33<Type>::operator / (Type a) const      // SCALAR DIVISION
+{
+  Mat33<Type> NewM;
+  Type ainv = Type(1.0)/a;
+  for (int i = 0; i < 9; i++) 
+    NewM[i] = M[i]*ainv;
+  return(NewM);
+}
+
+template <class Type>
+Mat33<Type> Mat33<Type>::operator + (Mat33& N) const    // ADDITION (+)
+{
+  Mat33<Type> NewM;
+  for (int i = 0; i < 9; i++) 
+    NewM[i] = M[i]+N.M[i];
+  return(NewM);
+}
+template <class Type>
+Mat33<Type>& Mat33<Type>::operator += (Mat33& N)  // ACCUMULATE ADD (+=)
+{
+  for (int i = 0; i < 9; i++) 
+    M[i] += N.M[i];
+  return(*this);
+}
+
+template <class Type>
+Mat33<Type>& Mat33<Type>::operator -= (Mat33& N)  // ACCUMULATE SUB (-=)
+{
+  for (int i = 0; i < 9; i++) 
+    M[i] -= N.M[i];
+  return(*this);
+}
+
+template <class Type>
+Mat33<Type>& Mat33<Type>::operator *= (Type a)   // ACCUMULATE MULTIPLY (*=)
+{
+  for (int i = 0; i < 9; i++) 
+    M[i] *= a;
+  return(*this);
+}
+template <class Type>
+Mat33<Type>& Mat33<Type>::operator /= (Type a)   // ACCUMULATE DIVIDE (/=)
+{
+  Type ainv = Type(1.0)/a;
+  for (int i = 0; i < 9; i++) 
+    M[i] *= ainv;
+  return(*this);
+}
+
+template<class Type>
+bool Mat33<Type>::Inverse(Mat33<Type> &inv, Type tolerance) const // MATRIX INVERSE
+{
+  // Invert using cofactors.  
+
+  inv[0] = M[4]*M[8] - M[7]*M[5];
+  inv[3] = M[6]*M[5] - M[3]*M[8];
+  inv[6] = M[3]*M[7] - M[6]*M[4];
+  inv[1] = M[7]*M[2] - M[1]*M[8];
+  inv[4] = M[0]*M[8] - M[6]*M[2];
+  inv[7] = M[6]*M[1] - M[0]*M[7];
+  inv[2] = M[1]*M[5] - M[4]*M[2];
+  inv[5] = M[3]*M[2] - M[0]*M[5];
+  inv[8] = M[0]*M[4] - M[3]*M[1];
+
+  Type det = M[0]*inv[0] + M[3]*inv[1] + M[6]*inv[2];
+
+  if (fabs(det) <= tolerance) // singular
+    return false;
+
+  Type invDet = 1.0f / det;
+  for (int i = 0; i < 9; i++) {
+    inv[i] *= invDet;
+  }
+
+  return true;
+}
+
+template<class Type>
+Mat33<Type>::operator const Type*() const
+{
+  return M;
+}
+
+template<class Type>
+Mat33<Type>::operator Type*()
+{
+  return M;
+}
+
+template<class Type>
+void Mat33<Type>::RowMajor(Type m[9])
+{
+  m[0] = M[0]; m[1] = M[3]; m[2] = M[6];
+  m[3] = M[1]; m[4] = M[4]; m[5] = M[7];
+  m[6] = M[2]; m[7] = M[5]; m[8] = M[8];
+}
+
+template<class Type>
+Type& Mat33<Type>::operator()(int col, int row)
+{
+  return M[3*col+row];
+}
+
+template<class Type>
+const Type& Mat33<Type>::operator()(int col, int row) const
+{
+  return M[3*col+row];
+}
+
+template<class Type>
+void Mat33<Type>::Set(const Type* a)
+{
+  for (int i=0;i<9;i++) {
+    M[i] = a[i];
+  }
+}
+
+template<class Type>
+void Mat33<Type>::Set(Type M0, Type M3, Type M6,
+                      Type M1, Type M4, Type M7,
+                      Type M2, Type M5, Type M8)
+{
+  M[0]=M0; M[3]=M3; M[6]=M6;
+  M[1]=M1; M[4]=M4; M[7]=M7;
+  M[2]=M2; M[5]=M5; M[8]=M8; 
+}
+
+
+//---------------------------------------------------------------------------
+// Standard Matrix Operations
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat33<Type>::Identity()
+{
+  M[0]=M[4]=M[8]=1;
+  M[1]=M[2]=M[3]=M[5]=M[6]=M[7]=0;
+}
+template<class Type>
+void Mat33<Type>::Zero()
+{
+  M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=M[6]=M[7]=M[8]=0;
+}
+
+template<class Type>
+void Mat33<Type>::Transpose()
+{
+  SWAP(M[1],M[3]);
+  SWAP(M[2],M[6]);
+  SWAP(M[5],M[7]);
+}
+
+//---------------------------------------------------------------------------
+// Standard Matrix Affine Transformations
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat33<Type>::Scale(Type Sx, Type Sy, Type Sz)
+{
+  M[0]=Sx; M[3]=0;  M[6]=0;
+  M[1]=0;  M[4]=Sy; M[7]=0;
+  M[2]=0;  M[5]=0;  M[8]=Sz;
+}
+
+template<class Type>
+void Mat33<Type>::Scale(const Vec3<Type>& S)
+{
+  M[0]=S.x; M[3]=0;   M[6]=0;  
+  M[1]=0;   M[4]=S.y; M[7]=0;  
+  M[2]=0;   M[5]=0;   M[8]=S.z;
+}
+
+template<class Type>
+void Mat33<Type>::invScale(Type Sx, Type Sy, Type Sz)
+{
+  M[0]=1/Sx; M[3]=0;    M[6]=0;    
+  M[1]=0;    M[4]=1/Sy; M[7]=0;    
+  M[2]=0;    M[5]=0;    M[8]=1/Sz;
+}
+
+template<class Type>
+void Mat33<Type>::invScale(const Vec3<Type>& S)
+{
+  M[0]=1/S.x; M[3]=0;     M[6]=0;     
+  M[1]=0;     M[4]=1/S.y; M[7]=0;     
+  M[2]=0;     M[5]=0;     M[8]=1/S.z;
+}
+
+template<class Type>
+void Mat33<Type>::Rotate(Type DegAng, const Vec3<Type>& Axis)
+{
+  Type RadAng = DegAng*Mat33TORADS;
+  Type ca=(Type)cos(RadAng),
+        sa=(Type)sin(RadAng);
+  if (Axis.x==1 && Axis.y==0 && Axis.z==0)  // ABOUT X-AXIS
+  {
+   M[0]=1; M[3]=0;  M[6]=0; 
+   M[1]=0; M[4]=ca; M[7]=-sa;
+   M[2]=0; M[5]=sa; M[8]=ca;
+    
+  }
+  else if (Axis.x==0 && Axis.y==1 && Axis.z==0)  // ABOUT Y-AXIS
+  {
+   M[0]=ca;  M[3]=0; M[6]=sa; 
+   M[1]=0;   M[4]=1; M[7]=0;  
+   M[2]=-sa; M[5]=0; M[8]=ca;
+  }
+  else if (Axis.x==0 && Axis.y==0 && Axis.z==1)  // ABOUT Z-AXIS
+  {
+   M[0]=ca; M[3]=-sa; M[6]=0;
+   M[1]=sa; M[4]=ca;  M[7]=0;
+   M[2]=0;  M[5]=0;   M[8]=1;
+  }
+  else                                      // ARBITRARY AXIS
+  {
+   Type l = Axis.LengthSqr();
+   Type x, y, z;
+   x=Axis.x, y=Axis.y, z=Axis.z;
+   if (l > Type(1.0001) || l < Type(0.9999) && l!=0)
+   {
+     // needs normalization
+     l=Type(1.0)/sqrt(l);
+     x*=l; y*=l; z*=l;
+   }
+   Type x2=x*x, y2=y*y, z2=z*z;
+   M[0]=x2+ca*(1-x2); M[3]=(x*y)+ca*(-x*y)+sa*(-z); M[6]=(x*z)+ca*(-x*z)+sa*y;
+   M[1]=(x*y)+ca*(-x*y)+sa*z; M[4]=y2+ca*(1-y2); M[7]=(y*z)+ca*(-y*z)+sa*(-x);
+   M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[5]=(y*z)+ca*(-y*z)+sa*x; M[8]=z2+ca*(1-z2);
+  }
+}
+
+template<class Type>
+void Mat33<Type>::invRotate(Type DegAng, const Vec3<Type>& Axis)
+{
+  Rotate(DegAng,Axis);
+  Transpose();
+}
+
+template <class Type>
+inline void Mat33<Type>::Star(const Vec3<Type>& v)
+{
+  M[0]=   0; M[3]=-v.z;  M[6]= v.y;
+  M[1]= v.z; M[4]=   0;  M[7]=-v.x;
+  M[2]=-v.y; M[5]= v.x; M[8]=   0;
+}
+
+template <class Type>
+inline void Mat33<Type>::OuterProduct(const Vec3<Type>& u, const Vec3<Type>& v)
+{
+  M[0]=u.x*v.x; M[3]=u.x*v.y;  M[6]=u.x*v.z;
+  M[1]=u.y*v.x; M[4]=u.y*v.y;  M[7]=u.y*v.z;
+  M[2]=u.z*v.x; M[5]=u.z*v.y; M[8]=u.z*v.z;
+}
+
+template<class Type>
+inline Type Mat33<Type>::Trace() const
+{
+  return M[0] + M[4] + M[8];
+}
+
+//---------------------------------------------------------------------------
+// Handy matrix printing routine.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat33<Type>::Print() const
+{
+  printf("\n%f %f %f\n",M[0],M[3],M[6]);
+  printf("%f %f %f\n",M[1],M[4],M[7]);
+  printf("%f %f %f\n",M[2],M[5],M[8]);
+}
+
+//---------------------------------------------------------------------------
+// Copy contents of matrix into matrix array.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat33<Type>::CopyInto(Type *Mat) const
+{
+  Mat[0]=M[0]; Mat[3]=M[3];  Mat[6]=M[6];  
+  Mat[1]=M[1]; Mat[4]=M[4];  Mat[7]=M[7];  
+  Mat[2]=M[2]; Mat[5]=M[5]; Mat[8]=M[8]; 
+}
+
diff --git a/simgear/scene/sky/clouds3d/mat44.hpp b/simgear/scene/sky/clouds3d/mat44.hpp
new file mode 100644 (file)
index 0000000..1d657b4
--- /dev/null
@@ -0,0 +1,135 @@
+//------------------------------------------------------------------------------
+// File : mat44.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// mat44.hpp : 4x4 OpenGL-style matrix template.
+//============================================================================
+
+#ifndef _MAT44_
+#define _MAT44_
+
+#include "vec3f.hpp"
+#include "vec4f.hpp"
+
+static const float Mat44TORADS = 0.0174532f;
+static const float Mat44VIEWPORT_TOL = 0.001f;
+
+//----------------------------------------------------------------------------
+// M[16] = [ 0  4  8 12 ]   |  16 floats were used instead of the normal [4][4]
+//         [ 1  5  9 13 ]   |  to be compliant with OpenGL. OpenGL uses
+//         [ 2  6 10 14 ]   |  premultiplication with column vectors. These
+//         [ 3  7 11 15 ]   |  matrices can be fed directly into the OpenGL
+//                          |  matrix stack with glLoadMatrix or glMultMatrix.
+//
+// [ x' y' z' w' ] = [ 0  4  8 12 ]   [ x ]
+//                   [ 1  5  9 13 ] * [ y ] 
+//                   [ 2  6 10 14 ]   [ z ]
+//                   [ 3  7 11 15 ]   [ w ]
+// 
+// Loading a [4][4] format matrix directly into the matrix stack (assuming
+// premult/col vecs) results in a transpose matrix. M[0]=M[0][0], but
+// M[1]!=M[1][0] since M[0][1] would cast to M[1].
+//
+// However, if we assumed postmult/row vectors we could use [4][4] format,
+// but all transformations in this module would be transposed.
+//----------------------------------------------------------------------------
+template<class Type>
+class Mat44
+{ 
+  public:
+    Type M[16];  // 0,1,2,3 = 1st col; 4,5,6,7 = 2nd col; etc.
+
+    Mat44();
+    Mat44(const Type *N);
+    Mat44(Type M0, Type M4, Type M8, Type M12,
+          Type M1, Type M5, Type M9, Type M13,
+          Type M2, Type M6, Type M10, Type M14,
+          Type M3, Type M7, Type M11, Type M15);
+    Mat44<Type>& operator = (const Mat44& A);         // ASSIGNMENT (=)
+    Mat44<Type>& operator = (const Type* a);                // ASSIGNMENT (=) FROM AN ARRAY OF TypeS 
+    Mat44<Type> operator * (const Mat44& A) const;    // MULTIPLICATION (*)
+    Vec3<Type> operator * (const Vec3<Type>& V) const;      // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV
+    Vec3<Type> multNormal(const Vec3<Type>& V) const;      // MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV
+    Vec3<Type> multPoint(const Vec3<Type>& V) const;      // MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV
+    Vec4<Type> operator * (const Vec4<Type>& V) const;      // MAT-VECTOR MULTIPLICATION (*)
+    Mat44<Type> operator * (Type a) const;                  // SCALAR POST-MULTIPLICATION
+    Mat44<Type>& operator *= (Type a);                    // ACCUMULATE MULTIPLY (*=)
+////////////// NOT IMPLEMENTED YET. ANY TAKERS?
+//    friend Vec3<Type> operator * (const Vec3<Type>& V, const Mat44& M);   // MAT-VECTOR PRE-MULTIPLICATON (*) W/ PERP DIV
+//    friend Vec4<Type> operator * (const Vec4<Type>& V, const Mat44& M);   // MAT-VECTOR PRE-MULTIPLICATON (*)
+//    friend Mat44<Type> operator * (Type a, const Mat44& M) const;         // SCALAR PRE-MULTIPLICATION
+//    Mat44<Type> operator / (Type a) const;                // SCALAR DIVISION
+//    Mat44<Type> operator + (Mat44& M) const;        // ADDITION (+)
+//    Mat44<Type>& operator += (Mat44& M);            // ACCUMULATE ADD (+=)
+//    Mat44<Type>& operator /= (Type a);                    // ACCUMULATE DIVIDE (/=)
+//    bool Invserse();                                      // MATRIX INVERSE
+////////////// NOT IMPLEMENTED YET. ANY TAKERS?
+
+    operator const Type*() const;                           // CAST TO A Type ARRAY
+    operator Type*();                                       // CAST TO A Type ARRAY
+    Type& operator()(int col, int row);                     // 2D ARRAY ACCESSOR
+    const Type& operator()(int col, int row) const;         // 2D ARRAY ACCESSOR
+    void Set(const Type* a);                                // SAME AS ASSIGNMENT (=) FROM AN ARRAY OF TypeS
+    void Set(Type M0, Type M4, Type M8, Type M12,
+             Type M1, Type M5, Type M9, Type M13,
+             Type M2, Type M6, Type M10, Type M14,
+             Type M3, Type M7, Type M11, Type M15);
+
+
+    void Identity();
+    void Transpose();
+    void Translate(Type Tx, Type Ty, Type Tz);
+    void Translate(const Vec3<Type>& T);
+    void invTranslate(Type Tx, Type Ty, Type Tz);
+    void invTranslate(const Vec3<Type>& T);
+    void Scale(Type Sx, Type Sy, Type Sz);
+    void Scale(const Vec3<Type>& S);
+    void invScale(Type Sx, Type Sy, Type Sz);
+    void invScale(const Vec3<Type>& S);
+    void Rotate(Type DegAng, const Vec3<Type>& Axis);
+    void invRotate(Type DegAng, const Vec3<Type>& Axis);
+    Type Trace(void) const;
+    void Frustum(Type l, Type r, Type b, Type t, Type n, Type f);
+    void invFrustum(Type l, Type r, Type b, Type t, Type n, Type f);
+    void Perspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist);
+    void invPerspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist);
+    void Viewport(int WW, int WH);
+    void invViewport(int WW, int WH);
+    void LookAt(const Vec3<Type>& Eye, 
+                const Vec3<Type>& LookAtPt,
+                const Vec3<Type>& ViewUp);
+    void invLookAt(const Vec3<Type>& Eye, 
+                   const Vec3<Type>& LookAtPt, 
+                   const Vec3<Type>& ViewUp);
+    void Viewport2(int WW, int WH);
+    void invViewport2(int WW, int WH);
+    void Print() const;
+    void CopyInto(Type *Mat) const;
+
+    static void SWAP(Type& a, Type& b) {Type t; t=a;a=b;b=t;}
+};
+
+#include "mat44impl.hpp"
+
+typedef Mat44<float> Mat44f;
+typedef Mat44<double> Mat44d;
+
+#endif
+
+
+
+
diff --git a/simgear/scene/sky/clouds3d/mat44impl.hpp b/simgear/scene/sky/clouds3d/mat44impl.hpp
new file mode 100644 (file)
index 0000000..5acbf13
--- /dev/null
@@ -0,0 +1,536 @@
+//------------------------------------------------------------------------------
+// File : mat44impl.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// mat44.hpp : 4x4 OpenGL-style matrix template.
+// This is the template implementation file. It is included by mat44.hpp.
+//============================================================================
+
+//---------------------------------------------------------------------------
+// CONSTRUCTORS
+//---------------------------------------------------------------------------
+template<class Type>
+Mat44<Type>::Mat44()
+{ 
+  Identity(); 
+}
+
+template<class Type>
+Mat44<Type>::Mat44(const Type *N)
+{
+  M[0]=N[0]; M[4]=N[4];  M[8]=N[8];  M[12]=N[12];
+  M[1]=N[1]; M[5]=N[5];  M[9]=N[9];  M[13]=N[13];
+  M[2]=N[2]; M[6]=N[6]; M[10]=N[10]; M[14]=N[14];
+  M[3]=N[3]; M[7]=N[7]; M[11]=N[11]; M[15]=N[15];
+}
+
+template<class Type>
+Mat44<Type>::Mat44(Type M0, Type M4, Type M8, Type M12,
+      Type M1, Type M5, Type M9, Type M13,
+      Type M2, Type M6, Type M10, Type M14,
+      Type M3, Type M7, Type M11, Type M15)
+{
+  M[0]=M0; M[4]=M4;  M[8]=M8;  M[12]=M12;
+  M[1]=M1; M[5]=M5;  M[9]=M9;  M[13]=M13;
+  M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
+  M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
+}
+
+//---------------------------------------------------------------------------
+// MATRIX/MATRIX AND MATRIX/VECTOR OPERATORS
+//---------------------------------------------------------------------------
+template<class Type>
+Mat44<Type>& Mat44<Type>::operator = (const Mat44& A)      // ASSIGNMENT (=)
+{
+  M[0]=A.M[0]; M[4]=A.M[4];  M[8]=A.M[8];  M[12]=A.M[12];
+  M[1]=A.M[1]; M[5]=A.M[5];  M[9]=A.M[9];  M[13]=A.M[13];
+  M[2]=A.M[2]; M[6]=A.M[6]; M[10]=A.M[10]; M[14]=A.M[14];
+  M[3]=A.M[3]; M[7]=A.M[7]; M[11]=A.M[11]; M[15]=A.M[15];
+  return(*this);
+}
+
+template<class Type>
+Mat44<Type>& Mat44<Type>::operator = (const Type* a) {
+  for (int i=0;i<16;i++) {
+    M[i] = a[i];
+  }
+  return *this;
+}
+
+template<class Type>
+Mat44<Type> Mat44<Type>::operator * (const Mat44& A) const  // MULTIPLICATION (*)
+{
+  Mat44<Type> NewM( M[0]*A.M[0] + M[4]*A.M[1] + M[8]*A.M[2] + M[12]*A.M[3],      // ROW 1
+              M[0]*A.M[4] + M[4]*A.M[5] + M[8]*A.M[6] + M[12]*A.M[7],
+              M[0]*A.M[8] + M[4]*A.M[9] + M[8]*A.M[10] + M[12]*A.M[11],
+              M[0]*A.M[12] + M[4]*A.M[13] + M[8]*A.M[14] + M[12]*A.M[15],
+
+              M[1]*A.M[0] + M[5]*A.M[1] + M[9]*A.M[2] + M[13]*A.M[3],      // ROW 2
+              M[1]*A.M[4] + M[5]*A.M[5] + M[9]*A.M[6] + M[13]*A.M[7],
+              M[1]*A.M[8] + M[5]*A.M[9] + M[9]*A.M[10] + M[13]*A.M[11],
+              M[1]*A.M[12] + M[5]*A.M[13] + M[9]*A.M[14] + M[13]*A.M[15],
+
+              M[2]*A.M[0] + M[6]*A.M[1] + M[10]*A.M[2] + M[14]*A.M[3],     // ROW 3
+              M[2]*A.M[4] + M[6]*A.M[5] + M[10]*A.M[6] + M[14]*A.M[7],
+              M[2]*A.M[8] + M[6]*A.M[9] + M[10]*A.M[10] + M[14]*A.M[11],
+              M[2]*A.M[12] + M[6]*A.M[13] + M[10]*A.M[14] + M[14]*A.M[15],
+
+              M[3]*A.M[0] + M[7]*A.M[1] + M[11]*A.M[2] + M[15]*A.M[3],     // ROW 4
+              M[3]*A.M[4] + M[7]*A.M[5] + M[11]*A.M[6] + M[15]*A.M[7],
+              M[3]*A.M[8] + M[7]*A.M[9] + M[11]*A.M[10] + M[15]*A.M[11],
+              M[3]*A.M[12] + M[7]*A.M[13] + M[11]*A.M[14] + M[15]*A.M[15] );
+  return(NewM);
+}
+
+template<class Type>
+Vec3<Type> Mat44<Type>::operator * (const Vec3<Type>& V) const  // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV
+{
+  Type       W = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15];
+  Vec3<Type> NewV( (M[0]*V.x + M[4]*V.y + M[8]*V.z  + M[12]) / W,
+              (M[1]*V.x + M[5]*V.y + M[9]*V.z  + M[13]) / W,
+              (M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]) / W );
+  return(NewV);
+}
+
+
+// MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV
+// For transforming normals or other pure vectors. 
+// Assumes matrix is affine, i.e. bottom row is 0,0,0,1
+template<class Type>
+Vec3<Type> Mat44<Type>::multNormal(const Vec3<Type>& N) const
+{
+  Vec3<Type> NewN( (M[0]*N.x + M[4]*N.y + M[8]*N.z ),
+                   (M[1]*N.x + M[5]*N.y + M[9]*N.z ),
+                   (M[2]*N.x + M[6]*N.y + M[10]*N.z) );
+  return (NewN);
+}
+
+// MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV 
+// (for transforming points in space)
+// Assumes matrix is affine, i.e. bottom row is 0,0,0,1
+template<class Type>
+Vec3<Type> Mat44<Type>::multPoint(const Vec3<Type>& P) const
+{
+  Vec3<Type> NewP( (M[0]*P.x + M[4]*P.y + M[8]*P.z  + M[12]),
+                   (M[1]*P.x + M[5]*P.y + M[9]*P.z  + M[13]),
+                   (M[2]*P.x + M[6]*P.y + M[10]*P.z + M[14]) );
+  return (NewP);
+}
+
+
+template<class Type>
+Vec4<Type> Mat44<Type>::operator * (const Vec4<Type>& V) const  // MAT-VECTOR MULTIPLICATION (*)
+{
+  Vec4<Type> NewV;
+  NewV.x = M[0]*V.x + M[4]*V.y + M[8]*V.z  + M[12]*V.w;
+  NewV.y = M[1]*V.x + M[5]*V.y + M[9]*V.z  + M[13]*V.w;
+  NewV.z = M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]*V.w;
+  NewV.w = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15]*V.w;
+  return(NewV);
+}
+
+
+template<class Type>
+Mat44<Type> Mat44<Type>::operator * (Type a) const              // SCALAR POST-MULTIPLICATION
+{
+  Mat44<Type> NewM( M[0] * a, M[1] * a, M[2] * a, M[3] * a, 
+                    M[4] * a, M[5] * a, M[6] * a, M[7] * a,
+                    M[8] * a, M[9] * a, M[10] * a, M[11] * a, 
+                    M[12] * a, M[13] * a, M[14] * a, M[15] * a);
+  return NewM;
+}
+
+template<class Type>
+Mat44<Type>& Mat44<Type>::operator *= (Type a)                  // SCALAR ACCUMULATE POST-MULTIPLICATION
+{
+  for (int i = 0; i < 16; i++)
+  {
+    M[i] *= a;
+  }
+
+  return *this;
+}
+
+template<class Type>
+Mat44<Type>::operator const Type*() const
+{
+  return M;
+}
+
+template<class Type>
+Mat44<Type>::operator Type*()
+{
+  return M;
+}
+
+template<class Type>
+Type& Mat44<Type>::operator()(int col, int row)
+{
+  return M[4*col+row];
+}
+
+template<class Type>
+const Type& Mat44<Type>::operator()(int col, int row) const
+{
+  return M[4*col+row];
+}
+
+template<class Type>
+void Mat44<Type>::Set(const Type* a)
+{
+  for (int i=0;i<16;i++) {
+    M[i] = a[i];
+  }
+  
+}
+
+template<class Type>
+void Mat44<Type>::Set(Type M0, Type M4, Type M8, Type M12,
+                      Type M1, Type M5, Type M9, Type M13,
+                      Type M2, Type M6, Type M10, Type M14,
+                      Type M3, Type M7, Type M11, Type M15)
+{
+  M[0]=M0; M[4]=M4;  M[8]=M8;  M[12]=M12;
+  M[1]=M1; M[5]=M5;  M[9]=M9;  M[13]=M13;
+  M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
+  M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
+}
+
+
+//---------------------------------------------------------------------------
+// Standard Matrix Operations
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Identity()
+{
+  M[0]=M[5]=M[10]=M[15]=1;
+  M[1]=M[2]=M[3]=M[4]=M[6]=M[7]=M[8]=M[9]=M[11]=M[12]=M[13]=M[14]=0;
+}
+
+template<class Type>
+void Mat44<Type>::Transpose()
+{
+  SWAP(M[1],M[4]);
+  SWAP(M[2],M[8]);
+  SWAP(M[6],M[9]);
+  SWAP(M[3],M[12]);
+  SWAP(M[7],M[13]);
+  SWAP(M[11],M[14]);
+}
+
+//---------------------------------------------------------------------------
+// Standard Matrix Affine Transformations
+//---------------------------------------------------------------------------
+template <class Type>
+void Mat44<Type>::Translate(Type Tx, Type Ty, Type Tz)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=Tx;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=Ty;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=Tz;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::Translate(const Vec3<Type>& T)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=T.x;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=T.y;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=T.z;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invTranslate(Type Tx, Type Ty, Type Tz)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=-Tx;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=-Ty;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=-Tz;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invTranslate(const Vec3<Type>& T)
+{
+  M[0]=1; M[4]=0;  M[8]=0;  M[12]=-T.x;
+  M[1]=0; M[5]=1;  M[9]=0;  M[13]=-T.y;
+  M[2]=0; M[6]=0;  M[10]=1; M[14]=-T.z;
+  M[3]=0; M[7]=0;  M[11]=0; M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::Scale(Type Sx, Type Sy, Type Sz)
+{
+  M[0]=Sx; M[4]=0;  M[8]=0;   M[12]=0;
+  M[1]=0;  M[5]=Sy; M[9]=0;   M[13]=0;
+  M[2]=0;  M[6]=0;  M[10]=Sz; M[14]=0;
+  M[3]=0;  M[7]=0;  M[11]=0;  M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::Scale(const Vec3<Type>& S)
+{
+  M[0]=S.x; M[4]=0;   M[8]=0;    M[12]=0;
+  M[1]=0;   M[5]=S.y; M[9]=0;    M[13]=0;
+  M[2]=0;   M[6]=0;   M[10]=S.z; M[14]=0;
+  M[3]=0;   M[7]=0;   M[11]=0;   M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invScale(Type Sx, Type Sy, Type Sz)
+{
+  M[0]=1/Sx; M[4]=0;    M[8]=0;     M[12]=0;
+  M[1]=0;    M[5]=1/Sy; M[9]=0;     M[13]=0;
+  M[2]=0;    M[6]=0;    M[10]=1/Sz; M[14]=0;
+  M[3]=0;    M[7]=0;    M[11]=0;    M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invScale(const Vec3<Type>& S)
+{
+  M[0]=1/S.x; M[4]=0;     M[8]=0;      M[12]=0;
+  M[1]=0;     M[5]=1/S.y; M[9]=0;      M[13]=0;
+  M[2]=0;     M[6]=0;     M[10]=1/S.z; M[14]=0;
+  M[3]=0;     M[7]=0;     M[11]=0;     M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::Rotate(Type DegAng, const Vec3<Type>& Axis)
+{
+  Type RadAng = DegAng*Mat44TORADS;
+  Type ca=(Type)cos(RadAng),
+        sa=(Type)sin(RadAng);
+  if (Axis.x==1 && Axis.y==0 && Axis.z==0)  // ABOUT X-AXIS
+  {
+   M[0]=1; M[4]=0;  M[8]=0;   M[12]=0;
+   M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
+   M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
+   M[3]=0; M[7]=0;  M[11]=0;  M[15]=1;
+  }
+  else if (Axis.x==0 && Axis.y==1 && Axis.z==0)  // ABOUT Y-AXIS
+  {
+   M[0]=ca;  M[4]=0; M[8]=sa;  M[12]=0;
+   M[1]=0;   M[5]=1; M[9]=0;   M[13]=0;
+   M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
+   M[3]=0;   M[7]=0; M[11]=0;  M[15]=1;
+  }
+  else if (Axis.x==0 && Axis.y==0 && Axis.z==1)  // ABOUT Z-AXIS
+  {
+   M[0]=ca; M[4]=-sa; M[8]=0;  M[12]=0;
+   M[1]=sa; M[5]=ca;  M[9]=0;  M[13]=0;
+   M[2]=0;  M[6]=0;   M[10]=1; M[14]=0;
+   M[3]=0;  M[7]=0;   M[11]=0; M[15]=1;
+  }
+  else                                      // ARBITRARY AXIS
+  {
+   Type l = Axis.LengthSqr();
+   Type x, y, z;
+   x=Axis.x, y=Axis.y, z=Axis.z;
+   if (l > Type(1.0001) || l < Type(0.9999) && l!=0)
+   {
+     // needs normalization
+     l=Type(1.0)/sqrt(l);
+     x*=l; y*=l; z*=l;
+   }
+   Type x2=x*x, y2=y*y, z2=z*z;
+   M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
+   M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
+   M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
+   M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
+   M[15]=1;
+  }
+}
+
+template<class Type>
+void Mat44<Type>::invRotate(Type DegAng, const Vec3<Type>& Axis)
+{
+  Rotate(DegAng,Axis);
+  Transpose();
+}
+
+template<class Type>
+inline Type Mat44<Type>::Trace() const
+{
+  return M[0] + M[5] + M[10] + M[15];
+}
+
+//---------------------------------------------------------------------------
+// Same as glFrustum() : Perspective transformation matrix defined by a
+//  truncated pyramid viewing frustum that starts at the origin (eye)
+//  going in the -Z axis direction (viewer looks down -Z)
+//  with the four pyramid sides passing through the sides of a window
+//  defined through x=l, x=r, y=b, y=t on the viewplane at z=-n.
+//  The top and bottom of the pyramid are truncated by the near and far
+//  planes at z=-n and z=-f. A 4-vector (x,y,z,w) inside this frustum
+//  transformed by this matrix will have x,y,z values in the range
+//  [-w,w]. Homogeneous clipping is applied to restrict (x,y,z) to
+//  this range. Later, a perspective divide by w will result in an NDC
+//  coordinate 3-vector of the form (x/w,y/w,z/w,w/w)=(x',y',z',1) where
+//  x', y', and z' all are in the range [-1,1]. Perspectively divided z'
+//  will be in [-1,1] with -1 being the near plane and +1 being the far.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Frustum(Type l, Type r, Type b, Type t, Type n, Type f)
+{
+  M[0]=(2*n)/(r-l); M[4]=0;           M[8]=(r+l)/(r-l);   M[12]=0;
+  M[1]=0;           M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b);   M[13]=0;
+  M[2]=0;           M[6]=0;           M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
+  M[3]=0;           M[7]=0;           M[11]=-1;           M[15]=0;
+}
+
+template<class Type>
+void Mat44<Type>::invFrustum(Type l, Type r, Type b, Type t, Type n, Type f)
+{
+  M[0]=(r-l)/(2*n); M[4]=0;           M[8]=0;               M[12]=(r+l)/(2*n);
+  M[1]=0;           M[5]=(t-b)/(2*n); M[9]=0;               M[13]=(t+b)/(2*n);
+  M[2]=0;           M[6]=0;           M[10]=0;              M[14]=-1;
+  M[3]=0;           M[7]=0;           M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
+}
+
+//---------------------------------------------------------------------------
+// Same as gluPerspective : calls Frustum()
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Perspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
+{
+  Yfov *= 0.0174532f;  // CONVERT TO RADIANS
+  Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
+  Type wR=wT*Aspect, wL=-wR;
+  Frustum(wL,wR,wB,wT,Ndist,Fdist);
+}
+
+template<class Type>
+void Mat44<Type>::invPerspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
+{
+  Yfov *= 0.0174532f;  // CONVERT TO RADIANS
+  Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
+  Type wR=wT*Aspect, wL=-wR;
+  invFrustum(wL,wR,wB,wT,Ndist,Fdist);
+}
+
+//---------------------------------------------------------------------------
+// OpenGL VIEWPORT XFORM MATRIX : given Window width and height in pixels
+// Transforms the x,y,z NDC values in [-1,1] to (x',y') pixel values and
+// normalized z' in [0,1] (near and far respectively).
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Viewport(int WW, int WH)
+{
+  Type WW2=(Type)WW*0.5f, WH2=(Type)WH*0.5f;
+  M[0]=WW2;  M[4]=0;     M[8]=0;    M[12]=WW2;
+  M[1]=0;    M[5]=WH2;   M[9]=0;    M[13]=WH2;
+  M[2]=0;    M[6]=0;     M[10]=0.5; M[14]=0.5;
+  M[3]=0;    M[7]=0;     M[11]=0;   M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invViewport(int WW, int WH)
+{
+  Type WW2=2.0f/(Type)WW, WH2=2.0f/(Type)WH;
+  M[0]=WW2;  M[4]=0;     M[8]=0;    M[12]=-1.0;
+  M[1]=0;    M[5]=WH2;   M[9]=0;    M[13]=-1.0;
+  M[2]=0;    M[6]=0;     M[10]=2.0; M[14]=-1.0;
+  M[3]=0;    M[7]=0;     M[11]=0;   M[15]=1;
+}
+
+//---------------------------------------------------------------------------
+// Same as gluLookAt()
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::LookAt(const Vec3<Type>& Eye, 
+                         const Vec3<Type>& LookAtPt, 
+                         const Vec3<Type>& ViewUp)
+{
+  Vec3<Type> Z = Eye-LookAtPt;  Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
+  Vec3<Type> X = ViewUp/Z;      X.Normalize();
+  Vec3<Type> Y = Z/X;           Y.Normalize();
+  Vec3<Type> Tr = -Eye;
+  M[0]=X.x;  M[4]=X.y;   M[8]=X.z; M[12]=X*Tr;  // TRANS->ROT
+  M[1]=Y.x;  M[5]=Y.y;   M[9]=Y.z; M[13]=Y*Tr;
+  M[2]=Z.x;  M[6]=Z.y;  M[10]=Z.z; M[14]=Z*Tr;
+  M[3]=0;    M[7]=0;    M[11]=0;   M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invLookAt(const Vec3<Type>& Eye, 
+                            const Vec3<Type>& LookAtPt,
+                            const Vec3<Type>& ViewUp)
+{
+  Vec3<Type> Z = Eye-LookAtPt;  Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
+  Vec3<Type> X = ViewUp/Z;      X.Normalize();
+  Vec3<Type> Y = Z/X;           Y.Normalize();
+  M[0]=X.x;  M[4]=Y.x;   M[8]=Z.x; M[12]=Eye.x;  // ROT->TRANS
+  M[1]=X.y;  M[5]=Y.y;   M[9]=Z.y; M[13]=Eye.y;
+  M[2]=X.z;  M[6]=Y.z;  M[10]=Z.z; M[14]=Eye.z;
+  M[3]=0;    M[7]=0;    M[11]=0;   M[15]=1;
+}
+
+//---------------------------------------------------------------------------
+// VIEWPORT TRANFORMATION MATRIX : given Window width and height in pixels
+// FROM "JIM BLINN'S CORNER" JULY '91. This function transforms an
+// 4-vector in homogeneous space of the form (x,y,z,w) where
+// -w<=x,y,z<=w into (x',y',z',1) where (x',y') is the vectors
+// projected pixel location in ([0,WW-1],[0,WH-1]) and z' is the
+// normalized depth value mapped into [0,1]; 0 is the near plane
+// and 1 is the far plane. Mat44VIEWPORT_TOL is introduced to have correct
+// mappings. (-1,-1,?,?) in NDC refers to the bottom-left of the
+// viewplane window and (0,0,?,?) in screen space refers to the
+// bottom-left pixel.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Viewport2(int WW, int WH)
+{
+  Type WW2=(WW-Mat44VIEWPORT_TOL)*0.5f, WH2=(WH-Mat44VIEWPORT_TOL)*0.5f;
+  M[0]=WW2;  M[4]=0;     M[8]=0;    M[12]=WW2;
+  M[1]=0;    M[5]=WH2;   M[9]=0;    M[13]=WH2;
+  M[2]=0;    M[6]=0;     M[10]=0.5; M[14]=0.5;
+  M[3]=0;    M[7]=0;     M[11]=0;   M[15]=1;
+}
+
+template<class Type>
+void Mat44<Type>::invViewport2(int WW, int WH)
+{
+  Type WW2=2.0f/(WW-Mat44VIEWPORT_TOL), WH2=2.0f/(WH-Mat44VIEWPORT_TOL);
+  M[0]=WW2;  M[4]=0;     M[8]=0;    M[12]=-1.0;
+  M[1]=0;    M[5]=WH2;   M[9]=0;    M[13]=-1.0;
+  M[2]=0;    M[6]=0;     M[10]=2.0; M[14]=-1.0;
+  M[3]=0;    M[7]=0;     M[11]=0;   M[15]=1;
+}
+
+//---------------------------------------------------------------------------
+// Handy matrix printing routine.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::Print() const
+{
+  printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
+  printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
+  printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
+  printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);
+}
+
+//---------------------------------------------------------------------------
+// Copy contents of matrix into matrix array.
+//---------------------------------------------------------------------------
+template<class Type>
+void Mat44<Type>::CopyInto(Type *Mat) const
+{
+  Mat[0]=M[0]; Mat[4]=M[4];  Mat[8]=M[8];  Mat[12]=M[12];
+  Mat[1]=M[1]; Mat[5]=M[5];  Mat[9]=M[9];  Mat[13]=M[13];
+  Mat[2]=M[2]; Mat[6]=M[6]; Mat[10]=M[10]; Mat[14]=M[14];
+  Mat[3]=M[3]; Mat[7]=M[7]; Mat[11]=M[11]; Mat[15]=M[15];
+}
+
diff --git a/simgear/scene/sky/clouds3d/mat44test.cpp b/simgear/scene/sky/clouds3d/mat44test.cpp
new file mode 100644 (file)
index 0000000..c99b809
--- /dev/null
@@ -0,0 +1,66 @@
+//------------------------------------------------------------------------------
+// File : mat44test.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//----------------------------------------------------------------------------
+// mat44test  -- test compilation of all the functions in mat44 library
+//----------------------------------------------------------------------------
+// $Id$
+//----------------------------------------------------------------------------
+#include <iostream.h>
+#include <vec3f.hpp>
+#include <mat44.hpp>
+
+int main(int argc, char *argv[])
+{
+  cout << "This is not a comprehensive correctness test. " << endl
+       << "It merely tests whether all the functions in mat44 will compile." <<endl;
+
+  Mat44f m;
+  float m2[16];
+  Vec3f v(1.0, 1.0, 1.0);
+  Vec3f up(0.0, 1.0, 0.0);
+
+  m.Identity();
+  m.Transpose();
+  m.Translate(1.0, 1.0, 1.0);
+  m.Translate(v);
+  m.invTranslate(v);
+  m.Scale(1.0, 1.0, 1.0);
+  m.Scale(v);
+  m.invScale(1.0, 1.0, 1.0);
+  m.invScale(v);
+  m.Rotate(90, v);
+  m.invRotate(90, v);
+  m.Frustum(-1.0, 1.0, -1.0, 1.0, 0.01, 20);
+  m.invFrustum(-1.0, 1.0, -1.0, 1.0, 0.01, 20);
+  m.Perspective(60, 1.4, 0.01, 20);
+  m.invPerspective(60, 1.4, 0.01, 20);
+  m.Viewport(200, 200);
+  m.invViewport(200, 200);
+  m.LookAt(Vec3f::ZERO, v, up);
+  m.invLookAt(Vec3f::ZERO, v, up);
+  m.Viewport2(200, 200);
+  m.invViewport2(200, 200);
+  m.Print();
+  m.Transpose();
+  m.Print();
+  // These two should be transpose of one another
+  m.CopyInto(m2);
+
+  cout << "Ok there is this one test to make sure Transpose() is correct.\n"
+    "The above two matricies should be the transpose of one another.\n" << endl;
+}
diff --git a/simgear/scene/sky/clouds3d/minmaxbox.cpp b/simgear/scene/sky/clouds3d/minmaxbox.cpp
new file mode 100644 (file)
index 0000000..712d93e
--- /dev/null
@@ -0,0 +1,108 @@
+//------------------------------------------------------------------------------
+// File : minmaxbox.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//=========================================================================
+// minmaxbox.cpp : min-max box routines
+//=========================================================================
+
+//-----------------------------------------------------------------------------
+// Calculates the eight corner vertices of the MinMaxBox.
+// V must be prealloced.
+//       5---4
+//      /   /|
+//     1---0 |   VERTS : 0=RTN,1=LTN,2=LBN,3=RBN,4=RTF,5=LTF,6=LBF,7=RBF
+//     |   | 7   (L,R, B,T, N,F) = (Left,Right, Bottom,Top, Near,Far)
+//     |   |/
+//     2---3
+//-----------------------------------------------------------------------------
+void GetMinMaxBoxVerts(const float Min[3], const float Max[3], float V[8][3])
+{
+  #define SET(v,x,y,z) v[0]=x; v[1]=y; v[2]=z;
+  SET(V[0],Max[0],Max[1],Max[2]); SET(V[4],Max[0],Max[1],Min[2]);
+  SET(V[1],Min[0],Max[1],Max[2]); SET(V[5],Min[0],Max[1],Min[2]);
+  SET(V[2],Min[0],Min[1],Max[2]); SET(V[6],Min[0],Min[1],Min[2]);
+  SET(V[3],Max[0],Min[1],Max[2]); SET(V[7],Max[0],Min[1],Min[2]);
+}
+
+//--------------------------------------------------------------------------
+// Ray-MinMaxBox intersection test. Returns 0 or 1, calcs In-Out "HitTimes"
+// IsectPts can be calculated as:
+//   InIsectPt = Start + Dir * InT      (if InT>0)
+//  OutIsectPt = Start + Dir * OutT     (if OutT>0)
+//--------------------------------------------------------------------------
+int RayMinMaxBoxIsect(const float Start[3], const float Dir[3], 
+                      const float Min[3], const float Max[3],
+                      float *InT, float *OutT)
+{
+  *InT=-99999, *OutT=99999;    // INIT INTERVAL T-VAL ENDPTS TO -/+ "INFINITY"
+  float NewInT, NewOutT;     // STORAGE FOR NEW T VALUES
+
+  // X-SLAB (PARALLEL PLANES PERPENDICULAR TO X-AXIS) INTERSECTION (Xaxis is Normal)
+  if (Dir[0] == 0)            // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
+  { if ((Start[0] < Min[0]) || (Start[0] > Max[0])) return(0); }
+  else
+  {
+    NewInT = (Min[0]-Start[0])/Dir[0];  // CALC Tval ENTERING MIN PLANE
+    NewOutT = (Max[0]-Start[0])/Dir[0]; // CALC Tval ENTERING MAX PLANE
+    if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT;  if (NewOutT<*OutT) *OutT=NewOutT; }
+                   else { if (NewOutT>*InT) *InT=NewOutT;  if (NewInT<*OutT) *OutT=NewInT; }
+    if (*InT>*OutT) return(0);
+  }
+
+  // Y-SLAB (PARALLEL PLANES PERPENDICULAR TO Y-AXIS) INTERSECTION (Yaxis is Normal)
+  if (Dir[1] == 0)                // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
+  { if ((Start[1] < Min[1]) || (Start[1] > Max[1])) return(0); }
+  else
+  {
+    NewInT = (Min[1]-Start[1])/Dir[1];  // CALC Tval ENTERING MIN PLANE
+    NewOutT = (Max[1] - Start[1])/Dir[1]; // CALC Tval ENTERING MAX PLANE
+    if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT;  if (NewOutT<*OutT) *OutT=NewOutT; }
+                   else { if (NewOutT>*InT) *InT=NewOutT;  if (NewInT<*OutT) *OutT=NewInT; }
+    if (*InT>*OutT) return(0);
+  }
+
+  // Z-SLAB (PARALLEL PLANES PERPENDICULAR TO Z-AXIS) INTERSECTION (Zaxis is Normal)
+  if (Dir[2] == 0)                // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
+  { if ((Start[2] < Min[2]) || (Start[2] > Max[2])) return(0); }
+  else
+  {
+    NewInT = (Min[2]-Start[2])/Dir[2];  // CALC Tval ENTERING MIN PLANE
+    NewOutT = (Max[2]-Start[2])/Dir[2]; // CALC Tval ENTERING MAX PLANE
+    if (NewOutT>NewInT) { if (NewInT>*InT) *InT=NewInT;  if (NewOutT<*OutT) *OutT=NewOutT; }
+                   else { if (NewOutT>*InT) *InT=NewOutT;  if (NewInT<*OutT) *OutT=NewInT; }
+    if (*InT>*OutT) return(0);
+  }
+
+  // CHECK IF INTERSECTIONS ARE "AT OR BEYOND" THE START OF THE RAY
+  if (*InT>=0 || *OutT>=0) return(1);
+  return(0);
+}
+
+//--------------------------------------------------------------------------
+// returns whether or not an edge intersects a MinMaxBox. The hit times
+// are returned just as in the ray isect test.
+//--------------------------------------------------------------------------
+int EdgeMinMaxBoxIsect(const float A[3], const float B[3], 
+                       const float Min[3], const float Max[3],
+                       float *InT, float *OutT)
+{
+  float Dir[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
+  if ( RayMinMaxBoxIsect(A,Dir,Min,Max,InT,OutT) )
+    if (*InT>=0 && *InT<=1) return(1);
+    else if (*OutT>=0 && *OutT<=1) return(1);
+  return(0);
+}
diff --git a/simgear/scene/sky/clouds3d/minmaxbox.hpp b/simgear/scene/sky/clouds3d/minmaxbox.hpp
new file mode 100644 (file)
index 0000000..9a8e808
--- /dev/null
@@ -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 (file)
index 0000000..6af97a6
--- /dev/null
@@ -0,0 +1,302 @@
+//------------------------------------------------------------------------------
+// File : plane.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//=========================================================================
+// plane.cpp
+//=========================================================================
+
+#include <math.h>
+
+//--------------------------------------------------------------------------
+// Calculates the plane equation coeffients P = [ A B C D ] for the plane
+// equation: Ax+By+Cz+D=0 given three vertices defining the plane. The
+// normalized plane normal (A,B,C) is defined using the right-hand rule.
+//--------------------------------------------------------------------------
+float* PlaneEquation(float P[4], 
+                     const float p0[3], const float p1[3], const float p2[3])
+{
+  // CALCULATE PLANE NORMAL - FIRST THREE COEFFICIENTS (A,B,C)
+  float u[3], v[3];
+  u[0]=p1[0]-p0[0];  u[1]=p1[1]-p0[1];  u[2]=p1[2]-p0[2];
+  v[0]=p2[0]-p0[0];  v[1]=p2[1]-p0[1];  v[2]=p2[2]-p0[2];
+
+  P[0] = u[1]*v[2] - u[2]*v[1];  // CROSS-PROD BETWEEN u AND v
+  P[1] = u[2]*v[0] - u[0]*v[2];  // DEFINES UNNORMALIZED NORMAL
+  P[2] = u[0]*v[1] - u[1]*v[0];
+
+  float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);  // NORMALIZE NORMAL
+  P[0]/=l; P[1]/=l; P[2]/=l; 
+
+  // CALCULATE D COEFFICIENT (USING FIRST PT ON PLANE - p0)
+  P[3] = -(P[0]*p0[0] + P[1]*p0[1] + P[2]*p0[2]);
+
+  return(P);
+}
+
+
+//--------------------------------------------------------------------------
+// Calculates the plane equation coeffients P = [ A B C D ] for the plane
+// equation: Ax+By+Cz+D=0 given an unnormalized normal N to the plane and
+// the distance along the normal to the plane Dist. The dot product between
+// the normalized normal and a point on the plane should equal the distance
+// along the normal to the plane (Dist): Ax+By+Cz=Dist, so D=-Dist.
+//--------------------------------------------------------------------------
+float* PlaneEquation(float P[4], const float N[3], float Dist)
+{
+  // COPY AND NORMALIZE NORMAL
+  P[0]=N[0]; P[1]=N[1]; P[2]=N[2];
+  float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
+  P[0]/=l; P[1]/=l; P[2]/=l; 
+
+  // CALCULATE D COEFFICIENT
+  P[3]=-Dist;
+
+  return(P);
+}
+
+
+//--------------------------------------------------------------------------
+// Calculates the plane equation coeffients P = [ A B C D ] for the plane
+// equation: Ax+By+Cz+D=0 given an unnormalized normal N to the plane and
+// a point pt on the plane. The dot product between the normalized normal
+// and the point should equal the distance along the normal to the plane,
+// thus equalling negative D.
+//--------------------------------------------------------------------------
+float* PlaneEquation(float P[4], const float N[3], const float pt[3])
+{
+  // COPY AND NORMALIZE NORMAL
+  P[0]=N[0]; P[1]=N[1]; P[2]=N[2];
+  float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);
+  P[0]/=l; P[1]/=l; P[2]/=l; 
+
+  // CALCULATE D COEFFICIENT (USING PT ON PLANE)
+  P[3] = -(P[0]*pt[0] + P[1]*pt[1] + P[2]*pt[2]);
+
+  return(P);
+}
+
+//--------------------------------------------------------------------------
+// Transforms a plane by a 4x4 matrix (col-major order, assumes premult/col vect). 
+// The given plane coefficients are altered. The normal (A,B,C) is normalized.
+// see HOFF tech report: "4x4 matrix transformation of the implicit form of the plane"
+//--------------------------------------------------------------------------
+void XformPlane(const float M[16], float P[4])
+{
+  float NewP[4], L2, L;
+  NewP[0] = M[0]*P[0] + M[4]*P[1] + M[8]*P[2]; 
+  NewP[1] = M[1]*P[0] + M[5]*P[1] + M[9]*P[2]; 
+  NewP[2] = M[2]*P[0] + M[6]*P[1] + M[10]*P[2]; 
+       L2 = NewP[0]*NewP[0] + NewP[1]*NewP[1] + NewP[2]*NewP[2];
+        L = (float)sqrt(L2);
+  P[0] = NewP[0] / L;
+  P[1] = NewP[1] / L;
+  P[2] = NewP[2] / L;
+  P[3] = P[3]*L2 - (NewP[0]*M[12] + NewP[1]*M[13] + NewP[2]*M[14]);
+}     
+
+//--------------------------------------------------------------------------
+// return 1 if point is "outside" (normal side) of plane, 0 if "inside" or on
+//--------------------------------------------------------------------------
+int PlanePtOutTest(const float P[4], const float Pt[3])
+{
+  return( (P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2]) > -P[3] );
+}
+
+//--------------------------------------------------------------------------
+// returns -1 inside, 0 on, 1 outside (normal side)
+//--------------------------------------------------------------------------
+int PlanePtInOutTest(const float P[4], const float Pt[3])
+{
+  float DotProd = P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2];
+  if (DotProd < -P[3]) return(-1);
+  if (DotProd > -P[3]) return(1);
+  return(0);
+}
+
+//--------------------------------------------------------------------------
+// Calculates the "signed" distance of a point from a plane (in units of
+// the normal length, if not normalized). +Dist is on normal dir side of plane.
+//--------------------------------------------------------------------------
+float PlaneDistToPt(const float P[4], const float Pt[3])
+{ 
+  return( P[0]*Pt[0] + P[1]*Pt[1] + P[2]*Pt[2] + P[3] );
+}
+
+//--------------------------------------------------------------------------
+// returns 1 if ray (Start,Dir) intersects plane, 0 if not
+//--------------------------------------------------------------------------
+int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3])
+{
+  float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
+  float NdotStart = P[0]*Start[0] + P[1]*Start[1] + P[2]*Start[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (-P[3] - NdotStart) / NdotDir;
+  if (t>=0) return(1);
+  return(0);
+}
+
+//--------------------------------------------------------------------------
+// Also computes intersection point, if possible
+//--------------------------------------------------------------------------
+int PlaneRayIsect(const float P[4], const float Start[3], const float Dir[3],
+                  float IsectPt[3])
+{
+  float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
+  float NdotStart = P[0]*Start[0] + P[1]*Start[1] + P[2]*Start[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (-P[3] - NdotStart) / NdotDir;
+  if (t>=0) 
+  {
+    IsectPt[0] = Start[0] + Dir[0]*t;
+    IsectPt[1] = Start[1] + Dir[1]*t;
+    IsectPt[2] = Start[2] + Dir[2]*t;
+    return(1);
+  }
+  return(0);
+}
+
+//--------------------------------------------------------------------------
+// Intersects a line with a plane with normal (0,0,-1) with distance d
+// from the origin.  The line is given by position Start and direction Dir.
+//--------------------------------------------------------------------------
+int ZPlaneLineIsect(float d, const float Start[3], const float Dir[3],
+                    float IsectPt[3])
+{
+  float NdotDir = -Dir[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (d + Start[2]) / NdotDir;
+  IsectPt[0] = Start[0] + Dir[0]*t;
+  IsectPt[1] = Start[1] + Dir[1]*t;
+  IsectPt[2] = Start[2] + Dir[2]*t;
+  return(1);
+}
+
+//--------------------------------------------------------------------------
+// returns 1 if edge AB intersects plane, 0 if not
+//--------------------------------------------------------------------------
+int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3])
+{
+  float Dir[3] = { B[0]-A[0], B[1]-A[1], B[2]-A[2] };
+  float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
+  float NdotA = P[0]*A[0] + P[1]*A[1] + P[2]*A[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (-P[3] - NdotA) / NdotDir;
+  if (t>=0 && t<=1) return(1);
+  return(0);
+}
+
+//--------------------------------------------------------------------------
+// Also computes intersection point, if possible
+//--------------------------------------------------------------------------
+int PlaneEdgeIsect(const float P[4], const float A[3], const float B[3],
+                   float IsectPt[3])
+{
+  float Dir[3] = { B[0]-A[0], B[1]-A[1], B[2]-A[2] };
+  float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
+  float NdotA = P[0]*A[0] + P[1]*A[1] + P[2]*A[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (-P[3] - NdotA) / NdotDir;
+  if (t>=0 && t<=1)
+  {
+    IsectPt[0] = A[0] + Dir[0]*t;
+    IsectPt[1] = A[1] + Dir[1]*t;
+    IsectPt[2] = A[2] + Dir[2]*t;
+    return(1);
+  }
+  return(0);
+}
+
+//---------------------------------------------------------------------------
+// Box (m,M)/ Plane P overlap test.
+// returns type of overlap: 1=OUT (side of normal dir), -1=IN, 0=Overlapping
+// Finds the "closest" and "farthest" points from the plane with respect
+// to the plane normal dir (the "extremes" of the aabb) and tests for overlap.
+// m and M are the Min and Max extents of the AABB.
+//---------------------------------------------------------------------------
+int PlaneMinMaxBoxOverlap(const float P[4], const float m[3], const float M[3])
+{
+  #define SET(v,x,y,z) v[0]=x; v[1]=y; v[2]=z;
+
+  // CALC EXTREME PTS (Neg,Pos) ALONG NORMAL AXIS (Pos in dir of norm, etc.)
+  float Neg[3], Pos[3];
+  if(P[0]>0)
+    if(P[1]>0) { if(P[2]>0) { SET(Pos,M[0],M[1],M[2]); SET(Neg,m[0],m[1],m[2]); }
+                       else { SET(Pos,M[0],M[1],m[2]); SET(Neg,m[0],m[1],M[2]); } }
+          else { if(P[2]>0) { SET(Pos,M[0],m[1],M[2]); SET(Neg,m[0],M[1],m[2]); }
+                       else { SET(Pos,M[0],m[1],m[2]); SET(Neg,m[0],M[1],M[2]); } }
+  else
+    if(P[1]>0) { if(P[2]>0) { SET(Pos,m[0],M[1],M[2]); SET(Neg,M[0],m[1],m[2]); }
+                       else { SET(Pos,m[0],M[1],m[2]); SET(Neg,M[0],m[1],M[2]); } }
+          else { if(P[2]>0) { SET(Pos,m[0],m[1],M[2]); SET(Neg,M[0],M[1],m[2]); }
+                       else { SET(Pos,m[0],m[1],m[2]); SET(Neg,M[0],M[1],M[2]); } }
+
+  // CHECK DISTANCE TO PLANE FROM EXTREMAL POINTS TO DETERMINE OVERLAP
+  if (PlaneDistToPt(P,Neg) > 0) return(1);
+  else if (PlaneDistToPt(P,Pos) <= 0) return(-1);
+  return(0);
+}
+
+//---------------------------------------------------------------------------
+// Edge/Planes intersection test. Returns 0 or 1, calcs In-Out "HitTimes"
+// IsectPts can be calculated as:
+//   InIsectPt = Start + Dir * InT      (if InT>0)
+//  OutIsectPt = Start + Dir * OutT     (if OutT>0)
+// Planes is defined as: float Planes[n][4] for n planes.
+//---------------------------------------------------------------------------
+int PlanesRayIsect(const float Planes[][4], int NumPlanes,
+                   const float Start[3], const float Dir[3], 
+                   float *InT, float *OutT)
+{
+  *InT=-99999, *OutT=99999;          // INIT INTERVAL T-VAL ENDPTS TO -/+ INFINITY
+  float NdotDir, NdotStart;          // STORAGE FOR REPEATED CALCS NEEDED FOR NewT CALC
+  float NewT;
+  for (int i=0; i<NumPlanes; i++)    // CHECK INTERSECTION AGAINST EACH VF PLANE
+  {
+    NdotDir = Planes[i][0]*Dir[0] + Planes[i][1]*Dir[1] + Planes[i][2]*Dir[2];
+    NdotStart = Planes[i][0]*Start[0] + Planes[i][1]*Start[1] + Planes[i][2]*Start[2];
+    if (NdotDir == 0)                // CHECK IF RAY IS PARALLEL TO THE SLAB PLANES
+    {
+      if (NdotStart > -Planes[i][3]) return(0); // IF STARTS "OUTSIDE", NO INTERSECTION
+    }
+    else
+    {
+      NewT = (-Planes[i][3] - NdotStart) / NdotDir;      // FIND HIT "TIME" (DISTANCE)
+      if (NdotDir < 0) { if (NewT > *InT) *InT=NewT; }   // IF "FRONTFACING", MUST BE NEW IN "TIME"
+                  else { if (NewT < *OutT) *OutT=NewT; } // IF "BACKFACING", MUST BE NEW OUT "TIME"
+    }
+    if (*InT > *OutT) return(0);   // CHECK FOR EARLY EXITS (INTERSECTION INTERVAL "OUTSIDE")
+  }
+
+  // IF AT LEAST ONE THE Tvals ARE IN THE INTERVAL [0,1] WE HAVE INTERSECTION
+  if (*InT>=0 || *OutT>=0) return(1);
+  return(0);
+}      
+
+//--------------------------------------------------------------------------
+// returns whether or not an edge AB intersects a set of planes. The hit 
+// times are returned just as in the ray isect test.
+//--------------------------------------------------------------------------
+int PlanesEdgeIsect(const float Planes[][4], int NumPlanes,
+                    const float A[3], const float B[3], 
+                    float *InT, float *OutT)
+{
+  float Dir[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
+  if ( PlanesRayIsect(Planes,NumPlanes,A,Dir,InT,OutT) )
+    if (*InT>=0 && *InT<=1) return(1);
+    else if (*OutT>=0 && *OutT<=1) return(1);
+  return(0);
+}
diff --git a/simgear/scene/sky/clouds3d/plane.hpp b/simgear/scene/sky/clouds3d/plane.hpp
new file mode 100644 (file)
index 0000000..7d843ef
--- /dev/null
@@ -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 (file)
index 0000000..6d8098b
--- /dev/null
@@ -0,0 +1,166 @@
+//------------------------------------------------------------------------------
+// File : quat.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+/**************************************************************************
+  
+  quat.hpp
+
+  A quaternion template class
+
+  ---------------------------------------------------------------------
+
+  Feb 1998, Paul Rademacher (rademach@cs.unc.edu)  
+
+  Modification History:
+  - Oct 2000, Bill Baxter.  Adapted to GLVU coding conventions and
+      templetized.  Also implemented many methods that were declared but
+      not defined.  Added some methods from quatlib and other sources.
+                
+**************************************************************************/
+
+#ifndef _QUAT_H_
+#define _QUAT_H_
+
+#include "vec3f.hpp"
+#include "mat44.hpp"
+#include "mat33.hpp"
+
+/****************************************************************
+*                    Quaternion                                 *
+****************************************************************/
+
+template <class Type>
+class Quat
+{
+public:
+  typedef Vec3<Type> qvec;
+
+  Type s;  /* scalar component */
+  qvec v;  /* quat vector component */
+
+  /* Constructors */
+
+  Quat(void);
+  Quat(Type s, Type x, Type y, Type z);
+  Quat(Type x, Type y, Type z); // s=0
+  Quat(Type s, const qvec& v);
+  Quat(const qvec& v, Type s = 0.0); 
+  Quat(const Type *d);        /* copy from four-element Type array s,x,y,z */
+  Quat(const Quat &q);        /* copy from other Quat */
+
+  /* Setters */
+
+  void  Set( Type x, Type y, Type z );
+  void  Set( Type s, Type x, Type y, Type z );
+  void  Set( Type s, const qvec& v );
+  void  Set( const qvec& v, Type s=0 );
+
+  /* Operators */
+
+  Quat &operator  = ( const Quat &v );      /* assignment of a Quat */
+  Quat &operator += ( const Quat &v );      /* incrementation by a Quat */
+  Quat &operator -= ( const Quat &v );      /* decrementation by a Quat */
+  Quat &operator *= ( const Type d );       /* multiplication by a scalar */
+  Quat &operator *= ( const Quat &v );      /* quat product (this*v) */
+  Quat &operator /= ( const Type d );       /* division by a scalar */
+  Type &operator [] ( int i);               /* indexing s=0,x=1,y=2,z=3 */
+  
+  /* special functions */
+  
+  Type Length(void) const;                  /* length of a Quat */
+  Type LengthSqr(void) const;               /* squared length of a Quat */
+  Type Norm(void) const;                    /* also squared length of a Quat */
+  Quat &Normalize(void);                    /* normalize a Quat */
+  Quat &Invert(void);                       /* q = q^-1 */
+  Quat &Conjugate(void);                    /* q = q* */
+  qvec Xform( const qvec &v ) const;        /* q*v*q-1 */
+  Quat &Log(void);                          /* log(q) */
+  Quat &Exp(void);                          /* exp(q) */
+  qvec GetAxis( void ) const;               /* Get rot axis */
+  Type GetAngle( void ) const;              /* Get rot angle (radians) */
+  void SetAngle( Type rad_ang );            /* set rot angle (radians) */
+  void ScaleAngle( Type f );                /* scale rot angle */
+  void Print( ) const;                      /* print Quat */
+
+  /* Conversions */
+  Mat44<Type>& ToMat( Mat44<Type> &dest ) const;   /* to 4x4 matrix */
+  Mat33<Type>& ToMat( Mat33<Type> &dest ) const;   /* to 3x3 matrix */
+  Quat& FromMat( const Mat44<Type>& src );         /* from 4x4 rot matrix */
+  Quat& FromMat( const Mat33<Type>& src );         /* from 3x3 rot matrix */
+
+  void ToAngleAxis( Type &ang, qvec &ax ) const;  /* to rot angle AND axis */
+  Quat& FromAngleAxis( Type ang, const qvec &ax );/*from rot angle AND axis */
+  Quat& FromTwoVecs(const qvec &a, const qvec& b); /* quat from a to b */
+  // to/from Euler Angles (XYZ-Fixed/ZYX-Relative, angles in radians)
+  // See quatimpl.hpp for more detailed comments.
+  Quat& FromEuler( Type yaw_Z, Type pitch_Y, Type roll_X);
+  void ToEuler(Type &yaw_Z, Type &pitch_Y, Type &roll_X) const;
+  
+
+  // HELPERS
+  static Type DEG2RAD(Type d);
+  static Type RAD2DEG(Type d);
+  static Type Sin(double d);
+  static Type Cos(double d);
+  static Type ACos(double d);
+  static Type ASin(double d);
+  static Type ATan(double d);
+  static Type ATan2(double n, double d);
+
+  // CONSTANTS
+  static Type FUDGE();
+  static Quat ZERO();
+  static Quat IDENTITY();
+}; 
+
+/* Utility functions */
+template <class Type>
+Quat<Type>& QuatSlerp(
+  Quat<Type> &dest, const Quat<Type>& from, const Quat<Type>& to, Type t );
+template <class Type>
+Quat<Type> QuatSlerp(const Quat<Type>& from, const Quat<Type>& to, Type t );
+
+/* "Friends" */
+template <class Type>
+Quat<Type> operator -(const Quat<Type> &v);                      // -q1
+template <class Type>
+Quat<Type> operator +(const Quat<Type> &a, const Quat<Type> &b); // q1 + q2
+template <class Type>
+Quat<Type> operator -(const Quat<Type> &a, const Quat<Type> &b); // q1 - q2
+template <class Type>
+Quat<Type> operator *(const Quat<Type> &a, const Type d);        // q1 * 3.0
+template <class Type>
+Quat<Type> operator *(const Type d, const Quat<Type> &a);        // 3.0 * q1
+template <class Type>
+Quat<Type> operator *(const Quat<Type> &a, const Quat<Type> &b); // q1 * q2
+template <class Type>
+Quat<Type> operator /(const Quat<Type> &a, const Type d);        // q1 / 3.0
+template <class Type>
+bool operator ==(const Quat<Type> &a, const Quat<Type> &b);      // q1 == q2 ?
+template <class Type>
+bool operator !=(const Quat<Type> &a, const Quat<Type> &b);      // q1 != q2 ?
+
+
+
+#include "quatimpl.hpp"
+
+
+
+typedef Quat<float> Quatf;
+typedef Quat<double> Quatd;
+
+#endif
diff --git a/simgear/scene/sky/clouds3d/quatimpl.hpp b/simgear/scene/sky/clouds3d/quatimpl.hpp
new file mode 100644 (file)
index 0000000..0d6fb56
--- /dev/null
@@ -0,0 +1,886 @@
+//------------------------------------------------------------------------------
+// File : quatimpl.hpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+/***********************************************************************
+
+  quatimpl.hpp
+
+  A quaternion template class 
+
+  -------------------------------------------------------------------
+
+  Feb 1998, Paul Rademacher (rademach@cs.unc.edu)
+  Oct 2000, Bill Baxter
+
+  Modification History:
+  - See main header file, quat.hpp
+
+************************************************************************/
+
+#include "quat.hpp"
+#include <math.h>
+#include <assert.h>
+
+
+//============================================================================
+// CONSTRUCTORS
+//============================================================================
+
+template <class Type>
+Quat<Type>::Quat( void )
+{
+  // do nothing so default construction is fast
+}
+
+template <class Type>
+Quat<Type>::Quat( Type _s, Type x, Type y, Type z )
+{
+  s = _s;
+  v.Set( x, y, z );
+}
+template <class Type>
+Quat<Type>::Quat( Type x, Type y, Type z )
+{
+  s = 0.0;
+  v.Set( x, y, z );
+}
+
+template <class Type>
+Quat<Type>::Quat( const qvec& _v, Type _s )
+{
+  Set( _v, _s );
+}
+
+template <class Type>
+Quat<Type>::Quat( Type _s, const qvec& _v )
+{
+  Set( _v, _s );
+}
+
+
+template <class Type>
+Quat<Type>::Quat( const Type *d )
+{
+  s = *d++;
+  v.Set(d);
+}
+
+template <class Type>
+Quat<Type>::Quat( const Quat &q )
+{
+  s = q.s;
+  v = q.v;
+}
+
+//============================================================================
+// SETTERS
+//============================================================================
+
+template <class Type>
+void Quat<Type>::Set( Type _s, Type x, Type y, Type z )
+{
+  s = _s;
+  v.Set(x,y,z);
+}
+template <class Type>
+void Quat<Type>::Set( Type x, Type y, Type z )
+{
+  s = 0.0;
+  v.Set(x,y,z);
+}
+
+template <class Type>
+void Quat<Type>::Set( const qvec& _v, Type _s )
+{
+  s = _s;
+  v = _v;
+}
+template <class Type>
+void Quat<Type>::Set( Type _s, const qvec& _v )
+{
+  s = _s;
+  v = _v;
+}
+
+
+//============================================================================
+// OPERATORS
+//============================================================================
+
+template <class Type>
+Quat<Type>& Quat<Type>::operator = (const Quat& q)
+{ 
+  v = q.v;  s = q.s; return *this; 
+}
+
+template <class Type>
+Quat<Type>& Quat<Type>::operator += ( const Quat &q )
+{
+  v += q.v; s += q.s; return *this;
+}
+
+template <class Type>
+Quat<Type>& Quat<Type>::operator -= ( const Quat &q )
+{
+  v -= q.v; s -= q.s; return *this;
+}
+
+template <class Type>
+Quat<Type> &Quat<Type>::operator *= ( const Type d ) 
+{
+  v *= d; s *= d; return *this;
+}
+
+template <class Type>
+Quat<Type> &Quat<Type>::operator *= ( const Quat& q ) 
+{
+#if 0
+  // Quaternion multiplication with 
+  // temporary object construction minimized (hopefully)
+  Type ns = s*q.s - v*q.v;
+  qvec nv(v^q.v);
+  v *= q.s;
+  v += nv;
+  nv.Set(s*q.v);
+  v += nv;
+  s = ns;
+  return *this;
+#else
+  // optimized (12 mults, and no compiler-generated temp objects)
+  Type A, B, C, D, E, F, G, H;
+
+  A = (s   + v.x)*(q.s   + q.v.x);
+  B = (v.z - v.y)*(q.v.y - q.v.z);
+  C = (s   - v.x)*(q.v.y + q.v.z); 
+  D = (v.y + v.z)*(q.s   - q.v.x);
+  E = (v.x + v.z)*(q.v.x + q.v.y);
+  F = (v.x - v.z)*(q.v.x - q.v.y);
+  G = (s   + v.y)*(q.s   - q.v.z);
+  H = (s   - v.y)*(q.s   + q.v.z);
+
+  v.x = A - (E + F + G + H) * Type(0.5); 
+  v.y = C + (E - F + G - H) * Type(0.5); 
+  v.z = D + (E - F - G + H) * Type(0.5);
+  s = B + (-E - F + G + H) * Type(0.5);
+
+  return *this;
+#endif
+}
+
+template <class Type>
+Quat<Type> &Quat<Type>::operator /= ( const Type d )
+{
+  Type r = Type(1.0)/d;
+  v *= r;
+  s *= r;
+  return *this;
+}
+
+template <class Type>
+Type &Quat<Type>::operator [] ( int i)
+{
+  switch (i) {
+    case 0: return s;
+    case 1: return v.x;
+    case 2: return v.y;
+    case 3: return v.z;
+  }
+  assert(false);
+  return s;
+}
+
+//============================================================================
+// SPECIAL FUNCTIONS
+//============================================================================
+template <class Type>
+inline Type Quat<Type>::Length( void ) const
+{
+  return Type( sqrt( v*v + s*s ) );
+}
+
+template <class Type>
+inline Type Quat<Type>::LengthSqr( void ) const
+{
+  return Norm();
+}
+
+template <class Type>
+inline Type Quat<Type>::Norm( void ) const
+{
+  return v*v + s*s;
+}
+
+template <class Type>
+inline Quat<Type>& Quat<Type>::Normalize( void )
+{
+  *this *= Type(1.0) / Type(sqrt(v*v + s*s));
+  return *this;
+}
+
+template <class Type>
+inline Quat<Type>& Quat<Type>::Invert( void )
+{
+  Type scale = Type(1.0)/Norm();
+  v *= -scale;
+  s *= scale;
+  return *this;
+}
+
+template <class Type>
+inline Quat<Type>& Quat<Type>::Conjugate( void )
+{
+  v.x = -v.x;
+  v.y = -v.y;
+  v.z = -v.z;
+  return *this;
+}
+
+
+//----------------------------------------------------------------------------
+// Xform
+//----------------------------------------------------------------------------
+// Transform a vector by this quaternion using q * v * q^-1
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>::qvec Quat<Type>::Xform( const qvec &vec ) const
+{
+  /* copy vector into temp quaternion for multiply     */
+  Quat  vecQuat(vec);
+  /* invert multiplier */
+  Quat  inverse(*this);
+  inverse.Invert();
+
+  /* do q * vec * q(inv)       */
+  Quat  tempVecQuat(*this * vecQuat);
+  tempVecQuat *= inverse;
+
+  /* return vector part */
+  return tempVecQuat.v;
+}
+
+//----------------------------------------------------------------------------
+// Log
+//----------------------------------------------------------------------------
+// Natural log of quat
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type> &Quat<Type>::Log(void)
+{
+  Type theta, scale;
+
+  scale = v.Length();
+  theta = ATan2(scale, s);
+
+  if (scale > 0.0)
+    scale = theta/scale;
+
+  v *= scale;
+  s = 0.0;
+  return *this;
+}
+
+//----------------------------------------------------------------------------
+// Exp
+//----------------------------------------------------------------------------
+// e to the quat: e^quat 
+// -- assuming scalar part 0
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type> &Quat<Type>::Exp(void)
+{
+  Type scale;
+  Type theta = v.Length();
+
+  if (theta > FUDGE()) {
+    scale = Sin(theta)/theta ;
+    v *= scale;
+  }
+
+  s = Cos(theta) ; 
+  return *this;
+}
+
+
+//----------------------------------------------------------------------------
+// SetAngle (radians)
+//----------------------------------------------------------------------------
+template <class Type>
+void Quat<Type>::SetAngle( Type f )
+{
+  qvec axis(GetAxis());
+  f *= Type(0.5);
+  s = Cos( f );
+  v = axis * Sin( f );
+}
+
+//----------------------------------------------------------------------------
+// ScaleAngle 
+//----------------------------------------------------------------------------
+template <class Type>
+inline void  Quat<Type>::ScaleAngle( Type f )
+{
+  SetAngle( f * GetAngle() );
+}
+
+//----------------------------------------------------------------------------
+// GetAngle (radians)
+//----------------------------------------------------------------------------
+// get rot angle in radians.  Assumes s is between -1 and 1, which will always
+// be the case for unit quaternions.
+//----------------------------------------------------------------------------
+template <class Type>
+inline Type Quat<Type>::GetAngle( void ) const
+{
+  return ( Type(2.0) * ACos( s ) );
+}
+
+//----------------------------------------------------------------------------
+// GetAxis
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>::qvec Quat<Type>::GetAxis( void ) const
+{
+  Type scale;
+
+  scale = Sin( acos( s ) ) ;
+  if ( scale < FUDGE() && scale > -FUDGE() )
+    return qvec( 0.0, 0.0, 0.0 );
+  else
+    return  v / scale;
+}
+
+//---------------------------------------------------------------------------- 
+// Print
+//---------------------------------------------------------------------------- 
+template <class Type>
+inline void Quat<Type>::Print( ) const
+{
+  printf( "(%3.2f, <%3.2f %3.2f %3.2f>)\n", s, v.x, v.y, v.z );
+}      
+
+
+//============================================================================
+// CONVERSIONS
+//============================================================================
+
+template <class Type>
+Mat44<Type>& Quat<Type>::ToMat( Mat44<Type>& dest ) const
+{
+  Type t, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
+  qvec  a, c, b, d;
+  
+  t  = Type(2.0) / (v*v + s*s);
+  const Type ONE(1.0);
+  
+  xs = v.x*t;   ys = v.y*t;   zs = v.z*t;
+  wx = s*xs;    wy = s*ys;    wz = s*zs;
+  xx = v.x*xs;  xy = v.x*ys;  xz = v.x*zs;
+  yy = v.y*ys;  yz = v.y*zs;  zz = v.z*zs;
+  
+  dest.Set( ONE-(yy+zz), xy-wz,       xz+wy,       0.0,
+            xy+wz,       ONE-(xx+zz), yz-wx,       0.0,
+            xz-wy,       yz+wx,       ONE-(xx+yy), 0.0,
+            0.0,         0.0,         0.0,         ONE );
+  
+  return dest;
+}
+
+template <class Type>
+Mat33<Type>&  Quat<Type>::ToMat( Mat33<Type>& dest ) const
+{
+  Type t, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
+  qvec  a, c, b, d;
+  
+  t  = Type(2.0) / Norm();
+  const Type ONE(1.0);
+  
+  xs = v.x*t;   ys = v.y*t;   zs = v.z*t;
+  wx = s*xs;    wy = s*ys;    wz = s*zs;
+  xx = v.x*xs;  xy = v.x*ys;  xz = v.x*zs;
+  yy = v.y*ys;  yz = v.y*zs;  zz = v.z*zs;
+  
+  dest.Set( ONE-(yy+zz), xy-wz,       xz+wy,       
+            xy+wz,       ONE-(xx+zz), yz-wx,       
+            xz-wy,       yz+wx,       ONE-(xx+yy) );
+
+  return dest;
+}
+
+//----------------------------------------------------------------------------
+// FromMat
+//----------------------------------------------------------------------------
+// Convert rotation matrix to quaternion
+// Results will be bad if matrix is not (very close to) orthonormal
+// Modified from gamasutra.com article:
+// http://www.gamasutra.com/features/programming/19980703/quaternions_07.htm
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>&  Quat<Type>::FromMat( const Mat44<Type>& m )
+{
+  Type tr = m.Trace();
+
+  // check the diagonal
+  if (tr > 0.0) {
+    Type scale = Type( sqrt (tr) );
+    s = scale * Type(0.5);
+    scale = Type(0.5) / scale;
+    v.x = (m(1,2) - m(2,1)) * scale;
+    v.y = (m(2,0) - m(0,2)) * scale;
+    v.z = (m(0,1) - m(1,0)) * scale;
+  } else {             
+    // diagonal is negative or zero
+    int i, j, k;
+    i = 0;
+    if (m(1,1) > m(0,0)) i = 1;
+    if (m(2,2) > m(i,i)) i = 2;
+    int nxt[3] = {1, 2, 0};
+    j = nxt[i];
+    k = nxt[j];
+
+    Type scale = Type( sqrt (Type(1.0) + m(i,i) - (m(j,j) + m(k,k)) ) );
+      
+    v[i] = scale * Type(0.5);
+            
+    if (scale != 0.0) scale = Type(0.5) / scale;
+
+    s = (m(j,k) - m(k,j)) * scale;
+    v[j] = (m(i,j) + m(j,i)) * scale;
+    v[k] = (m(i,k) + m(k,i)) * scale;
+  }
+  return *this;
+}
+
+template <class Type>
+Quat<Type>&  Quat<Type>::FromMat( const Mat33<Type>& m )
+{
+  Type tr = m.Trace();
+
+  // check the diagonal
+  if (tr > 0.0) {
+    Type scale = Type( sqrt (tr + Type(1.0)) );
+    s = scale * Type(0.5);
+    scale = Type(0.5) / scale;
+    v.x = (m(1,2) - m(2,1)) * scale;
+    v.y = (m(2,0) - m(0,2)) * scale;
+    v.z = (m(0,1) - m(1,0)) * scale;
+  } else {             
+    // diagonal is negative or zero
+    int i, j, k;
+    i = 0;
+    if (m(1,1) > m(0,0)) i = 1;
+    if (m(2,2) > m(i,i)) i = 2;
+    int nxt[3] = {1, 2, 0};
+    j = nxt[i];
+    k = nxt[j];
+
+    Type scale = Type( sqrt (Type(1.0) + m(i,i) - (m(j,j) + m(k,k)) ) );
+      
+    v[i] = scale * Type(0.5);
+            
+    if (scale != 0.0) scale = Type(0.5) / scale;
+
+    s = (m(j,k) - m(k,j)) * scale;
+    v[j] = (m(i,j) + m(j,i)) * scale;
+    v[k] = (m(i,k) + m(k,i)) * scale;
+  }
+  return *this;
+}
+
+//----------------------------------------------------------------------------
+// ToAngleAxis (radians)
+//----------------------------------------------------------------------------
+// Convert to angle & axis representation
+//----------------------------------------------------------------------------
+template <class Type>
+void Quat<Type>::ToAngleAxis( Type &angle, qvec &axis ) const
+{
+  Type cinv = ACos( s );
+  angle = Type(2.0) * cinv;
+
+  Type scale;
+
+  scale = Sin( cinv );
+  if ( scale < FUDGE() && scale > -FUDGE() )
+    axis = qvec::ZERO;
+  else {
+    axis = v;
+    axis /= scale;
+  }
+}
+
+//----------------------------------------------------------------------------
+// FromAngleAxis (radians)
+//----------------------------------------------------------------------------
+// Convert to quat from angle & axis representation
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>& Quat<Type>::FromAngleAxis( Type angle, const qvec &axis )
+{
+  /* normalize vector */
+  Type length = axis.Length();
+
+  /* if zero vector passed in, just set to identity quaternion */
+  if ( length < FUDGE() )
+  {
+    *this = IDENTITY();
+    return *this;
+  }
+  length = Type(1.0)/length;
+  angle *= 0.5;
+  v = axis;
+  v *= length;
+  v *= Sin(angle);
+
+  s = Cos(angle);
+  return *this;
+}
+
+//----------------------------------------------------------------------------
+// FromTwoVecs
+//----------------------------------------------------------------------------
+// Return the quat that rotates vector a into vector b
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>& Quat<Type>::FromTwoVecs(const qvec &a, const qvec& b)
+{
+  qvec u1(a);
+  qvec u2(b);
+  double theta ;                                    /* angle of rotation about axis */
+  double theta_complement ;
+  double crossProductMagnitude ;
+
+
+  // Normalize both vectors and take cross product to get rotation axis. 
+  u1.Normalize();
+  u2.Normalize();
+  qvec axis( u1 ^ u2 );
+
+
+  // | u1 X u2 | = |u1||u2|sin(theta)
+  //
+  // Since u1 and u2 are normalized, 
+  //
+  //  theta = arcsin(|axis|)
+  crossProductMagnitude = axis.Length();
+
+  // Occasionally, even though the vectors are normalized, the
+  // magnitude will be calculated to be slightly greater than one.  If
+  // this happens, just set it to 1 or asin() will barf.
+  if( crossProductMagnitude > Type(1.0) )
+    crossProductMagnitude = Type(1.0) ;
+
+  // Take arcsin of magnitude of rotation axis to compute rotation
+  // angle.  Since crossProductMagnitude=[0,1], we will have
+  // theta=[0,pi/2].
+  theta = ASin( crossProductMagnitude ) ;
+  theta_complement = Type(3.14159265358979323846) - theta ;
+
+  // If cos(theta) < 0, use complement of theta as rotation angle.
+  if( u1 * u2 < 0.0 )
+  {
+    double tmp = theta;
+    theta = theta_complement ;
+    theta_complement = tmp;
+  }
+
+  // if angle is 0, just return identity quaternion
+  if( theta < FUDGE() )
+  {
+    *this = IDENTITY();
+  }
+  else
+  {
+    if( theta_complement < FUDGE() )
+    {
+      // The two vectors are opposed.  Find some arbitrary axis vector.
+      // First try cross product with x-axis if u1 not parallel to x-axis.
+      if( (u1.y*u1.y + u1.z*u1.z) >= FUDGE() )
+      {
+        axis.Set( 0.0, u1.z, -u1.y ) ;
+      }
+      else
+      {
+        // u1 is parallel to to x-axis.  Use z-axis as axis of rotation.
+        axis.Set(0.0, 0.0, 1.0);
+      }
+    }
+
+    axis.Normalize();
+    FromAngleAxis(Type(theta), axis);
+    Normalize();
+  }
+  return *this;  
+}
+
+//----------------------------------------------------------------------------
+// FromEuler
+//----------------------------------------------------------------------------
+// converts 3 euler angles (in radians) to a quaternion
+//
+// angles are in radians; Assumes roll is rotation about X, pitch is
+// rotation about Y, yaw is about Z.  (So thinking of
+// Z as up) Assumes order of yaw, pitch, roll applied as follows:
+//
+//         p' = roll( pitch( yaw(p) ) )
+//
+// Where yaw, pitch, and roll are defined in the BODY coordinate sys.
+// In other words these are ZYX-relative (or XYZ-fixed) Euler Angles.
+//
+// For a complete Euler angle implementation that handles all 24 angle
+// sets, see "Euler Angle Conversion" by Ken Shoemake, in "Graphics
+// Gems IV", Academic Press, 1994
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>& Quat<Type>::FromEuler(Type yaw, Type pitch, Type roll)
+{
+  Type  cosYaw, sinYaw, cosPitch, sinPitch, cosRoll, sinRoll;
+  Type  half_roll, half_pitch, half_yaw;
+
+  /* put angles into radians and divide by two, since all angles in formula
+   *  are (angle/2)
+   */
+  const Type HALF(0.5);
+  half_yaw   = yaw   * HALF;
+  half_pitch = pitch * HALF;
+  half_roll  = roll  * HALF;
+
+  cosYaw = Cos(half_yaw);
+  sinYaw = Sin(half_yaw);
+
+  cosPitch = Cos(half_pitch);
+  sinPitch = Sin(half_pitch);
+
+  cosRoll = Cos(half_roll);
+  sinRoll = Sin(half_roll);
+
+  Type cpcy = cosPitch * cosYaw;
+  Type spsy = sinPitch * sinYaw;
+
+  v.x = sinRoll * cpcy              - cosRoll * spsy;
+  v.y = cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw;
+  v.z = cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw;
+  s   = cosRoll * cpcy              + sinRoll * spsy;
+
+  return *this;
+}
+
+//----------------------------------------------------------------------------
+// ToEuler
+//----------------------------------------------------------------------------
+// converts a quaternion to  3 euler angles (in radians)
+//
+// See FromEuler for details of which set of Euler Angles are returned
+//----------------------------------------------------------------------------
+template <class Type>
+void Quat<Type>::ToEuler(Type& yaw, Type& pitch, Type& roll) const
+{
+  // This is probably wrong
+  Mat33<Type> M;
+  ToMat(M);
+  const int i = 0, j = 1, k = 2;
+  double cy = sqrt(M(i,i)*M(i,i) + M(i,j)*M(i,j));
+  if (cy > FUDGE()) {
+    roll = ATan2(M(j,k), M(k,k));
+    pitch = ATan2(-M(i,k), cy);
+    yaw = ATan2(M(i,j), M(i,i));
+  } else {
+    roll = ATan2(-M(k,j), M(j,j));
+    pitch = ATan2(-M(i,k), cy);
+    yaw = 0;
+  }
+}
+
+//============================================================================
+// QUAT FRIENDS
+//============================================================================
+
+
+template <class Type>
+Quat<Type> operator + (const Quat<Type> &a, const Quat<Type> &b)
+{
+  return Quat<Type>( a.s+b.s, a.v+b.v );
+}
+
+template <class Type>
+Quat<Type> operator - (const Quat<Type> &a, const Quat<Type> &b)
+{
+  return Quat<Type>( a.s-b.s, a.v-b.v );
+}
+
+template <class Type>
+Quat<Type> operator - (const Quat<Type> &a )
+{
+  return Quat<Type>( -a.s, -a.v );
+}
+
+template <class Type>
+Quat<Type> operator * ( const Quat<Type> &a, const Quat<Type> &b)
+{
+#if 0
+  // 16 mults
+  return Quat<Type>( a.s*b.s - a.v*b.v, a.s*b.v + b.s*a.v + a.v^b.v );
+#else 
+  // optimized (12 mults, and no compiler-generated temp objects)
+  Type A, B, C, D, E, F, G, H;
+
+  A = (a.s   + a.v.x)*(b.s   + b.v.x);
+  B = (a.v.z - a.v.y)*(b.v.y - b.v.z);
+  C = (a.s   - a.v.x)*(b.v.y + b.v.z); 
+  D = (a.v.y + a.v.z)*(b.s   - b.v.x);
+  E = (a.v.x + a.v.z)*(b.v.x + b.v.y);
+  F = (a.v.x - a.v.z)*(b.v.x - b.v.y);
+  G = (a.s   + a.v.y)*(b.s   - b.v.z);
+  H = (a.s   - a.v.y)*(b.s   + b.v.z);
+
+  return Quat<Type>(
+    B + (-E - F + G + H) * Type(0.5),
+    A - (E + F + G + H) * Type(0.5), 
+    C + (E - F + G - H) * Type(0.5), 
+    D + (E - F - G + H) * Type(0.5));
+#endif
+}
+
+template <class Type>
+Quat<Type> operator * ( const Quat<Type> &a, const Type t)
+{
+  return Quat<Type>( a.v * t, a.s * t );
+}
+
+template <class Type>
+Quat<Type> operator * ( const Type t, const Quat<Type> &a )
+{
+  return Quat<Type>( a.v * t, a.s * t );
+}
+template <class Type>
+Quat<Type> operator / ( const Quat<Type> &a, const Type t )
+{
+  return Quat<Type>( a.v / t, a.s / t );
+}
+
+template <class Type>
+bool operator == (const Quat<Type> &a, const Quat<Type> &b)
+{
+  return (a.s == b.s && a.v == b.v);
+}
+template <class Type>
+bool operator != (const Quat<Type> &a, const Quat<Type> &b)
+{
+  return (a.s != b.s || a.v != b.v);
+}
+
+
+//============================================================================
+// UTILS
+//============================================================================
+template <class Type>
+inline Type Quat<Type>::DEG2RAD(Type d)
+{
+  return d * Type(0.0174532925199432957692369076848861);
+}
+template <class Type>
+inline Type Quat<Type>::RAD2DEG(Type d)
+{
+  return d * Type(57.2957795130823208767981548141052);
+}
+
+template <class Type>
+inline Type Quat<Type>::Sin(double d)  { return Type(sin(d)); }
+template <class Type>
+inline Type Quat<Type>::Cos(double d)  { return Type(cos(d)); }
+template <class Type>
+inline Type Quat<Type>::ACos(double d) { return Type(acos(d)); }
+template <class Type>
+inline Type Quat<Type>::ASin(double d) { return Type(asin(d)); }
+template <class Type>
+inline Type Quat<Type>::ATan(double d) { return Type(atan(d)); }
+template <class Type>
+inline Type Quat<Type>::ATan2(double n, double d) {return Type(atan2(n,d));}
+
+template <class Type>
+inline Quat<Type> Quat<Type>::ZERO() {return Quat(0,0,0,0); }
+template <class Type>
+inline Quat<Type> Quat<Type>::IDENTITY() {return Quat(1,0,0,0); }
+
+template<class Type>
+inline Type Quat<Type>::FUDGE()    { return 1e-6; }
+template<>
+inline double Quat<double>::FUDGE() { return 1e-10; }
+
+//----------------------------------------------------------------------------
+// QuatSlerp
+//----------------------------------------------------------------------------
+template <class Type>
+Quat<Type>& QuatSlerp(
+  Quat<Type> &dest, 
+  const Quat<Type> &from, const Quat<Type> &to, Type t )
+{
+#if 0
+  // compact mathematical version
+  // exp(t*log(to*from^-1))*from
+  Quat<Type> fminv(from); 
+  Quat<Type> tofrom(to*fminv.Invert());
+  Quat<Type> slerp = t*tofrom.Log();
+  slerp.Exp();
+  slerp *= from;
+  return slerp;
+#endif
+  Quat<Type> to1;
+  double omega, cosom, sinom, scale0, scale1;
+
+  /* calculate cosine */
+  cosom = from.v * to.v + from.s + to.s;
+
+  /* Adjust signs (if necessary) so we take shorter path */
+  if ( cosom < 0.0 ) {
+    cosom = -cosom;
+    to1 = -to;
+  }
+  else
+  {
+    to1 = to;
+  }
+
+  /* Calculate coefficients */
+  if ((1.0 - cosom) > Quat<Type>::FUDGE ) {
+    /* standard case (slerp) */
+    omega = acos( cosom );
+    sinom = sin( omega );
+    scale0 = sin((1.0 - t) * omega) / sinom;
+    scale1 = sin(t * omega) / sinom;
+  }
+  else {
+    /* 'from' and 'to' are very close - just do linear interpolation */
+    scale0 = 1.0 - t;
+    scale1 = t;      
+  }
+
+  dest = from;
+  dest *= Type(scale0);
+  dest += Type(scale1) * to1;
+  return dest;
+}
+
+// This version creates more temporary objects
+template <class Type>
+inline Quat<Type> QuatSlerp(
+  const Quat<Type>& from, const Quat<Type>& to, Type t )
+{
+  Quat<Type> q;
+  return QuatSlerp(q, from, to, t);
+}
+
+
diff --git a/simgear/scene/sky/clouds3d/quattest.cpp b/simgear/scene/sky/clouds3d/quattest.cpp
new file mode 100644 (file)
index 0000000..1c15fea
--- /dev/null
@@ -0,0 +1,196 @@
+//------------------------------------------------------------------------------
+// File : quattest.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//----------------------------------------------------------------------------
+// Quattest.cpp
+//  Quaternion coverage (and maybe functionality) test.
+//  The main objective is to just make sure every API gets called
+//  to flush out lurking template bugs that might not otherwise get tickled.
+//  A few checks to make sure things are functioning properly are also 
+//  included.
+//
+//  For the API coverage, if the thing simply compiles then it was a success.
+//----------------------------------------------------------------------------
+
+
+#include "quat.hpp"
+
+void coverage_test()
+{
+  float x = 0.5f, y = 1.1f, z = -0.1f, s = 0.2f;
+  // TEST CONSTRUCTORS
+  Quatf q1;
+  Quatf q2 = Quatf(x, y, z, s);
+  Quatf q3(x, y, z);
+  Quatf q4(Vec3f(1,2,3)); 
+  Quatf q5(Vec3f(2,3,4), 2.0);
+  Quatf q6(1.0, Vec3f(-1,-2,-3));
+  float floatarray[4] = { 1, 2, 3, 4 };
+  Quatf q7(floatarray);
+  Quatf q8(q7);
+
+  // TEST SETTERS
+  q1.Set(1,2,3);
+  q2.Set(1,2,3,4);
+  q3.Set(Vec3f(1.0,1.0,1.0));
+  q3.Set(Vec3f(1.0,1.0,1.0),-0.5);
+
+  // TEST OPERATORS
+  // Quat &operator  = ( const Quat &v );      /* assignment of a Quat */
+  q4 = q6;
+  // Quat &operator += ( const Quat &v );      /* incrementation by a Quat */
+  q3 += q2;
+  // Quat &operator -= ( const Quat &v );      /* decrementation by a Quat */
+  q3 -= q2;
+  // Quat &operator *= ( const Type d );       /* multiplication by a scalar */
+  q4 *= 0.5f;
+  // Quat &operator *= ( const Quat &v );      /* quat product (this*v) */
+  q2 *= q1;
+  // Quat &operator /= ( const Type d );       /* division by a scalar */
+  q5 /= 2.0f;
+  // Type &operator [] ( int i);               /* indexing x=0, s=3 */
+  float c0 = q1[0];
+  float c1 = q1[1];
+  float c2 = q1[2];
+  float c3 = q1[3];
+  
+  // TEST SPECIAL FUNCTIONS
+  
+  // Type Length(void) const;                  /* length of a Quat */
+  float l = q4.Length();
+  // Type LengthSqr(void) const;               /* squared length of a Quat */
+  l = q4.LengthSqr();
+  // Type LengthSqr(void) const;               /* squared length of a Quat */
+  l = q4.Norm();
+  // Quat &Normalize(void);                    /* normalize a Quat */
+  Quatf q9 = q4.Normalize();
+  // Quat &Invert(void);                       /* q = q^-1 */
+  q9 = q4.Invert();
+  // Quat &Conjugate(void);                    /* q = q* */
+  q9 = q4.Conjugate();
+  // qvec Xform( const qvec &v );              /* q*v*q-1 */
+  Vec3f v1 = q4.Xform(Vec3f(1.0,1.0,1.0));
+  // Quat &Log(void);                          /* log(q) */
+  q9 = q4.Log();
+  // Quat &Exp(void);                          /* exp(q) */
+  q9 = q4.Exp();
+  // qvec GetAxis( void ) const;               /* Get rot axis */
+  v1 = q5.GetAxis();
+  // Type GetAngle( void ) const;              /* Get rot angle (radians) */
+  float a = q5.GetAngle();
+  // void SetAngle( Type rad_ang );            /* set rot angle (radians) */
+  q2.SetAngle(a);
+  // void ScaleAngle( Type f );                /* scale rot angle */
+  q2.ScaleAngle(1.5);
+  // void Print( ) const;                      /* print Quat */
+  q3.Print();
+
+  /* TEST CONVERSIONS */
+  Mat44f m44;
+  Mat33f m33;
+  //Mat44& ToMat( Mat44 &dest ) const;        
+  //Mat33& ToMat( Mat33 &dest ) const;        
+  // Quat& FromMat( const Mat44<Type>& src ) const;
+  // Quat& FromMat( const Mat33<Type>& src ) const;
+  q3.Normalize();
+  m44 = q3.ToMat(m44);
+  m33 = q3.ToMat(m33);
+  q5 = q3.FromMat(m44);
+  q5 = q3.FromMat(m33);
+  //void ToAngleAxis( Type &ang, qvec &ax ) const;  
+  q3.ToAngleAxis( a, v1 );
+  //Quat& FromAngleAxis( Type ang, const qvec &ax );
+  q4 = q3.FromAngleAxis( a, v1 );
+  //Quat& FromTwoVecs(const qvec &a, const qvec& b); 
+  Vec3f v2(-1,-2,-3);
+  q4 = q3.FromTwoVecs( v2, v1 );
+  //Quat& FromEuler( Type yaw, Type pitch, Type roll);
+  q4 = q3.FromEuler( 2.2f, 1.2f, -0.4f );
+  //void ToEuler(Type &yaw, Type &pitch, Type &roll) const;
+  float p=0.3f,r=-1.57f; y= 0.1f;
+  q3.ToEuler( y,p,r );
+
+  /* TEST FRIENDS */
+
+  //friend Quat operator - (const Quat &v);                 /* -q1 */
+  q1 = -q2;
+  //friend Quat operator + (const Quat &a, const Quat &b);  /* q1 + q2 */
+  q1 = q2 + q3;
+  //friend Quat operator - (const Quat &a, const Quat &b);  /* q1 - q2 */
+  q1 = q2 - q3;
+  //friend Quat operator * (const Quat &a, const Type d);   /* q1 * 3.0 */
+  q1 = q2 * 0.2f;
+  //friend Quat operator * (const Type d, const Quat &a);   /* 3.0 * q1 */
+  q1 = 0.2f * q2;
+  //friend Quat operator * (const Quat &a, const Quat &b);  /* q1 * q2 */
+  q1 = q2 * q3;
+  //friend Quat operator / (const Quat &a, const Type d);   /* q1 / 3.0 */
+  q1 = q2 / 1.2f;
+  //friend bool operator == (const Quat &a, const Quat &b); /* q1 == q2 ? */
+  bool eq = (q1 == q2);
+  //friend bool operator != (const Quat &a, const Quat &b); /* q1 != q2 ? */
+  bool neq = (q1 != q2);
+
+  // HELPERS
+  // static Type DEG2RAD(Type d);
+  // static Type RAD2DEG(Type d);
+  a = Quatf::RAD2DEG(a);
+  a = Quatf::DEG2RAD(a);
+  a = Quatf::Sin(a);
+  a = Quatf::Cos(a);
+  a = Quatf::ACos(a);
+  a = Quatf::ASin(a);
+  a = Quatf::ATan(a);
+  a = Quatf::ATan2(a, p);
+
+  // CONSTANTS
+  // static const Type FUDGE;
+  // static const Quat ZERO;
+  // static const Quat IDENTITY;
+  a = Quatf::FUDGE;
+  q3 = Quatf::ZERO();
+  q4 = Quatf::IDENTITY();
+
+  q1 = QuatSlerp(q1, q3, q4, 0.5f );
+  q1 = QuatSlerp(q3, q4, 0.5f );
+  
+}
+
+Quatf StatQuat(Quatf::IDENTITY());
+Quatf StatQuat2 = Quatf::IDENTITY();
+
+void functional_test()
+{
+  printf("The ZERO quat: ");
+  Quatf::ZERO().Print();
+  printf("The IDENTITY quat: ");
+  Quatf::IDENTITY().Print();
+  printf("Statically constructed copy of IDENTITY quat: ");
+  StatQuat.Print();
+  printf("A different static copy of IDENTITY quat: ");
+  StatQuat2.Print();
+
+
+}
+
+int main(int argc, char *argv[])
+{
+  coverage_test();
+  functional_test();
+
+  return (0);
+}
diff --git a/simgear/scene/sky/clouds3d/tri.cpp b/simgear/scene/sky/clouds3d/tri.cpp
new file mode 100644 (file)
index 0000000..e4dc465
--- /dev/null
@@ -0,0 +1,106 @@
+//------------------------------------------------------------------------------
+// File : tri.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// tri.cpp : triangle defs and intersection routines.
+//============================================================================
+
+#include <math.h>
+
+//----------------------------------------------------------------------------
+// CHECKS IF 2D POINT P IS IN A 2D TRI ABC.
+//----------------------------------------------------------------------------
+int PtInTri2D(float Px, float Py, 
+              float Ax, float Ay, float Bx, float By, float Cx, float Cy)
+{
+  float dABx=Bx-Ax, dABy=By-Ay, dBCx=Cx-Bx, dBCy=Cy-By; // "REPEATS"
+  if (dABx*dBCy < dABy*dBCx) // CW
+  {
+    if (dABx*(Py-Ay) >= dABy*(Px-Ax)) return(0);        // ABxAP
+    if (dBCx*(Py-By) >= dBCy*(Px-Bx)) return(0);        // BCxBP
+    if ((Ax-Cx)*(Py-Cy) >= (Ay-Cy)*(Px-Cx)) return(0);  // CAxCP
+  }
+  else // CCW
+  {
+    if (dABx*(Py-Ay) < dABy*(Px-Ax)) return(0);         // ABxAP
+    if (dBCx*(Py-By) < dBCy*(Px-Bx)) return(0);         // BCxBP
+    if ((Ax-Cx)*(Py-Cy) < (Ay-Cy)*(Px-Cx)) return(0);   // CAxCP
+  }
+  return(1); // "INSIDE" EACH EDGE'S IN-HALF-SPACE (PT P IS INSIDE TRIANGLE)
+};
+
+//----------------------------------------------------------------------------
+// CHECKS IF 3D POINT P (ON ABC'S PLANE) IS IN 3D TRI ABC.
+// P=PtOnTriPlane, N=PlaneNormal (does not have to be normalized)
+//----------------------------------------------------------------------------
+int PtInTri3D(const float P[3], float N[3], 
+              const float A[3], const float B[3], const float C[3])
+{
+  #define ABS(x) (((x)<0)?(-(x)):x)  // HANDY UNIVERSAL ABSOLUTE VALUE FUNC
+
+  // DETERMINE LARGEST COMPONENT OF NORMAL (magnitude, since we want the largest projection)
+  N[0]=ABS(N[0]); N[1]=ABS(N[1]); N[2]=ABS(N[2]);
+
+  // PROJECT ONTO PLANE WHERE PERPENDICULAR TO LARGEST NORMAL COMPONENT AXIS
+  if (N[0]>N[1] && N[0]>N[2])      // X IS LARGEST SO PROJECT ONTO YZ-PLANE
+    return( PtInTri2D(P[1],P[2], A[1],A[2], B[1],B[2], C[1],C[2]) );
+  else if (N[1]>N[0] && N[1]>N[2]) // Y IS LARGEST SO PROJECT ONTO XZ-PLANE
+    return( PtInTri2D(P[0],P[2], A[0],A[2], B[0],B[2], C[0],C[2]) );
+  else                         // Z IS LARGEST SO PROJECT ONTO XY-PLANE
+    return( PtInTri2D(P[0],P[1], A[0],A[1], B[0],B[1], C[0],C[1]) );
+}
+
+//--------------------------------------------------------------------------
+// Checks if an edge UV intersects a triangle ABC. Returns whether or
+// not the edge intersects the plane (0 or 1) and the IsectPt.
+//--------------------------------------------------------------------------
+int EdgeTriIsect(const float U[3], const float V[3],
+                 const float A[3], const float B[3], const float C[3],
+                 float IsectPt[3])
+{
+  // CALCULATE PLANE EQUATION COEFFICIENTS P FOR TRI ABC
+  float P[4];
+  float u[3] = {B[0]-A[0],B[1]-A[1],B[2]-A[2]};
+  float v[3] = {C[0]-A[0],C[1]-A[1],C[2]-A[2]};
+  P[0] = u[1]*v[2] - u[2]*v[1];  // CROSS-PROD BETWEEN u AND v
+  P[1] = u[2]*v[0] - u[0]*v[2];  // DEFINES UNNORMALIZED NORMAL
+  P[2] = u[0]*v[1] - u[1]*v[0];
+  float l = (float)sqrt(P[0]*P[0] + P[1]*P[1] + P[2]*P[2]);  // NORMALIZE NORMAL
+  P[0]/=l; P[1]/=l; P[2]/=l; 
+  P[3] = -(P[0]*A[0] + P[1]*A[1] + P[2]*A[2]);
+
+  // FIND INTERSECTION OF EDGE UV WITH PLANE P
+  int EdgeIsectsPlane=0;
+  float Dir[3] = { V[0]-U[0], V[1]-U[1], V[2]-U[2] };
+  float NdotDir = P[0]*Dir[0] + P[1]*Dir[1] + P[2]*Dir[2];
+  float NdotU = P[0]*U[0] + P[1]*U[1] + P[2]*U[2];
+  if (NdotDir==(float)0) return(0);
+  float t = (-P[3] - NdotU) / NdotDir;
+  if (t>=0 && t<=1)
+  {
+    IsectPt[0] = U[0] + Dir[0]*t;
+    IsectPt[1] = U[1] + Dir[1]*t;
+    IsectPt[2] = U[2] + Dir[2]*t;
+    EdgeIsectsPlane=1;
+  }
+
+  // FIRST, DOES THE EDGE INTERSECT THE PLANE?
+  if (!EdgeIsectsPlane) return(0);
+
+  // SEE IF ISECT PT IS IN THE TRI
+  return( PtInTri3D(IsectPt,P,A,B,C) );
+}
diff --git a/simgear/scene/sky/clouds3d/tri.hpp b/simgear/scene/sky/clouds3d/tri.hpp
new file mode 100644 (file)
index 0000000..f4480da
--- /dev/null
@@ -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 (file)
index 0000000..6398462
--- /dev/null
@@ -0,0 +1,137 @@
+//-----------------------------------------------------------------------------
+// File : vec2f.hpp
+//-----------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//-----------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without
+// fee, provided that the above copyright notice appear in all copies
+// and that both that copyright notice and this permission notice
+// appear in supporting documentation.  Binaries may be compiled with
+// this software without any royalties or restrictions.
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//==========================================================================
+// vec2.hpp : 2d vector class template. Works for any integer or real type.
+//==========================================================================
+
+#ifndef VEC2_H
+#define VEC2_H
+
+#include <stdio.h>
+#include <math.h>
+
+template<class Type>
+class Vec2
+{
+  public:
+    Type x, y;
+
+    Vec2 (void) {};
+    Vec2 (const Type X, const Type Y) { x=X; y=Y; };
+    Vec2 (const Vec2& v) { x=v.x; y=v.y; };
+    Vec2 (const Type v[2]) { x=v[0]; y=v[1]; };
+    void Set (const Type X, const Type Y) { x=X; y=Y; }
+    void Set (const Type v[2]) { x=v[0]; y=v[1]; };
+
+    operator Type*()                            // Type * CONVERSION
+      { return (Type *)&x; }
+    operator const Type*() const                // CONST Type * CONVERSION
+      { return &x; }
+
+    Vec2& operator = (const Vec2& A)            // ASSIGNMENT (=)
+      { x=A.x; y=A.y;
+        return(*this);  };
+
+    bool operator == (const Vec2& A) const       // COMPARISON (==)
+      { return (x==A.x && y==A.y); }
+    bool operator != (const Vec2& A) const       // COMPARISON (!=)
+      { return (x!=A.x || y!=A.y); }
+
+    Vec2 operator + (const Vec2& A) const       // ADDITION (+)
+      { Vec2 Sum(x+A.x, y+A.y); 
+        return(Sum); }
+    Vec2 operator - (const Vec2& A) const       // SUBTRACTION (-)
+      { Vec2 Diff(x-A.x, y-A.y);
+        return(Diff); }
+    Type operator * (const Vec2& A) const       // DOT-PRODUCT (*)
+      { Type DotProd = x*A.x+y*A.y; 
+        return(DotProd); }
+    Type operator / (const Vec2& A) const       // CROSS-PRODUCT (/)
+      { Type CrossProd = x*A.y-y*A.x;
+        return(CrossProd); }
+    Type operator ^ (const Vec2& A) const       // ALSO CROSS-PRODUCT (^)
+      { Type CrossProd = x*A.y-y*A.x;
+        return(CrossProd); }
+    Vec2 operator * (const Type s) const        // MULTIPLY BY SCALAR (*)
+      { Vec2 Scaled(x*s, y*s); 
+        return(Scaled); }
+    Vec2 operator / (const Type s) const        // DIVIDE BY SCALAR (/)
+      { Vec2 Scaled(x/s, y/s);
+        return(Scaled); }
+    Vec2 operator & (const Vec2& A) const       // COMPONENT MULTIPLY (&)
+      { Vec2 CompMult(x*A.x, y*A.y);
+        return(CompMult); }
+
+    friend inline Vec2 operator *(Type s, const Vec2& v)  // SCALAR MULT s*V
+      { return Vec2(v.x*s, v.y*s); }
+
+    Vec2& operator += (const Vec2& A)  // ACCUMULATED VECTOR ADDITION (+=)
+      { x+=A.x; y+=A.y; return *this; }
+    Vec2& operator -= (const Vec2& A)  // ACCUMULATED VECTOR SUBTRACTION (-=)
+      { x-=A.x; y-=A.y; return *this; }
+    Vec2& operator *= (const Type s)   // ACCUMULATED SCALAR MULT (*=)
+      { x*=s; y*=s; return *this; }
+    Vec2& operator /= (const Type s)   // ACCUMULATED SCALAR DIV (/=)
+      { x/=s; y/=s; return *this; }
+    Vec2& operator &= (const Vec2& A)  // ACCUMULATED COMPONENT MULTIPLY (&=)
+      { x*=A.x; y*=A.y; return *this; }
+    Vec2 operator - (void) const      // NEGATION (-)
+      { Vec2 Negated(-x, -y);
+        return(Negated); };
+
+/*
+    const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
+      { return( (i==0)?x:y ); };
+    Type & operator [] (const int i)
+      { return( (i==0)?x:y ); };
+*/
+
+    Type Length (void) const                     // LENGTH OF VECTOR
+      { return ((Type)sqrt(x*x+y*y)); };
+    Type LengthSqr (void) const                  // LENGTH OF VECTOR (SQUARED)
+      { return (x*x+y*y); };
+    Vec2& Normalize (void)                       // NORMALIZE VECTOR
+      { Type L = Length();                       // CALCULATE LENGTH
+        if (L>0) { x/=L; y/=L; }
+        return *this;
+      };                                          // DIV COMPONENTS BY LENGTH
+
+    Vec2 Perpendicular() const                    // RETURNS A PERPENDICULAR
+      { Vec2 Perp(-y,x);
+        return(Perp); }
+
+    void UpdateMinMax(Vec2 &Min, Vec2 &Max)
+    {
+      if (x<Min.x) Min.x=x; else if (x>Max.x) Max.x=x;
+      if (y<Min.y) Min.y=y; else if (y>Max.y) Max.y=y;
+    }
+
+    void Print() const
+      { printf("(%.3f, %.3f)\n",x, y); }
+
+    static Vec2 ZERO;
+};
+
+typedef Vec2<float> Vec2f;
+typedef Vec2<double> Vec2d;
+
+template<class Type> Vec2<Type> Vec2<Type>::ZERO = Vec2<Type>(0,0);
+
+#endif
+
+
diff --git a/simgear/scene/sky/clouds3d/vec3f.hpp b/simgear/scene/sky/clouds3d/vec3f.hpp
new file mode 100644 (file)
index 0000000..f39dede
--- /dev/null
@@ -0,0 +1,244 @@
+//-----------------------------------------------------------------------------
+// File : vec3f.hpp
+//-----------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//-----------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without
+// fee, provided that the above copyright notice appear in all copies
+// and that both that copyright notice and this permission notice
+// appear in supporting documentation.  Binaries may be compiled with
+// this software without any royalties or restrictions.
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//==========================================================================
+// Vec3.hpp : 3d vector class template. Works for any integer or real type.
+//==========================================================================
+
+#ifndef VEC3_H
+#define VEC3_H
+
+#include <stdio.h>
+#include <math.h>
+
+/**
+ * @class Vec3
+ * @brief A templated 3-vector class
+ *
+ * Everybody in graphics has to write their own basic 3-vector class.
+ * And we're no exception.  This one uses templates, so that with one
+ * definition of the class you can have a 3-vector of floats or doubles
+ * depending on how precise you are, or you can make 3-vectors of ints
+ * or unsigned char, handy for representing colors.
+ *
+ * A couple of typedefs for common instatiations are provided by
+ * default: Vec3f, and Vec3d, the float and double versions,
+ * respectively.
+ *
+ */
+template<class Type>
+class Vec3
+{
+  public:
+    Type x, y, z;  ///< The storage for the three components of the vector
+
+    /// Default constructor.
+    /// Note: does \em not initialize x, y, and z!
+    Vec3 (void) 
+      {};
+    /// Three component constructor
+    Vec3 (const Type X, const Type Y, const Type Z) 
+      { x=X; y=Y; z=Z; };
+    /// Copy constructor
+    Vec3 (const Vec3& v) 
+      { x=v.x; y=v.y; z=v.z; };
+    /// Construct from array
+    Vec3 (const Type v[3])
+      { x=v[0]; y=v[1]; z=v[2]; };
+    /// Set from components
+    void Set (const Type X, const Type Y, const Type Z)
+      { x=X; y=Y; z=Z; }
+    /// Set from array
+    void Set (const Type v[3])
+      { x=v[0]; y=v[1]; z=v[2]; };
+
+    operator Type*()                            /// Type * CONVERSION
+      { return (Type *)&x; }
+    operator const Type*() const                /// CONST Type * CONVERSION
+      { return &x; }
+
+    bool operator == (const Vec3& A) const       /// COMPARISON (==)
+      { return (x==A.x && y==A.y && z==A.z); }
+    bool operator != (const Vec3& A) const       /// COMPARISON (!=)
+      { return (x!=A.x || y!=A.y || z!=A.z); }
+
+    Vec3& operator = (const Vec3& A)            /// ASSIGNMENT (=)
+      { x=A.x; y=A.y; z=A.z; 
+        return(*this);  };
+    Vec3 operator + (const Vec3& A) const       /// ADDITION (+)
+      { Vec3 Sum(x+A.x, y+A.y, z+A.z); 
+        return(Sum); };
+    Vec3 operator - (const Vec3& A) const       /// SUBTRACTION (-)
+      { Vec3 Diff(x-A.x, y-A.y, z-A.z);
+        return(Diff); };
+    Type operator * (const Vec3& A) const       /// DOT-PRODUCT (*)
+      { Type DotProd = x*A.x+y*A.y+z*A.z; 
+        return(DotProd); };
+    Vec3 operator / (const Vec3& A) const       /// CROSS-PRODUCT (/)
+      { Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
+        return(CrossProd); };
+    Vec3 operator ^ (const Vec3& A) const       /// ALSO CROSS-PRODUCT (^)
+      { Vec3 CrossProd(y*A.z-z*A.y, z*A.x-x*A.z, x*A.y-y*A.x);
+        return(CrossProd); };
+    Vec3 operator * (const Type s) const        /// MULTIPLY BY SCALAR V*s (*)
+      { Vec3 Scaled(x*s, y*s, z*s); 
+        return(Scaled); };
+    Vec3 operator / (const Type s) const        /// DIVIDE BY SCALAR (/)
+      { Vec3 Scaled(x/s, y/s, z/s);
+        return(Scaled); };
+    Vec3 operator & (const Vec3& A) const       /// COMPONENT MULTIPLY (&)
+      { Vec3 CompMult(x*A.x, y*A.y, z*A.z);
+        return(CompMult); }
+
+    friend inline Vec3 operator *(Type s, const Vec3& v)  /// SCALAR MULT s*V
+      { return Vec3(v.x*s, v.y*s, v.z*s); }
+
+    Vec3& operator += (const Vec3& A)    /// ACCUMULATED VECTOR ADDITION (+=)
+      { x+=A.x; y+=A.y; z+=A.z;
+        return *this;}
+    Vec3& operator -= (const Vec3& A)    /// ACCUMULATED VECTOR SUBTRACTION (-=)
+      { x-=A.x; y-=A.y; z-=A.z; 
+        return *this; }
+    Vec3& operator *= (const Type s)     /// ACCUMULATED SCALAR MULT (*=)
+      { x*=s; y*=s; z*=s; 
+        return *this; }
+    Vec3& operator /= (const Type s)     /// ACCUMULATED SCALAR DIV (/=)
+      { x/=s; y/=s; z/=s; 
+        return *this; }
+    Vec3& operator &= (const Vec3& A)  /// ACCUMULATED COMPONENT MULTIPLY (&=)
+      { x*=A.x; y*=A.y; z*=A.z; return *this; }
+    Vec3 operator - (void) const        /// NEGATION (-)
+      { Vec3 Negated(-x, -y, -z);
+        return(Negated); };
+
+/*
+    const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
+      { return( (i==0)?x:((i==1)?y:z) ); };
+    Type & operator [] (const int i)
+      { return( (i==0)?x:((i==1)?y:z) ); };
+*/
+
+    Type Length (void) const                     /// LENGTH OF VECTOR
+      { return ((Type)sqrt(x*x+y*y+z*z)); };
+    Type LengthSqr (void) const                  /// LENGTH OF VECTOR (SQUARED)
+      { return (x*x+y*y+z*z); };
+    Vec3& Normalize (void)                       /// NORMALIZE VECTOR
+      { Type L = Length();                       //  CALCULATE LENGTH
+        if (L>0) { x/=L; y/=L; z/=L; }           //  DIV COMPONENTS BY LENGTH
+        return *this;
+      };                                         
+
+    /// Returns the 'star' matrix for a vector
+    /** This is the skew-symmetric matrix \b A such that 
+     *  \b A \b v == \p this x \b v 
+     * (the cross-product of \p this and \b v), for any vector \b v.
+     *  The matrix looks like this given vector (x,y,z):
+     *  @verbatim
+            | 0  -z   y|
+            | z   0  -x|
+            |-y   x   0|
+        @endverbatim
+     * 
+     * Return format is just an array in row-major (OpenGL/Fortran) order. 
+     * That is [0, -z, y, z, 0, -x, -y, x, 0].
+     */
+    Type* Star() const {
+      Type s[] = ( 0, -z,  y,
+                   z,  0, -x,
+                  -y,  x,  0);
+      return s;
+    }
+
+    /// Update \p Min and \p Max to enclose \p this
+    /** A very handy routine for working with min-max or axis aligned 
+     *  bounding boxes.
+     */
+    void UpdateMinMax(Vec3 &Min, Vec3 &Max) const
+    {
+      if (x<Min.x) Min.x=x; else if (x>Max.x) Max.x=x;
+      if (y<Min.y) Min.y=y; else if (y>Max.y) Max.y=y;
+      if (z<Min.z) Min.z=z; else if (z>Max.z) Max.z=z;
+    }
+
+    /// Construct an orthonormal basis from \p this
+    /** Compute two unit vectors \p U and \p V that are orthogonal
+     * to this vector and to each other.  Note that \p *this need
+     * not be a unit vector.
+     *
+     * The algorithm works as follows:
+     * Find smallest component of L (this), zero it, 
+     * negate one of the other two and swap them.  Then normalize.
+     * Ex. if x1 is the smallest, assign (x2,y2,z2):=(0,z1,-y1)
+     * Clearly now v1 dot v2 = x1*0 + y1*z1 + z1*-y1 = 0;
+     * Zeroing out the smallest means that the magnitude of 
+     * the remaining vector will be as  big as possible so that 
+     * when we normalize, we are safe from dividing by anything
+     * close to zero (unless *this was near 0 magnitude to 
+     * begin with, in which case lack of precision can't be avoided)
+     */
+  void CompleteOrthonormalBasis(Vec3 &U, Vec3 &V) const
+    {
+      U = *this;
+      unsigned char s[3] = {0, 1, 2}; 
+      unsigned char tmpa;
+      U.x = U.x < 0 ? -U.x : -U.x;
+      U.y = U.y < 0 ? -U.y : -U.y;
+      U.z = U.z < 0 ? -U.z : -U.z;
+      if ( U[0] > U[1] )
+      {
+        tmpa = s[0];
+        s[0] = s[1];
+        s[1] = tmpa;
+      }
+      // xy min in s[0] now.
+      if ( U[s[0]] > U[2] ) {
+        tmpa = s[2];
+        s[2] = s[0];
+        s[0] = tmpa;
+      }
+      // xyz min in s[0] now
+      U = *this;
+      U[s[0]] = 0;
+
+      // Voila U is now perpendicular to *this
+      U.Normalize();
+
+      // And so it's easy to find a v that is too, with cross product.
+      V = *this ^ U;
+      // Or by removing components projected onto other two...
+      // I think the cross product may be cheaper
+      // V = something - V * (*this.Normalize() + U);
+
+      V.Normalize(); // wouldn't be necessary if we knew *this were normalized
+    }
+
+    /// Dump the vector to \c stdout in a pretty way
+    void Print() const
+      { printf("(%.3f, %.3f, %.3f)\n",x, y, z); }
+
+    /// This is a handy way to get the zero vector just use Vec3<Type>::ZERO
+    static Vec3 ZERO;
+};
+
+typedef Vec3<float> Vec3f;
+typedef Vec3<double> Vec3d;
+
+template<class Type> Vec3<Type> Vec3<Type>::ZERO = Vec3<Type>(0,0,0);
+
+#endif
+
+
diff --git a/simgear/scene/sky/clouds3d/vec3fv.cpp b/simgear/scene/sky/clouds3d/vec3fv.cpp
new file mode 100644 (file)
index 0000000..2711326
--- /dev/null
@@ -0,0 +1,95 @@
+//------------------------------------------------------------------------------
+// File : vec3fv.cpp
+//------------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//------------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software and its 
+// documentation for any purpose is hereby granted without fee, provided that 
+// the above copyright notice appear in all copies and that both that copyright 
+// notice and this permission notice appear in supporting documentation. 
+// Binaries may be compiled with this software without any royalties or 
+// restrictions. 
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//============================================================================
+// vec3fv.cpp
+//============================================================================
+
+#include <stdio.h>
+#include <math.h>
+
+void Set3fv(float v[3], float x, float y, float z)
+{
+  v[0]=x;
+  v[1]=y;
+  v[2]=z;
+}
+
+void Copy3fv(float A[3], const float B[3]) // A=B
+{
+  A[0]=B[0];
+  A[1]=B[1];
+  A[2]=B[2];
+}
+
+void ScalarMult3fv(float c[3], const float a[3], float s) // c=a*s
+{
+  c[0] = a[0] * s;
+  c[1] = a[1] * s;
+  c[2] = a[2] * s;
+}
+
+void ScalarDiv3fv(float v[3], float s)
+{
+  v[0] /= s;
+  v[1] /= s;
+  v[2] /= s;
+}
+
+void Add3fv(float c[3], const float a[3], const float b[3]) // c = a + b
+{
+  c[0] = a[0] + b[0];
+  c[1] = a[1] + b[1];
+  c[2] = a[2] + b[2];
+}
+
+void Subtract3fv(float c[3], const float a[3], const float b[3]) // c = a - b
+{
+  c[0] = a[0] - b[0];
+  c[1] = a[1] - b[1];
+  c[2] = a[2] - b[2];
+}
+
+void Negate3fv(float a[3], const float b[3])  // a = -b
+{
+  a[0] = -b[0];
+  a[1] = -b[1];
+  a[2] = -b[2];
+}
+
+float Length3fv(const float v[3])
+{
+  return( (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
+}
+
+void Normalize3fv(float v[3])
+{
+  float l = Length3fv(v);
+  v[0] /= l;
+  v[1] /= l;
+  v[2] /= l;
+}
+
+float DotProd3fv(const float a[3], const float b[3])
+{
+  return( a[0]*b[0] + a[1]*b[1] + a[2]*b[2] );
+}
+
+void CrossProd3fv(float* C, const float* A, const float* B) // C = A X B
+{ 
+  Set3fv(C, A[1]*B[2]-A[2]*B[1], A[2]*B[0]-A[0]*B[2], A[0]*B[1]-A[1]*B[0]);
+}
diff --git a/simgear/scene/sky/clouds3d/vec3fv.hpp b/simgear/scene/sky/clouds3d/vec3fv.hpp
new file mode 100644 (file)
index 0000000..d0cb2a8
--- /dev/null
@@ -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 (file)
index 0000000..6de765e
--- /dev/null
@@ -0,0 +1,136 @@
+//-----------------------------------------------------------------------------
+// File : vec4f.hpp
+//-----------------------------------------------------------------------------
+// GLVU : Copyright 1997 - 2002 
+//        The University of North Carolina at Chapel Hill
+//-----------------------------------------------------------------------------
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without
+// fee, provided that the above copyright notice appear in all copies
+// and that both that copyright notice and this permission notice
+// appear in supporting documentation.  Binaries may be compiled with
+// this software without any royalties or restrictions.
+//
+// The University of North Carolina at Chapel Hill makes no representations 
+// about the suitability of this software for any purpose. It is provided 
+// "as is" without express or implied warranty.
+
+//==========================================================================
+// vec4.hpp : 4d vector class template. Works for any integer or real type.
+//==========================================================================
+
+#ifndef VEC4_H
+#define VEC4_H
+
+#include <stdio.h>
+#include <math.h>
+
+template <class Type>
+class Vec4
+{
+  public:
+    Type x, y, z, w;
+
+    Vec4 (void) 
+      {};
+    Vec4 (const Type X, const Type Y, const Type Z, const Type W) 
+      { x=X; y=Y; z=Z; w=W; };
+    Vec4 (const Vec4& v) 
+      { x=v.x; y=v.y; z=v.z; w=v.w; };
+    Vec4 (const Type v[4])
+      { x=v[0]; y=v[1]; z=v[2]; w=v[3]; };
+    void Set (const Type X, const Type Y, const Type Z, const Type W)
+      { x=X; y=Y; z=Z; w=W; }
+    void Set (const Type v[4])
+      { x=v[0]; y=v[1]; z=v[2]; w=v[3]; };
+
+    operator Type*()                             // Type * CONVERSION
+      { return (Type *)&x; }
+    operator const Type*() const                 // CONST Type * CONVERSION
+      { return &x; }
+
+    Vec4& operator = (const Vec4& A)            // ASSIGNMENT (=)
+      { x=A.x; y=A.y; z=A.z; w=A.w; 
+        return(*this);  };
+
+    bool operator == (const Vec4& A) const        // COMPARISON (==)
+      { return (x==A.x && y==A.y && 
+        z==A.z && w==A.w); }
+    bool operator != (const Vec4& A) const        // COMPARISON (!=)
+      { return (x!=A.x || y!=A.y || 
+        z!=A.z || w!=A.w); }
+
+    Vec4 operator + (const Vec4& A) const       // ADDITION (+)
+      { Vec4 Sum(x+A.x, y+A.y, z+A.z, w+A.w); 
+        return(Sum); };
+    Vec4 operator - (const Vec4& A) const       // SUBTRACTION (-)
+      { Vec4 Diff(x-A.x, y-A.y, z-A.z, w-A.w);
+        return(Diff); };
+    Type operator * (const Vec4& A) const       // DOT-PRODUCT (*)
+      { Type DotProd = x*A.x+y*A.y+z*A.z+w*A.w; 
+        return(DotProd); };
+    Vec4 operator * (const Type s) const        // MULTIPLY BY SCALAR (*)
+      { Vec4 Scaled(x*s, y*s, z*s, w*s); 
+        return(Scaled); };
+    Vec4 operator / (const Type s) const        // DIVIDE BY SCALAR (/)
+      { Vec4 Scaled(x/s, y/s, z/s, w/s);
+        return(Scaled); };
+    Vec4 operator & (const Vec4& A) const       // COMPONENT MULTIPLY (&)
+      { Vec4 CompMult(x*A.x, y*A.y, z*A.z, w*A.w);
+        return(CompMult); }
+
+    friend inline Vec4 operator *(Type s, const Vec4& v)  // SCALAR MULT s*V
+      { return Vec4(v.x*s, v.y*s, v.z*s, v.w*s); }
+
+    Vec4& operator += (const Vec4& A)      // ACCUMULATED VECTOR ADDITION (+=)
+      { x+=A.x; y+=A.y; z+=A.z; w+=A.w; 
+        return *this; }
+    Vec4& operator -= (const Vec4& A)      // ACCUMULATED VECTOR SUBTRCT (-=)
+      { x-=A.x; y-=A.y; z-=A.z; w-=A.w;
+        return *this; }
+    Vec4& operator *= (const Type s)       // ACCUMULATED SCALAR MULT (*=)
+      { x*=s; y*=s; z*=s; w*=s; 
+        return *this; }
+    Vec4& operator /= (const Type s)       // ACCUMULATED SCALAR DIV (/=)
+      { x/=s; y/=s; z/=s; w/=s;
+        return *this; }
+    Vec4& operator &= (const Vec4& A)  // ACCUMULATED COMPONENT MULTIPLY (&=)
+      { x*=A.x; y*=A.y; z*=A.z; w*=A.w; return *this; }
+    Vec4 operator - (void) const          // NEGATION (-)
+      { Vec4 Negated(-x, -y, -z, -w);
+        return(Negated); };
+
+/*
+    const Type& operator [] (const int i) const // ALLOWS VECTOR ACCESS AS AN ARRAY.
+      { return( (i==0)?x:((i==1)?y:((i==2)?z:w)) ); };
+    Type & operator [] (const int i)
+      { return( (i==0)?x:((i==1)?y:((i==2)?z:w)) ); };
+*/
+
+    Type Length (void) const                     // LENGTH OF VECTOR
+      { return ((Type)sqrt(x*x+y*y+z*z+w*w)); };
+    Type LengthSqr (void) const                  // LENGTH OF VECTOR (SQUARED)
+      { return (x*x+y*y+z*z+w*w); };
+    Vec4& Normalize (void)                       // NORMALIZE VECTOR
+      { Type L = Length();                       // CALCULATE LENGTH
+        if (L>0) { x/=L; y/=L; z/=L; w/=L; }
+        return *this;
+      };                                          // DIV COMPONENTS BY LENGTH
+
+    void Wdiv(void)
+      { x/=w; y/=w; z/=w; w=1; }
+
+    void Print() const
+      { printf("(%.3f, %.3f, %.3f, %.3f)\n",x, y, z, w); }
+
+    static Vec4 ZERO;
+};
+
+typedef Vec4<float> Vec4f;
+typedef Vec4<double> Vec4d;
+
+template<class Type> Vec4<Type> Vec4<Type>::ZERO = Vec4<Type>(0,0,0,0);
+
+#endif
+
+