private void Enqueue(ref DrawCallInfo call) { //if (Calls > 0 && call.TryMerge(ref _drawCalls[Calls - 1])) //{ // Merged++; // return; //} if (Calls >= _drawCalls.Length) { Flush(); } _drawCalls[Calls++] = call; }
private void EnqueueBuiltGeometry(Texture2D texture, float depth) { if ((_vertexCount + _geometryBuilder.VertexCount > _vertices.Length) || (_indexCount + _geometryBuilder.IndexCount > _indices.Length)) { Flush(); } var drawCall = new DrawCallInfo(texture, _geometryBuilder.PrimitiveType, _indexCount, _geometryBuilder.PrimitivesCount, depth); Array.Copy(_geometryBuilder.Vertices, 0, _vertices, _vertexCount, _geometryBuilder.VertexCount); _vertexCount += _geometryBuilder.VertexCount; Array.Copy(_geometryBuilder.Indices, 0, _indices, _indexCount, _geometryBuilder.IndexCount); _indexCount += _geometryBuilder.IndexCount; Enqueue(ref drawCall); }
private unsafe void Push(Texture2D texture, SpriteVertex[] vertices, Techniques technique) { AddQuadrilateralIndices(_vertexCount); if (_vertexCount + VERTEX_COUNT > _vertices.Length || _indicesCount + INDEX_COUNT > _indices.Length) { Flush(); } DrawCallInfo call = new DrawCallInfo(texture, technique, _indicesCount, PRIMITIVES_COUNT, 0); fixed(SpriteVertex *p = &_vertices[_vertexCount]) { fixed(SpriteVertex *t = &vertices[0]) { SpriteVertex *ptr = p; SpriteVertex *tptr = t; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr = *tptr; } } fixed(short *p = &_indices[_indicesCount]) { fixed(short *t = &_geometryIndices[0]) { short *ptr = p; short *tptr = t; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr++ = *tptr++; *ptr = *tptr; } } _vertexCount += VERTEX_COUNT; _indicesCount += INDEX_COUNT; Enqueue(ref call); }
private void SortIndicesAndMerge() { Array.Sort(_drawCalls, 0, Calls); int newDrawCallCount = 0; int start = _drawCalls[0].StartIndex; _drawCalls[0].StartIndex = 0; DrawCallInfo currentDrawCall = _drawCalls[0]; _drawCalls[newDrawCallCount++] = _drawCalls[0]; int drawCallIndexCount = currentDrawCall.PrimitiveCount * 3; Array.Copy(_indices, start, _sortedIndices, 0, drawCallIndexCount); int sortedIndexCount = drawCallIndexCount; for (int i = 1; i < Calls; i++) { currentDrawCall = _drawCalls[i]; drawCallIndexCount = currentDrawCall.PrimitiveCount * 3; Array.Copy(_indices, currentDrawCall.StartIndex, _sortedIndices, sortedIndexCount, drawCallIndexCount); sortedIndexCount += drawCallIndexCount; if (currentDrawCall.TryMerge(ref _drawCalls[newDrawCallCount - 1])) { Merged++; continue; } currentDrawCall.StartIndex = sortedIndexCount - drawCallIndexCount; _drawCalls[newDrawCallCount++] = currentDrawCall; } Calls = newDrawCallCount; }
private void InternalDraw() { if (Calls == 0) { return; } Techniques last = Techniques.None; for (int i = 0; i < Calls; i++) { ref DrawCallInfo call = ref _drawCalls[i]; switch (call.Technique) { case Techniques.Hued: if (last != call.Technique) { _effect.CurrentTechnique = _huesTechnique; _effect.CurrentTechnique.Passes[0].Apply(); } break; case Techniques.ShadowSet: if (last != call.Technique) { _effect.CurrentTechnique = _shadowTechnique; _effect.CurrentTechnique.Passes[0].Apply(); } break; } last = call.Technique; DoDraw(ref call); }
/// <summary> /// Submits a draw operation to the <see cref="GraphicsDevice" /> using the specified <see cref="DrawCallInfo"/>. /// </summary> /// <param name="drawCall">The draw call information.</param> protected override void InvokeDrawCall(ref DrawCallInfo drawCall) { GraphicsDevice.DrawIndexedPrimitives(drawCall.PrimitiveType, 0, drawCall.StartIndex, drawCall.PrimitiveCount); }
public static void Run() { using (var app = /*new VulkanApplication() */ new OpenGlApplication()) { var win = app.CreateSimpleRenderWindow(samples: 8); // create CPU side array var indices = new int[] { 0, 1, 2, 0, 2, 3 }; // wrap it into cpu buffer. ArrayBuffer is a CPU buffer (which will be uploaded on demand), // In contrast, BackendBuffer would be a buffer prepared for a specific backend. // both implement the IBuffer interface. var indexBuffer = (IBuffer) new ArrayBuffer(indices); // same applies for vertex data. Here we do not explicitly create an ArrayBuffer since // we use convinience functions which internally create the ArrayBuffer for us var vertices = new V3f[] { new V3f(-1, -1, 0), new V3f(1, -1, 0), new V3f(1, 1, 0), new V3f(-1, 1, 0) }; var colors = new C4b[] { C4b.Green, C4b.Red, C4b.Blue, C4b.White }; // In this low level API, we manually construct a drawCallInfo which essentially map // to the arguments of glDrawElements etc. var drawCallInfo = new DrawCallInfo() { FaceVertexCount = 6, InstanceCount = 1, // DrawCallInfo is a struct and is initialized with zeros. make sure to set instanceCount to 1 FirstIndex = 0, }; // next we create a scene graph node which describes a simple scene which, when rendered // uses the supplied drawCallInfo to render geometry of type TriangleList (in constrast to points, linestrip etc) var drawNode = new Sg.RenderNode(drawCallInfo, IndexedGeometryMode.TriangleList); // the main principle is to use scene graph nodes as small building blocks to build together the // complete scene description - a bit like lego ;) // the same applies for applying geometry data. just like any other attribute (e.g. model trafos), // vertex data can be inherited along the edges in the scene graph. thus the scene graph would look like this // VertexIndexApplicator (applies index buffer to sub graph) // ^ // | // drawNode (performs draw call using attributes inherited along scene graph edges) var sceneWithIndexBuffer = new Sg.VertexIndexApplicator( new BufferView(AValModule.constant(indexBuffer), typeof(int)), drawNode ); // of course constructing scene graph nodes manually is tedious. therefore we use // convinience extension functions which can be chaned together, each // wrapping a node around the previously constructed scene graph var scene = sceneWithIndexBuffer .WithVertexAttribute("Positions", vertices) // there are a lot such extension functions defined to conviniently work with scene graphs .VertexAttribute(DefaultSemantic.Colors, colors) // next, we apply the shaders (this way, the shader becomes the root node -> all children now use // this so called effect (a pipeline shader which combines all shader stages into one object) .WithEffects(new[] { Aardvark.Rendering.Effects.VertexColor.Effect }); // next we use the aardvark scene graph compiler to construct a so called render task, // an optimized representation of the scene graph. var renderTask = app.Runtime.CompileRender(win.FramebufferSignature, scene); // next, we assign the rendertask to our render window. win.RenderTask = renderTask; win.Run(); } }