ROAMTriangle.h
上传用户:ghyvgy
上传日期:2009-05-26
资源大小:547k
文件大小:8k
源码类别:

其他游戏

开发平台:

Python

  1. /*
  2. s_p_oneil@hotmail.com
  3. Copyright (c) 2000, Sean O'Neil
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8.   this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10.   this list of conditions and the following disclaimer in the documentation
  11.   and/or other materials provided with the distribution.
  12. * Neither the name of this project nor the names of its contributors
  13.   may be used to endorse or promote products derived from this software
  14.   without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifndef __ROAMTriangle_h__
  28. #define __ROAMTriangle_h__
  29. #include "GLUtil.h"
  30. typedef enum
  31. {
  32. PriorityWaitMask = 0x03,
  33. TriangleFaceMask = 0x1C,
  34. TriangleDrawMask = 0x20
  35. } ROAMFlags;
  36. class CROAMPriority
  37. {
  38. public:
  39. CVector m_vMidpoint; // The midpoint of the third edge (the one to split)
  40. float m_fOffset; // The offset in height the midpoint will require when split
  41. float m_fLength; // The length of the third edge (the one to split)
  42. public:
  43. void CopyPriorityInfo(CROAMPriority *p)
  44. {
  45. m_vMidpoint = p->m_vMidpoint;
  46. m_fOffset = p->m_fOffset;
  47. m_fLength = p->m_fLength;
  48. }
  49. float GetPriority(const CVector &vPosition, const CVector &vHeading, const float fHorizon)
  50. {
  51. float fPriority = 0.0f;
  52. float fDistance = vPosition.DistanceSquared(m_vMidpoint);
  53. // Only calculate priority for vertices closer than the horizon
  54. // (Make an exception if the triangle is larger than the camera's distance to it)
  55. if(fDistance < m_fLength || fDistance < fHorizon)
  56. {
  57. // Only calculate priority for vertices inside the angle of view
  58. // (Make an exception if the triangle is larger than the camera's distance to it)
  59. if(fDistance < m_fLength || (vHeading | DirectionVector(vPosition, m_vMidpoint)) > 0.75f)
  60. {
  61. float fError = m_fOffset;
  62. if(m_fOffset > 1.0f)
  63. fError *= m_fOffset;
  64. fPriority = (fDistance > 25.0f) ? fError / sqrtf(fDistance) : fError * 0.2f;
  65. }
  66. }
  67. return fPriority;
  68. }
  69. };
  70. /****************************************************************************
  71. * Class: CROAMTriangle
  72. *****************************************************************************
  73. * This class implements the ROAM triangle. It is quite large because it
  74. * relies heavily on caching information so it doesn't have to calculate things
  75. * every frame. Some deal with calculating split priority while others deal
  76. * with handling the actual split. Like CVertex, it is derived from CListNode
  77. * and uses CMemoryBlock if USE_ALLOCATOR is defined.
  78. *
  79. * Note that the parent pointer points to the parent of this triangle, but this
  80. * is still not a tree-like structure! I do not keep a binary tree of all
  81. * triangles used to reach the current model, I only keep the triangles that
  82. * are part of the current model. When I split 2 triangles into 4, I modify
  83. * the 2 existing triangles and add 2 new ones, setting the parent pointers of
  84. * the new triangles to point to the existing ones. Later when I merge 4 into
  85. * 2, the two child triangles get deleted and the parents get changed back.
  86. *
  87. * One more important thing to note is vertex and edge order. ROAM will only
  88. * split two right triangles that make up a square, so I think of every
  89. * triangle as a right triangle (even though it's not really a right triangle
  90. * because it's on a sphere). My vertices always run counter-clockwise with
  91. * the middle vertex being in the middle. Edges are handled in a similar
  92. * fashion. Edge 0 indicates vertices 0 - 1, edge 1 indicates vertices 1 - 2,
  93. * and edge 2 indicates vertices 2 - 0.
  94. *
  95. * It looks something like this:
  96. * (square)
  97. * 1----0 /2   Note: m_pEdge[2] is always the edge that is split, and a
  98. * |   / / |         triangle can be split only if m_pEdge[2]->m_pEdge[2]
  99. * |  / /  |         points back to itself. If it doesn't, its neighbor must
  100. * | / /   |         be split first (recursively).
  101. * 2/ 0----1
  102. ****************************************************************************/
  103. class CROAMDiamond; // Forward reference
  104. #define CROAMTriangleList CLinkedList<CROAMTriangle>
  105. class CROAMTriangle : public CListNode<CROAMTriangle>, public CROAMPriority
  106. {
  107. // Attributes
  108. public:
  109. // Triangle members
  110. unsigned short m_nVertex[3]; // Indices into a CVertexArray
  111. CROAMTriangle *m_pEdge[3]; // Pointers to the triangles sharing edges with this one
  112. CROAMTriangle *m_pParent; // Pointer to the parent triangle that created this one
  113. CROAMDiamond *m_pDiamond; // Set if this triangle is part of a diamond
  114. CVector m_vNormal;
  115. // Split priority members
  116. unsigned char m_nFlags;
  117. // Operations
  118. public:
  119. CROAMTriangle() { memset((char *)this, 0, sizeof(CROAMTriangle)); }
  120. CROAMTriangle(unsigned short n1, unsigned short n2, unsigned short n3)
  121. {
  122. memset((char *)this, 0, sizeof(CROAMTriangle));
  123. SetVertices(n1, n2, n3);
  124. }
  125. int GetPriorityWait() { return (m_nFlags & PriorityWaitMask); }
  126. void SetPriorityWait(int n) { m_nFlags = n | (m_nFlags & ~PriorityWaitMask); }
  127. int GetTriangleFace() { return (m_nFlags & TriangleFaceMask) >> 2; }
  128. void SetTriangleFace(int n) { m_nFlags = (n<<2) | (m_nFlags & ~TriangleFaceMask); }
  129. CVertex *Vertex(unsigned short n) { return CVertex::Array[m_nVertex[n]]; }
  130. void SetVertices(unsigned short n1, unsigned short n2, unsigned short n3)
  131. {
  132. m_nVertex[0] = n1; m_nVertex[1] = n2; m_nVertex[2] = n3;
  133. m_vNormal = NormalVector(Vertex(0)->m_vPosition, Vertex(1)->m_vPosition, Vertex(2)->m_vPosition);
  134. }
  135. void SetEdges(CROAMTriangle *p1, CROAMTriangle *p2, CROAMTriangle *p3)
  136. {
  137. m_pEdge[0] = p1; m_pEdge[1] = p2; m_pEdge[2] = p3;
  138. }
  139. void ReplaceEdge(CROAMTriangle *pOld, CROAMTriangle *pNew)
  140. {
  141. if(m_pEdge[0] == pOld)
  142. m_pEdge[0] = pNew;
  143. else if(m_pEdge[1] == pOld)
  144. m_pEdge[1] = pNew;
  145. else if(m_pEdge[2] == pOld)
  146. m_pEdge[2] = pNew;
  147. }
  148. const CVector &GetNormal() { return m_vNormal; }
  149. bool HasVertex(CVertex *pVertex){ return (pVertex->m_vPosition == Vertex(0)->m_vPosition || pVertex->m_vPosition == Vertex(1)->m_vPosition || pVertex->m_vPosition == Vertex(2)->m_vPosition); }
  150. bool HasVertex(unsigned short n)
  151. {
  152. if(m_nVertex[0] == n || m_nVertex[1] == n || m_nVertex[2] == n)
  153. return true;
  154. return HasVertex(CVertex::Array[n]);
  155. }
  156. void UpdateVertexNormal(unsigned short nVertex)
  157. {
  158. // Go counter-clockwise through neighbors to add up normals of all triangles using this vertex
  159. CVertex *pVertex = Vertex(nVertex);
  160. pVertex->m_vNormal = GetNormal();
  161. CROAMTriangle *pPrev = this;
  162. CROAMTriangle *pNext = m_pEdge[nVertex];
  163. while(pNext != this)
  164. {
  165. pVertex->m_vNormal += pNext->GetNormal();
  166. int nNext = pNext->m_pEdge[0] == pPrev ? 1 : pNext->m_pEdge[1] == pPrev ? 2 : 0;
  167. pPrev = pNext;
  168. pNext = pNext->m_pEdge[nNext];
  169. }
  170. CVertex::Array.UpdateElement(m_nVertex[nVertex]);
  171. }
  172. void UpdateVertexNormals()
  173. {
  174. for(int i=0; i<3; i++)
  175. UpdateVertexNormal(i);
  176. }
  177. unsigned short GetOpposite(unsigned short n1, unsigned short n2)
  178. {
  179. if(m_nVertex[0] != n1 && m_nVertex[0] != n2)
  180. return m_nVertex[0];
  181. if(m_nVertex[1] != n1 && m_nVertex[1] != n2)
  182. return m_nVertex[1];
  183. return m_nVertex[2];
  184. }
  185. void Draw(unsigned short *nArray, int &nIndex)
  186. {
  187. //if(m_nFlags & TriangleDrawMask)
  188. {
  189. nArray[nIndex++] = m_nVertex[0];
  190. nArray[nIndex++] = m_nVertex[1];
  191. nArray[nIndex++] = m_nVertex[2];
  192. }
  193. }
  194. };
  195. #endif // __ROAMTriangle_h__