Geometry.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. //
  2. // Copyright (c) 2008-2017 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Graphics/Geometry.h"
  24. #include "../Graphics/Graphics.h"
  25. #include "../Graphics/IndexBuffer.h"
  26. #include "../Graphics/VertexBuffer.h"
  27. #include "../IO/Log.h"
  28. #include "../Math/Ray.h"
  29. #include "../DebugNew.h"
  30. namespace Atomic
  31. {
  32. Geometry::Geometry(Context* context) :
  33. Object(context),
  34. primitiveType_(TRIANGLE_LIST),
  35. indexStart_(0),
  36. indexCount_(0),
  37. vertexStart_(0),
  38. vertexCount_(0),
  39. rawVertexSize_(0),
  40. rawIndexSize_(0),
  41. lodDistance_(0.0f)
  42. {
  43. SetNumVertexBuffers(1);
  44. }
  45. Geometry::~Geometry()
  46. {
  47. }
  48. bool Geometry::SetNumVertexBuffers(unsigned num)
  49. {
  50. if (num >= MAX_VERTEX_STREAMS)
  51. {
  52. ATOMIC_LOGERROR("Too many vertex streams");
  53. return false;
  54. }
  55. unsigned oldSize = vertexBuffers_.Size();
  56. vertexBuffers_.Resize(num);
  57. return true;
  58. }
  59. bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer)
  60. {
  61. if (index >= vertexBuffers_.Size())
  62. {
  63. ATOMIC_LOGERROR("Stream index out of bounds");
  64. return false;
  65. }
  66. vertexBuffers_[index] = buffer;
  67. return true;
  68. }
  69. void Geometry::SetIndexBuffer(IndexBuffer* buffer)
  70. {
  71. indexBuffer_ = buffer;
  72. }
  73. bool Geometry::SetDrawRange(PrimitiveType type, unsigned indexStart, unsigned indexCount, bool getUsedVertexRange)
  74. {
  75. if (!indexBuffer_ && !rawIndexData_)
  76. {
  77. ATOMIC_LOGERROR("Null index buffer and no raw index data, can not define indexed draw range");
  78. return false;
  79. }
  80. if (indexBuffer_ && indexStart + indexCount > indexBuffer_->GetIndexCount())
  81. {
  82. ATOMIC_LOGERROR("Illegal draw range " + String(indexStart) + " to " + String(indexStart + indexCount - 1) + ", index buffer has " +
  83. String(indexBuffer_->GetIndexCount()) + " indices");
  84. return false;
  85. }
  86. primitiveType_ = type;
  87. indexStart_ = indexStart;
  88. indexCount_ = indexCount;
  89. // Get min.vertex index and num of vertices from index buffer. If it fails, use full range as fallback
  90. if (indexCount)
  91. {
  92. vertexStart_ = 0;
  93. vertexCount_ = vertexBuffers_[0] ? vertexBuffers_[0]->GetVertexCount() : 0;
  94. if (getUsedVertexRange && indexBuffer_)
  95. indexBuffer_->GetUsedVertexRange(indexStart_, indexCount_, vertexStart_, vertexCount_);
  96. }
  97. else
  98. {
  99. vertexStart_ = 0;
  100. vertexCount_ = 0;
  101. }
  102. return true;
  103. }
  104. bool Geometry::SetDrawRange(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
  105. bool checkIllegal)
  106. {
  107. if (indexBuffer_)
  108. {
  109. // We can allow setting an illegal draw range now if the caller guarantees to resize / fill the buffer later
  110. if (checkIllegal && indexStart + indexCount > indexBuffer_->GetIndexCount())
  111. {
  112. ATOMIC_LOGERROR("Illegal draw range " + String(indexStart) + " to " + String(indexStart + indexCount - 1) +
  113. ", index buffer has " + String(indexBuffer_->GetIndexCount()) + " indices");
  114. return false;
  115. }
  116. }
  117. else if (!rawIndexData_)
  118. {
  119. indexStart = 0;
  120. indexCount = 0;
  121. }
  122. primitiveType_ = type;
  123. indexStart_ = indexStart;
  124. indexCount_ = indexCount;
  125. vertexStart_ = minVertex;
  126. vertexCount_ = vertexCount;
  127. return true;
  128. }
  129. void Geometry::SetLodDistance(float distance)
  130. {
  131. if (distance < 0.0f)
  132. distance = 0.0f;
  133. lodDistance_ = distance;
  134. }
  135. void Geometry::SetRawVertexData(SharedArrayPtr<unsigned char> data, const PODVector<VertexElement>& elements)
  136. {
  137. rawVertexData_ = data;
  138. rawVertexSize_ = VertexBuffer::GetVertexSize(elements);
  139. rawElements_ = elements;
  140. }
  141. void Geometry::SetRawVertexData(SharedArrayPtr<unsigned char> data, unsigned elementMask)
  142. {
  143. rawVertexData_ = data;
  144. rawVertexSize_ = VertexBuffer::GetVertexSize(elementMask);
  145. rawElements_ = VertexBuffer::GetElements(elementMask);
  146. }
  147. void Geometry::SetRawIndexData(SharedArrayPtr<unsigned char> data, unsigned indexSize)
  148. {
  149. rawIndexData_ = data;
  150. rawIndexSize_ = indexSize;
  151. }
  152. void Geometry::Draw(Graphics* graphics)
  153. {
  154. if (indexBuffer_ && indexCount_ > 0)
  155. {
  156. graphics->SetIndexBuffer(indexBuffer_);
  157. graphics->SetVertexBuffers(vertexBuffers_);
  158. graphics->Draw(primitiveType_, indexStart_, indexCount_, vertexStart_, vertexCount_);
  159. }
  160. else if (vertexCount_ > 0)
  161. {
  162. graphics->SetVertexBuffers(vertexBuffers_);
  163. graphics->Draw(primitiveType_, vertexStart_, vertexCount_);
  164. }
  165. }
  166. VertexBuffer* Geometry::GetVertexBuffer(unsigned index) const
  167. {
  168. return index < vertexBuffers_.Size() ? vertexBuffers_[index] : (VertexBuffer*)0;
  169. }
  170. unsigned short Geometry::GetBufferHash() const
  171. {
  172. unsigned short hash = 0;
  173. for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
  174. {
  175. VertexBuffer* vBuf = vertexBuffers_[i];
  176. hash += *((unsigned short*)&vBuf);
  177. }
  178. IndexBuffer* iBuf = indexBuffer_;
  179. hash += *((unsigned short*)&iBuf);
  180. return hash;
  181. }
  182. void Geometry::GetRawData(const unsigned char*& vertexData, unsigned& vertexSize, const unsigned char*& indexData,
  183. unsigned& indexSize, const PODVector<VertexElement>*& elements) const
  184. {
  185. if (rawVertexData_)
  186. {
  187. vertexData = rawVertexData_;
  188. vertexSize = rawVertexSize_;
  189. elements = &rawElements_;
  190. }
  191. else if (vertexBuffers_.Size() && vertexBuffers_[0])
  192. {
  193. vertexData = vertexBuffers_[0]->GetShadowData();
  194. vertexSize = vertexBuffers_[0]->GetVertexSize();
  195. elements = &vertexBuffers_[0]->GetElements();
  196. }
  197. else
  198. {
  199. vertexData = 0;
  200. vertexSize = 0;
  201. elements = 0;
  202. }
  203. if (rawIndexData_)
  204. {
  205. indexData = rawIndexData_;
  206. indexSize = rawIndexSize_;
  207. }
  208. else
  209. {
  210. if (indexBuffer_)
  211. {
  212. indexData = indexBuffer_->GetShadowData();
  213. if (indexData)
  214. indexSize = indexBuffer_->GetIndexSize();
  215. else
  216. indexSize = 0;
  217. }
  218. else
  219. {
  220. indexData = 0;
  221. indexSize = 0;
  222. }
  223. }
  224. }
  225. void Geometry::GetRawDataShared(SharedArrayPtr<unsigned char>& vertexData, unsigned& vertexSize,
  226. SharedArrayPtr<unsigned char>& indexData, unsigned& indexSize, const PODVector<VertexElement>*& elements) const
  227. {
  228. if (rawVertexData_)
  229. {
  230. vertexData = rawVertexData_;
  231. vertexSize = rawVertexSize_;
  232. elements = &rawElements_;
  233. }
  234. else if (vertexBuffers_.Size() && vertexBuffers_[0])
  235. {
  236. vertexData = vertexBuffers_[0]->GetShadowDataShared();
  237. vertexSize = vertexBuffers_[0]->GetVertexSize();
  238. elements = &vertexBuffers_[0]->GetElements();
  239. }
  240. else
  241. {
  242. vertexData = 0;
  243. vertexSize = 0;
  244. elements = 0;
  245. }
  246. if (rawIndexData_)
  247. {
  248. indexData = rawIndexData_;
  249. indexSize = rawIndexSize_;
  250. }
  251. else
  252. {
  253. if (indexBuffer_)
  254. {
  255. indexData = indexBuffer_->GetShadowDataShared();
  256. if (indexData)
  257. indexSize = indexBuffer_->GetIndexSize();
  258. else
  259. indexSize = 0;
  260. }
  261. else
  262. {
  263. indexData = 0;
  264. indexSize = 0;
  265. }
  266. }
  267. }
  268. float Geometry::GetHitDistance(const Ray& ray, Vector3* outNormal, Vector2* outUV) const
  269. {
  270. const unsigned char* vertexData;
  271. const unsigned char* indexData;
  272. unsigned vertexSize;
  273. unsigned indexSize;
  274. const PODVector<VertexElement>* elements;
  275. GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
  276. if (!vertexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
  277. return M_INFINITY;
  278. unsigned uvOffset = VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR2, SEM_TEXCOORD);
  279. if (outUV && uvOffset == M_MAX_UNSIGNED)
  280. {
  281. // requested UV output, but no texture data in vertex buffer
  282. ATOMIC_LOGWARNING("Illegal GetHitDistance call: UV return requested on vertex buffer without UV coords");
  283. *outUV = Vector2::ZERO;
  284. outUV = 0;
  285. }
  286. return indexData ? ray.HitDistance(vertexData, vertexSize, indexData, indexSize, indexStart_, indexCount_, outNormal, outUV,
  287. uvOffset) : ray.HitDistance(vertexData, vertexSize, vertexStart_, vertexCount_, outNormal, outUV, uvOffset);
  288. }
  289. bool Geometry::IsInside(const Ray& ray) const
  290. {
  291. const unsigned char* vertexData;
  292. const unsigned char* indexData;
  293. unsigned vertexSize;
  294. unsigned indexSize;
  295. const PODVector<VertexElement>* elements;
  296. GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
  297. return vertexData ? (indexData ? ray.InsideGeometry(vertexData, vertexSize, indexData, indexSize, indexStart_, indexCount_) :
  298. ray.InsideGeometry(vertexData, vertexSize, vertexStart_, vertexCount_)) : false;
  299. }
  300. }