OGLVertexBuffer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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 "Graphics.h"
  24. #include "GraphicsImpl.h"
  25. #include "Log.h"
  26. #include "VertexBuffer.h"
  27. #include <cstring>
  28. #include "DebugNew.h"
  29. namespace Urho3D
  30. {
  31. const unsigned VertexBuffer::elementSize[] =
  32. {
  33. 3 * sizeof(float), // Position
  34. 3 * sizeof(float), // Normal
  35. 4 * sizeof(unsigned char), // Color
  36. 2 * sizeof(float), // Texcoord1
  37. 2 * sizeof(float), // Texcoord2
  38. 3 * sizeof(float), // Cubetexcoord1
  39. 3 * sizeof(float), // Cubetexcoord2
  40. 4 * sizeof(float), // Tangent
  41. 4 * sizeof(float), // Blendweights
  42. 4 * sizeof(unsigned char), // Blendindices
  43. 4 * sizeof(float), // Instancematrix1
  44. 4 * sizeof(float), // Instancematrix2
  45. 4 * sizeof(float) // Instancematrix3
  46. };
  47. const unsigned VertexBuffer::elementType[] =
  48. {
  49. GL_FLOAT, // Position
  50. GL_FLOAT, // Normal
  51. GL_UNSIGNED_BYTE, // Color
  52. GL_FLOAT, // Texcoord1
  53. GL_FLOAT, // Texcoord2
  54. GL_FLOAT, // Cubetexcoord1
  55. GL_FLOAT, // Cubetexcoord2
  56. GL_FLOAT, // Tangent
  57. GL_FLOAT, // Blendweights
  58. GL_UNSIGNED_BYTE, // Blendindices
  59. GL_FLOAT, // Instancematrix1
  60. GL_FLOAT, // Instancematrix2
  61. GL_FLOAT // Instancematrix3
  62. };
  63. const unsigned VertexBuffer::elementComponents[] =
  64. {
  65. 3, // Position
  66. 3, // Normal
  67. 4, // Color
  68. 2, // Texcoord1
  69. 2, // Texcoord2
  70. 3, // Cubetexcoord1
  71. 3, // Cubetexcoord2
  72. 4, // Tangent
  73. 4, // Blendweights
  74. 4, // Blendindices
  75. 4, // Instancematrix1
  76. 4, // Instancematrix2
  77. 4 // Instancematrix3
  78. };
  79. const unsigned VertexBuffer::elementNormalize[] =
  80. {
  81. GL_FALSE, // Position
  82. GL_FALSE, // Normal
  83. GL_TRUE, // Color
  84. GL_FALSE, // Texcoord1
  85. GL_FALSE, // Texcoord2
  86. GL_FALSE, // Cubetexcoord1
  87. GL_FALSE, // Cubetexcoord2
  88. GL_FALSE, // Tangent
  89. GL_FALSE, // Blendweights
  90. GL_FALSE, // Blendindices
  91. GL_FALSE, // Instancematrix1
  92. GL_FALSE, // Instancematrix2
  93. GL_FALSE // Instancematrix3
  94. };
  95. VertexBuffer::VertexBuffer(Context* context) :
  96. Object(context),
  97. GPUObject(GetSubsystem<Graphics>()),
  98. vertexCount_(0),
  99. elementMask_(0),
  100. lockState_(LOCK_NONE),
  101. lockStart_(0),
  102. lockCount_(0),
  103. lockScratchData_(0),
  104. shadowed_(false),
  105. dynamic_(false)
  106. {
  107. UpdateOffsets();
  108. // Force shadowing mode if graphics subsystem does not exist
  109. if (!graphics_)
  110. shadowed_ = true;
  111. }
  112. VertexBuffer::~VertexBuffer()
  113. {
  114. Release();
  115. }
  116. void VertexBuffer::OnDeviceReset()
  117. {
  118. if (!object_)
  119. {
  120. Create();
  121. dataLost_ = !UpdateToGPU();
  122. }
  123. else if (dataPending_)
  124. dataLost_ = !UpdateToGPU();
  125. dataPending_ = false;
  126. }
  127. void VertexBuffer::Release()
  128. {
  129. Unlock();
  130. if (object_)
  131. {
  132. if (!graphics_ || graphics_->IsDeviceLost())
  133. return;
  134. for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
  135. {
  136. if (graphics_->GetVertexBuffer(i) == this)
  137. graphics_->SetVertexBuffer(0);
  138. }
  139. glDeleteBuffers(1, &object_);
  140. object_ = 0;
  141. }
  142. }
  143. void VertexBuffer::SetShadowed(bool enable)
  144. {
  145. // If no graphics subsystem, can not disable shadowing
  146. if (!graphics_)
  147. enable = true;
  148. if (enable != shadowed_)
  149. {
  150. if (enable && vertexSize_ && vertexCount_)
  151. shadowData_ = new unsigned char[vertexCount_ * vertexSize_];
  152. else
  153. shadowData_.Reset();
  154. shadowed_ = enable;
  155. }
  156. }
  157. bool VertexBuffer::SetSize(unsigned vertexCount, unsigned elementMask, bool dynamic)
  158. {
  159. Unlock();
  160. dynamic_ = dynamic;
  161. vertexCount_ = vertexCount;
  162. elementMask_ = elementMask;
  163. UpdateOffsets();
  164. if (shadowed_ && vertexCount_ && vertexSize_)
  165. shadowData_ = new unsigned char[vertexCount_ * vertexSize_];
  166. else
  167. shadowData_.Reset();
  168. return Create();
  169. }
  170. bool VertexBuffer::SetData(const void* data)
  171. {
  172. if (!data)
  173. {
  174. LOGERROR("Null pointer for vertex buffer data");
  175. return false;
  176. }
  177. if (!vertexSize_)
  178. {
  179. LOGERROR("Vertex elements not defined, can not set vertex buffer data");
  180. return false;
  181. }
  182. if (shadowData_ && data != shadowData_.Get())
  183. memcpy(shadowData_.Get(), data, vertexCount_ * vertexSize_);
  184. if (object_)
  185. {
  186. if (!graphics_->IsDeviceLost())
  187. {
  188. glBindBuffer(GL_ARRAY_BUFFER, object_);
  189. glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
  190. }
  191. else
  192. {
  193. LOGWARNING("Vertex buffer data assignment while device is lost");
  194. dataPending_ = true;
  195. }
  196. }
  197. dataLost_ = false;
  198. return true;
  199. }
  200. bool VertexBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard)
  201. {
  202. if (start == 0 && count == vertexCount_)
  203. return SetData(data);
  204. if (!data)
  205. {
  206. LOGERROR("Null pointer for vertex buffer data");
  207. return false;
  208. }
  209. if (!vertexSize_)
  210. {
  211. LOGERROR("Vertex elements not defined, can not set vertex buffer data");
  212. return false;
  213. }
  214. if (start + count > vertexCount_)
  215. {
  216. LOGERROR("Illegal range for setting new vertex buffer data");
  217. return false;
  218. }
  219. if (!count)
  220. return true;
  221. if (shadowData_ && shadowData_.Get() + start * vertexSize_ != data)
  222. memcpy(shadowData_.Get() + start * vertexSize_, data, count * vertexSize_);
  223. if (object_)
  224. {
  225. if (!graphics_->IsDeviceLost())
  226. {
  227. glBindBuffer(GL_ARRAY_BUFFER, object_);
  228. if (!discard || start != 0)
  229. glBufferSubData(GL_ARRAY_BUFFER, start * vertexSize_, count * vertexSize_, data);
  230. else
  231. glBufferData(GL_ARRAY_BUFFER, count * vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
  232. }
  233. else
  234. {
  235. LOGWARNING("Vertex buffer data assignment while device is lost");
  236. dataPending_ = true;
  237. }
  238. }
  239. return true;
  240. }
  241. void* VertexBuffer::Lock(unsigned start, unsigned count, bool discard)
  242. {
  243. if (lockState_ != LOCK_NONE)
  244. {
  245. LOGERROR("Vertex buffer already locked");
  246. return 0;
  247. }
  248. if (!vertexSize_)
  249. {
  250. LOGERROR("Vertex elements not defined, can not lock vertex buffer");
  251. return 0;
  252. }
  253. if (start + count > vertexCount_)
  254. {
  255. LOGERROR("Illegal range for locking vertex buffer");
  256. return 0;
  257. }
  258. if (!count)
  259. return 0;
  260. lockStart_ = start;
  261. lockCount_ = count;
  262. if (shadowData_)
  263. {
  264. lockState_ = LOCK_SHADOW;
  265. return shadowData_.Get() + start * vertexSize_;
  266. }
  267. else if (graphics_)
  268. {
  269. lockState_ = LOCK_SCRATCH;
  270. lockScratchData_ = graphics_->ReserveScratchBuffer(count * vertexSize_);
  271. return lockScratchData_;
  272. }
  273. else
  274. return 0;
  275. }
  276. void VertexBuffer::Unlock()
  277. {
  278. switch (lockState_)
  279. {
  280. case LOCK_SHADOW:
  281. SetDataRange(shadowData_.Get() + lockStart_ * vertexSize_, lockStart_, lockCount_);
  282. lockState_ = LOCK_NONE;
  283. break;
  284. case LOCK_SCRATCH:
  285. SetDataRange(lockScratchData_, lockStart_, lockCount_);
  286. if (graphics_)
  287. graphics_->FreeScratchBuffer(lockScratchData_);
  288. lockScratchData_ = 0;
  289. lockState_ = LOCK_NONE;
  290. break;
  291. default:
  292. break;
  293. }
  294. }
  295. void VertexBuffer::UpdateOffsets()
  296. {
  297. unsigned elementOffset = 0;
  298. for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
  299. {
  300. if (elementMask_ & (1 << i))
  301. {
  302. elementOffset_[i] = elementOffset;
  303. elementOffset += elementSize[i];
  304. }
  305. else
  306. elementOffset_[i] = NO_ELEMENT;
  307. }
  308. vertexSize_ = elementOffset;
  309. }
  310. unsigned VertexBuffer::GetVertexSize(unsigned elementMask)
  311. {
  312. unsigned vertexSize = 0;
  313. for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
  314. {
  315. if (elementMask & (1 << i))
  316. vertexSize += elementSize[i];
  317. }
  318. return vertexSize;
  319. }
  320. unsigned VertexBuffer::GetElementOffset(unsigned elementMask, VertexElement element)
  321. {
  322. unsigned offset = 0;
  323. for (unsigned i = 0; i != element; ++i)
  324. {
  325. if (elementMask & (1 << i))
  326. offset += elementSize[i];
  327. }
  328. return offset;
  329. }
  330. bool VertexBuffer::Create()
  331. {
  332. if (!vertexCount_ || !elementMask_)
  333. {
  334. Release();
  335. return true;
  336. }
  337. if (graphics_)
  338. {
  339. if (graphics_->IsDeviceLost())
  340. {
  341. LOGWARNING("Vertex buffer creation while device is lost");
  342. return true;
  343. }
  344. if (!object_)
  345. glGenBuffers(1, &object_);
  346. if (!object_)
  347. {
  348. LOGERROR("Failed to create vertex buffer");
  349. return false;
  350. }
  351. glBindBuffer(GL_ARRAY_BUFFER, object_);
  352. glBufferData(GL_ARRAY_BUFFER, vertexCount_ * vertexSize_, 0, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
  353. }
  354. return true;
  355. }
  356. bool VertexBuffer::UpdateToGPU()
  357. {
  358. if (object_ && shadowData_)
  359. return SetData(shadowData_.Get());
  360. else
  361. return false;
  362. }
  363. }