1 /* 2 Copyright (c) 2013 Andrey Penechko 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license the "Software" to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 module anchovy.graphics.renderers.ogl3renderer; 30 31 import std.conv; 32 import std.stdio; 33 import std.string; 34 35 import derelict.freeimage.freeimage; 36 import derelict.freetype.ft; 37 38 import anchovy.utils.string; 39 40 public import anchovy.core.types; 41 42 //import anchovy.graphics.all; 43 import anchovy.graphics.shaderprogram; 44 import anchovy.graphics.texture; 45 46 import anchovy.graphics.interfaces.irenderer; 47 import anchovy.core.interfaces.iwindow; 48 49 50 class Vbo 51 { 52 this(uint bufferUsage, uint target = GL_ARRAY_BUFFER) 53 { 54 this.bufferUsage = bufferUsage; 55 this.target = target; 56 glGenBuffers(1, &handle); 57 } 58 59 ~this() 60 { 61 glDeleteBuffers(1, &handle); 62 } 63 64 ref const(void[]) data(void[] newData) @property 65 { 66 _data = newData; 67 glBindBuffer(target, handle); 68 glBufferData(target, _data.length, _data.ptr, bufferUsage); 69 glBindBuffer(target, 0); 70 return _data; 71 } 72 73 ref const(void[]) data() @property 74 { 75 return _data; 76 } 77 78 void bind() 79 { 80 glBindBuffer(target, handle); 81 } 82 83 void unbind() 84 { 85 glBindBuffer(target, 0); 86 } 87 88 uint handle; 89 uint bufferUsage; 90 uint target; 91 void[] _data; 92 } 93 94 class Vao 95 { 96 this() 97 { 98 glGenVertexArrays(1, &handle); 99 } 100 ~this() 101 { 102 glDeleteVertexArrays(1, &handle); 103 } 104 void bind() 105 { 106 glBindVertexArray(handle); 107 } 108 109 static void unbind() 110 { 111 glBindVertexArray(0); 112 } 113 uint handle; 114 } 115 116 string primVertTex2d = `#version 330 117 layout (location = 0) in vec2 position; 118 layout (location = 1) in vec2 texCoord; 119 uniform sampler2D gSampler; 120 uniform vec2 gHalfTarget; 121 uniform vec2 gPosition; 122 out vec2 texCoord0; 123 124 void main() 125 { 126 gl_Position = vec4((position.x + gPosition.x) / gHalfTarget.x - 1, 127 1 - ((position.y + gPosition.y) / gHalfTarget.y), 128 0.0, 1.0); 129 ivec2 texSize = textureSize(gSampler, 0); 130 texCoord0 = vec2(texCoord.x/texSize.x, texCoord.y/texSize.y); 131 } 132 `; 133 134 string primFragTex2d=`#version 330 135 in vec2 texCoord0; 136 out vec4 FragColor; 137 138 uniform sampler2D gSampler; 139 uniform vec4 gColor = vec4(1, 1, 1, 1); 140 141 void main() 142 { 143 FragColor = texture2D(gSampler, texCoord0)*gColor; 144 }`; 145 146 string primVertFill2d = `#version 330 147 in vec2 position; 148 149 uniform vec2 gHalfTarget; 150 uniform vec4 gColor; 151 152 smooth out vec4 theColor; 153 154 void main() 155 { 156 gl_Position = vec4(((position.x+0.5)/gHalfTarget.x)-1, 1-((position.y+0.5)/gHalfTarget.y), 0.0, 1.0); 157 theColor = gColor; 158 } 159 `; 160 //in smooth vec4 theColor DOESN'T works use smooth in unstead 161 string primFragFill2d=`#version 330 162 smooth in vec4 theColor; 163 out vec4 fragColor; 164 165 void main() 166 { 167 fragColor = theColor; 168 } 169 `; 170 171 class Ogl3Renderer : IRenderer 172 { 173 this(IWindow window) 174 { 175 this.window = window; 176 177 DerelictFI.load(); 178 DerelictFT.load(); 179 180 FreeImage_SetOutputMessage(&FreeImageErrorHandler); 181 shaders = new IdArray!(ShaderProgram); 182 183 primShader = new ShaderProgram(primVertFill2d, primFragFill2d); 184 if (!primShader.compile) 185 throw new Exception(primShader.errorLog); 186 187 primTexShader = new ShaderProgram(primVertTex2d, primFragTex2d); 188 if (!primTexShader.compile) 189 throw new Exception("textured primitive shader failed compilation\n"~primTexShader.errorLog); 190 191 rectVao = new Vao; 192 texRectVao = new Vao; 193 rectVbo = new Vbo(GL_STREAM_DRAW); 194 texRectVbo = new Vbo(GL_STREAM_DRAW); 195 196 rectVao.bind; 197 rectVbo.bind; 198 glEnableVertexAttribArray(0); 199 glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 2*short.sizeof, null); 200 rectVbo.unbind; 201 rectVao.unbind; 202 texRectVao.bind; 203 texRectVbo.bind; 204 glEnableVertexAttribArray(0); 205 glEnableVertexAttribArray(1); 206 glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, null); 207 glVertexAttribPointer(1, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, cast(void*)(2*short.sizeof)); 208 texRectVbo.unbind; 209 texRectVao.unbind; 210 } 211 212 void drawText(string text, uint x, uint y, uint font) 213 { 214 215 } 216 217 override uint createShaderProgram(string vertexSource, string fragmentSource) 218 { 219 ShaderProgram newProgram = new ShaderProgram(vertexSource, fragmentSource); 220 if (!newProgram.compile) 221 writeln(newProgram.errorLog); 222 return shaders.add(newProgram); 223 } 224 225 override uint registerShaderProgram(ShaderProgram program) 226 { 227 return shaders.add(program); 228 } 229 230 override Texture createTexture(string filename) 231 in 232 { 233 assert(textures !is null); 234 } 235 body 236 { 237 Texture tex = new Texture(filename, TextureTarget.target2d, TextureFormat.rgba); 238 return tex; 239 } 240 241 override void bindTexture(Texture texture, uint textureUnit = 0) 242 in 243 { 244 assert(texture !is null); 245 } 246 body 247 { 248 texture.validateBind(textureUnit); 249 } 250 251 override void bindShaderProgram(uint programName) 252 { 253 ShaderProgram program = shaders[programName]; 254 assert(program !is null); 255 bindShaderProgram(program); 256 } 257 258 override void bindShaderProgram(ref ShaderProgram program) 259 { 260 //if (currentShaderProgram == program) return; 261 program.bind; 262 _currentShaderProgram = program; 263 } 264 265 void setProgram(in uint program) 266 { 267 268 } 269 270 override void setClearColor(in Color color) 271 { 272 with(color) 273 { 274 glClearColor(cast(float)r/255, cast(float)g/255, cast(float)b/255, cast(float)a/255); 275 } 276 } 277 278 override void setColor(in Color newColor) 279 { 280 Color4f c4f = Color4f(newColor); 281 if (c4f != curColor) 282 { 283 curColor = c4f; 284 } 285 } 286 287 override void setColor(in Color4f newColor) 288 { 289 curColor = newColor; 290 } 291 292 override void enableAlphaBlending() 293 { 294 glEnable(GL_BLEND); 295 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 296 } 297 298 override void disableAlphaBlending() 299 { 300 glDisable(GL_BLEND); 301 } 302 303 override void drawRect(Rect rect) 304 { 305 bindShaderProgram(primShader); 306 primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 307 primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 308 rectVao.bind; 309 rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y, 310 rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height]; 311 glDrawArrays(GL_LINE_LOOP, 0, 4); 312 rectVao.unbind; 313 } 314 315 override void fillRect(Rect rect) 316 { 317 bindShaderProgram(primShader); 318 primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 319 primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 320 rectVao.bind; 321 rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y, 322 rect.x + rect.width, rect.y, rect.x, rect.y + rect.height, 323 rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height]; 324 glDrawArrays(GL_TRIANGLES, 0, 6); 325 rectVao.unbind; 326 } 327 328 /+++++ 329 + Draws textured rectangle to the current target 330 + target - position and size on the screen. 331 + source - position and size of rectangle in texture 332 +++++/ 333 override void drawTexRect(Rect target, Rect source, Texture texture) 334 in 335 { 336 assert(texture !is null); 337 } 338 body 339 { 340 if (texture.size == uvec2(0, 0)) return; 341 342 bindShaderProgram(primTexShader); 343 primTexShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 344 primTexShader.setUniform2!float("gPosition", target.x, target.y); 345 primTexShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 346 347 texture.validateBind(); 348 texRectVao.bind; 349 int ty2 = source.y + source.height; 350 int tx2 = source.x + source.width; 351 int y2 = target.y + target.height; 352 int x2 = target.x + target.width; 353 texRectVbo.data = cast(short[])[0, target.height, source.x, ty2, 354 0, 0, source.x, source.y, 355 target.width, 0, tx2, source.y, 356 0, target.height, source.x, ty2, 357 target.width, 0, tx2, source.y, 358 target.width, target.height, tx2, ty2]; 359 glDrawArrays(GL_TRIANGLES, 0, 6); 360 texRectVao.unbind; 361 texture.unbind; 362 } 363 364 override void drawTexRectArray(TexRectArray array, ivec2 position, Texture texture, ShaderProgram customProgram = null) 365 in 366 { 367 assert(texture !is null); 368 } 369 body 370 { 371 ShaderProgram program = customProgram; 372 if (customProgram is null) program = primTexShader; 373 drawTexRectArrayImpl(array, position, texture, program); 374 } 375 376 private void drawTexRectArrayImpl(TexRectArray array, ivec2 position, Texture texture, ShaderProgram program) 377 in 378 { 379 assert(texture !is null); 380 } 381 body 382 { 383 bindShaderProgram(program); 384 program.setUniform2!float("gHalfTarget", cast(float)window.size.x / 2, cast(float)window.size.y / 2); 385 program.setUniform2!float("gPosition", position.x, position.y); 386 program.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 387 388 texture.validateBind(); 389 array.bind; 390 glDrawArrays(GL_TRIANGLES, 0, array.vertieces.length); 391 array.unbind; 392 texture.unbind; 393 } 394 395 override uvec2 windowSize() 396 { 397 return window.size(); 398 } 399 400 override void flush() 401 { 402 window.swapBuffers; 403 } 404 405 private: 406 407 ShaderProgram _currentShaderProgram; 408 ShaderProgram primShader; 409 ShaderProgram primTexShader; 410 411 IdArray!(ShaderProgram) shaders; 412 413 IWindow window; 414 415 Vbo rectVbo; 416 Vbo texRectVbo; 417 Vao rectVao; 418 Vao texRectVao; 419 420 Color4f curColor; 421 uint primColorLoc, primTargetSizeLoc; 422 } 423 424 extern(C) 425 { 426 nothrow void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const( char)*message) 427 { 428 try 429 { 430 writeln("\n*** "); 431 if(fif != FIF_UNKNOWN) { 432 writefln("%s Format\n", FreeImage_GetFormatFromFIF(fif)); 433 } 434 writeln(ZToString(message)); 435 writeln(" ***\n"); 436 } 437 catch(Exception e) 438 { 439 //writeln(e.msg); 440 } 441 } 442 } 443