CustomGeometry.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. //
  2. // Copyright (c) 2008-2013 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 "Batch.h"
  24. #include "Camera.h"
  25. #include "Context.h"
  26. #include "CustomGeometry.h"
  27. #include "Geometry.h"
  28. #include "Log.h"
  29. #include "Material.h"
  30. #include "Node.h"
  31. #include "OcclusionBuffer.h"
  32. #include "OctreeQuery.h"
  33. #include "Profiler.h"
  34. #include "VertexBuffer.h"
  35. #include "DebugNew.h"
  36. namespace Urho3D
  37. {
  38. OBJECTTYPESTATIC(CustomGeometry);
  39. CustomGeometry::CustomGeometry(Context* context) :
  40. Drawable(context, DRAWABLE_GEOMETRY),
  41. vertexBuffer_(new VertexBuffer(context)),
  42. elementMask_(MASK_POSITION),
  43. geometryIndex_(0)
  44. {
  45. vertexBuffer_->SetShadowed(true);
  46. SetNumGeometries(1);
  47. }
  48. CustomGeometry::~CustomGeometry()
  49. {
  50. }
  51. void CustomGeometry::RegisterObject(Context* context)
  52. {
  53. context->RegisterFactory<CustomGeometry>();
  54. ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_BOOL, "Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  55. ATTRIBUTE(CustomGeometry, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
  56. ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
  57. ATTRIBUTE(CustomGeometry, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
  58. ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
  59. ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
  60. ACCESSOR_ATTRIBUTE(CustomGeometry, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
  61. COPY_BASE_ATTRIBUTES(CustomGeometry, Drawable);
  62. }
  63. void CustomGeometry::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
  64. {
  65. RayQueryLevel level = query.level_;
  66. switch (level)
  67. {
  68. case RAY_AABB_NOSUBOBJECTS:
  69. case RAY_AABB:
  70. Drawable::ProcessRayQuery(query, results);
  71. break;
  72. case RAY_OBB:
  73. case RAY_TRIANGLE:
  74. Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
  75. Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
  76. float distance = localRay.HitDistance(boundingBox_);
  77. if (distance <= query.maxDistance_)
  78. {
  79. if (level == RAY_TRIANGLE)
  80. {
  81. for (unsigned i = 0; i < batches_.Size(); ++i)
  82. {
  83. Geometry* geometry = batches_[i].geometry_;
  84. if (geometry)
  85. {
  86. distance = geometry->GetHitDistance(localRay);
  87. if (distance <= query.maxDistance_)
  88. {
  89. RayQueryResult result;
  90. result.drawable_ = this;
  91. result.node_ = node_;
  92. result.distance_ = distance;
  93. result.subObject_ = M_MAX_UNSIGNED;
  94. results.Push(result);
  95. break;
  96. }
  97. }
  98. }
  99. }
  100. else
  101. {
  102. RayQueryResult result;
  103. result.drawable_ = this;
  104. result.node_ = node_;
  105. result.distance_ = distance;
  106. result.subObject_ = M_MAX_UNSIGNED;
  107. results.Push(result);
  108. }
  109. }
  110. break;
  111. }
  112. }
  113. Geometry* CustomGeometry::GetLodGeometry(unsigned batchIndex, unsigned level)
  114. {
  115. return batchIndex < geometries_.Size() ? geometries_[batchIndex] : (Geometry*)0;
  116. }
  117. unsigned CustomGeometry::GetNumOccluderTriangles()
  118. {
  119. unsigned triangles = 0;
  120. for (unsigned i = 0; i < batches_.Size(); ++i)
  121. {
  122. Geometry* geometry = GetLodGeometry(i, 0);
  123. if (!geometry)
  124. continue;
  125. // Check that the material is suitable for occlusion (default material always is)
  126. Material* mat = batches_[i].material_;
  127. if (mat && !mat->GetOcclusion())
  128. continue;
  129. triangles += geometry->GetVertexCount() / 3;
  130. }
  131. return triangles;
  132. }
  133. bool CustomGeometry::DrawOcclusion(OcclusionBuffer* buffer)
  134. {
  135. bool success = true;
  136. for (unsigned i = 0; i < batches_.Size(); ++i)
  137. {
  138. Geometry* geometry = GetLodGeometry(i, 0);
  139. if (!geometry)
  140. continue;
  141. // Check that the material is suitable for occlusion (default material always is) and set culling mode
  142. Material* material = batches_[i].material_;
  143. if (material)
  144. {
  145. if (!material->GetOcclusion())
  146. continue;
  147. buffer->SetCullMode(material->GetCullMode());
  148. }
  149. else
  150. buffer->SetCullMode(CULL_CCW);
  151. const unsigned char* vertexData;
  152. unsigned vertexSize;
  153. const unsigned char* indexData;
  154. unsigned indexSize;
  155. unsigned elementMask;
  156. geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
  157. // Check for valid geometry data
  158. if (!vertexData)
  159. continue;
  160. // Draw and check for running out of triangles
  161. success = buffer->Draw(node_->GetWorldTransform(), vertexData, vertexSize, geometry->GetVertexStart(), geometry->GetVertexCount());
  162. if (!success)
  163. break;
  164. }
  165. return success;
  166. }
  167. void CustomGeometry::Clear()
  168. {
  169. elementMask_ = MASK_POSITION;
  170. batches_.Clear();
  171. geometries_.Clear();
  172. primitiveTypes_.Clear();
  173. vertices_.Clear();
  174. }
  175. void CustomGeometry::SetNumGeometries(unsigned num)
  176. {
  177. batches_.Resize(num);
  178. geometries_.Resize(num);
  179. primitiveTypes_.Resize(num);
  180. vertices_.Resize(num);
  181. for (unsigned i = 0; i < geometries_.Size(); ++i)
  182. {
  183. if (!geometries_[i])
  184. geometries_[i] = new Geometry(context_);
  185. batches_[i].geometry_ = geometries_[i];
  186. }
  187. }
  188. void CustomGeometry::BeginGeometry(unsigned index, PrimitiveType type)
  189. {
  190. if (index > geometries_.Size())
  191. {
  192. LOGERROR("Geometry index out of bounds");
  193. return;
  194. }
  195. geometryIndex_ = index;
  196. primitiveTypes_[index] = type;
  197. vertices_[index].Clear();
  198. }
  199. void CustomGeometry::DefineVertex(const Vector3& position)
  200. {
  201. if (vertices_.Size() < geometryIndex_)
  202. return;
  203. vertices_[geometryIndex_].Resize(vertices_[geometryIndex_].Size() + 1);
  204. vertices_[geometryIndex_].Back().position_ = position;
  205. }
  206. void CustomGeometry::DefineNormal(const Vector3& normal)
  207. {
  208. if (vertices_.Size() < geometryIndex_ || vertices_[geometryIndex_].Empty())
  209. return;
  210. vertices_[geometryIndex_].Back().normal_ = normal;
  211. elementMask_ |= MASK_NORMAL;
  212. }
  213. void CustomGeometry::DefineColor(const Color& color)
  214. {
  215. if (vertices_.Size() < geometryIndex_ || vertices_[geometryIndex_].Empty())
  216. return;
  217. vertices_[geometryIndex_].Back().color_ = color.ToUInt();
  218. elementMask_ |= MASK_COLOR;
  219. }
  220. void CustomGeometry::DefineTexCoord(const Vector2& texCoord)
  221. {
  222. if (vertices_.Size() < geometryIndex_ || vertices_[geometryIndex_].Empty())
  223. return;
  224. vertices_[geometryIndex_].Back().texCoord_ = texCoord;
  225. elementMask_ |= MASK_TEXCOORD1;
  226. }
  227. void CustomGeometry::DefineTangent(const Vector4& tangent)
  228. {
  229. if (vertices_.Size() < geometryIndex_ || vertices_[geometryIndex_].Empty())
  230. return;
  231. vertices_[geometryIndex_].Back().tangent_ = tangent;
  232. elementMask_ |= MASK_TANGENT;
  233. }
  234. void CustomGeometry::Commit()
  235. {
  236. PROFILE(CommitCustomGeometry);
  237. unsigned totalVertices = 0;
  238. boundingBox_.Clear();
  239. for (unsigned i = 0; i < vertices_.Size(); ++i)
  240. {
  241. totalVertices += vertices_[i].Size();
  242. for (unsigned j = 0; j < vertices_[i].Size(); ++j)
  243. boundingBox_.Merge(vertices_[i][j].position_);
  244. }
  245. vertexBuffer_->SetSize(totalVertices, elementMask_);
  246. if (totalVertices)
  247. {
  248. unsigned char* dest = (unsigned char*)vertexBuffer_->Lock(0, totalVertices, true);
  249. if (dest)
  250. {
  251. unsigned vertexStart = 0;
  252. for (unsigned i = 0; i < vertices_.Size(); ++i)
  253. {
  254. unsigned vertexCount = 0;
  255. for (unsigned j = 0; j < vertices_[i].Size(); ++j)
  256. {
  257. *((Vector3*)dest) = vertices_[i][j].position_;
  258. dest += sizeof(Vector3);
  259. if (elementMask_ & MASK_NORMAL)
  260. {
  261. *((Vector3*)dest) = vertices_[i][j].normal_;
  262. dest += sizeof(Vector3);
  263. }
  264. if (elementMask_ & MASK_COLOR)
  265. {
  266. *((unsigned*)dest) = vertices_[i][j].color_;
  267. dest += sizeof(unsigned);
  268. }
  269. if (elementMask_ & MASK_TEXCOORD1)
  270. {
  271. *((Vector2*)dest) = vertices_[i][j].texCoord_;
  272. dest += sizeof(Vector2);
  273. }
  274. if (elementMask_ & MASK_TANGENT)
  275. {
  276. *((Vector4*)dest) = vertices_[i][j].tangent_;
  277. dest += sizeof(Vector4);
  278. }
  279. ++vertexCount;
  280. }
  281. geometries_[i]->SetVertexBuffer(0, vertexBuffer_, elementMask_);
  282. geometries_[i]->SetDrawRange(primitiveTypes_[i], 0, 0, vertexStart, vertexCount);
  283. vertexStart += vertexCount;
  284. }
  285. vertexBuffer_->Unlock();
  286. }
  287. else
  288. LOGERROR("Failed to lock custom geometry vertex buffer");
  289. }
  290. else
  291. {
  292. for (unsigned i = 0; i < geometries_.Size(); ++i)
  293. {
  294. geometries_[i]->SetVertexBuffer(0, vertexBuffer_, elementMask_);
  295. geometries_[i]->SetDrawRange(primitiveTypes_[i], 0, 0, 0, 0);
  296. }
  297. }
  298. vertexBuffer_->ClearDataLost();
  299. }
  300. void CustomGeometry::SetMaterial(Material* material)
  301. {
  302. for (unsigned i = 0; i < batches_.Size(); ++i)
  303. batches_[i].material_ = material;
  304. MarkNetworkUpdate();
  305. }
  306. bool CustomGeometry::SetMaterial(unsigned index, Material* material)
  307. {
  308. if (index >= batches_.Size())
  309. {
  310. LOGERROR("Material index out of bounds");
  311. return false;
  312. }
  313. batches_[index].material_ = material;
  314. MarkNetworkUpdate();
  315. return true;
  316. }
  317. Material* CustomGeometry::GetMaterial(unsigned index) const
  318. {
  319. return index < batches_.Size() ? batches_[index].material_ : (Material*)0;
  320. }
  321. void CustomGeometry::OnWorldBoundingBoxUpdate()
  322. {
  323. worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
  324. }
  325. }