1 module unecht.core.components.camera; 2 3 import unecht.core.components.misc; 4 import unecht.core.components.renderer; 5 import unecht.core.component; 6 import unecht.core.object; 7 import unecht.core.componentManager; 8 import unecht.core.entity; 9 10 import unecht.core.types; 11 import unecht.core.math.ray; 12 13 import gl3n.linalg; 14 15 //TODO: create mixin and automation 16 version(UEIncludeEditor) 17 @EditorInspector("UECamera") 18 static class UECameraInspector : IComponentEditor 19 { 20 /// render custom inspector for UECamera 21 override bool render(UEObject _component) 22 { 23 auto thisT = cast(UECamera)_component; 24 25 import derelict.imgui.imgui; 26 import unecht.core.components.internal.gui; 27 import std.format; 28 29 igColorEdit4("clearColor",thisT.clearColor.vector,true); 30 UEGui.DragFloat("fov",thisT.fieldOfView,1,360); 31 UEGui.DragFloat("near",thisT.clipNear,0.01f); 32 UEGui.DragFloat("far",thisT.clipFar,0.01f); 33 34 igCheckbox("isOrthographic",&thisT.isOrthographic); 35 if(thisT.isOrthographic) 36 { 37 UEGui.DragFloat("orthoSize",thisT.orthoSize,0.01f); 38 } 39 40 //TODO: impl 41 return false; 42 } 43 44 mixin UERegisterInspector!UECameraInspector; 45 } 46 47 //TODO: add properties and make matrix updates implicit 48 /// camera component - handles rendering the world through its perspective 49 final class UECamera : UEComponent 50 { 51 mixin(UERegisterObject!()); 52 53 /// return projection matrix multiplied by look matrix 54 @property auto projectionLook() const { return matProjection * matLook; } 55 56 @Serialize{ 57 float fieldOfView = 60; 58 float clipNear = 1; 59 float clipFar = 1000; 60 61 vec4 clearColor = vec4(0,0,0,1); 62 bool clearBitColor = true; 63 bool clearBitDepth = true; 64 int visibleLayers = UECameraDefaultLayers; 65 66 bool isOrthographic=false; 67 float orthoSize=1; 68 69 UERect viewport; 70 } 71 72 /// 73 public ray screenToRay(vec2 screenPos) 74 { 75 import unecht.ue:ue; 76 77 UESize viewportSize = UESize( 78 cast(int)(viewport.size.x * ue.application.windowSize.width), 79 cast(int)(viewport.size.y * ue.application.windowSize.height)); 80 81 float x = (2.0f * screenPos.x) / viewportSize.width - 1.0f; 82 float y = (2.0f * screenPos.y) / viewportSize.height - 1.0f; 83 84 auto mouseClip = vec4 (x, -y, 1, 1); 85 86 auto matUnproj = matProjection.inverse(); 87 88 auto mouseWorld = matUnproj * mouseClip; 89 90 mouseWorld /= (mouseWorld.w); 91 92 auto dir = mouseWorld.xyz; 93 94 dir.normalize(); 95 96 dir = dir.xyz * matLook.get_rotation(); 97 98 return ray(entity.sceneNode.position, dir); 99 } 100 101 /// 102 private void updateLook() 103 { 104 auto lookat = entity.sceneNode.position + entity.sceneNode.forward; 105 106 matLook = mat4.look_at(entity.sceneNode.position, lookat, entity.sceneNode.up); 107 } 108 109 /// 110 private void updateProjection() 111 { 112 if(!isOrthographic) 113 { 114 import unecht.ue:ue; 115 auto w = ue.application.framebufferSize.width; 116 auto h = ue.application.framebufferSize.height; 117 matProjection = mat4.perspective(w, h, fieldOfView, clipNear, clipFar); 118 } 119 else 120 { 121 matProjection = mat4.orthographic(-(orthoSize/2),(orthoSize/2),-(orthoSize/2),(orthoSize/2),clipNear,clipFar); 122 } 123 } 124 125 /// render all renderables through the perspective of this camera 126 ///TODO: note: needs to be moved aways 127 public void render() 128 { 129 import unecht.ue:ue; 130 import derelict.opengl3.gl3; 131 132 updateProjection(); 133 updateLook(); 134 135 int clearBits = 0; 136 if(clearBitColor) clearBits |= GL_COLOR_BUFFER_BIT; 137 if(clearBitDepth) clearBits |= GL_DEPTH_BUFFER_BIT; 138 139 if(clearBits!=0) 140 { 141 glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); 142 glClear(clearBits); 143 } 144 145 UESize viewportSize = UESize( 146 cast(int)(viewport.size.x * ue.application.framebufferSize.width), 147 cast(int)(viewport.size.y * ue.application.framebufferSize.height)); 148 glViewport(viewport.pos.left,viewport.pos.top,viewportSize.width,viewportSize.height); 149 150 auto renderers = ue.scene.gatherAllComponents!UERenderer; 151 152 foreach(r; renderers) 153 { 154 if(r.enabled && r.sceneNode.enabled) 155 { 156 import unecht.core.stdex; 157 if(testBit(visibleLayers, r.entity.layer)) 158 r.render(this); 159 } 160 } 161 } 162 163 private: 164 mat4 matProjection = mat4.identity; 165 mat4 matLook = mat4.identity; 166 }