1 /* 2 Inochi2D Rendering 3 4 Copyright © 2020, Inochi2D Project 5 Distributed under the 2-Clause BSD License, see LICENSE file. 6 7 Authors: Luna Nielsen 8 */ 9 module inochi2d.core; 10 11 public import inochi2d.core.shader; 12 public import inochi2d.core.texture; 13 public import inochi2d.core.nodes; 14 public import inochi2d.core.puppet; 15 public import inochi2d.core.meshdata; 16 public import inochi2d.core.param; 17 public import inochi2d.core.automation; 18 public import inochi2d.core.animation; 19 public import inochi2d.integration; 20 import inochi2d.core.dbg; 21 22 import bindbc.opengl; 23 import inochi2d.math; 24 import std.stdio; 25 26 version(Windows) { 27 // Ask Windows nicely to use dedicated GPUs :) 28 export extern(C) int NvOptimusEnablement = 0x00000001; 29 export extern(C) int AmdPowerXpressRequestHighPerformance = 0x00000001; 30 } 31 32 struct PostProcessingShader { 33 private: 34 GLint[string] uniformCache; 35 36 public: 37 Shader shader; 38 this(Shader shader) { 39 this.shader = shader; 40 41 shader.use(); 42 shader.setUniform(shader.getUniformLocation("albedo"), 0); 43 shader.setUniform(shader.getUniformLocation("emissive"), 1); 44 shader.setUniform(shader.getUniformLocation("bumpmap"), 2); 45 } 46 47 /** 48 Gets the location of the specified uniform 49 */ 50 GLuint getUniform(string name) { 51 if (this.hasUniform(name)) return uniformCache[name]; 52 GLint element = shader.getUniformLocation(name); 53 uniformCache[name] = element; 54 return element; 55 } 56 57 /** 58 Returns true if the uniform is present in the shader cache 59 */ 60 bool hasUniform(string name) { 61 return (name in uniformCache) !is null; 62 } 63 } 64 65 // Internal rendering constants 66 private { 67 // Viewport 68 int inViewportWidth; 69 int inViewportHeight; 70 71 GLuint sceneVAO; 72 GLuint sceneVBO; 73 74 GLuint fBuffer; 75 GLuint fAlbedo; 76 GLuint fEmissive; 77 GLuint fBump; 78 GLuint fStencil; 79 80 GLuint cfBuffer; 81 GLuint cfAlbedo; 82 GLuint cfEmissive; 83 GLuint cfBump; 84 GLuint cfStencil; 85 86 vec4 inClearColor; 87 88 PostProcessingShader basicSceneShader; 89 PostProcessingShader basicSceneLighting; 90 PostProcessingShader[] postProcessingStack; 91 92 // Camera 93 Camera inCamera; 94 95 bool isCompositing; 96 97 void renderScene(vec4 area, PostProcessingShader shaderToUse, GLuint albedo, GLuint emissive, GLuint bump) { 98 glViewport(0, 0, cast(int)area.z, cast(int)area.w); 99 100 // Bind our vertex array 101 glBindVertexArray(sceneVAO); 102 103 glDisable(GL_CULL_FACE); 104 glDisable(GL_DEPTH_TEST); 105 glEnable(GL_BLEND); 106 glBlendEquation(GL_FUNC_ADD); 107 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 108 109 shaderToUse.shader.use(); 110 shaderToUse.shader.setUniform(shaderToUse.getUniform("mvp"), 111 mat4.orthographic(0, area.z, area.w, 0, 0, max(area.z, area.w)) * 112 mat4.translation(area.x, area.y, 0) 113 ); 114 115 // Ambient light 116 GLint ambientLightUniform = shaderToUse.getUniform("ambientLight"); 117 if (ambientLightUniform != -1) shaderToUse.shader.setUniform(ambientLightUniform, inSceneAmbientLight); 118 119 // framebuffer size 120 GLint fbSizeUniform = shaderToUse.getUniform("fbSize"); 121 if (fbSizeUniform != -1) shaderToUse.shader.setUniform(fbSizeUniform, vec2(inViewportWidth, inViewportHeight)); 122 123 // Bind the texture 124 glActiveTexture(GL_TEXTURE0); 125 glBindTexture(GL_TEXTURE_2D, albedo); 126 glActiveTexture(GL_TEXTURE1); 127 glBindTexture(GL_TEXTURE_2D, emissive); 128 glActiveTexture(GL_TEXTURE2); 129 glBindTexture(GL_TEXTURE_2D, bump); 130 131 // Enable points array 132 glEnableVertexAttribArray(0); // verts 133 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*float.sizeof, null); 134 135 // Enable UVs array 136 glEnableVertexAttribArray(1); // uvs 137 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*float.sizeof, cast(float*)(2*float.sizeof)); 138 139 // Draw 140 glDrawArrays(GL_TRIANGLES, 0, 6); 141 142 // Disable the vertex attribs after use 143 glDisableVertexAttribArray(0); 144 glDisableVertexAttribArray(1); 145 146 glDisable(GL_BLEND); 147 } 148 } 149 150 // Things only available internally for Inochi2D rendering 151 package(inochi2d) { 152 153 /** 154 Initializes the renderer 155 */ 156 void initRenderer() { 157 158 // Set the viewport and by extension set the textures 159 inSetViewport(640, 480); 160 161 // Initialize dynamic meshes 162 inInitBlending(); 163 inInitNodes(); 164 inInitDrawable(); 165 inInitPart(); 166 inInitMask(); 167 inInitComposite(); 168 inInitMeshGroup(); 169 version(InDoesRender) inInitDebug(); 170 171 inParameterSetFactory((data) { 172 import fghj : deserializeValue; 173 Parameter param = new Parameter; 174 data.deserializeValue(param); 175 return param; 176 }); 177 178 // Some defaults that should be changed by app writer 179 inCamera = new Camera; 180 181 inClearColor = vec4(0, 0, 0, 0); 182 183 version (InDoesRender) { 184 185 // Shader for scene 186 basicSceneShader = PostProcessingShader(new Shader(import("scene.vert"), import("scene.frag"))); 187 glGenVertexArrays(1, &sceneVAO); 188 glGenBuffers(1, &sceneVBO); 189 190 // Generate the framebuffer we'll be using to render the model and composites 191 glGenFramebuffers(1, &fBuffer); 192 glGenFramebuffers(1, &cfBuffer); 193 194 // Generate the color and stencil-depth textures needed 195 // Note: we're not using the depth buffer but OpenGL 3.4 does not support stencil-only buffers 196 glGenTextures(1, &fAlbedo); 197 glGenTextures(1, &fEmissive); 198 glGenTextures(1, &fBump); 199 glGenTextures(1, &fStencil); 200 201 glGenTextures(1, &cfAlbedo); 202 glGenTextures(1, &cfEmissive); 203 glGenTextures(1, &cfBump); 204 glGenTextures(1, &cfStencil); 205 206 // Attach textures to framebuffer 207 glBindFramebuffer(GL_FRAMEBUFFER, fBuffer); 208 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fAlbedo, 0); 209 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fEmissive, 0); 210 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, fBump, 0); 211 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fStencil, 0); 212 213 glBindFramebuffer(GL_FRAMEBUFFER, cfBuffer); 214 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cfAlbedo, 0); 215 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, cfEmissive, 0); 216 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, cfBump, 0); 217 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, cfStencil, 0); 218 219 // go back to default fb 220 glBindFramebuffer(GL_FRAMEBUFFER, 0); 221 } 222 } 223 } 224 225 vec3 inSceneAmbientLight = vec3(1, 1, 1); 226 227 /** 228 Begins rendering to the framebuffer 229 */ 230 void inBeginScene() { 231 glBindVertexArray(sceneVAO); 232 glEnable(GL_BLEND); 233 glEnablei(GL_BLEND, 0); 234 glEnablei(GL_BLEND, 1); 235 glEnablei(GL_BLEND, 2); 236 glDisable(GL_DEPTH_TEST); 237 glDisable(GL_CULL_FACE); 238 239 // Make sure to reset our viewport if someone has messed with it 240 glViewport(0, 0, inViewportWidth, inViewportHeight); 241 242 // Bind and clear composite framebuffer 243 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, cfBuffer); 244 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 245 glClearColor(0, 0, 0, 0); 246 247 // Bind our framebuffer 248 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fBuffer); 249 250 // First clear buffer 0 251 glDrawBuffers(1, [GL_COLOR_ATTACHMENT0].ptr); 252 glClearColor(inClearColor.r, inClearColor.g, inClearColor.b, inClearColor.a); 253 glClear(GL_COLOR_BUFFER_BIT); 254 255 // Then clear others with black 256 glDrawBuffers(2, [GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 257 glClearColor(0, 0, 0, 1); 258 glClear(GL_COLOR_BUFFER_BIT); 259 260 // Everything else is the actual texture used by the meshes at id 0 261 glActiveTexture(GL_TEXTURE0); 262 263 // Finally we render to all buffers 264 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 265 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 266 } 267 268 /** 269 Begins a composition step 270 */ 271 void inBeginComposite() { 272 273 // We don't allow recursive compositing 274 if (isCompositing) return; 275 isCompositing = true; 276 277 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, cfBuffer); 278 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 279 glClearColor(0, 0, 0, 0); 280 glClear(GL_COLOR_BUFFER_BIT); 281 282 // Everything else is the actual texture used by the meshes at id 0 283 glActiveTexture(GL_TEXTURE0); 284 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 285 } 286 287 /** 288 Ends a composition step, re-binding the internal framebuffer 289 */ 290 void inEndComposite() { 291 292 // We don't allow recursive compositing 293 if (!isCompositing) return; 294 isCompositing = false; 295 296 glBindFramebuffer(GL_FRAMEBUFFER, fBuffer); 297 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 298 glFlush(); 299 } 300 301 /** 302 Ends rendering to the framebuffer 303 */ 304 void inEndScene() { 305 glBindFramebuffer(GL_FRAMEBUFFER, 0); 306 307 glDisablei(GL_BLEND, 0); 308 glDisablei(GL_BLEND, 1); 309 glDisablei(GL_BLEND, 2); 310 glEnable(GL_DEPTH_TEST); 311 glEnable(GL_CULL_FACE); 312 glDisable(GL_BLEND); 313 glFlush(); 314 glDrawBuffers(1, [GL_COLOR_ATTACHMENT0].ptr); 315 } 316 317 /** 318 Runs post processing on the scene 319 */ 320 void inPostProcessScene() { 321 if (postProcessingStack.length == 0) return; 322 323 bool targetBuffer; 324 325 float r, g, b, a; 326 inGetClearColor(r, g, b, a); 327 328 // Render area 329 vec4 area = vec4( 330 0, 0, 331 inViewportWidth, inViewportHeight 332 ); 333 334 // Tell OpenGL the resolution to render at 335 float[] data = [ 336 area.x, area.y+area.w, 0, 0, 337 area.x, area.y, 0, 1, 338 area.x+area.z, area.y+area.w, 1, 0, 339 340 area.x+area.z, area.y+area.w, 1, 0, 341 area.x, area.y, 0, 1, 342 area.x+area.z, area.y, 1, 1, 343 ]; 344 glBindBuffer(GL_ARRAY_BUFFER, sceneVBO); 345 glBufferData(GL_ARRAY_BUFFER, 24*float.sizeof, data.ptr, GL_DYNAMIC_DRAW); 346 347 348 glActiveTexture(GL_TEXTURE1); 349 glBindTexture(GL_TEXTURE_2D, fEmissive); 350 glGenerateMipmap(GL_TEXTURE_2D); 351 352 // We want to be able to post process all the attachments 353 glBindFramebuffer(GL_FRAMEBUFFER, cfBuffer); 354 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 355 glClear(GL_COLOR_BUFFER_BIT); 356 357 glBindFramebuffer(GL_FRAMEBUFFER, fBuffer); 358 glDrawBuffers(3, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2].ptr); 359 360 foreach(shader; postProcessingStack) { 361 targetBuffer = !targetBuffer; 362 363 if (targetBuffer) { 364 365 // Main buffer -> Composite buffer 366 glBindFramebuffer(GL_FRAMEBUFFER, cfBuffer); // dst 367 renderScene(area, shader, fAlbedo, fEmissive, fBump); // src 368 } else { 369 370 // Composite buffer -> Main buffer 371 glBindFramebuffer(GL_FRAMEBUFFER, fBuffer); // dst 372 renderScene(area, shader, cfAlbedo, cfEmissive, cfBump); // src 373 } 374 } 375 376 if (targetBuffer) { 377 glBindFramebuffer(GL_READ_FRAMEBUFFER, cfBuffer); 378 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fBuffer); 379 glBlitFramebuffer( 380 0, 0, inViewportWidth, inViewportHeight, // src rect 381 0, 0, inViewportWidth, inViewportHeight, // dst rect 382 GL_COLOR_BUFFER_BIT, // blit mask 383 GL_LINEAR // blit filter 384 ); 385 } 386 387 glBindFramebuffer(GL_FRAMEBUFFER, 0); 388 } 389 390 /** 391 Add basic lighting shader to processing stack 392 */ 393 void inPostProcessingAddBasicLighting() { 394 postProcessingStack ~= PostProcessingShader( 395 new Shader( 396 import("scene.vert"), 397 import("lighting.frag") 398 ) 399 ); 400 } 401 402 /** 403 Clears the post processing stack 404 */ 405 ref PostProcessingShader[] inGetPostProcessingStack() { 406 return postProcessingStack; 407 } 408 409 /** 410 Gets the global camera 411 */ 412 Camera inGetCamera() { 413 return inCamera; 414 } 415 416 /** 417 Sets the global camera, allows switching between cameras 418 */ 419 void inSetCamera(Camera camera) { 420 inCamera = camera; 421 } 422 423 /** 424 Draw scene to area 425 */ 426 void inDrawScene(vec4 area) { 427 float[] data = [ 428 area.x, area.y+area.w, 0, 0, 429 area.x, area.y, 0, 1, 430 area.x+area.z, area.y+area.w, 1, 0, 431 432 area.x+area.z, area.y+area.w, 1, 0, 433 area.x, area.y, 0, 1, 434 area.x+area.z, area.y, 1, 1, 435 ]; 436 437 glBindBuffer(GL_ARRAY_BUFFER, sceneVBO); 438 glBufferData(GL_ARRAY_BUFFER, 24*float.sizeof, data.ptr, GL_DYNAMIC_DRAW); 439 renderScene(area, basicSceneShader, fAlbedo, fEmissive, fBump); 440 } 441 442 void incCompositePrepareRender() { 443 glActiveTexture(GL_TEXTURE0); 444 glBindTexture(GL_TEXTURE_2D, cfAlbedo); 445 glActiveTexture(GL_TEXTURE1); 446 glBindTexture(GL_TEXTURE_2D, cfEmissive); 447 glActiveTexture(GL_TEXTURE2); 448 glBindTexture(GL_TEXTURE_2D, cfBump); 449 } 450 451 /** 452 Gets the Inochi2D framebuffer 453 454 DO NOT MODIFY THIS IMAGE! 455 */ 456 GLuint inGetFramebuffer() { 457 return fBuffer; 458 } 459 460 /** 461 Gets the Inochi2D framebuffer render image 462 463 DO NOT MODIFY THIS IMAGE! 464 */ 465 GLuint inGetRenderImage() { 466 return fAlbedo; 467 } 468 469 /** 470 Gets the Inochi2D composite render image 471 472 DO NOT MODIFY THIS IMAGE! 473 */ 474 GLuint inGetCompositeImage() { 475 return cfAlbedo; 476 } 477 478 /** 479 Sets the viewport area to render to 480 */ 481 void inSetViewport(int width, int height) nothrow { 482 483 // Skip resizing when not needed. 484 if (width == inViewportWidth && height == inViewportHeight) return; 485 486 inViewportWidth = width; 487 inViewportHeight = height; 488 489 version(InDoesRender) { 490 // Render Framebuffer 491 glBindTexture(GL_TEXTURE_2D, fAlbedo); 492 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 494 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 495 496 glBindTexture(GL_TEXTURE_2D, fEmissive); 497 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, null); 498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 500 501 glBindTexture(GL_TEXTURE_2D, fBump); 502 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 505 506 glBindTexture(GL_TEXTURE_2D, fStencil); 507 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null); 508 509 glBindFramebuffer(GL_FRAMEBUFFER, fBuffer); 510 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fAlbedo, 0); 511 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fEmissive, 0); 512 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, fBump, 0); 513 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fStencil, 0); 514 515 516 // Composite framebuffer 517 glBindTexture(GL_TEXTURE_2D, cfAlbedo); 518 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 520 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 521 522 glBindTexture(GL_TEXTURE_2D, cfEmissive); 523 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, null); 524 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 526 527 glBindTexture(GL_TEXTURE_2D, cfBump); 528 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); 529 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 530 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 531 532 glBindTexture(GL_TEXTURE_2D, cfStencil); 533 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null); 534 535 glBindFramebuffer(GL_FRAMEBUFFER, cfBuffer); 536 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cfAlbedo, 0); 537 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, cfEmissive, 0); 538 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, cfBump, 0); 539 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, cfStencil, 0); 540 541 glBindFramebuffer(GL_FRAMEBUFFER, 0); 542 543 glViewport(0, 0, width, height); 544 } 545 } 546 547 /** 548 Gets the viewport 549 */ 550 void inGetViewport(out int width, out int height) nothrow { 551 width = inViewportWidth; 552 height = inViewportHeight; 553 } 554 555 /** 556 Returns length of viewport data for extraction 557 */ 558 size_t inViewportDataLength() { 559 return inViewportWidth * inViewportHeight * 4; 560 } 561 562 /** 563 Dumps viewport data to texture stream 564 */ 565 void inDumpViewport(ref ubyte[] dumpTo) { 566 import std.exception : enforce; 567 enforce(dumpTo.length >= inViewportDataLength(), "Invalid data destination length for inDumpViewport"); 568 glBindTexture(GL_TEXTURE_2D, fAlbedo); 569 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, dumpTo.ptr); 570 571 // We need to flip it because OpenGL renders stuff with a different coordinate system 572 ubyte[] tmpLine = new ubyte[inViewportWidth * 4]; 573 size_t ri = 0; 574 foreach_reverse(i; inViewportHeight/2..inViewportHeight) { 575 size_t lineSize = inViewportWidth*4; 576 size_t oldLineStart = (lineSize*ri); 577 size_t newLineStart = (lineSize*i); 578 import core.stdc.string : memcpy; 579 580 memcpy(tmpLine.ptr, dumpTo.ptr+oldLineStart, lineSize); 581 memcpy(dumpTo.ptr+oldLineStart, dumpTo.ptr+newLineStart, lineSize); 582 memcpy(dumpTo.ptr+newLineStart, tmpLine.ptr, lineSize); 583 584 ri++; 585 } 586 } 587 588 /** 589 Sets the background clear color 590 */ 591 void inSetClearColor(float r, float g, float b, float a) { 592 inClearColor = vec4(r, g, b, a); 593 } 594 595 /** 596 597 */ 598 void inGetClearColor(out float r, out float g, out float b, out float a) { 599 r = inClearColor.r; 600 g = inClearColor.g; 601 b = inClearColor.b; 602 a = inClearColor.a; 603 } 604 605 /** 606 UDA for sub-classable parts of the spec 607 eg. Nodes and Automation can be extended by 608 adding new subclasses that aren't in the base spec. 609 */ 610 struct TypeId { string id; } 611 612 /** 613 Different modes of interpolation between values. 614 */ 615 enum InterpolateMode { 616 617 /** 618 Round to nearest 619 */ 620 Nearest, 621 622 /** 623 Linear interpolation 624 */ 625 Linear, 626 627 /** 628 Round to nearest 629 */ 630 Stepped, 631 632 /** 633 Cubic interpolation 634 */ 635 Cubic, 636 637 /** 638 Interpolation using beziér splines 639 */ 640 Bezier, 641 642 COUNT 643 }