Example #1
0
        /// <summary>
        /// Generates scene graph updates for renderer.
        /// </summary>
        public async IAsyncEnumerable <IRenderCommand> Process(AssertionBatch assertionBatch)
        {
            var knownUpdateObjects = new List <ObjectIdentityBase>();

            foreach (var assertion in assertionBatch.Assertions)
            {
                if (assertion is GetPickingInfo getPickingInfo)
                {
                    yield return(new RenderCommands.RequestPickingInfo(getPickingInfo.ScreenX, getPickingInfo.ScreenY));
                }
                else if (assertion is Core.Assertions.ClearColor clearColor)
                {
                    _sceneGraph.RgbClearColor = new (clearColor.Red, clearColor.Green, clearColor.Blue, 1.0f);
                    yield return(new RenderCommands.ClearColor(_sceneGraph.RgbClearColor));
                }
                else if (assertion is CameraProjectionPerspective projectionPerspective)
                {
                    // Projection matrix is set in uniforms
                    yield return(new RenderCommands.SetProjectionMatrix(_sceneGraph, projectionPerspective.FieldOfViewVerticalDegrees,
                                                                        projectionPerspective.NearPlane, projectionPerspective.FarPlane));
                }
                else if (assertion is CameraOrientation cameraOrientation)
                {
                    // View matrix is set in uniforms
                    _sceneGraph.ViewMatrix = cameraOrientation.ToMatrix();
                }
                else if (assertion is Core.Assertions.Vertex assertionVertex)
                {
                    if (!_sceneGraph.Vertices.TryGetValue(assertionVertex.VertexId, out Core.Scene.Vertex vertex))
                    {
                        vertex = new Core.Scene.Vertex(_sceneGraph, assertionVertex.VertexId);
                        _sceneGraph.Vertices[assertionVertex.VertexId] = vertex;
                    }
                    if (assertionVertex.Coordinates != default)
                    {
                        vertex.Coordinates = assertionVertex.Coordinates;
                        knownUpdateObjects.Add(vertex);
                    }
                }
                else if (assertion is Core.Assertions.Triangle triangle)
                {
                    var newTriangle = new Core.Scene.Triangle(_sceneGraph, triangle.TriangleId)
                    {
                        VertexIds = triangle.VertexIds
                    };
                    _partialObjectsWatchList.AddLast(newTriangle);
                    _sceneGraph.Triangles[triangle.TriangleId] = newTriangle;
                }
                else if (assertion is Core.Assertions.GrabScreenshot)
                {
                    yield return(new RenderCommands.GrabScreenshot(_renderWindow, _cancellationTokenManager));
                }
                else if (assertion is Core.Assertions.Texture texture)
                {
                    // Pre-load texture to avoid doing this in the function setting OpenGL state
                    var loadedImage = await _imageLoader.LoadImage(new Uri(texture.Uri));

                    _sceneGraph.Textures[texture.TextureId] = new Core.Scene.Texture(_sceneGraph, texture.TextureId, loadedImage.BufferRgba,
                                                                                     loadedImage.Width, loadedImage.Height);
                }
                else if (assertion is TexCoords texCoords)
                {
                    _sceneGraph.SurfaceVertexTexCoords[texCoords.ObjectIdentifier] = texCoords;
                }
                else if (assertion is SurfaceColor surfaceColor)
                {
                    _sceneGraph.SurfaceVertexColors[surfaceColor.ObjectIdentifier] = surfaceColor;
                }
                else
                {
                    throw new ArgumentException($"Unknown assertion type: {assertion.GetType()}");
                }
            }

            // Split objects into new and update lists
            var newRenderTriangles = new List <Core.Scene.Triangle>();

            // Get known complete geometry
            LinkedListNode <Core.Scene.Triangle> currentNode = _partialObjectsWatchList.First;

            while (currentNode != null)
            {
                if (_bufferManager.HasExistingTriangleBuffer(currentNode.Value))
                {
                    knownUpdateObjects.Add(currentNode.Value);
                    currentNode = currentNode.Next;
                    continue;
                }

                if (!currentNode.Value.HasMinimumRenderInfo)
                {
                    currentNode = currentNode.Next;
                    continue;
                }

                newRenderTriangles.Add(currentNode.Value);
                var next = currentNode.Next;
                _partialObjectsWatchList.Remove(currentNode);
                currentNode = next;
            }

            if (newRenderTriangles.Any())
            {
                yield return(_bufferManager.CreateRenderCommands(newRenderTriangles));
            }

            if (knownUpdateObjects.Any())
            {
                foreach (var reloadCommand in _bufferManager.CreateReloadCommands(knownUpdateObjects))
                {
                    yield return(reloadCommand);
                }
            }
        }