Exemple #1
0
        private void OnFrameUpdate(OutputFrame outputFrame)
        {
            if (!controller || (!enabled && request == null && OnFrameRenderUpdate == null))
            {
                return;
            }

            if (request != null)
            {
                RenderTexture texture;
                if (TargetTextureChange != null && request.UpdateTexture(controller.TargetCamera, material, out texture))
                {
                    TargetTextureChange(controller.TargetCamera, texture);
                }
            }

            if (!material)
            {
                return;
            }

            bool cameraFront     = cameraParameters.cameraDeviceType() == CameraDeviceType.Front;
            var  imageProjection = cameraParameters.imageProjection(controller.TargetCamera.aspect, arSession.Assembly.Display.Rotation, true, cameraFront? !renderImageHFlip : renderImageHFlip).ToUnityMatrix();
            var  gpuProjection   = GL.GetGPUProjectionMatrix(imageProjection, false);

            material.SetMatrix("_projection", gpuProjection);
            if (OnFrameRenderUpdate != null)
            {
                OnFrameRenderUpdate(material, new Vector2(Screen.width * controller.TargetCamera.rect.width, Screen.height * controller.TargetCamera.rect.height));
            }
        }
Exemple #2
0
        /// <summary>
        /// Read output data from the decoder. You should not use the specified region of the buffer until the returned task completes.
        /// </summary>
        /// <param name="buffer">The buffer into which output data should be written.</param>
        /// <param name="offset">The offset at which output data should be written.</param>
        /// <param name="length">The maximum number of bytes which should be written.</param>
        /// <param name="mode">
        /// Specifies whether to wait until the whole output buffer has been filled,
        /// or wether to return as soon as some data is available.
        /// </param>
        /// <returns>A task which, when completed, tells you how much data has been read.</returns>
        public Task <int> ReadOutputAsync(byte[] buffer, int offset, int length, StreamMode mode)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (length < 0 || length > buffer.Length - offset)
            {
                throw new ArgumentOutOfRangeException(nameof(length));
            }

            if (mode != StreamMode.Complete && mode != StreamMode.Partial)
            {
                throw new ArgumentOutOfRangeException(nameof(mode));
            }

            var frame = new OutputFrame();

            frame.mBuffer = buffer;
            frame.mOrigin = offset;
            frame.mOffset = offset;
            frame.mEnding = offset + length;
            frame.mMode   = mode;
            PushOutputFrame(frame);
            return(frame.mCompletion.Task);
        }
Exemple #3
0
        public Task <OutputFrame> ApplyFilter(OutputFrame frame)
        {
            var pixels = OptimizeBandwidth(frame.Pixels);

            this.frameCount++;
            return(Task.FromResult(new OutputFrame(frame.OffsetX, frame.OffsetY, pixels, frame.CacheId, frame.OffsetStatic)));
        }
Exemple #4
0
        //////////////////////////////////////////////////////////////////////////



        private void OnFrameChange(OutputFrame outputFrame, Matrix4x4 displayCompensation)
        {
            if (outputFrame == null)
            {
                material = null;
                UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                if (request != null)
                {
                    request.UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                    RenderTexture texture;
                    if (TargetTextureChange != null && request.UpdateTexture(controller.TargetCamera, material, out texture))
                    {
                        TargetTextureChange(controller.TargetCamera, texture);
                    }
                }
                return;
            }
            if (!enabled && request == null && OnFrameRenderUpdate == null)
            {
                return;
            }
            using (var frame = outputFrame.inputFrame())
            {
                using (var image = frame.image())
                {
                    // HERE WE GET ALL BYTES FROM EASYAR AND TRANSFER TO ZXING TO DECODE //

                    byte[] allbyte = new byte[image.buffer().size()];
                    image.buffer().copyToByteArray(0, allbyte, 0, image.buffer().size());

                    if (dataSignal)
                    {
                        data.image       = allbyte;
                        data.imageHeight = image.height();
                        data.imageWidth  = image.width();
                        data.imageSize   = image.buffer().size();
                        dataSignal       = false;
                    }

                    ///////////////////////////////////////////////////////////////////////


                    var materialUpdated = arMaterial.UpdateByImage(image);
                    if (material != materialUpdated)
                    {
                        material = materialUpdated;
                        UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                        if (request != null)
                        {
                            request.UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                        }
                    }
                }
                if (cameraParameters != null)
                {
                    cameraParameters.Dispose();
                }
                cameraParameters = frame.cameraParameters();
            }
        }
        public Task <OutputFrame> ApplyFilter(OutputFrame frame)
        {
            var random = _random.Value;
            var copy   = frame.Pixels.ToArray();

            Shuffle(random, copy);
            return(Task.FromResult(new OutputFrame(frame.OffsetX, frame.OffsetY, copy, frame.CacheId, frame.OffsetStatic)));
        }
        private ArraySegment <byte> Render(OutputFrame pixels)
        {
            ArraySegment <byte> bytes = _renderService.PreRender(pixels);

            Interlocked.Add(ref _bytesHandled, (ulong)bytes.Count);
            Interlocked.Add(ref _pixelsHandled, (ulong)pixels.Pixels.Length);
            return(bytes);
        }
Exemple #7
0
        private void PushOutputFrame(OutputFrame frame)
        {
            lock (mSyncObject)
            {
                if (mDisposeTask != null)
                {
                    throw new ObjectDisposedException(null);
                }

                mTotalOutputCapacity = checked (mTotalOutputCapacity + (frame.mEnding - frame.mOffset));
                mOutputQueue.Enqueue(frame);
                TryStartDecoding();
            }
        }
        public void UnsafeRenderService_SimpleFrame_Correct()
        {
            var pixels = new[] {
                new OutputPixel(0, 0, 0xFFFF00FF),
                new OutputPixel(0, 1, 0xFF00FF00),
                new OutputPixel(1, 0, 0xFF0000FF),
                new OutputPixel(0, 0, 0xFFFFFF00),
            };

            var frame  = new OutputFrame(0, 0, pixels);
            var sut    = new PixelFlutLookupTableUnsafeRenderService(ServerCapabilities.None);
            var actual = Encoding.ASCII.GetString(sut.PreRender(frame));

            Assert.AreEqual("PX 0 0 FF00FF\nPX 0 1 00FF00\nPX 1 0 0000FF\nPX 0 0 FFFF00\n", actual);
        }
        public void SimpleRenderService_SimpleFrame_Correct()
        {
            var pixels = new[] {
                new OutputPixel(0, 0, 0xFFFF00FF),
                new OutputPixel(0, 1, 0xFF00FF00),
                new OutputPixel(1, 0, 0xFF0000FF),
                new OutputPixel(0, 0, 0xFFFFFF00),
                new OutputPixel(0, 0, 0xAAFFFF00),
            };

            var frame  = new OutputFrame(0, 0, pixels);
            var sut    = new SimpleRenderService();
            var actual = Encoding.ASCII.GetString(sut.PreRender(frame));

            Assert.AreEqual("PX 0 0 FF00FF\nPX 0 1 00FF00\nPX 1 0 0000FF\nPX 0 0 FFFF00\nPX 0 0 FFFF00AA\n", actual);
        }
Exemple #10
0
 public Player(string name, int xDim, int yDim, OutputFrame oob)
 {
     OrderOfBattle = oob;
     YDimension    = yDim;
     XDimension    = xDim;
     Name          = name;
     Units         = new Dictionary <string, Unit>();
     MissingMenMap = new int[YDimension, XDimension];
     OffMapStorage = new SuppliesStorage(1000000);
     for (int y = 0; y < YDimension; y++)
     {
         for (int x = 0; x < XDimension; x++)
         {
             MissingMenMap[y, x] = 0;
         }
     }
 }
        public async Task <OutputFrame> ApplyFilter(OutputFrame frame)
        {
            lock (_samples)
            {
                _samples.Enqueue(DateTime.UtcNow);

                if (_samples.Count > NumSamples)
                {
                    _samples.Dequeue();
                }
            }
            if (GetFps() > this.targetFps)
            {
                await Task.Delay(1000 / targetFps);
            }

            return(frame);
        }
        private void AutoResolve(OutputFrame oframe, Matrix4x4 displayCompensation)
        {
            var time = Time.time;

            if (isTracking || resolveInfo.Running || time - resolveInfo.ResolveTime < autoResolveRate)
            {
                return;
            }

            resolveInfo.ResolveTime = time;
            resolveInfo.Running     = true;

            using (var iFrame = oframe.inputFrame())
            {
                CloudRecognizer.Resolve(iFrame, (result) =>
                {
                    if (resolveInfo == null)
                    {
                        return;
                    }

                    resolveInfo.Index++;
                    resolveInfo.Running             = false;
                    resolveInfo.CostTime            = Time.time - resolveInfo.ResolveTime;
                    resolveInfo.CloudStatus         = result.getStatus();
                    resolveInfo.TargetName          = "-";
                    resolveInfo.UnknownErrorMessage = result.getUnknownErrorMessage();

                    var target = result.getTarget();
                    if (target.OnSome)
                    {
                        using (var targetValue = target.Value)
                        {
                            resolveInfo.TargetName = targetValue.name();

                            if (!loadedCloudTargetUids.Contains(targetValue.uid()))
                            {
                                LoadCloudTarget(targetValue.Clone());
                            }
                        }
                    }
                });
            }
        }
Exemple #13
0
        private void OnFrameUpdate(OutputFrame outputFrame)
        {
            var camParameters = ExternalParameters ? ExternalParameters.Parameters : cameraParameters;
            var projection    = camParameters.projection(TargetCamera.nearClipPlane, TargetCamera.farClipPlane, TargetCamera.aspect, EasyARController.Instance.Display.Rotation, false, false).ToUnityMatrix();

            if (ExternalParameters)
            {
                projection *= ExternalParameters.Transform;
            }
            projection *= currentDisplayCompensation;
            if (projectHFilp)
            {
                var translateMatrix = Matrix4x4.identity;
                translateMatrix.m00 = -1;
                projection          = translateMatrix * projection;
            }
            TargetCamera.projectionMatrix = projection;
            GL.invertCulling = projectHFilp;
        }
Exemple #14
0
 private void OnFrameChange(OutputFrame outputFrame, Matrix4x4 displayCompensation)
 {
     if (outputFrame == null)
     {
         material = null;
         UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
         if (request != null)
         {
             request.UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
             RenderTexture texture;
             if (TargetTextureChange != null && request.UpdateTexture(controller.TargetCamera, material, out texture))
             {
                 TargetTextureChange(controller.TargetCamera, texture);
             }
         }
         return;
     }
     if (!enabled && request == null && OnFrameRenderUpdate == null)
     {
         return;
     }
     using (var frame = outputFrame.inputFrame())
     {
         using (var image = frame.image())
         {
             var materialUpdated = arMaterial.UpdateByImage(image);
             if (material != materialUpdated)
             {
                 material = materialUpdated;
                 UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                 if (request != null)
                 {
                     request.UpdateCommandBuffer(controller ? controller.TargetCamera : null, material);
                 }
             }
         }
         if (cameraParameters != null)
         {
             cameraParameters.Dispose();
         }
         cameraParameters = frame.cameraParameters();
     }
 }
        private void OnFrameChange(OutputFrame outputFrame, Matrix4x4 displayCompensation)
        {
            if (outputFrame == null)
            {
                return;
            }
            currentDisplayCompensation = displayCompensation.inverse;

            using (var frame = outputFrame.inputFrame())
            {
                if (cameraParameters != null)
                {
                    cameraParameters.Dispose();
                }
                cameraParameters = frame.cameraParameters();
                if (ExternalParameters)
                {
                    ExternalParameters.Build(cameraParameters);
                }
            }
        }
Exemple #16
0
        protected override void AddFileRecord(OutputFrame data)
        {
            if (data == null || (data.LeftForce == null && data.RightForce == null))
            {
                return;
            }

            var force = data.LeftForce;

            if (force == null || force.DeviceID != this.deviceID)
            {
                force = data.RightForce;
            }

            if (force == null || force.DeviceID != this.deviceID)
            {
                return;
            }

            this.records.Add(new RawGrfFileRecord(data.RelativeTime, force));
        }
 private void OnFrameUpdate(OutputFrame outputFrame)
 {
     if (CloudRecognizer == null)
     {
         return;
     }
     while (pendingRequets.Count > 0)
     {
         using (var iFrame = outputFrame.inputFrame())
         {
             var request = pendingRequets.Dequeue();
             if (request.StartCallback != null)
             {
                 request.StartCallback(iFrame);
             }
             {
                 CloudRecognizer.resolve(iFrame, EasyARController.Scheduler, request.DoneCallback);
             }
         }
     }
 }
        private void OnFrameUpdate(OutputFrame outputFrame)
        {
            var camParameters = ExternalParameters ? ExternalParameters.Parameters : cameraParameters;
            var projection    = camParameters.projection(TargetCamera.nearClipPlane, TargetCamera.farClipPlane, TargetCamera.aspect, EasyARController.Instance.Display.Rotation, false, false).ToUnityMatrix();

            if (ExternalParameters)
            {
                projection *= ExternalParameters.Transform;
            }
            projection *= currentDisplayCompensation;
            if (projectHFilp)
            {
                var translateMatrix = Matrix4x4.identity;
                translateMatrix.m00 = -1;
                projection          = translateMatrix * projection;
            }
            TargetCamera.projectionMatrix = projection;

            if (renderEvent == null)
            {
                if (TargetCamera)
                {
                    renderEvent             = TargetCamera.gameObject.AddComponent <CameraRenderEvent>();
                    renderEvent.PreRender  += () => { GL.invertCulling = projectHFilp; };
                    renderEvent.PostRender += () => { if (projectHFilp)
                                                      {
                                                          GL.invertCulling = false;
                                                      }
                    };
                }
            }
            else
            {
                if (!TargetCamera)
                {
                    Destroy(renderEvent);
                }
            }
        }
        public void UnsafeRenderService_TryToFuckItUpFrame_Correct()
        {
            var r = new Random();

            for (int i = 0; i < 10; i++)
            {
                var pixels = new List <OutputPixel>();
                for (int pxNum = 0; pxNum < 100000; pxNum++)
                {
                    pixels.Add(new OutputPixel(r.Next(2000), r.Next(2000), (uint)r.Next(0xFFFFFF) | 0xFF000000U));
                }

                var frame = new OutputFrame(0, 0, pixels.ToArray());

                var simpleSut = new SimpleRenderService();
                var unsafeSut = new PixelFlutLookupTableUnsafeRenderService(ServerCapabilities.None);

                var simpleFrame = Encoding.ASCII.GetString(simpleSut.PreRender(frame));
                var unsafeFrame = Encoding.ASCII.GetString(unsafeSut.PreRender(frame));

                Assert.AreEqual(simpleFrame, unsafeFrame);
            }
        }
Exemple #20
0
        private void OnFrameUpdate(OutputFrame outputFrame)
        {
            if (!controller || (!enabled && request == null && OnFrameRenderUpdate == null))
            {
                return;
            }

            if (request != null)
            {
                RenderTexture texture;
                if (TargetTextureChange != null && request.UpdateTexture(controller.TargetCamera, material, out texture))
                {
                    TargetTextureChange(controller.TargetCamera, texture);
                }
            }

            if (!material)
            {
                return;
            }

            bool cameraFront     = cameraParameters.cameraDeviceType() == CameraDeviceType.Front ? true : false;
            var  imageProjection = cameraParameters.imageProjection(controller.TargetCamera.aspect, EasyARController.Instance.Display.Rotation, false, cameraFront? !renderImageHFlip : renderImageHFlip).ToUnityMatrix();

            if (renderImageHFlip)
            {
                var translateMatrix = Matrix4x4.identity;
                translateMatrix.m00 = -1;
                imageProjection     = translateMatrix * imageProjection;
            }
            material.SetMatrix("_TextureRotation", imageProjection);
            if (OnFrameRenderUpdate != null)
            {
                OnFrameRenderUpdate(material, new Vector2(Screen.width * controller.TargetCamera.rect.width, Screen.height * controller.TargetCamera.rect.height));
            }
        }
Exemple #21
0
        public MainWindow()
        {
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            InitializeComponent();

            string locationString = System.IO.Path.GetFullPath(System.IO.Path.Combine(@AppDomain.CurrentDomain.BaseDirectory, @"..\\..\\")) + "GameData\\TestMap.txt";

            Grid grid = new Grid();

            grid.RowDefinitions.Add(new RowDefinition());
            grid.ColumnDefinitions.Add(new ColumnDefinition());
            grid.ColumnDefinitions.Add(new ColumnDefinition());
            grid.ColumnDefinitions.Add(new ColumnDefinition());

            Grid leftGrid = new Grid();

            leftGrid.RowDefinitions.Add(new RowDefinition());
            leftGrid.RowDefinitions.Add(new RowDefinition());
            leftGrid.RowDefinitions.Add(new RowDefinition());
            leftGrid.ColumnDefinitions.Add(new ColumnDefinition());

            Grid rightGrid = new Grid();

            rightGrid.RowDefinitions.Add(new RowDefinition());
            rightGrid.RowDefinitions.Add(new RowDefinition());
            rightGrid.ColumnDefinitions.Add(new ColumnDefinition());

            Grid.SetRow(leftGrid, 0);
            Grid.SetColumn(leftGrid, 0);
            leftGrid.SetValue(Grid.ColumnSpanProperty, 2);

            Grid.SetRow(rightGrid, 0);
            Grid.SetColumn(rightGrid, 2);

            grid.Children.Add(rightGrid);
            grid.Children.Add(leftGrid);

            InfoControl info = new InfoControl();

            TabControl tabCtrl = info.TabCtrl;

            Grid.SetRow(tabCtrl, 1);
            Grid.SetColumn(tabCtrl, 0);

            rightGrid.Children.Add(tabCtrl);

            this.output = info.Output;
            Player player = new Player("USA", 20, 20, info.OrderOfBattle);

            player.AddUnit(new SuperUnit("2nd Infantry Division"));

            MapFrame map = new MapFrame(locationString, output);

            Grid.SetRow(map, 1);
            Grid.SetColumn(map, 0);
            map.SetValue(Grid.RowSpanProperty, 2);

            leftGrid.Children.Add(map);

            this.Content = grid;

            MapControlFrame mapControl = new MapControlFrame(map, output);

            Grid.SetRow(mapControl, 0);
            Grid.SetColumn(mapControl, 0);

            leftGrid.Children.Add(mapControl);

            stopWatch.Stop();

            long ts = stopWatch.ElapsedMilliseconds;

            output.postMessage("Application started.");
            output.postMessage(locationString);
            output.postMessage(map.ActualWidth.ToString());
            output.postMessage(map.ActualHeight.ToString());
            output.postMessage("Took " + ts.ToString() + " MS to start.");
        }
Exemple #22
0
        private void PushOutputFrame(OutputFrame frame)
        {
            lock (mSyncObject)
            {
                if (mDisposeTask != null)
                    throw new ObjectDisposedException(null);

                mTotalOutputCapacity = checked(mTotalOutputCapacity + (frame.mEnding - frame.mOffset));
                mOutputQueue.Enqueue(frame);
                TryStartDecoding();
            }
        }
Exemple #23
0
        /// <summary>
        /// Read output data from the decoder. You should not use the specified region of the buffer until the returned task completes.
        /// </summary>
        /// <param name="buffer">The buffer into which output data should be written.</param>
        /// <param name="offset">The offset at which output data should be written.</param>
        /// <param name="length">The maximum number of bytes which should be written.</param>
        /// <param name="mode">
        /// Specifies whether to wait until the whole output buffer has been filled,
        /// or wether to return as soon as some data is available.
        /// </param>
        /// <returns>A task which, when completed, tells you how much data has been read.</returns>
        public Task<int> ReadOutputAsync(byte[] buffer, int offset, int length, StreamMode mode)
        {
            if (buffer == null)
                throw new ArgumentNullException(nameof(buffer));

            if (offset < 0 || offset > buffer.Length)
                throw new ArgumentOutOfRangeException(nameof(offset));

            if (length < 0 || length > buffer.Length - offset)
                throw new ArgumentOutOfRangeException(nameof(length));

            if (mode != StreamMode.Complete && mode != StreamMode.Partial)
                throw new ArgumentOutOfRangeException(nameof(mode));

            var frame = new OutputFrame();
            frame.mBuffer = buffer;
            frame.mOrigin = offset;
            frame.mOffset = offset;
            frame.mEnding = offset + length;
            frame.mMode = mode;
            PushOutputFrame(frame);
            return frame.mCompletion.Task;
        }
Exemple #24
0
        /// <summary>
        /// Callback from the EasyAR component whic renders the foreground nodes.
        /// </summary>
        /// <param name="oFrame"></param>
        /// <param name="cameraParameters"></param>
        /// <param name="aspectRatio"></param>
        /// <param name="rotation"></param>
        protected void OnARFrameUpdated(OutputFrame oFrame, CameraParameters cameraParameters, float aspectRatio, int rotation)
        {
            var       far  = 100f;
            var       near = 0.01f;
            Matrix44F sp   = cameraParameters.projection(near, far, aspectRatio, rotation, true, false);

            foreach (Optional <FrameFilterResult> unTypedResult in oFrame.results())
            {
                if (unTypedResult.OnSome)
                {
                    if (unTypedResult.Some is ImageTrackerResult result)
                    {
                        int targetIndex = 0;
                        List <TargetInstance> targetInstances = result.targetInstances();
                        foreach (TargetInstance targetInstance in targetInstances)
                        {
                            TargetStatus status = targetInstance.status();
                            if (status == TargetStatus.Tracked)
                            {
                                Optional <Target> optionalTarget = targetInstance.target();
                                if (optionalTarget.OnSome)
                                {
                                    Target target = optionalTarget.Some;
                                    if (target is ImageTarget imageTarget)
                                    {
                                        List <Image> images      = imageTarget.images();
                                        Image        targetImage = images[0];

                                        Matrix4 prj = sp.ToUrhoMatrix();
                                        prj.M34 /= 2f;
                                        prj.M33  = far / (far - near);
                                        prj.M43 *= -1;
                                        fgCamera.SetProjection(prj);

                                        Matrix4 convertedPoseMatrix = targetInstance.pose().ToUrhoMatrix();
                                        Vector3 scale = new Vector3(imageTarget.scale(), imageTarget.scale() * targetImage.height() / targetImage.width(), 1);
                                        UpdateArScene(targetIndex, convertedPoseMatrix, scale);
                                        foreach (Image targetImageToRelease in images)
                                        {
                                            targetImageToRelease.Dispose();
                                        }
                                    }
                                    target.Dispose();
                                }
                            }
                            targetInstance.Dispose();
                            targetIndex++;
                        }

                        // Remove any targets that can no longer be located
                        while (targetNodes.Count > targetIndex)
                        {
                            Node node = targetNodes[targetIndex];
                            targetNodes.RemoveAt(targetIndex);
                            node.Remove();
                        }
                    }
                    unTypedResult.Some.Dispose();
                }
            }
        }
Exemple #25
0
        private void OnFrameUpdate(OutputFrame outputFrame, InputFrame inputFrame, Matrix4x4 displayCompensation)
        {
            // world root
            if (Assembly.RequireWorldCenter && !WorldRootController)
            {
                Debug.Log("WorldRoot not found, create from " + typeof(ARSession));
                var gameObject = new GameObject("WorldRoot");
                WorldRootController = gameObject.AddComponent <WorldRootController>();
                if (WorldRootChanged != null)
                {
                    WorldRootChanged(WorldRootController);
                }
                previousWorldRootController = WorldRootController;
            }
            if (!Assembly.RequireWorldCenter && CenterMode == ARCenterMode.WorldRoot)
            {
                Debug.LogWarning("ARCenterMode.WorldRoot not available for target only tracking");
                CenterMode = ARCenterMode.FirstTarget;
            }

            // horizontal flip
            var hflip = HorizontalFlipNormal;

            using (var cameraParameters = inputFrame.cameraParameters())
            {
                if (cameraParameters.cameraDeviceType() == CameraDeviceType.Front)
                {
                    hflip = HorizontalFlipFront;
                }
            }
            var worldHFlip  = false;
            var targetHFlip = false;

            switch (hflip)
            {
            case ARHorizontalFlipMode.World:
                worldHFlip  = true;
                targetHFlip = false;
                break;

            case ARHorizontalFlipMode.Target:
                worldHFlip  = false;
                targetHFlip = true;
                break;

            default:
                break;
            }
            foreach (var renderCamera in Assembly.RenderCameras)
            {
                renderCamera.SetProjectHFlip(worldHFlip);
                renderCamera.SetRenderImageHFilp(worldHFlip || targetHFlip);
            }
            foreach (var filter in Assembly.FrameFilters)
            {
                filter.SetHFlip(targetHFlip);
            }

            // dispatch results
            var results = outputFrame.results();
            var motionTrackingStatus = Optional <MotionTrackingStatus> .CreateNone();

            if (inputFrame.hasSpatialInformation())
            {
                motionTrackingStatus = inputFrame.trackingStatus();
            }
            var resultControllers = DispatchResults(results, motionTrackingStatus);

            // get camera pose if available
            var cameraPose = Optional <Matrix44F> .Empty;

            if (Assembly.RequireWorldCenter)
            {
                if (motionTrackingStatus.OnSome)
                {
                    if (motionTrackingStatus.Value != MotionTrackingStatus.NotTracking)
                    {
                        cameraPose = inputFrame.cameraTransform();
                    }
                }
                else
                {
                    foreach (var result in resultControllers)
                    {
                        if (result.Key.OnNone)
                        {
                            cameraPose = result.Value;
                            break;
                        }
                    }
                }
            }

            // get center target pose if available
            var centerTargetPose = Optional <Matrix44F> .Empty;

            if (CenterMode == ARCenterMode.FirstTarget || CenterMode == ARCenterMode.SpecificTarget)
            {
                foreach (var result in resultControllers)
                {
                    if (!CenterTarget)
                    {
                        break;
                    }
                    if (result.Key.OnNone)
                    {
                        continue;
                    }
                    if (result.Key == CenterTarget)
                    {
                        centerTargetPose = result.Value;
                        break;
                    }
                }

                if (CenterMode == ARCenterMode.FirstTarget && centerTargetPose.OnNone)
                {
                    foreach (var result in resultControllers)
                    {
                        if (result.Key.OnNone)
                        {
                            continue;
                        }
                        CenterTarget     = result.Key.Value;
                        centerTargetPose = result.Value;
                        break;
                    }
                }
            }
            else
            {
                CenterTarget = null;
            }

            // set camera transform first
            if (CenterMode == ARCenterMode.FirstTarget || CenterMode == ARCenterMode.SpecificTarget)
            {
                if (CenterTarget && centerTargetPose.OnSome)
                {
                    TransformUtil.SetTargetPoseOnCamera(Assembly.CameraRoot, CenterTarget, centerTargetPose.Value, displayCompensation, targetHFlip);
                }
            }
            else if (CenterMode == ARCenterMode.WorldRoot)
            {
                if (WorldRootController && cameraPose.OnSome)
                {
                    TransformUtil.SetCameraPoseOnCamera(Assembly.CameraRoot, WorldRootController, cameraPose.Value, displayCompensation, targetHFlip);
                }
            }

            // set target and world root transform
            if (CenterMode == ARCenterMode.Camera)
            {
                foreach (var result in resultControllers)
                {
                    if (result.Key.OnSome)
                    {
                        TransformUtil.SetTargetPoseOnTarget(Assembly.CameraRoot, result.Key.Value, result.Value, displayCompensation, targetHFlip);
                    }
                }
                if (WorldRootController && cameraPose.OnSome)
                {
                    TransformUtil.SetCameraPoseOnWorldRoot(Assembly.CameraRoot, WorldRootController, cameraPose.Value, displayCompensation, targetHFlip);
                }
            }
            else if (CenterMode == ARCenterMode.WorldRoot)
            {
                foreach (var result in resultControllers)
                {
                    if (result.Key.OnSome)
                    {
                        TransformUtil.SetTargetPoseOnTarget(Assembly.CameraRoot, result.Key.Value, result.Value, displayCompensation, targetHFlip);
                    }
                }
            }
            else if (CenterMode == ARCenterMode.FirstTarget || CenterMode == ARCenterMode.SpecificTarget)
            {
                foreach (var result in resultControllers)
                {
                    if (result.Key.OnSome && result.Key.Value != CenterTarget)
                    {
                        TransformUtil.SetTargetPoseOnTarget(Assembly.CameraRoot, result.Key.Value, result.Value, displayCompensation, targetHFlip);
                    }
                }
                if (WorldRootController && cameraPose.OnSome)
                {
                    TransformUtil.SetCameraPoseOnWorldRoot(Assembly.CameraRoot, WorldRootController, cameraPose.Value, displayCompensation, targetHFlip);
                }
            }
            else if (CenterMode == ARCenterMode.ExternalControl)
            {
                foreach (var result in resultControllers)
                {
                    if (result.Key.OnSome)
                    {
                        TransformUtil.SetTargetPoseOnTarget(Assembly.CameraRoot, result.Key.Value, result.Value, displayCompensation, targetHFlip);
                    }
                }
            }

            // dispose results
            foreach (var result in results)
            {
                if (result.OnSome)
                {
                    result.Value.Dispose();
                }
            }
        }
        /// <summary>
        /// Detects new output frames and updates the camera, then passes the output frame through an event to update the foreground
        /// </summary>
        /// <param name="timeStep"></param>
        protected override void OnUpdate(float timeStep)
        {
            if (paused)
            {
                return;
            }

            Optional <OutputFrame> optionalOframe = OutputFrameBuffer.peek();

            if (optionalOframe.OnSome)
            {
                OutputFrame           oframe         = optionalOframe.Some;
                Optional <InputFrame> optionalIframe = oframe.inputFrame();
                if (optionalIframe.OnSome)
                {
                    InputFrame       iframe           = optionalIframe.Some;
                    CameraParameters cameraParameters = iframe.cameraParameters();
                    if (cameraParameters != null)
                    {
                        Image image       = iframe.image();
                        float aspectRatio = (float)(DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Height);

                        int rotation = 0;
                        switch (DeviceDisplay.MainDisplayInfo.Rotation)
                        {
                        case DisplayRotation.Rotation90:
                            rotation = 90;
                            break;

                        case DisplayRotation.Rotation180:
                            rotation = 180;
                            break;

                        case DisplayRotation.Rotation270:
                            rotation = 270;
                            break;
                        }

                        if (iframe.index() != previousInputFrameIndex)
                        {
                            Matrix44F ip   = cameraParameters.imageProjection(aspectRatio, rotation, true, false);
                            Matrix4   iprj = ip.ToUrhoMatrix();
                            bgCamera.SetProjection(iprj);
                            EasyAR.Buffer buffer = image.buffer();
                            try
                            {
                                backgroundUpdater.UpdateTexture(Application, image.format(), image.width(), image.height(), buffer);
                            }
                            finally
                            {
                                buffer.Dispose();
                            }
                            previousInputFrameIndex = iframe.index();
                        }

                        ARFrameUpdated?.Invoke(oframe, cameraParameters, aspectRatio, rotation);

                        image.Dispose();
                        cameraParameters.Dispose();
                    }
                    iframe.Dispose();
                }
                oframe.Dispose();
            }

            base.OnUpdate(timeStep);
        }