Matrix.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. }
  108. void GLContext::gl_push_matrix()
  109. {
  110. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_push_matrix);
  111. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  112. RETURN_WITH_ERROR_IF(m_current_matrix_stack->size() >= matrix_stack_limit(m_current_matrix_mode), GL_STACK_OVERFLOW);
  113. m_current_matrix_stack->append(*m_current_matrix);
  114. m_current_matrix = &m_current_matrix_stack->last();
  115. }
  116. void GLContext::gl_rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
  117. {
  118. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_rotate, angle, x, y, z);
  119. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  120. FloatVector3 axis = { x, y, z };
  121. if (axis.length() > 0.f)
  122. axis.normalize();
  123. auto rotation_mat = Gfx::rotation_matrix(axis, angle * static_cast<float>(M_PI * 2 / 360));
  124. update_current_matrix(*m_current_matrix * rotation_mat);
  125. }
  126. void GLContext::gl_scale(GLfloat x, GLfloat y, GLfloat z)
  127. {
  128. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scale, x, y, z);
  129. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  130. auto scale_matrix = Gfx::scale_matrix(FloatVector3 { x, y, z });
  131. update_current_matrix(*m_current_matrix * scale_matrix);
  132. }
  133. void GLContext::gl_translate(GLfloat x, GLfloat y, GLfloat z)
  134. {
  135. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_translate, x, y, z);
  136. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  137. auto translation_matrix = Gfx::translation_matrix(FloatVector3 { x, y, z });
  138. update_current_matrix(*m_current_matrix * translation_matrix);
  139. }
  140. }