|
|
@@ -9,249 +9,176 @@ import three.viewport;
|
|
|
import std.string : toStringz;
|
|
|
import std.exception : collectException;
|
|
|
|
|
|
-enum deferredRendererVertexShaderSource = "
|
|
|
- #version 420 core
|
|
|
-
|
|
|
- layout(location = 0) in vec3 in_position;
|
|
|
- layout(location = 1) in vec3 in_normal;
|
|
|
- layout(location = 2) in vec2 in_texcoord;
|
|
|
- layout(location = 3) in vec4 in_color;
|
|
|
-
|
|
|
- //==============
|
|
|
- out vec2 _normal;
|
|
|
- out vec2 _texture;
|
|
|
- out vec3 _color;
|
|
|
- //==============
|
|
|
-
|
|
|
- out gl_PerVertex
|
|
|
- {
|
|
|
- vec4 gl_Position;
|
|
|
- };
|
|
|
-
|
|
|
- vec2 encode(vec3 n)
|
|
|
- {
|
|
|
- float f = sqrt(8*n.z+8);
|
|
|
- return n.xy / f + 0.5;
|
|
|
- }
|
|
|
-
|
|
|
- void main()
|
|
|
- {
|
|
|
- gl_Position = vec4(0.005 * in_position.x, 0.005 * in_position.y, 0.005* in_position.z, 1.0);
|
|
|
- _normal = encode(in_normal);
|
|
|
- _texture = in_texcoord;
|
|
|
- _color = in_color.xyz;
|
|
|
- };
|
|
|
-";
|
|
|
-
|
|
|
-enum deferredRendererFragmentShaderSource = "
|
|
|
- #version 420 core
|
|
|
-
|
|
|
- //==============
|
|
|
- in vec2 _normal;
|
|
|
- in vec2 _texture;
|
|
|
- in vec3 _color;
|
|
|
- //==============
|
|
|
-
|
|
|
- layout(location = 0) out float depth;
|
|
|
- layout(location = 1) out vec4 normal;
|
|
|
- layout(location = 2) out vec4 color;
|
|
|
-
|
|
|
- void main()
|
|
|
- {
|
|
|
- depth = gl_FragCoord.z;
|
|
|
- normal.xy = _normal.xy;
|
|
|
- color.xyz = _color;
|
|
|
+import std.experimental.logger;
|
|
|
+
|
|
|
+
|
|
|
+enum GlBufferTarget {
|
|
|
+ Array = GL_ARRAY_BUFFER,
|
|
|
+ AtomicCounter = GL_ATOMIC_COUNTER_BUFFER,
|
|
|
+ CopyRead= GL_COPY_READ_BUFFER,
|
|
|
+ CopyWrite = GL_COPY_WRITE_BUFFER,
|
|
|
+ DrawIndirect = GL_DRAW_INDIRECT_BUFFER,
|
|
|
+ DispatchIndirect = GL_DISPATCH_INDIRECT_BUFFER,
|
|
|
+ ElementArray = GL_ELEMENT_ARRAY_BUFFER,
|
|
|
+ PixelPack = GL_PIXEL_PACK_BUFFER,
|
|
|
+ PixelUnpack = GL_PIXEL_UNPACK_BUFFER,
|
|
|
+ QueryBuffer = GL_QUERY_BUFFER,
|
|
|
+ ShaderStorage = GL_SHADER_STORAGE_BUFFER,
|
|
|
+ Texture = GL_TEXTURE_BUFFER,
|
|
|
+ TransformFeedback = GL_TRANSFORM_FEEDBACK_BUFFER,
|
|
|
+ Uniform = GL_UNIFORM_BUFFER
|
|
|
+}
|
|
|
+
|
|
|
+struct GlBuffer(GlBufferTarget Target, T) {
|
|
|
+ alias BufferTarget = Target;
|
|
|
+ alias ValueType = T;
|
|
|
+ GLuint handle;
|
|
|
+ GLuint length;
|
|
|
+ T* data;
|
|
|
+}
|
|
|
+
|
|
|
+void construct(GlBufferTarget Target, T)(out GlBuffer!(Target, T) buffer, GLuint length, GLbitfield createFlags, GLbitfield mapFlags) {
|
|
|
+ glCheck!glGenBuffers(1, &buffer.handle);
|
|
|
+ glCheck!glBindBuffer(Target, buffer.handle);
|
|
|
+ glCheck!glBufferStorage(Target, length * T.sizeof, null, createFlags);
|
|
|
+ buffer.data = cast(T*)glCheck!glMapBufferRange(Target, 0, length * T.sizeof, mapFlags);
|
|
|
+ buffer.length = length;
|
|
|
+ if (buffer.data is null) {
|
|
|
+ throw new Exception("glMapBufferRange failed, probable bug.");
|
|
|
}
|
|
|
-";
|
|
|
+}
|
|
|
|
|
|
-struct GBuffer {
|
|
|
- uint width;
|
|
|
- uint height;
|
|
|
- GLuint texturePosition;
|
|
|
- GLuint textureNormal;
|
|
|
- GLuint textureColor;
|
|
|
- GLuint textureDepthStencil;
|
|
|
- GLuint fbo;
|
|
|
+void destruct(GlBufferTarget Target, T)(ref GlBuffer!(Target, T) buffer) {
|
|
|
+ glCheck!glBindBuffer(Target, buffer.handle);
|
|
|
+ glCheck!glUnmapBuffer(Target);
|
|
|
+ glCheck!glDeleteBuffers(1, &buffer.handle);
|
|
|
+ buffer = buffer.init;
|
|
|
}
|
|
|
|
|
|
-void construct(out GBuffer gBuffer, uint width, uint height) nothrow {
|
|
|
- gBuffer.width = width;
|
|
|
- gBuffer.height = height;
|
|
|
-
|
|
|
- glCheck!glGenTextures(1, &gBuffer.texturePosition);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.texturePosition);
|
|
|
- glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
- glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
- // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
- // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
|
- // glCheck!glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
|
|
|
- glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, width, height);
|
|
|
- glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_FLOAT, null);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
-
|
|
|
- glCheck!glGenTextures(1, &gBuffer.textureNormal);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureNormal);
|
|
|
- glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
- glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
- // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
|
- // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
|
- glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB10_A2, width, height);
|
|
|
- glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
-
|
|
|
- glCheck!glGenTextures(1, &gBuffer.textureColor);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureColor);
|
|
|
- glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
|
|
|
- glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
-
|
|
|
- glCheck!glGenTextures(1, &gBuffer.textureDepthStencil);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureDepthStencil);
|
|
|
- glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
|
|
|
- glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
|
|
|
- glCheck!glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
-
|
|
|
- glCheck!glGenFramebuffers(1, &gBuffer.fbo);
|
|
|
- glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gBuffer.fbo);
|
|
|
-
|
|
|
- glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, gBuffer.texturePosition, 0);
|
|
|
- glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_TEXTURE_2D, gBuffer.textureNormal, 0);
|
|
|
- glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 2, GL_TEXTURE_2D, gBuffer.textureColor, 0);
|
|
|
- glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gBuffer.textureDepthStencil, 0);
|
|
|
-
|
|
|
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
+void bind(GlBufferTarget Target, T)(ref GlBuffer!(Target, T) buffer) {
|
|
|
+ glCheck!glBindBuffer(Target, buffer.handle);
|
|
|
}
|
|
|
|
|
|
-void destruct(ref GBuffer gBuffer) nothrow {
|
|
|
- glCheck!glDeleteFramebuffers(1, &gBuffer.fbo);
|
|
|
- glCheck!glDeleteTextures(1, &gBuffer.textureDepthStencil);
|
|
|
- glCheck!glDeleteTextures(1, &gBuffer.textureColor);
|
|
|
- glCheck!glDeleteTextures(1, &gBuffer.textureNormal);
|
|
|
- glCheck!glDeleteTextures(1, &gBuffer.texturePosition);
|
|
|
- gBuffer = GBuffer.init;
|
|
|
+void unbind(GlBufferTarget Target, T)(ref GlBuffer!(Target, T) buffer) {
|
|
|
+ glCheck!glBindBuffer(Target, 0);
|
|
|
}
|
|
|
|
|
|
-struct Pipeline {
|
|
|
- GLuint pipeline;
|
|
|
- GLuint vertexShaderGeometryPass;
|
|
|
- GLuint fragmentShaderGeometryPass;
|
|
|
+alias GlArrayBuffer(T) = GlBuffer!(GlBufferTarget.Array, T);
|
|
|
+alias GlElementArrayBuffer(T) = GlBuffer!(GlBufferTarget.ElementArray, T);
|
|
|
+alias GlShaderStorageBuffer(T) = GlBuffer!(GlBufferTarget.ShaderStorage, T);
|
|
|
+alias GlDispatchIndirectBuffer(T) = GlBuffer!(GlBufferTarget.DispatchIndirect, T);
|
|
|
+alias GlTextureBuffer(T) = GlBuffer!(GlBufferTarget.Texture, T);
|
|
|
+alias GlUniformBuffer(T) = GlBuffer!(GlBufferTarget.Uniform, T);
|
|
|
+
|
|
|
+struct DrawElementsIndirectCommand {
|
|
|
+ GLuint count;
|
|
|
+ GLuint instanceCount;
|
|
|
+ GLuint firstIndex;
|
|
|
+ GLuint baseVertex;
|
|
|
+ GLuint baseInstance;
|
|
|
}
|
|
|
|
|
|
-void construct(out Pipeline pipeline) nothrow {
|
|
|
- glCheck!glGenProgramPipelines(1, &pipeline.pipeline);
|
|
|
-
|
|
|
- auto szVertexSource = [deferredRendererVertexShaderSource.toStringz()];
|
|
|
- pipeline.vertexShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_VERTEX_SHADER, 1, szVertexSource.ptr);
|
|
|
- int len;
|
|
|
- glCheck!glGetProgramiv(pipeline.vertexShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
|
|
|
- if (len > 1) {
|
|
|
- char[] msg = new char[len];
|
|
|
- glCheck!glGetProgramInfoLog(pipeline.vertexShaderGeometryPass, len, null, cast(char*) msg);
|
|
|
- log(cast(string)msg).collectException;
|
|
|
- }
|
|
|
|
|
|
- auto szFragmentSource = [deferredRendererFragmentShaderSource.toStringz()];
|
|
|
- pipeline.fragmentShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, szFragmentSource.ptr);
|
|
|
-// int len;
|
|
|
- glCheck!glGetProgramiv(pipeline.fragmentShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
|
|
|
- if (len > 1) {
|
|
|
- char[] msg = new char[len];
|
|
|
- glCheck!glGetProgramInfoLog(pipeline.fragmentShaderGeometryPass, len, null, cast(char*) msg);
|
|
|
- log(cast(string)msg).collectException;
|
|
|
- }
|
|
|
|
|
|
- glCheck!glUseProgramStages(pipeline.pipeline, GL_VERTEX_SHADER_BIT, pipeline.vertexShaderGeometryPass);
|
|
|
- glCheck!glUseProgramStages(pipeline.pipeline, GL_FRAGMENT_SHADER_BIT, pipeline.fragmentShaderGeometryPass);
|
|
|
+struct Position {
|
|
|
+ float x, y, z;
|
|
|
+}
|
|
|
|
|
|
- glCheck!glValidateProgramPipeline(pipeline.pipeline);
|
|
|
- GLint status;
|
|
|
- glCheck!glGetProgramPipelineiv(pipeline.pipeline, GL_VALIDATE_STATUS, &status);
|
|
|
- //TODO: add error handling
|
|
|
- assert(status != 0);
|
|
|
+struct Normal {
|
|
|
+ float x, y, z;
|
|
|
}
|
|
|
|
|
|
-void destruct(ref Pipeline pipeline) nothrow {
|
|
|
- glDeleteProgramPipelines(1, &pipeline.pipeline);
|
|
|
- pipeline = Pipeline.init;
|
|
|
+struct Color {
|
|
|
+ float r, g, b, a;
|
|
|
}
|
|
|
|
|
|
+struct Matrix4 {
|
|
|
+ float[4*4] data;
|
|
|
+}
|
|
|
|
|
|
-struct OpenGlTiledDeferredRenderer {
|
|
|
- GBuffer gBuffer;
|
|
|
- Pipeline pipeline;
|
|
|
+struct VertexData {
|
|
|
+ Position position;
|
|
|
+ Normal normal;
|
|
|
+ Color color;
|
|
|
}
|
|
|
|
|
|
-void construct(out OpenGlTiledDeferredRenderer deferredRenderer, uint width, uint height) nothrow {
|
|
|
- deferredRenderer.gBuffer.construct(width, height);
|
|
|
- deferredRenderer.pipeline.construct();
|
|
|
+alias IndexData = uint;
|
|
|
+
|
|
|
+struct DrawParameter {
|
|
|
+ Matrix4 transformationMatrix;
|
|
|
}
|
|
|
|
|
|
-void destruct(ref OpenGlTiledDeferredRenderer deferredRenderer) nothrow {
|
|
|
- deferredRenderer.pipeline.destruct();
|
|
|
- deferredRenderer.gBuffer.destruct();
|
|
|
- deferredRenderer = OpenGlTiledDeferredRenderer.init;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+struct Renderer {
|
|
|
+ uint width;
|
|
|
+ uint height;
|
|
|
+ GlArrayBuffer!VertexData vertexBuffer; // vertex data for all meshes
|
|
|
+ GlElementArrayBuffer!IndexData indexBuffer; //index data for all meshes
|
|
|
+ GlShaderStorageBuffer!DrawParameter perInstanceParamBuffer; // is filled with draw parameters for each instance each frame. shall be accessed as a ringbuffer
|
|
|
+ GlDispatchIndirectBuffer!DrawElementsIndirectCommand dispatchIndirectCommandBuffer; // is filled with DrawElementsIndirectCommand for each mesh each frame. shall be accessed as a ringbuffer
|
|
|
}
|
|
|
|
|
|
-// draw the scene supersampled with renderer's with+height onto renderTarget at position+size of viewport
|
|
|
-void renderOneFrame(ref OpenGlTiledDeferredRenderer renderer, ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
|
|
|
- // 1. Render the (opaque) geometry into the G-Buffers.
|
|
|
- // 2. Construct a screen space grid, covering the frame buffer, with some fixed tile
|
|
|
- // size, t = (x, y), e.g. 32 × 32 pixels.
|
|
|
- // 3. For each light: find the screen space extents of the light volume and append the
|
|
|
- // light ID to each affected grid cell.
|
|
|
- // 4. For each fragment in the frame buffer, with location f = (x, y).
|
|
|
- // (a) sample the G-Buffers at f.
|
|
|
- // (b) accumulate light contributions from all lights in tile at ⌊f /t⌋
|
|
|
- // (c) output total light contributions to frame buffer at f
|
|
|
-
|
|
|
- with(renderer.gBuffer) glCheck!glViewport(0, 0, width, height);
|
|
|
+void construct(out Renderer renderer, uint width, uint height) {
|
|
|
+ GLbitfield createFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;//TODO: ?? | GL_MAP_DYNAMIC_STORAGE_BIT;
|
|
|
+ GLbitfield mapFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
|
|
+
|
|
|
+ renderer.vertexBuffer.construct(1024, createFlags, mapFlags);
|
|
|
+ renderer.indexBuffer.construct(1024, createFlags, mapFlags);
|
|
|
+ renderer.perInstanceParamBuffer.construct(1024, createFlags, mapFlags);
|
|
|
+ renderer.dispatchIndirectCommandBuffer.construct(1024, createFlags, mapFlags);
|
|
|
+}
|
|
|
+
|
|
|
+void destruct(ref Renderer renderer) {
|
|
|
+ renderer.vertexBuffer.destruct();
|
|
|
+ renderer.indexBuffer.destruct();
|
|
|
+ renderer.perInstanceParamBuffer.destruct();
|
|
|
+ renderer.dispatchIndirectCommandBuffer.destruct();
|
|
|
+ renderer = renderer.init;
|
|
|
+}
|
|
|
+
|
|
|
+void renderOneFrame(ref Renderer renderer, ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
|
|
|
+
|
|
|
+ /*
|
|
|
+ foreach(renderTarget) //framebuffer
|
|
|
+ foreach(pass)
|
|
|
+ foreach(material) //shaders
|
|
|
+ foreach(materialInstance) //textures
|
|
|
+ foreach(vertexFormat) //vertex buffers
|
|
|
+ foreach(object) {
|
|
|
+ write uniform data;
|
|
|
+ glDrawElementsBaseVertex
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+ GLsizei meshCount = 0;
|
|
|
+
|
|
|
+ glCheck!glViewport(0, 0, renderer.width, renderer.height);
|
|
|
|
|
|
//enable depth mask _before_ glClear ing the depth buffer!
|
|
|
glCheck!glDepthMask(GL_TRUE); scope(exit) glCheck!glDepthMask(GL_FALSE);
|
|
|
glCheck!glEnable(GL_DEPTH_TEST); scope(exit) glCheck!glDisable(GL_DEPTH_TEST);
|
|
|
glCheck!glDepthFunc(GL_LEQUAL);
|
|
|
+
|
|
|
+ // write draw parameters
|
|
|
|
|
|
- //bind gBuffer
|
|
|
- glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderer.gBuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
- GLenum[] drawBuffers = [GL_COLOR_ATTACHMENT0 + 0, GL_COLOR_ATTACHMENT0 + 1, GL_COLOR_ATTACHMENT0 + 2];
|
|
|
- glCheck!glDrawBuffers(drawBuffers.length, drawBuffers.ptr); scope(exit) glCheck!glDrawBuffer(GL_NONE);
|
|
|
- glCheck!glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
-
|
|
|
-// glCheck!glClearColor(0, 0, 0.3, 1);
|
|
|
- //bind pipeline
|
|
|
- glCheck!glBindProgramPipeline(renderer.pipeline.pipeline); scope(exit) glCheck!glBindProgramPipeline(0);
|
|
|
+ // write draw commmands
|
|
|
|
|
|
- {// Draw Geometry
|
|
|
- scope(exit) glCheck!glBindVertexArray(0);
|
|
|
- scope(exit) glCheck!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // TODO: GL_ELEMENT_ARRAY_BUFFER should be vao state, but bugs might make this necessary
|
|
|
-
|
|
|
- for(size_t meshIdx = 0; meshIdx < scene.mesh.cnt; ++meshIdx) {
|
|
|
- glCheck!glBindVertexArray(scene.mesh.vao[meshIdx]);
|
|
|
-
|
|
|
- glCheck!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, scene.mesh.vboIndices[meshIdx]); // TODO: GL_ELEMENT_ARRAY_BUFFER should be vao state, but bugs might make this necessary
|
|
|
-
|
|
|
- glCheck!glDrawElements(GL_TRIANGLES, scene.mesh.cntIndices[meshIdx], GL_UNSIGNED_INT, null);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+ //draw //TODO: pass offset (cast to ptr) into command buffer instead of null
|
|
|
|
|
|
|
|
|
-debug {
|
|
|
- void blitGBufferToScreen(ref OpenGlTiledDeferredRenderer renderer) {
|
|
|
- glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, renderer.gBuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
|
-
|
|
|
- GLsizei width = renderer.gBuffer.width;
|
|
|
- GLsizei height = renderer.gBuffer.height;
|
|
|
+ renderer.vertexBuffer.bind();
|
|
|
+ renderer.indexBuffer.bind();
|
|
|
+ renderer.perInstanceParamBuffer.bind();
|
|
|
+ renderer.dispatchIndirectCommandBuffer.bind();
|
|
|
|
|
|
- scope(exit) glCheck!glReadBuffer(GL_NONE);
|
|
|
+ glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, toGlType!(renderer.indexBuffer.ValueType), null, meshCount, 0);
|
|
|
|
|
|
- glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 0);
|
|
|
- glCheck!glBlitFramebuffer(0, 0, width, height, 0, height-300, 400, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
|
|
|
|
- glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 1);
|
|
|
- glCheck!glBlitFramebuffer(0, 0, width, height, 0, 0, 400, 300, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
|
+}
|
|
|
|
|
|
- glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 2);
|
|
|
- glCheck!glBlitFramebuffer(0, 0, width, height, width-400, height-300, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
|
+debug {
|
|
|
+ void blitGBufferToScreen(ref Renderer renderer) {
|
|
|
}
|
|
|
}
|