Vertex.cpp 12 KB

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