Matrix.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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 <LibGL/GLContext.h>
  10. namespace GL {
  11. static constexpr size_t matrix_stack_limit(GLenum matrix_mode)
  12. {
  13. switch (matrix_mode) {
  14. case GL_MODELVIEW:
  15. return MODELVIEW_MATRIX_STACK_LIMIT;
  16. case GL_PROJECTION:
  17. return PROJECTION_MATRIX_STACK_LIMIT;
  18. case GL_TEXTURE:
  19. return TEXTURE_MATRIX_STACK_LIMIT;
  20. }
  21. VERIFY_NOT_REACHED();
  22. }
  23. void GLContext::gl_frustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  24. {
  25. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_frustum, left, right, bottom, top, near_val, far_val);
  26. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  27. RETURN_WITH_ERROR_IF(near_val < 0 || far_val < 0, GL_INVALID_VALUE);
  28. RETURN_WITH_ERROR_IF(left == right || bottom == top || near_val == far_val, GL_INVALID_VALUE);
  29. // Let's do some math!
  30. auto a = static_cast<float>((right + left) / (right - left));
  31. auto b = static_cast<float>((top + bottom) / (top - bottom));
  32. auto c = static_cast<float>(-((far_val + near_val) / (far_val - near_val)));
  33. auto d = static_cast<float>(-((2 * far_val * near_val) / (far_val - near_val)));
  34. FloatMatrix4x4 frustum {
  35. static_cast<float>(2 * near_val / (right - left)), 0, a, 0,
  36. 0, static_cast<float>(2 * near_val / (top - bottom)), b, 0,
  37. 0, 0, c, d,
  38. 0, 0, -1, 0
  39. };
  40. update_current_matrix(*m_current_matrix * frustum);
  41. }
  42. void GLContext::gl_load_identity()
  43. {
  44. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_load_identity);
  45. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  46. update_current_matrix(FloatMatrix4x4::identity());
  47. }
  48. void GLContext::gl_load_matrix(FloatMatrix4x4 const& matrix)
  49. {
  50. APPEND_TO_CALL_LIST_WITH_ARG_AND_RETURN_IF_NEEDED(gl_load_matrix, matrix);
  51. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  52. update_current_matrix(matrix);
  53. }
  54. void GLContext::gl_matrix_mode(GLenum mode)
  55. {
  56. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_matrix_mode, mode);
  57. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  58. RETURN_WITH_ERROR_IF(mode < GL_MODELVIEW || mode > GL_TEXTURE, GL_INVALID_ENUM);
  59. m_current_matrix_mode = mode;
  60. switch (mode) {
  61. case GL_MODELVIEW:
  62. m_current_matrix_stack = &m_model_view_matrix_stack;
  63. break;
  64. case GL_PROJECTION:
  65. m_current_matrix_stack = &m_projection_matrix_stack;
  66. break;
  67. case GL_TEXTURE:
  68. m_current_matrix_stack = &m_active_texture_unit->texture_matrix_stack();
  69. break;
  70. default:
  71. VERIFY_NOT_REACHED();
  72. }
  73. m_current_matrix = &m_current_matrix_stack->last();
  74. }
  75. void GLContext::gl_mult_matrix(FloatMatrix4x4 const& matrix)
  76. {
  77. APPEND_TO_CALL_LIST_WITH_ARG_AND_RETURN_IF_NEEDED(gl_mult_matrix, matrix);
  78. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  79. update_current_matrix(*m_current_matrix * matrix);
  80. }
  81. void GLContext::gl_ortho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
  82. {
  83. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_ortho, left, right, bottom, top, near_val, far_val);
  84. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  85. RETURN_WITH_ERROR_IF(left == right || bottom == top || near_val == far_val, GL_INVALID_VALUE);
  86. auto rl = right - left;
  87. auto tb = top - bottom;
  88. auto fn = far_val - near_val;
  89. auto tx = -(right + left) / rl;
  90. auto ty = -(top + bottom) / tb;
  91. auto tz = -(far_val + near_val) / fn;
  92. FloatMatrix4x4 projection {
  93. static_cast<float>(2 / rl), 0, 0, static_cast<float>(tx),
  94. 0, static_cast<float>(2 / tb), 0, static_cast<float>(ty),
  95. 0, 0, static_cast<float>(-2 / fn), static_cast<float>(tz),
  96. 0, 0, 0, 1
  97. };
  98. update_current_matrix(*m_current_matrix * projection);
  99. }
  100. void GLContext::gl_pop_matrix()
  101. {
  102. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_pop_matrix);
  103. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  104. RETURN_WITH_ERROR_IF(m_current_matrix_stack->size() <= 1, GL_STACK_UNDERFLOW);
  105. m_current_matrix_stack->take_last();
  106. m_current_matrix = &m_current_matrix_stack->last();
  107. m_matrices_dirty = true;
  108. }
  109. void GLContext::gl_push_matrix()
  110. {
  111. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_matrix);
  112. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  113. RETURN_WITH_ERROR_IF(m_current_matrix_stack->size() >= matrix_stack_limit(m_current_matrix_mode), GL_STACK_OVERFLOW);
  114. m_current_matrix_stack->append(*m_current_matrix);
  115. m_current_matrix = &m_current_matrix_stack->last();
  116. m_matrices_dirty = true;
  117. }
  118. void GLContext::gl_rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
  119. {
  120. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rotate, angle, x, y, z);
  121. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  122. FloatVector3 axis = { x, y, z };
  123. if (axis.length() > 0.f)
  124. axis.normalize();
  125. auto rotation_mat = Gfx::rotation_matrix(axis, AK::to_radians(angle));
  126. update_current_matrix(*m_current_matrix * rotation_mat);
  127. }
  128. void GLContext::gl_scale(GLfloat x, GLfloat y, GLfloat z)
  129. {
  130. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scale, x, y, z);
  131. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  132. auto scale_matrix = Gfx::scale_matrix(FloatVector3 { x, y, z });
  133. update_current_matrix(*m_current_matrix * scale_matrix);
  134. }
  135. void GLContext::gl_translate(GLfloat x, GLfloat y, GLfloat z)
  136. {
  137. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_translate, x, y, z);
  138. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  139. auto translation_matrix = Gfx::translation_matrix(FloatVector3 { x, y, z });
  140. update_current_matrix(*m_current_matrix * translation_matrix);
  141. }
  142. void GLContext::sync_matrices()
  143. {
  144. if (!m_matrices_dirty)
  145. return;
  146. m_rasterizer->set_model_view_transform(model_view_matrix());
  147. m_rasterizer->set_projection_transform(projection_matrix());
  148. m_matrices_dirty = false;
  149. }
  150. }