Matrix.cpp 6.0 KB

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