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