1 /** 2 * Copyright: Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved 3 * Authors: $(Gabriel Gheorghe) 4 * License: $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007) 5 * Source: $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/graphics/backend/impl.d) 6 * Documentation: 7 * Coverage: 8 **/ 9 module liberty.graphics.backend.impl; 10 11 import bindbc.opengl; 12 import liberty.logger; 13 import liberty.graphics.backend.data; 14 import liberty.graphics.backend.factory; 15 import liberty.math.vector; 16 17 /// Backend class for graphics engine. 18 /// It implements $(D IGfxBackendFactory) service. 19 final class GfxBackend : IGfxBackendFactory { 20 private { 21 // getInfo 22 GfxBackendInfo info; 23 // getOptions 24 GfxBackendOptions options; 25 } 26 27 /// Instantiate class using $(D GfxBackendInfo) and $(D GfxBackendOptions). 28 this(GfxBackendInfo info, GfxBackendOptions options) { 29 // Initialize backend info and options 30 this.info = info; 31 this.options = options; 32 // Enable depth and stencil test by default 33 setDepthTestEnabled(true); 34 setStencilTestEnabled(true); 35 // TODO. Apply options to this, call graphics api functions 36 setBackColor(45, 45, 45, 255); 37 enableAnisotropicFiltering(0.0f); 38 Logger.info("Graphics backend has been created successfully", typeof(this).stringof); 39 } 40 41 /// Clear the depth, stencil and color of the screen. 42 /// Returns reference to this so it can be used in a stream. 43 typeof(this) clearScreen() { 44 glClearDepth(1.0); 45 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 46 glClearColor( 47 options.backColor.r / 255.0f, 48 options.backColor.g / 255.0f, 49 options.backColor.b / 255.0f, 50 options.backColor.a / 255.0f 51 ); // TODO. Optimize 52 glDepthFunc(GL_LEQUAL); 53 return this; 54 } 55 56 /// Enable or disable wireframe. 57 /// Returns reference to this so it can be used in a stream. 58 typeof(this) setWireframeEnabled(bool enabled = true) { 59 glPolygonMode(GL_FRONT_AND_BACK, enabled ? GL_LINE : GL_FILL); 60 options.wireframeEnabled = enabled; 61 return this; 62 } 63 64 /// Swap between wireframe and non-wireframe mode. 65 /// Returns reference to this so it can be used in a stream. 66 typeof(this) swapWireframe() { 67 glPolygonMode(GL_FRONT_AND_BACK, options.wireframeEnabled ? GL_FILL : GL_LINE); 68 options.wireframeEnabled = !options.wireframeEnabled; 69 return this; 70 } 71 72 /// Enable or disable depth test. 73 /// Returns reference to this so it can be used in a stream. 74 typeof(this) setDepthTestEnabled(bool enabled = true) { 75 enabled 76 ? glEnable(GL_DEPTH_TEST) 77 : glDisable(GL_DEPTH_TEST); 78 options.depthTestEnabled = enabled; 79 return this; 80 } 81 82 /// Set false depth mask to disable writing to depth buffer, render stuff that 83 /// shouldn't influence the depth buffer then set true to enable it again. 84 /// Returns reference to this so it can be used in a stream. 85 typeof(this) setDepthMask(bool value = true) { 86 glDepthMask(value); 87 return this; 88 } 89 90 /// Enable or disable stencil test. 91 /// Returns reference to this so it can be used in a stream. 92 typeof(this) setStencilTestEnabled(bool enabled = true) { 93 enabled 94 ? glEnable(GL_STENCIL_TEST) 95 : glDisable(GL_STENCIL_TEST); 96 options.stencilTestEnabled = enabled; 97 return this; 98 } 99 100 /// Set true stencil mask and each bit is written to the stencil buffer as is. 101 /// Set false stencil mask and each bit ends up as 0 in the stencil buffer, disabling writes. 102 /// TODO: Enable custom stencil mask. 103 /// Returns reference to this so it can be used in a stream. 104 typeof(this) setStencilMask(bool value = true) { 105 glStencilMask(value ? 0xFF : 0x00); 106 return this; 107 } 108 109 /// Enable or disable texture. 110 /// Returns reference to this so it can be used in a stream. 111 typeof(this) setTextureEnabled(bool enabled = true) { 112 enabled 113 ? glEnable(GL_TEXTURE_2D) 114 : glDisable(GL_TEXTURE_2D); 115 options.textureEnabled = enabled; 116 return this; 117 } 118 119 /// Enable or disable culling. 120 /// Returns reference to this so it can be used in a stream. 121 typeof(this) setCullingEnabled(bool enabled = true) { 122 enabled 123 ? (glEnable(GL_CULL_FACE), glCullFace(GL_BACK)) 124 : glDisable(GL_CULL_FACE); 125 options.cullingEnabled = enabled; 126 return this; 127 } 128 129 /** 130 * Set back color r-red, g-green, b-blue, a-alpha scalars. 131 * A channel value must be in range 0-255, so it can handle 256 possible values. 132 * Returns reference to this so it can be used in a stream. 133 **/ 134 typeof(this) setBackColor(ubyte r, ubyte g, ubyte b, ubyte a) { 135 return setBackColor(Color4(r, g, b, a)); 136 } 137 138 /** 139 * Set back color using $(Color4). 140 * A channel value must be in range 0-255, so it can handle 256 possible values. 141 * Returns reference to this so it can be used in a stream. 142 **/ 143 typeof(this) setBackColor(Color4 color) { 144 options.backColor = color; 145 return this; 146 } 147 148 /** 149 * Enable the alpha blend. 150 * Returns reference to this so it can be used in a stream. 151 **/ 152 typeof(this) enableAlphaBlend() { 153 glEnable(GL_BLEND); 154 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 155 options.alphaBlendEnabled = true; 156 return this; 157 } 158 159 /** 160 * Disable the blend. 161 * Returns reference to this so it can be used in a stream. 162 **/ 163 typeof(this) disableBlend() { 164 glDisable(GL_BLEND); 165 options.alphaBlendEnabled = false; 166 return this; 167 } 168 169 /** 170 * Enable and set anisotropic filtering if possible. 171 * Use 0.0f to disable it. 172 * Only values 4.0f, 8.0f and 16.0f are supported for enabling it. 173 * Returns reference to this so it can be used in a stream. 174 **/ 175 typeof(this) enableAnisotropicFiltering(float value) 176 in (value == 0.0f || value == 4.0f || value == 8.0f || value == 16.0f, 177 "Only values 0.0f, 4.0f, 8.0f and 16.0f are supported.") 178 do { 179 options.anisotropicFiltering = value; 180 return this; 181 } 182 183 /** 184 * Returns true if the given extension is supported. 185 **/ 186 bool supportsExtension(string extension) const { 187 foreach (el; info.extensions) 188 if (el == extension) 189 return true; 190 191 return false; 192 } 193 194 /// Returns backend info. 195 GfxBackendInfo getInfo() { 196 return info; 197 } 198 199 /// Returns backend options. 200 GfxBackendOptions getOptions() { 201 return options; 202 } 203 }