Vertex.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
  4. * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Assertions.h>
  9. #include <AK/NumericLimits.h>
  10. #include <LibGL/GLContext.h>
  11. namespace GL {
  12. // General helper function to read arbitrary vertex attribute data into a float array
  13. static void read_from_vertex_attribute_pointer(VertexAttribPointer const& attrib, int index, float* elements)
  14. {
  15. auto const* byte_ptr = reinterpret_cast<char const*>(attrib.pointer);
  16. auto read_values = [&]<typename T>() {
  17. auto const stride = (attrib.stride == 0) ? sizeof(T) * attrib.size : attrib.stride;
  18. for (int i = 0; i < attrib.size; ++i) {
  19. elements[i] = *(reinterpret_cast<T const*>(byte_ptr + stride * index) + i);
  20. if constexpr (IsIntegral<T>) {
  21. if (attrib.normalize)
  22. elements[i] /= NumericLimits<T>::max();
  23. }
  24. }
  25. };
  26. switch (attrib.type) {
  27. case GL_BYTE:
  28. read_values.operator()<GLbyte>();
  29. break;
  30. case GL_UNSIGNED_BYTE:
  31. read_values.operator()<GLubyte>();
  32. break;
  33. case GL_SHORT:
  34. read_values.operator()<GLshort>();
  35. break;
  36. case GL_UNSIGNED_SHORT:
  37. read_values.operator()<GLushort>();
  38. break;
  39. case GL_INT:
  40. read_values.operator()<GLint>();
  41. break;
  42. case GL_UNSIGNED_INT:
  43. read_values.operator()<GLuint>();
  44. break;
  45. case GL_FLOAT:
  46. read_values.operator()<GLfloat>();
  47. break;
  48. case GL_DOUBLE:
  49. read_values.operator()<GLdouble>();
  50. break;
  51. }
  52. }
  53. void GLContext::gl_array_element(GLint i)
  54. {
  55. // NOTE: This always dereferences data; display list support is deferred to the
  56. // individual vertex attribute calls such as `gl_color`, `gl_normal` etc.
  57. RETURN_WITH_ERROR_IF(i < 0, GL_INVALID_VALUE);
  58. if (m_client_side_color_array_enabled) {
  59. float color[4] { 0.f, 0.f, 0.f, 1.f };
  60. read_from_vertex_attribute_pointer(m_client_color_pointer, i, color);
  61. gl_color(color[0], color[1], color[2], color[3]);
  62. }
  63. for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) {
  64. if (m_client_side_texture_coord_array_enabled[t]) {
  65. float tex_coords[4] { 0.f, 0.f, 0.f, 1.f };
  66. read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords);
  67. gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]);
  68. }
  69. }
  70. if (m_client_side_normal_array_enabled) {
  71. float normal[3];
  72. read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal);
  73. gl_normal(normal[0], normal[1], normal[2]);
  74. }
  75. if (m_client_side_vertex_array_enabled) {
  76. float vertex[4] { 0.f, 0.f, 0.f, 1.f };
  77. read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex);
  78. gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]);
  79. }
  80. }
  81. void GLContext::gl_color(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
  82. {
  83. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_color, r, g, b, a);
  84. m_current_vertex_color = { r, g, b, a };
  85. }
  86. void GLContext::gl_color_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer)
  87. {
  88. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  89. RETURN_WITH_ERROR_IF(!(size == 3 || size == 4), GL_INVALID_VALUE);
  90. RETURN_WITH_ERROR_IF(type != GL_BYTE
  91. && type != GL_UNSIGNED_BYTE
  92. && type != GL_SHORT
  93. && type != GL_UNSIGNED_SHORT
  94. && type != GL_INT
  95. && type != GL_UNSIGNED_INT
  96. && type != GL_FLOAT
  97. && type != GL_DOUBLE,
  98. GL_INVALID_ENUM);
  99. RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE);
  100. void const* data_pointer = pointer;
  101. if (m_array_buffer) {
  102. size_t data_offset = reinterpret_cast<size_t>(pointer);
  103. data_pointer = m_array_buffer->offset_data(data_offset);
  104. }
  105. m_client_color_pointer = { .size = size, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer };
  106. }
  107. void GLContext::gl_draw_arrays(GLenum mode, GLint first, GLsizei count)
  108. {
  109. // NOTE: This always dereferences data; display list support is deferred to the
  110. // individual vertex attribute calls such as `gl_color`, `gl_normal` etc.
  111. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  112. // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES)
  113. RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP
  114. || mode == GL_TRIANGLE_FAN
  115. || mode == GL_TRIANGLES
  116. || mode == GL_QUADS
  117. || mode == GL_QUAD_STRIP
  118. || mode == GL_POLYGON),
  119. GL_INVALID_ENUM);
  120. RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE);
  121. auto last = first + count;
  122. gl_begin(mode);
  123. for (int i = first; i < last; i++) {
  124. if (m_client_side_color_array_enabled) {
  125. float color[4] { 0.f, 0.f, 0.f, 1.f };
  126. read_from_vertex_attribute_pointer(m_client_color_pointer, i, color);
  127. gl_color(color[0], color[1], color[2], color[3]);
  128. }
  129. for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) {
  130. if (m_client_side_texture_coord_array_enabled[t]) {
  131. float tex_coords[4] { 0.f, 0.f, 0.f, 1.f };
  132. read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords);
  133. gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]);
  134. }
  135. }
  136. if (m_client_side_normal_array_enabled) {
  137. float normal[3];
  138. read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal);
  139. gl_normal(normal[0], normal[1], normal[2]);
  140. }
  141. if (m_client_side_vertex_array_enabled) {
  142. float vertex[4] { 0.f, 0.f, 0.f, 1.f };
  143. read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex);
  144. gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]);
  145. }
  146. }
  147. gl_end();
  148. }
  149. void GLContext::gl_draw_elements(GLenum mode, GLsizei count, GLenum type, void const* indices)
  150. {
  151. // NOTE: This always dereferences data; display list support is deferred to the
  152. // individual vertex attribute calls such as `gl_color`, `gl_normal` etc.
  153. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  154. // FIXME: Some modes are still missing (GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES)
  155. RETURN_WITH_ERROR_IF(!(mode == GL_TRIANGLE_STRIP
  156. || mode == GL_TRIANGLE_FAN
  157. || mode == GL_TRIANGLES
  158. || mode == GL_QUADS
  159. || mode == GL_QUAD_STRIP
  160. || mode == GL_POLYGON),
  161. GL_INVALID_ENUM);
  162. RETURN_WITH_ERROR_IF(!(type == GL_UNSIGNED_BYTE
  163. || type == GL_UNSIGNED_SHORT
  164. || type == GL_UNSIGNED_INT),
  165. GL_INVALID_ENUM);
  166. RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE);
  167. void const* index_data = indices;
  168. if (m_element_array_buffer) {
  169. size_t data_offset = reinterpret_cast<size_t>(indices);
  170. index_data = m_element_array_buffer->offset_data(data_offset);
  171. }
  172. gl_begin(mode);
  173. for (int index = 0; index < count; index++) {
  174. int i = 0;
  175. switch (type) {
  176. case GL_UNSIGNED_BYTE:
  177. i = reinterpret_cast<GLubyte const*>(index_data)[index];
  178. break;
  179. case GL_UNSIGNED_SHORT:
  180. i = reinterpret_cast<GLushort const*>(index_data)[index];
  181. break;
  182. case GL_UNSIGNED_INT:
  183. i = reinterpret_cast<GLuint const*>(index_data)[index];
  184. break;
  185. }
  186. if (m_client_side_color_array_enabled) {
  187. float color[4] { 0.f, 0.f, 0.f, 1.f };
  188. read_from_vertex_attribute_pointer(m_client_color_pointer, i, color);
  189. gl_color(color[0], color[1], color[2], color[3]);
  190. }
  191. for (size_t t = 0; t < m_client_tex_coord_pointer.size(); ++t) {
  192. if (m_client_side_texture_coord_array_enabled[t]) {
  193. float tex_coords[4] { 0.f, 0.f, 0.f, 1.f };
  194. read_from_vertex_attribute_pointer(m_client_tex_coord_pointer[t], i, tex_coords);
  195. gl_multi_tex_coord(GL_TEXTURE0 + t, tex_coords[0], tex_coords[1], tex_coords[2], tex_coords[3]);
  196. }
  197. }
  198. if (m_client_side_normal_array_enabled) {
  199. float normal[3];
  200. read_from_vertex_attribute_pointer(m_client_normal_pointer, i, normal);
  201. gl_normal(normal[0], normal[1], normal[2]);
  202. }
  203. if (m_client_side_vertex_array_enabled) {
  204. float vertex[4] { 0.f, 0.f, 0.f, 1.f };
  205. read_from_vertex_attribute_pointer(m_client_vertex_pointer, i, vertex);
  206. gl_vertex(vertex[0], vertex[1], vertex[2], vertex[3]);
  207. }
  208. }
  209. gl_end();
  210. }
  211. void GLContext::gl_normal(GLfloat nx, GLfloat ny, GLfloat nz)
  212. {
  213. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_normal, nx, ny, nz);
  214. m_current_vertex_normal = { nx, ny, nz };
  215. }
  216. void GLContext::gl_normal_pointer(GLenum type, GLsizei stride, void const* pointer)
  217. {
  218. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  219. RETURN_WITH_ERROR_IF(type != GL_BYTE
  220. && type != GL_SHORT
  221. && type != GL_INT
  222. && type != GL_FLOAT
  223. && type != GL_DOUBLE,
  224. GL_INVALID_ENUM);
  225. RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE);
  226. void const* data_pointer = pointer;
  227. if (m_array_buffer) {
  228. size_t data_offset = reinterpret_cast<size_t>(pointer);
  229. data_pointer = m_array_buffer->offset_data(data_offset);
  230. }
  231. m_client_normal_pointer = { .size = 3, .type = type, .normalize = true, .stride = stride, .pointer = data_pointer };
  232. }
  233. void GLContext::gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer)
  234. {
  235. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  236. RETURN_WITH_ERROR_IF(!(size == 1 || size == 2 || size == 3 || size == 4), GL_INVALID_VALUE);
  237. RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM);
  238. RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE);
  239. auto& tex_coord_pointer = m_client_tex_coord_pointer[m_client_active_texture];
  240. void const* data_pointer = pointer;
  241. if (m_array_buffer) {
  242. size_t data_offset = reinterpret_cast<size_t>(pointer);
  243. data_pointer = m_array_buffer->offset_data(data_offset);
  244. }
  245. tex_coord_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer };
  246. }
  247. void GLContext::gl_vertex(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
  248. {
  249. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_vertex, x, y, z, w);
  250. GPU::Vertex vertex;
  251. vertex.position = { x, y, z, w };
  252. vertex.color = m_current_vertex_color;
  253. for (size_t i = 0; i < m_device_info.num_texture_units; ++i)
  254. vertex.tex_coords[i] = m_current_vertex_tex_coord[i];
  255. vertex.normal = m_current_vertex_normal;
  256. // Optimization: by pulling in the Vector size vs. capacity check, we can always perform an unchecked append
  257. if (m_vertex_list.size() == m_vertex_list.capacity())
  258. m_vertex_list.grow_capacity(m_vertex_list.size() + 1);
  259. m_vertex_list.unchecked_append(vertex);
  260. }
  261. void GLContext::gl_vertex_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer)
  262. {
  263. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  264. RETURN_WITH_ERROR_IF(!(size == 2 || size == 3 || size == 4), GL_INVALID_VALUE);
  265. RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM);
  266. RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE);
  267. void const* data_pointer = pointer;
  268. if (m_array_buffer) {
  269. size_t data_offset = reinterpret_cast<size_t>(pointer);
  270. data_pointer = m_array_buffer->offset_data(data_offset);
  271. }
  272. m_client_vertex_pointer = { .size = size, .type = type, .normalize = false, .stride = stride, .pointer = data_pointer };
  273. }
  274. }