/** * Copyright (c) 2026 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "display/camera/camera.h" #include "display/framebuffer/framebuffer.h" #include "display/screen/screen.h" #include "assert/assertgl.h" void cameraPushMatrixGL(camera_t *camera) { assertNotNull(camera, "Not a camera component"); mat4 projection; mat4 view; switch(camera->projType) { case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC: { assertTrue( camera->orthographic.right != camera->orthographic.left && camera->orthographic.top != camera->orthographic.bottom, "Invalid orthographic projection parameters" ); glm_ortho( camera->orthographic.left, camera->orthographic.right, camera->orthographic.bottom, camera->orthographic.top, camera->nearClip, camera->farClip, projection ); break; } case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED: case CAMERA_PROJECTION_TYPE_PERSPECTIVE: { const float_t aspect = ( (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) / (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND) ); glm_perspective( camera->perspective.fov, aspect, camera->nearClip, camera->farClip, projection ); if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) { // Flip Y axis projection[1][1] *= -1; } break; } } switch(camera->viewType) { case CAMERA_VIEW_TYPE_MATRIX: glm_mat4_copy(camera->view, view); break; case CAMERA_VIEW_TYPE_LOOKAT: glm_lookat( camera->lookat.position, camera->lookat.target, camera->lookat.up, view ); break; case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT: assertTrue( camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE || camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED, "Pixel perfect camera view requires perspective projection" ); // const float_t viewportHeight = ( // (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND) // ); const float_t viewportHeight = (float_t)SCREEN.height; const float_t z = (viewportHeight / 2.0f) / ( camera->lookatPixelPerfect.pixelsPerUnit * tanf(camera->perspective.fov / 2.0f) ); vec3 position; glm_vec3_copy(camera->lookatPixelPerfect.target, position); glm_vec3_add(position, camera->lookatPixelPerfect.offset, position); position[2] += z; glm_lookat( position, camera->lookatPixelPerfect.target, camera->lookatPixelPerfect.up, view ); break; case CAMERA_VIEW_TYPE_2D: glm_mat4_identity(view); glm_translate(view, (vec3){ -camera->_2d.position[0], -camera->_2d.position[1], 0.0f }); glm_scale(view, (vec3){ camera->_2d.zoom, camera->_2d.zoom, 1.0f }); break; default: assertUnreachable("Invalid camera view type"); } // glPushMatrix(); // glMatrixMode(GL_PROJECTION); // glLoadIdentity(); // glLoadMatrixf((const GLfloat*)projection); assertNoGLError("Failed to set projection matrix"); // glMatrixMode(GL_MODELVIEW); // glLoadIdentity(); // glLoadMatrixf((const GLfloat*)view); assertNoGLError("Failed to set view matrix"); } void cameraPopMatrixGL(void) { // glPopMatrix(); assertNoGLError("Failed to pop camera matrix"); }