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