You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

670 lines
22 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include "core.h"
  14. #include "lolgl.h"
  15. #if defined _WIN32 && defined USE_D3D9
  16. # define FAR
  17. # define NEAR
  18. # include <d3d9.h>
  19. #endif
  20. using namespace std;
  21. #if defined USE_D3D9
  22. extern IDirect3DDevice9 *g_d3ddevice;
  23. #elif defined _XBOX
  24. extern D3DDevice *g_d3ddevice;
  25. #endif
  26. namespace lol
  27. {
  28. //
  29. // The VertexBufferData class
  30. // --------------------------
  31. //
  32. class VertexBufferData
  33. {
  34. friend class VertexBuffer;
  35. friend class VertexDeclaration;
  36. size_t m_size;
  37. #if defined USE_D3D9
  38. IDirect3DVertexBuffer9 *m_vbo;
  39. #elif defined _XBOX
  40. D3DVertexBuffer *m_vbo;
  41. #else
  42. GLuint m_vbo;
  43. uint8_t *m_memory;
  44. #endif
  45. };
  46. //
  47. // The VertexDeclaration class
  48. // ---------------------------
  49. //
  50. VertexStreamBase const VertexStreamBase::Empty;
  51. VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
  52. VertexStreamBase const &s2,
  53. VertexStreamBase const &s3,
  54. VertexStreamBase const &s4,
  55. VertexStreamBase const &s5,
  56. VertexStreamBase const &s6,
  57. VertexStreamBase const &s7,
  58. VertexStreamBase const &s8,
  59. VertexStreamBase const &s9,
  60. VertexStreamBase const &s10,
  61. VertexStreamBase const &s11,
  62. VertexStreamBase const &s12) : m_count(0)
  63. {
  64. if (&s1 != &VertexStreamBase::Empty) AddStream(s1);
  65. if (&s2 != &VertexStreamBase::Empty) AddStream(s2);
  66. if (&s3 != &VertexStreamBase::Empty) AddStream(s3);
  67. if (&s4 != &VertexStreamBase::Empty) AddStream(s4);
  68. if (&s5 != &VertexStreamBase::Empty) AddStream(s5);
  69. if (&s6 != &VertexStreamBase::Empty) AddStream(s6);
  70. if (&s7 != &VertexStreamBase::Empty) AddStream(s7);
  71. if (&s8 != &VertexStreamBase::Empty) AddStream(s8);
  72. if (&s9 != &VertexStreamBase::Empty) AddStream(s9);
  73. if (&s10 != &VertexStreamBase::Empty) AddStream(s10);
  74. if (&s11 != &VertexStreamBase::Empty) AddStream(s11);
  75. if (&s12 != &VertexStreamBase::Empty) AddStream(s12);
  76. Initialize();
  77. }
  78. VertexDeclaration::~VertexDeclaration()
  79. {
  80. #if defined _XBOX || defined USE_D3D9
  81. # if defined USE_D3D9
  82. IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
  83. # elif defined _XBOX
  84. D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
  85. # endif
  86. if (FAILED(vdecl->Release()))
  87. Abort();
  88. #else
  89. #endif
  90. }
  91. void VertexDeclaration::Bind()
  92. {
  93. #if defined _XBOX || defined USE_D3D9
  94. # if defined USE_D3D9
  95. IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
  96. # elif defined _XBOX
  97. D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
  98. # endif
  99. if (FAILED(g_d3ddevice->SetVertexDeclaration(vdecl)))
  100. Abort();
  101. #else
  102. /* FIXME: Nothing to do? */
  103. #endif
  104. }
  105. void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count)
  106. {
  107. if (count <= 0)
  108. return;
  109. #if defined _XBOX || defined USE_D3D9
  110. g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
  111. g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  112. g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  113. if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
  114. Abort();
  115. switch (type)
  116. {
  117. case MeshPrimitive::Triangles:
  118. if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST,
  119. skip, count)))
  120. Abort();
  121. break;
  122. case MeshPrimitive::TriangleStrips:
  123. if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
  124. skip, count)))
  125. Abort();
  126. break;
  127. case MeshPrimitive::TriangleFans:
  128. if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,
  129. skip, count)))
  130. Abort();
  131. break;
  132. case MeshPrimitive::Points:
  133. if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_POINTLIST,
  134. skip, count)))
  135. Abort();
  136. break;
  137. case MeshPrimitive::Lines:
  138. if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_LINELIST,
  139. skip, count)))
  140. Abort();
  141. break;
  142. }
  143. #else
  144. /* FIXME: this has nothing to do here! */
  145. glFrontFace(GL_CCW);
  146. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  147. switch (type)
  148. {
  149. case MeshPrimitive::Triangles:
  150. glDrawArrays(GL_TRIANGLES, skip, count);
  151. break;
  152. case MeshPrimitive::TriangleStrips:
  153. glDrawArrays(GL_TRIANGLE_STRIP, skip, count);
  154. break;
  155. case MeshPrimitive::TriangleFans:
  156. glDrawArrays(GL_TRIANGLE_FAN, skip, count);
  157. break;
  158. case MeshPrimitive::Points:
  159. glDrawArrays(GL_POINTS, skip, count);
  160. break;
  161. case MeshPrimitive::Lines:
  162. glDrawArrays(GL_LINES, skip, count);
  163. break;
  164. }
  165. #endif
  166. }
  167. void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase,
  168. int vskip, int vcount,
  169. int skip, int count)
  170. {
  171. if (count <= 0)
  172. return;
  173. #if defined _XBOX || defined USE_D3D9
  174. g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
  175. g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  176. g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  177. if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
  178. Abort();
  179. switch (type)
  180. {
  181. case MeshPrimitive::Triangles:
  182. count = count / 3;
  183. if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
  184. vbase, vskip, vcount, skip, count)))
  185. Abort();
  186. break;
  187. case MeshPrimitive::TriangleStrips:
  188. count = count - 2;
  189. if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,
  190. vbase, vskip, vcount, skip, count)))
  191. Abort();
  192. break;
  193. case MeshPrimitive::TriangleFans:
  194. count = count - 2;
  195. if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN,
  196. vbase, vskip, vcount, skip, count)))
  197. Abort();
  198. break;
  199. case MeshPrimitive::Points:
  200. if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_POINTLIST,
  201. vbase, vskip, vcount, skip, count)))
  202. Abort();
  203. break;
  204. case MeshPrimitive::Lines:
  205. if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_LINELIST,
  206. vbase, vskip, vcount, skip, count)))
  207. Abort();
  208. break;
  209. }
  210. #else
  211. /* FIXME: this has nothing to do here! */
  212. glFrontFace(GL_CCW);
  213. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  214. switch (type)
  215. {
  216. case MeshPrimitive::Triangles:
  217. /* FIXME: ignores most of the arguments! */
  218. (void)vbase; (void)vskip; (void)vcount; (void)skip;
  219. glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 0);
  220. break;
  221. case MeshPrimitive::TriangleStrips:
  222. /* FIXME: ignores most of the arguments! */
  223. (void)vbase; (void)vskip; (void)vcount; (void)skip;
  224. glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_SHORT, 0);
  225. break;
  226. case MeshPrimitive::TriangleFans:
  227. /* FIXME: ignores most of the arguments! */
  228. (void)vbase; (void)vskip; (void)vcount; (void)skip;
  229. glDrawElements(GL_TRIANGLE_FAN, count, GL_UNSIGNED_SHORT, 0);
  230. break;
  231. case MeshPrimitive::Points:
  232. /* FIXME: ignores most of the arguments! */
  233. (void)vbase; (void)vskip; (void)vcount; (void)skip;
  234. glDrawElements(GL_POINTS, count, GL_UNSIGNED_SHORT, 0);
  235. break;
  236. case MeshPrimitive::Lines:
  237. /* FIXME: ignores most of the arguments! */
  238. (void)vbase; (void)vskip; (void)vcount; (void)skip;
  239. glDrawElements(GL_LINES, count, GL_UNSIGNED_SHORT, 0);
  240. break;
  241. }
  242. #endif
  243. }
  244. void VertexDeclaration::Unbind()
  245. {
  246. #if defined _XBOX || defined USE_D3D9
  247. int stream = -1;
  248. for (int i = 0; i < m_count; i++)
  249. if (m_streams[i].index != stream)
  250. {
  251. stream = m_streams[i].index;
  252. if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
  253. Abort();
  254. }
  255. /* "NULL is an invalid input to SetVertexDeclaration" (DX9 guide), so
  256. * we just don't touch the current vertex declaration. */
  257. #elif !defined __CELLOS_LV2__
  258. for (int i = 0; i < m_count; i++)
  259. {
  260. if (m_streams[i].reg >= 0)
  261. {
  262. for (int j = i + 1; j < m_count; j++)
  263. if (m_streams[j].reg == m_streams[i].reg)
  264. m_streams[j].reg = -1;
  265. glDisableVertexAttribArray(m_streams[i].reg);
  266. }
  267. }
  268. glBindBuffer(GL_ARRAY_BUFFER, 0);
  269. #else
  270. /* Or even: */
  271. glDisableClientState(GL_VERTEX_ARRAY);
  272. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  273. glDisableClientState(GL_NORMAL_ARRAY);
  274. glDisableClientState(GL_COLOR_ARRAY);
  275. #endif
  276. }
  277. void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
  278. ShaderAttrib attr2,
  279. ShaderAttrib attr3,
  280. ShaderAttrib attr4,
  281. ShaderAttrib attr5,
  282. ShaderAttrib attr6,
  283. ShaderAttrib attr7,
  284. ShaderAttrib attr8,
  285. ShaderAttrib attr9,
  286. ShaderAttrib attr10,
  287. ShaderAttrib attr11,
  288. ShaderAttrib attr12)
  289. {
  290. if (!vb->m_data->m_size)
  291. return;
  292. #if defined _XBOX || defined USE_D3D9
  293. /* Only the first item is required to know which stream this
  294. * is about; the rest of the information is stored in the
  295. * vertex declaration already. */
  296. uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
  297. uint32_t index = attr1.m_flags & 0xffff;
  298. /* Find the stream number */
  299. uint32_t usage_index = 0;
  300. int stream = -1;
  301. for (int i = 0; i < m_count; i++)
  302. if (m_streams[i].usage == usage)
  303. if (usage_index++ == index)
  304. {
  305. stream = m_streams[i].index;
  306. break;
  307. }
  308. /* Compute this stream's stride */
  309. int stride = 0;
  310. for (int i = 0; i < m_count; i++)
  311. if (stream == m_streams[i].index)
  312. stride += m_streams[i].size;
  313. /* Now we know the stream index and the element stride */
  314. /* FIXME: precompute most of the crap above! */
  315. if (stream >= 0)
  316. {
  317. if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
  318. Abort();
  319. }
  320. #else
  321. glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
  322. ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
  323. attr7, attr8, attr9, attr10, attr11, attr12 };
  324. for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
  325. {
  326. uint32_t reg = l[n].m_flags >> 32;
  327. uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
  328. uint32_t index = l[n].m_flags & 0xffff;
  329. # if !defined __CELLOS_LV2__
  330. glEnableVertexAttribArray((GLint)reg);
  331. # else
  332. switch (usage)
  333. {
  334. case VertexUsage::Position:
  335. glEnableClientState(GL_VERTEX_ARRAY);
  336. break;
  337. case VertexUsage::TexCoord:
  338. case VertexUsage::TexCoordExt:
  339. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  340. break;
  341. case VertexUsage::Normal:
  342. glEnableClientState(GL_NORMAL_ARRAY);
  343. break;
  344. case VertexUsage::Color:
  345. glEnableClientState(GL_COLOR_ARRAY);
  346. break;
  347. }
  348. # endif
  349. /* We need to parse the whole vertex declaration to retrieve
  350. * the information. It sucks. */
  351. int attr_index = 0;
  352. /* First, find the stream index */
  353. for (uint32_t usage_index = 0; attr_index < m_count; attr_index++)
  354. if (m_streams[attr_index].usage == usage)
  355. if (usage_index++ == index)
  356. break;
  357. if (attr_index == m_count)
  358. {
  359. Log::Error("stream #%d with usage %x not found in declaration\n",
  360. index, usage);
  361. attr_index = 0;
  362. }
  363. /* Now compute the stride and offset up to this stream index */
  364. int stride = 0, offset = 0;
  365. for (int i = 0; i < m_count; i++)
  366. if (m_streams[i].index == m_streams[attr_index].index)
  367. {
  368. /* Remember the register used for this stream */
  369. m_streams[i].reg = reg;
  370. stride += m_streams[i].size;
  371. if (i < attr_index)
  372. offset += m_streams[i].size;
  373. }
  374. /* Finally, we need to retrieve the type of the data */
  375. # if !defined GL_DOUBLE
  376. # define GL_DOUBLE 0
  377. # endif
  378. static struct { GLint size; GLenum type; } const tlut[] =
  379. {
  380. { 0, 0 },
  381. { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
  382. { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
  383. { 4, GL_FLOAT }, /* float */
  384. { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
  385. { 4, GL_DOUBLE }, /* double */
  386. { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
  387. { 4, GL_BYTE }, /* int8_t */
  388. { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
  389. { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
  390. { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
  391. { 4, GL_SHORT }, /* int16_t */
  392. { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
  393. GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
  394. { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
  395. { 4, GL_INT }, /* int32_t */
  396. { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
  397. { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
  398. };
  399. int type_index = m_streams[attr_index].stream_type;
  400. if (type_index < 0 || type_index >= (int)(sizeof(tlut) / sizeof(*tlut)))
  401. type_index = 0;
  402. # if !defined __CELLOS_LV2__
  403. if (tlut[type_index].type == GL_FLOAT
  404. || tlut[type_index].type == GL_DOUBLE
  405. || tlut[type_index].type == GL_BYTE
  406. || tlut[type_index].type == GL_UNSIGNED_BYTE
  407. # if defined USE_GLEW && !defined __APPLE__
  408. /* If this is not available, don't use it */
  409. || !glVertexAttribIPointer
  410. # endif
  411. || false)
  412. {
  413. /* Normalize unsigned bytes by default, because it's usually
  414. * some color information. */
  415. GLboolean normalize = (tlut[type_index].type == GL_UNSIGNED_BYTE)
  416. || (tlut[type_index].type == GL_BYTE);
  417. glVertexAttribPointer((GLint)reg, tlut[type_index].size,
  418. tlut[type_index].type, normalize,
  419. stride, (GLvoid const *)(uintptr_t)offset);
  420. }
  421. # if defined GL_VERSION_3_0
  422. else
  423. {
  424. glVertexAttribIPointer((GLint)reg, tlut[type_index].size,
  425. tlut[type_index].type,
  426. stride, (GLvoid const *)(uintptr_t)offset);
  427. }
  428. # endif
  429. # else
  430. switch (usage)
  431. {
  432. case VertexUsage::Position:
  433. glVertexPointer(tlut[type_index].size, tlut[type_index].type,
  434. stride, (GLvoid const *)(uintptr_t)offset);
  435. break;
  436. case VertexUsage::TexCoord:
  437. case VertexUsage::TexCoordExt:
  438. glTexCoordPointer(tlut[type_index].size, tlut[type_index].type,
  439. stride, (GLvoid const *)(uintptr_t)offset);
  440. break;
  441. case VertexUsage::Normal:
  442. glNormalPointer(tlut[type_index].type,
  443. stride, (GLvoid const *)(uintptr_t)offset);
  444. break;
  445. case VertexUsage::Color:
  446. glColorPointer(tlut[type_index].size, tlut[type_index].type,
  447. stride, (GLvoid const *)(uintptr_t)offset);
  448. break;
  449. default:
  450. Log::Error("vertex usage %d is not supported yet\n", usage);
  451. break;
  452. }
  453. # endif
  454. }
  455. #endif
  456. }
  457. void VertexDeclaration::Initialize()
  458. {
  459. #if defined _XBOX || defined USE_D3D9
  460. static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
  461. static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
  462. static D3DDECLTYPE const tlut[] =
  463. {
  464. D3DDECLTYPE_UNUSED,
  465. X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
  466. D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
  467. D3DDECLTYPE_FLOAT4, /* float */
  468. X, X, X, X, /* double */
  469. X, X, X, X, /* int8_t */
  470. X, X, X, D3DDECLTYPE_UBYTE4N, /* uint8_t */
  471. X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
  472. X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
  473. X, X, X, X, /* int32_t */
  474. X, X, X, X, /* uint32_t */
  475. };
  476. static D3DDECLUSAGE const ulut[] =
  477. {
  478. D3DDECLUSAGE_POSITION,
  479. D3DDECLUSAGE_BLENDWEIGHT,
  480. D3DDECLUSAGE_BLENDINDICES,
  481. D3DDECLUSAGE_NORMAL,
  482. D3DDECLUSAGE_PSIZE,
  483. D3DDECLUSAGE_TEXCOORD,
  484. D3DDECLUSAGE_TANGENT,
  485. D3DDECLUSAGE_BINORMAL,
  486. D3DDECLUSAGE_TESSFACTOR,
  487. #if defined _XBOX
  488. D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
  489. #else
  490. D3DDECLUSAGE_POSITIONT,
  491. #endif
  492. D3DDECLUSAGE_COLOR,
  493. D3DDECLUSAGE_FOG,
  494. D3DDECLUSAGE_DEPTH,
  495. D3DDECLUSAGE_SAMPLE,
  496. };
  497. D3DVERTEXELEMENT9 elements[12 + 1];
  498. for (int n = 0; n < m_count; n++)
  499. {
  500. elements[n].Stream = m_streams[n].index;
  501. elements[n].Offset = 0;
  502. for (int i = 0; i < n; i++)
  503. if (m_streams[i].index == m_streams[n].index)
  504. elements[n].Offset += m_streams[i].size;
  505. if (m_streams[n].stream_type >= 0
  506. && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
  507. elements[n].Type = tlut[m_streams[n].stream_type];
  508. else
  509. elements[n].Type = D3DDECLTYPE_UNUSED;
  510. elements[n].Method = D3DDECLMETHOD_DEFAULT;
  511. if (m_streams[n].usage >= 0
  512. && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
  513. elements[n].Usage = ulut[m_streams[n].usage];
  514. else
  515. elements[n].Usage = D3DDECLUSAGE_POSITION;
  516. elements[n].UsageIndex = 0;
  517. for (int i = 0; i < n; i++)
  518. if (elements[i].Stream == elements[n].Stream
  519. && elements[i].Usage == elements[n].Usage)
  520. elements[n].UsageIndex++;
  521. }
  522. elements[m_count] = end_element[0];
  523. # if defined USE_D3D9
  524. IDirect3DVertexDeclaration9 *vdecl;
  525. # elif defined _XBOX
  526. D3DVertexDeclaration *vdecl;
  527. # endif
  528. if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
  529. Abort();
  530. m_data = vdecl;
  531. #else
  532. #endif
  533. }
  534. void VertexDeclaration::AddStream(VertexStreamBase const &s)
  535. {
  536. int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
  537. for (int i = 0; s.m_streams[i].size; i++)
  538. {
  539. m_streams[m_count].stream_type = s.m_streams[i].stream_type;
  540. m_streams[m_count].usage = s.m_streams[i].usage;
  541. m_streams[m_count].size = s.m_streams[i].size;
  542. m_streams[m_count].index = index;
  543. m_streams[m_count].reg = -1;
  544. m_count++;
  545. }
  546. }
  547. //
  548. // The VertexBuffer class
  549. // ----------------------
  550. //
  551. VertexBuffer::VertexBuffer(size_t size)
  552. : m_data(new VertexBufferData)
  553. {
  554. m_data->m_size = size;
  555. if (!size)
  556. return;
  557. #if defined USE_D3D9 || defined _XBOX
  558. if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, nullptr,
  559. D3DPOOL_MANAGED, &m_data->m_vbo, nullptr)))
  560. Abort();
  561. #else
  562. glGenBuffers(1, &m_data->m_vbo);
  563. m_data->m_memory = new uint8_t[size];
  564. #endif
  565. }
  566. VertexBuffer::~VertexBuffer()
  567. {
  568. if (m_data->m_size)
  569. {
  570. #if defined USE_D3D9 || defined _XBOX
  571. if (FAILED(m_data->m_vbo->Release()))
  572. Abort();
  573. #else
  574. glDeleteBuffers(1, &m_data->m_vbo);
  575. delete[] m_data->m_memory;
  576. #endif
  577. }
  578. delete m_data;
  579. }
  580. void *VertexBuffer::Lock(size_t offset, size_t size)
  581. {
  582. if (!m_data->m_size)
  583. return nullptr;
  584. #if defined USE_D3D9 || defined _XBOX
  585. void *ret;
  586. if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
  587. Abort();
  588. return ret;
  589. #else
  590. /* FIXME: is there a way to use "size"? */
  591. (void)size;
  592. return m_data->m_memory + offset;
  593. #endif
  594. }
  595. void VertexBuffer::Unlock()
  596. {
  597. if (!m_data->m_size)
  598. return;
  599. #if defined USE_D3D9 || defined _XBOX
  600. if (FAILED(m_data->m_vbo->Unlock()))
  601. Abort();
  602. #else
  603. glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
  604. glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
  605. GL_STATIC_DRAW);
  606. glBindBuffer(GL_ARRAY_BUFFER, 0);
  607. #endif
  608. }
  609. } /* namespace lol */