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 void close() 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 void close() 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 FreeImage_SetOutputMessage(&FreeImageErrorHandler); 178 shaders = new IdArray!(ShaderProgram); 179 180 primShader = new ShaderProgram(primVertFill2d, primFragFill2d); 181 if (!primShader.compile) 182 throw new Exception(primShader.errorLog); 183 registerShaderProgram(primShader); 184 185 primTexShader = new ShaderProgram(primVertTex2d, primFragTex2d); 186 if (!primTexShader.compile) 187 throw new Exception("textured primitive shader failed compilation\n"~primTexShader.errorLog); 188 registerShaderProgram(primTexShader); 189 190 rectVao = new Vao; 191 texRectVao = new Vao; 192 rectVbo = new Vbo(GL_STREAM_DRAW); 193 texRectVbo = new Vbo(GL_STREAM_DRAW); 194 195 rectVao.bind; 196 rectVbo.bind; 197 glEnableVertexAttribArray(0); 198 glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 2*short.sizeof, null); 199 rectVbo.unbind; 200 rectVao.unbind; 201 texRectVao.bind; 202 texRectVbo.bind; 203 glEnableVertexAttribArray(0); 204 glEnableVertexAttribArray(1); 205 glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, null); 206 glVertexAttribPointer(1, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, cast(void*)(2*short.sizeof)); 207 texRectVbo.unbind; 208 texRectVao.unbind; 209 } 210 211 override void close() 212 { 213 foreach(k; shaders.array.byKey) 214 { 215 shaders[k].close; 216 shaders.remove(k); 217 } 218 } 219 220 void drawText(string text, uint x, uint y, uint font) 221 { 222 223 } 224 225 override uint createShaderProgram(string vertexSource, string fragmentSource) 226 { 227 ShaderProgram newProgram = new ShaderProgram(vertexSource, fragmentSource); 228 if (!newProgram.compile) 229 writeln(newProgram.errorLog); 230 return shaders.add(newProgram); 231 } 232 233 override uint registerShaderProgram(ShaderProgram program) 234 { 235 return shaders.add(program); 236 } 237 238 override Texture createTexture(string filename) 239 in 240 { 241 assert(textures !is null); 242 } 243 body 244 { 245 Texture tex = new Texture(filename, TextureTarget.target2d, TextureFormat.rgba); 246 return tex; 247 } 248 249 override void bindTexture(Texture texture, uint textureUnit = 0) 250 in 251 { 252 assert(texture !is null); 253 } 254 body 255 { 256 texture.validateBind(textureUnit); 257 } 258 259 override void bindShaderProgram(uint programName) 260 { 261 ShaderProgram program = shaders[programName]; 262 assert(program !is null); 263 bindShaderProgram(program); 264 } 265 266 override void bindShaderProgram(ref ShaderProgram program) 267 { 268 //if (currentShaderProgram == program) return; 269 program.bind; 270 _currentShaderProgram = program; 271 } 272 273 void setProgram(in uint program) 274 { 275 276 } 277 278 override void setClearColor(in Color color) 279 { 280 with(color) 281 { 282 glClearColor(cast(float)r/255, cast(float)g/255, cast(float)b/255, cast(float)a/255); 283 } 284 } 285 286 override void setColor(in Color newColor) 287 { 288 Color4f c4f = Color4f(newColor); 289 if (c4f != curColor) 290 { 291 curColor = c4f; 292 } 293 } 294 295 override void setColor(in Color4f newColor) 296 { 297 curColor = newColor; 298 } 299 300 override void enableAlphaBlending() 301 { 302 glEnable(GL_BLEND); 303 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 304 } 305 306 override void disableAlphaBlending() 307 { 308 glDisable(GL_BLEND); 309 } 310 311 override void drawRect(Rect rect) 312 { 313 bindShaderProgram(primShader); 314 primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 315 primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 316 rectVao.bind; 317 rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y, 318 rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height]; 319 glDrawArrays(GL_LINE_LOOP, 0, 4); 320 rectVao.unbind; 321 } 322 323 override void fillRect(Rect rect) 324 { 325 bindShaderProgram(primShader); 326 primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 327 primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 328 rectVao.bind; 329 rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y, 330 rect.x + rect.width, rect.y, rect.x, rect.y + rect.height, 331 rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height]; 332 glDrawArrays(GL_TRIANGLES, 0, 6); 333 rectVao.unbind; 334 } 335 336 /+++++ 337 + Draws textured rectangle to the current target 338 + target - position and size on the screen. 339 + source - position and size of rectangle in texture 340 +++++/ 341 override void drawTexRect(Rect target, Rect source, Texture texture) 342 in 343 { 344 assert(texture !is null); 345 } 346 body 347 { 348 if (texture.size == uvec2(0, 0)) return; 349 350 bindShaderProgram(primTexShader); 351 primTexShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2); 352 primTexShader.setUniform2!float("gPosition", target.x, target.y); 353 primTexShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 354 355 texture.validateBind(); 356 texRectVao.bind; 357 int ty2 = source.y + source.height; 358 int tx2 = source.x + source.width; 359 int y2 = target.y + target.height; 360 int x2 = target.x + target.width; 361 texRectVbo.data = cast(short[])[0, target.height, source.x, ty2, 362 0, 0, source.x, source.y, 363 target.width, 0, tx2, source.y, 364 0, target.height, source.x, ty2, 365 target.width, 0, tx2, source.y, 366 target.width, target.height, tx2, ty2]; 367 glDrawArrays(GL_TRIANGLES, 0, 6); 368 texRectVao.unbind; 369 texture.unbind; 370 } 371 372 override void drawTexRectArray(TexRectArray array, ivec2 position, Texture texture, ShaderProgram customProgram = null) 373 in 374 { 375 assert(texture !is null); 376 } 377 body 378 { 379 ShaderProgram program = customProgram; 380 if (customProgram is null) program = primTexShader; 381 drawTexRectArrayImpl(array, position, texture, program); 382 } 383 384 private void drawTexRectArrayImpl(TexRectArray array, ivec2 position, Texture texture, ShaderProgram program) 385 in 386 { 387 assert(texture !is null); 388 } 389 body 390 { 391 bindShaderProgram(program); 392 program.setUniform2!float("gHalfTarget", cast(float)window.size.x / 2, cast(float)window.size.y / 2); 393 program.setUniform2!float("gPosition", position.x, position.y); 394 program.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a); 395 396 texture.validateBind(); 397 array.bind; 398 glDrawArrays(GL_TRIANGLES, 0, cast(uint)array.vertieces.length); 399 array.unbind; 400 texture.unbind; 401 } 402 403 override uvec2 windowSize() 404 { 405 return window.size(); 406 } 407 408 override void flush() 409 { 410 window.swapBuffers; 411 } 412 413 private: 414 415 ShaderProgram _currentShaderProgram; 416 ShaderProgram primShader; 417 ShaderProgram primTexShader; 418 419 IdArray!(ShaderProgram) shaders; 420 421 IWindow window; 422 423 Vbo rectVbo; 424 Vbo texRectVbo; 425 Vao rectVao; 426 Vao texRectVao; 427 428 Color4f curColor; 429 uint primColorLoc, primTargetSizeLoc; 430 } 431 432 extern(C) 433 { 434 nothrow void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const( char)*message) 435 { 436 try 437 { 438 writeln("\n*** "); 439 if(fif != FIF_UNKNOWN) { 440 writefln("%s Format\n", FreeImage_GetFormatFromFIF(fif)); 441 } 442 writeln(ZToString(message)); 443 writeln(" ***\n"); 444 } 445 catch(Exception e) 446 { 447 //writeln(e.msg); 448 } 449 } 450 } 451