示例#1
0
        //static functions
        public static RenderObject Create(Vector3Df pos)
        {
            RenderObject renderObject = new RenderObject();

            renderObject.transform = new Transform(pos);
            return(renderObject);
        }
示例#2
0
        public void AddPoint(Vector3Df point)
        {
            points.Add(point);

            // add front line
            Vertex3D v1front = new Vertex3D(point, new Vector3Df(0), new Color(0));
            Vertex3D v2front = new Vertex3D((point - Center).Normalize() * height, new Vector3Df(0), FrontColor);

            vertFront.Add(v1front);
            vertFront.Add(v2front);

            // add back line
            Vertex3D v1back = v1front;
            Vertex3D v2back = new Vertex3D(v2front);

            v2back.Color = BackColor;
            vertBack.Add(v1back);
            vertBack.Add(v2back);

            // add connection line if possible (front and back)
            if (vertFront.Count >= 4)
            {
                vertFront.Add(vertFront.Get(vertFront.Count - 3));
                vertFront.Add(v2front);

                vertBack.Add(vertBack.Get(vertBack.Count - 3));
                vertBack.Add(v2back);
            }

            // update indices "used" count
            indBoth.SetCount(vertFront.Count);
        }
示例#3
0
		public void AddPoint(Vector3Df point)
		{
			points.Add(point);

			// add front line
			Vertex3D v1front = new Vertex3D(point, new Vector3Df(0), new Color(0));
			Vertex3D v2front = new Vertex3D((point - Center).Normalize() * height, new Vector3Df(0), FrontColor);
			vertFront.Add(v1front);
			vertFront.Add(v2front);

			// add back line
			Vertex3D v1back = v1front;
			Vertex3D v2back = new Vertex3D(v2front);
			v2back.Color = BackColor;
			vertBack.Add(v1back);
			vertBack.Add(v2back);

			// add connection line if possible (front and back)
			if (vertFront.Count >= 4)
			{
				vertFront.Add(vertFront.Get(vertFront.Count - 3));
				vertFront.Add(v2front);

				vertBack.Add(vertBack.Get(vertBack.Count - 3));
				vertBack.Add(v2back);
			}

			// update indices "used" count
			indBoth.SetCount(vertFront.Count);
		}
示例#4
0
        public void Fire(Vector3Df position, Vector3Df direction, uint time)
        {
            Shot s = new Shot();

            s.direction = direction;

            Vector3Df e = position + s.direction * worldInfinity;
            Line3Df   l = new Line3Df(position, e);

            Vector3Df   cv;
            Triangle3Df ct;
            SceneNode   cn;

            if (sceneManager.SceneCollisionManager.GetCollisionPoint(l, worldTriangles, out cv, out ct, out cn))
            {
                e = cv;
            }

            s.deathTime = time + (uint)((e - position).Length / shotSpeed);

            s.node = sceneManager.AddSphereSceneNode(10);
            s.node.SetMaterialFlag(MaterialFlag.Lighting, false);
            sceneManager.MeshManipulator.SetVertexColors(((MeshSceneNode)s.node).Mesh, Color.OpaqueWhite);

            s.node.AddAnimator(sceneManager.CreateFlyStraightAnimator(position, e, (s.deathTime - time) / 1000.0f));
            s.node.AnimatorList[0].Drop();

            sceneManager.AddLightSceneNode(s.node);

            shots.Add(s);
        }
示例#5
0
        public bool TenterMouvement(SceneNode objet, Vector3Df direction, float rayon = .25f)
        {
            Vector2Df nouvellePosition = new Vector2Df(objet.Position.X + direction.X + .5f, objet.Position.Z + direction.Z + .5f);

            int minX = (int)(nouvellePosition.X - rayon);
            int maxX = (int)(nouvellePosition.X + rayon);

            int minY = (int)(nouvellePosition.Y - rayon);
            int maxY = (int)(nouvellePosition.Y + rayon);

            int x, y;

            for (x = minX; x <= maxX; x++)
            {
                for (y = minY; y <= maxY; y++)
                {
                    if (x < 0 || y < 0 || x >= 32 || y >= 32)
                    {
                        return(false);
                    }

                    if (Murs[x, y])
                    {
                        return(false);
                    }
                }
            }

            objet.Position += direction;
            return(true);
        }
            public Vector3Df UnitVector()
            {
                float     tmp    = 1 / this.Mag();
                Vector3Df result = this * tmp;

                return(result);
            }
示例#7
0
        static bool device_OnEvent(Event evnt)
        {
            if (evnt.Type == EventType.Mouse)
            {
                if (evnt.Mouse.IsLeftPressed())
                {
                    if (!mouseCanShoot)
                    {
                        return(true);
                    }

                    Vector3Df p = device.SceneManager.ActiveCamera.Position;
                    Vector3Df d = (device.SceneManager.ActiveCamera.Target - p).Normalize();
                    lightningShot.Fire(p + d * 20, d, device.Timer.Time);

                    mouseCanShoot = false;
                    return(true);
                }
                else
                {
                    mouseCanShoot = true;
                }
            }

            return(false);
        }
示例#8
0
		public void Fire(Vector3Df position, Vector3Df direction, uint time)
		{
			Shot s = new Shot();
			s.direction = direction;

			Vector3Df e = position + s.direction * worldInfinity;
			Line3Df l = new Line3Df(position, e);

			Vector3Df cv;
			Triangle3Df ct;
			SceneNode cn;
			if (sceneManager.SceneCollisionManager.GetCollisionPoint(l, worldTriangles, out cv, out ct, out cn))
				e = cv;

			s.deathTime = time + (uint)((e - position).Length / shotSpeed);

			s.node = sceneManager.AddSphereSceneNode(10);
			s.node.SetMaterialFlag(MaterialFlag.Lighting, false);
			sceneManager.MeshManipulator.SetVertexColors(((MeshSceneNode)s.node).Mesh, Color.OpaqueWhite);

			s.node.AddAnimator(sceneManager.CreateFlyStraightAnimator(position, e, (s.deathTime - time) / 1000.0f));
			s.node.AnimatorList[0].Drop();

			sceneManager.AddLightSceneNode(s.node);

			shots.Add(s);
		}
		public void Add(SceneNode node, uint duration, Vector3Df targetPosition, Vector3Df targetRotation, Vector3Df targetScale)
		{
			Remove(node);

			irrDevice.Timer.Tick();

			AnimationItem a = new AnimationItem();
			a.Node = node;
			a.Node.Grab();
			a.Duration = duration;
			a.StartTime = irrDevice.Timer.Time;
			
			if (targetPosition != null)
			{
				a.TargetPosition = targetPosition;
				a.StartPosition = node.Position;
			}

			if (targetRotation != null)
			{
				a.TargetRotation = targetRotation;
				a.StartRotation = node.Rotation;
			}

			if (targetScale != null)
			{
				a.TargetScale = targetScale;
				a.StartScale = node.Scale;
			}

			lock (animationItems)
			{
				animationItems.Add(a);
			}
		}
            public static CG_Matrix ViewSpace(ref Vector3Df Eye, ref Vector3Df Target, ref Vector3Df UpVector)
            {
                CG_Matrix result     = CG_Matrix.Zero();
                Vector3Df VDirection = (Target - Eye);

                VDirection = VDirection.UnitVector();


                Vector3Df RightDirection = Vector3Df.CrossProduct(ref VDirection, ref UpVector);

                RightDirection = RightDirection.UnitVector();
                Vector3Df UpDirection = Vector3Df.CrossProduct(ref RightDirection, ref VDirection);

                UpDirection = UpDirection.UnitVector();

                result.col[0][0] = RightDirection.X;
                result.col[1][0] = RightDirection.Y;
                result.col[2][0] = RightDirection.Z;

                result.col[0][1] = UpDirection.X;
                result.col[1][1] = UpDirection.Y;
                result.col[2][1] = UpDirection.Z;

                result.col[0][2] = -1 * VDirection.X;
                result.col[1][2] = -1 * VDirection.Y;
                result.col[2][2] = -1 * VDirection.Z;

                result.col[3][0] = -1 * Vector3Df.DotProduct(ref RightDirection, ref Eye);
                result.col[3][1] = -1 * Vector3Df.DotProduct(ref UpDirection, ref Eye);
                result.col[3][2] = Vector3Df.DotProduct(ref VDirection, ref Eye);

                result.col[3][3] = 1;

                return(result);
            }
示例#11
0
        internal static void RotatePlane(ref Vector3Df Vector, double cosa, double sina)
        {
            double u = (double)Vector.X * cosa - (double)Vector.Z * sina;
            double v = (double)Vector.X * sina + (double)Vector.Z * cosa;

            Vector.X = (float)u;
            Vector.Z = (float)v;
        }
            public static float DotProduct(ref Vector3Df Vector1, ref Vector3Df Vector2)
            {
                float result = Vector1.X * Vector2.X +
                               Vector1.Y * Vector2.Y +
                               Vector1.Z * Vector2.Z;

                return(result);
            }
示例#13
0
        public static RenderObject Create(Vector3Df pos, Instance linkIns)
        {
            RenderObject renderObject = new RenderObject();

            renderObject.transform      = new Transform(pos);
            renderObject.linkedInstance = linkIns;
            return(renderObject);
        }
示例#14
0
        public static RenderObject Create(Vector3Df pos, Quaternion rotation, Vector3Df scale, Instance linkIns)
        {
            RenderObject renderObject = new RenderObject();

            renderObject.transform      = new Transform(pos, rotation, scale);
            renderObject.linkedInstance = linkIns;
            return(renderObject);
        }
            public static Vector3Df operator *(CG_Matrix lfs, Vector3Df V)
            {
                Vector3Df result = new Vector3Df();

                result.X = lfs.col[0][0] * V.X + lfs.col[1][0] * V.Y + lfs.col[2][0] * V.Z + lfs.col[3][0] * 1.0f;
                result.Y = lfs.col[0][1] * V.X + lfs.col[1][1] * V.Y + lfs.col[2][1] * V.Z + lfs.col[3][1] * 1.0f;
                result.Z = lfs.col[0][2] * V.X + lfs.col[1][2] * V.Y + lfs.col[2][2] * V.Z + lfs.col[3][2] * 1.0f;
                return(result);
            }
示例#16
0
 void getVectorAsStringLine(Vector3Df v, ref string s)
 {
     s  = (-v.X).ToString();
     s += " ";
     s += v.Y.ToString();
     s += " ";
     s += v.Z.ToString();
     s += "\n";
 }
示例#17
0
        public void Setup(Vector3Df gravity)
        {
            bulletCollisionConfiguration = new DefaultCollisionConfiguration();
            bulletCollisionDispatcher    = new CollisionDispatcher(bulletCollisionConfiguration);
            bulletBroadphase             = new DbvtBroadphase();

            bulletWorld         = new DiscreteDynamicsWorld(bulletCollisionDispatcher, bulletBroadphase, null, bulletCollisionConfiguration);
            bulletWorld.Gravity = new Vector3(gravity.X, gravity.Y, gravity.Z);
        }
示例#18
0
		public void Setup(Vector3Df gravity)
		{
			bulletCollisionConfiguration = new DefaultCollisionConfiguration();
			bulletCollisionDispatcher = new CollisionDispatcher(bulletCollisionConfiguration);
			bulletBroadphase = new DbvtBroadphase();

			bulletWorld = new DiscreteDynamicsWorld(bulletCollisionDispatcher, bulletBroadphase, null, bulletCollisionConfiguration);
			bulletWorld.Gravity = new Vector3(gravity.X, gravity.Y, gravity.Z);
		}
示例#19
0
 private void selectAnimationToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
 {
     selectedAnimIdx = Animations.AnimationNames.FindIndex(kv => kv.Key.Equals(e.ClickedItem.Text));
     anims           = new Animations();
     anims.SelectAnimation(AnimFile, selectedAnimIdx);
     modelAngle        = new Vector3Df(startModelAngleWithAnim.X, startModelAngleWithAnim.Y, startModelAngle.Z);
     modelAutorotating = true;
     modelPosition     = new Vector3Df(0.0f);
     RestartIrrThread();
 }
            public static CG_Matrix ScaleMatrix(ref Vector3Df Location, float Scale)
            {
                CG_Matrix result = new CG_Matrix(Scale);

                result.col[3][3] = 1;
                result.col[3][0] = Location.X;
                result.col[3][1] = Location.Y;
                result.col[3][2] = Location.Z;
                return(result);
            }
示例#21
0
        internal static void RotateUpDown(ref Vector3Df Vector, double dx, double dy, double cosa, double sina)
        {
            double x = (double)Vector.X, y = (double)Vector.Y, z = (double)Vector.Z;
            double u = dy * x - dx * z;
            double v = dx * x + dy * z;

            Vector.X = (float)(dy * u + dx * v * cosa - dx * y * sina);
            Vector.Y = (float)(y * cosa + v * sina);
            Vector.Z = (float)(-dx * u + dy * v * cosa - dy * y * sina);
        }
示例#22
0
 private void Bithack3D_KeyDown(object sender, KeyEventArgs e)
 {
     if (e.KeyCode == Keys.Space)
     {
         // Restart autorotation
         modelAutorotating = true;
         modelAngle        = new Vector3Df(270.0f, 270.0f, 0.0f);
         modelPosition     = new Vector3Df(0.0f);
     }
 }
示例#23
0
        CollisionShape bulletGetCollisionShape(Shape shape, SceneNode node)
        {
            switch (shape)
            {
            case Shape.Box:
            {
                return(new BoxShape(node.BoundingBox.Extent.X / 2));
            }

            case Shape.Shpere:
            {
                return(new SphereShape(node.BoundingBox.Extent.X / 2));
            }

            case Shape.Mesh:
            {
                MeshSceneNode meshNode = node as MeshSceneNode;
                if (meshNode == null)
                {
                    throw new ArgumentException();
                }

                TriangleMesh triangleMesh = new TriangleMesh();
                for (int i = 0; i < meshNode.Mesh.MeshBufferCount; i++)
                {
                    MeshBuffer         b     = meshNode.Mesh.GetMeshBuffer(i);
                    ushort[]           inds  = b.Indices as ushort[];
                    Vertex3DTTCoords[] verts = b.Vertices as Vertex3DTTCoords[];

                    if (inds == null || verts == null)
                    {
                        throw new ArgumentException();
                    }

                    for (int j = 0; j < inds.Length; j += 3)
                    {
                        Vector3Df v0 = verts[inds[j + 0]].Position;
                        Vector3Df v1 = verts[inds[j + 1]].Position;
                        Vector3Df v2 = verts[inds[j + 2]].Position;

                        triangleMesh.AddTriangle(
                            new Vector3(v0.X, v0.Y, v0.Z),
                            new Vector3(v1.X, v1.Y, v1.Z),
                            new Vector3(v2.X, v2.Y, v2.Z));
                    }
                }

                return(new BvhTriangleMeshShape(triangleMesh, false));
            }

            default:
                throw new ArgumentException();
            }
        }
示例#24
0
        private void selectAnimationToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            node.DebugDataVisible = DebugSceneType.Off;
            currAnimIdx           = Animations.AnimationNames.FindIndex(kv => kv.Key.Equals(e.ClickedItem.Text));
            anims.SelectAnimation(AnimFile, currAnimIdx);
            anims.Apply(skinnedMesh);

            modelPosition = new Vector3Df(0.0f);
            modelAngle    = new Vector3Df(startModelAngleWithAnim.X, startModelAngleWithAnim.Y, startModelAngle.Z);

            RestartIrrThread();
        }
示例#25
0
		public SpherePath(float height)
		{
			this.height = height;

			Center = new Vector3Df(0);
			FrontColor = Color.OpaqueCyan;
			BackColor = Color.OpaqueBlue;

			// we allocated once 64000 indices, initialize the sequence and never touch them in future... we will only use SetCount() method to set actual number of used indices
			indBoth.Reallocate(64000);
			for (int i = 0; i < indBoth.AllocatedCount - 1; i++)
				indBoth.Add(i);
		}
示例#26
0
        void setupCameraProperties()
        {
            const double deg2rad = Math.PI / 180;

            Vector3Df p = new Vector3Df();

            p.X = (float)(radius * Math.Cos(inclination * deg2rad) * Math.Cos(azimuth * deg2rad));
            p.Y = (float)(radius * Math.Sin(azimuth * deg2rad));
            p.Z = (float)(radius * Math.Sin(inclination * deg2rad) * Math.Cos(azimuth * deg2rad));

            camera.Position = p + target;
            camera.Target   = target;
        }
示例#27
0
        public bool BuildShadowVolume()
        {
            if (buildThread != null)
            {
                return(false);
            }

            buildThread = new Thread(new ThreadStart(delegate()
            {
                List <Vector3Df> v = new List <Vector3Df>();

                foreach (SceneNode lightNode in lights)
                {
                    Vector3Df l = lightNode.AbsolutePosition;

                    foreach (SceneNode objectNode in objects)
                    {
                        Matrix t = objectNode.AbsoluteTransformation;
                        Mesh m   = null;

                        if (objectNode is MeshSceneNode)
                        {
                            m = (objectNode as MeshSceneNode).Mesh;
                        }
                        else if (objectNode is AnimatedMeshSceneNode)
                        {
                            m = (objectNode as AnimatedMeshSceneNode).Mesh;
                        }

                        for (int i = 0; i < m.MeshBufferCount; i++)
                        {
                            buildShadowVolume(v, m.GetMeshBuffer(i), t, l);
                        }
                    }
                }

                lock (visibleShadowVerticesBufferLocker)
                {
                    visibleShadowVerticesBuffer.Clear();
                    visibleShadowVerticesBuffer.AddRange(v);
                }

                Thread.Sleep(300);                 // let GC actually do its work

                buildThread = null;
            }));

            buildThread.Start();

            return(true);
        }
示例#28
0
        static bool device_OnEvent(Event evnt)
        {
            if (evnt.Type == EventType.Key &&
                evnt.Key.PressedDown)
            {
                switch (evnt.Key.Key)
                {
                case KeyCode.Space:
                    simPaused = !simPaused;
                    return(true);

                case KeyCode.KeyT:
                    useTrails = !useTrails;
                    return(true);
                }
            }

            if (evnt.Type == EventType.Mouse)
            {
                if (evnt.Mouse.IsLeftPressed())
                {
                    if (!mouseCanShoot)
                    {
                        return(true);
                    }

                    MeshSceneNode n = device.SceneManager.AddSphereSceneNode(sphereRadius);
                    n.SetMaterialTexture(0, device.VideoDriver.GetTexture("../../media/wall.bmp"));
                    n.SetMaterialFlag(MaterialFlag.Lighting, false);

                    Vector3Df v = (device.SceneManager.ActiveCamera.Target - device.SceneManager.ActiveCamera.Position).Normalize();
                    n.Position = device.SceneManager.ActiveCamera.Position + v * 100;

                    if (useTrails)
                    {
                        particles.Add(n, device.Timer.Time);
                    }

                    physics.AddShape(Physics.Shape.Shpere, n, sphereMass, false, v * cubeMass * 10000);

                    mouseCanShoot = false;
                    return(true);
                }
                else
                {
                    mouseCanShoot = true;
                }
            }

            return(false);
        }
示例#29
0
        public RenderMessage(MessageType m, string name, Vector3Df translation, Vector3Df rotation, TreeNode tn)
        {
            Message     = m;
            MeshName    = name;
            TreeNode    = tn;
            Translation = translation;
            Rotation    = rotation;

            Node        = null;
            MaxHeight   = 0.0f;
            MinHeight   = 0.0f;
            TileRes     = 0;
            TerrainSize = 0.0f;
        }
示例#30
0
        public RenderMessage(MessageType m, string name, uint tileRes, float maxHeight, float minHeight, float terrainSize, Vector3Df anchorPt, TreeNode tn)
        {
            Message     = m;
            MeshName    = name;
            TreeNode    = tn;
            Translation = anchorPt;
            MaxHeight   = maxHeight;
            MinHeight   = minHeight;
            TileRes     = tileRes;
            TerrainSize = terrainSize;

            Node     = null;
            Rotation = new Vector3Df(0.0f, 0.0f, 0.0f);
        }
示例#31
0
        public RenderMessage(MessageType m)
        {
            Message = m;

            Node        = null;
            MeshName    = "";
            TreeNode    = null;
            Rotation    = new Vector3Df(0.0f, 0.0f, 0.0f);
            Translation = new Vector3Df(0.0f, 0.0f, 0.0f);
            MaxHeight   = 0.0f;
            MinHeight   = 0.0f;
            TileRes     = 0;
            TerrainSize = 0.0f;
        }
示例#32
0
        public SphereCamera(IrrlichtDevice device, Vector3Df target, double minRadius, double maxRadius, double initRadius, double initInclination, double initAzimuth)
        {
            this.target = target;
            this.camera = device.SceneManager.AddCameraSceneNode();

            this.minRadius   = minRadius;
            this.maxRadius   = maxRadius;
            this.radius      = initRadius;
            this.inclination = initInclination;
            this.azimuth     = initAzimuth;
            setupCameraProperties();

            device.OnEvent += new IrrlichtDevice.EventHandler(device_OnEvent);
        }
示例#33
0
        public void Run()
        {
            lock (animationItems)
            {
                uint       t = irrDevice.Timer.Time;
                List <int> candidatesToBeRemoved = new List <int>();

                for (int i = 0; i < animationItems.Count; i++)
                {
                    AnimationItem a = animationItems[i];
                    if (t >= a.StartTime + a.Duration)
                    {
                        setFinalAnimationState(i);
                        candidatesToBeRemoved.Add(i);
                    }
                    else
                    {
                        double d = (double)(t - a.StartTime) / a.Duration;

                        if (a.TargetPosition != null)
                        {
                            Vector3Df v = a.Node.Position;
                            v.Interpolate(a.TargetPosition, a.StartPosition, d);
                            a.Node.Position = v;
                        }

                        if (a.TargetRotation != null)
                        {
                            Vector3Df v = a.Node.Rotation;
                            v.Interpolate(a.TargetRotation, a.StartRotation, d);
                            a.Node.Rotation = v;
                        }

                        if (a.TargetScale != null)
                        {
                            Vector3Df v = a.Node.Scale;
                            v.Interpolate(a.TargetScale, a.StartScale, d);
                            a.Node.Scale = v;
                        }
                    }
                }

                for (int i = candidatesToBeRemoved.Count - 1; i >= 0; i--)
                {
                    animationItems[candidatesToBeRemoved[i]].Node.Drop();
                    animationItems.RemoveAt(candidatesToBeRemoved[i]);
                }
            }
        }
示例#34
0
        public SpherePath(float height)
        {
            this.height = height;

            Center     = new Vector3Df(0);
            FrontColor = Color.SolidCyan;
            BackColor  = Color.SolidBlue;

            // we allocated once 64000 indices, initialize the sequence and never touch them in future... we will only use SetCount() method to set actual number of used indices
            indBoth.Reallocate(64000);
            for (int i = 0; i < indBoth.AllocatedCount - 1; i++)
            {
                indBoth.Add(i);
            }
        }
        private void selectAnimationToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            node.DebugDataVisible = DebugSceneType.Off;

            SkinnedMesh sm = helper.applyAnimation(e.ClickedItem.Text, meshToAnimate);

            if (sm != null)
            {
                modelPosition = new Vector3Df(0.0f);
                modelAngle    = new Vector3Df(0.0f);
                node.Mesh     = sm;
                resetDebugViewMenu();
                setMaterialsSettings(node);
                activeAnim = e.ClickedItem.Text;
            }
        }
示例#36
0
		public SphereCamera(IrrlichtDevice device, Vector3Df target, double minRadius, double maxRadius, double initRadius, double initInclination, double initAzimuth)
		{
			this.device = device;
			this.target = target;

			this.camera = device.SceneManager.AddCameraSceneNode();

			this.minRadius = minRadius;
			this.maxRadius = maxRadius;
			this.radius = initRadius;
			this.inclination = initInclination;
			this.azimuth = initAzimuth;
			setupCameraProperties();

			device.OnEvent += new IrrlichtDevice.EventHandler(device_OnEvent);
		}
示例#37
0
		public void AddShape(Shape shape, SceneNode node, float mass = 0.0f, bool sleeping = true, Vector3Df startImpulse = null)
		{
			CollisionShape collShape = bulletGetCollisionShape(shape, node);

			if (simThread != null)
				simThread.Join();

			bulletShapes.Add(collShape);

			RigidBody body = bulletCreateRigidBody(
				mass,
				BulletSharp.Matrix.Translation(node.Position.X, node.Position.Y, node.Position.Z),
				collShape);

			if (sleeping)
				body.ForceActivationState(ActivationState.IslandSleeping);

			if (startImpulse != null)
				body.ApplyCentralImpulse(new Vector3(startImpulse.X, startImpulse.Y, startImpulse.Z));

			body.SetSleepingThresholds(body.LinearSleepingThreshold * 20, body.AngularSleepingThreshold * 20);

			body.UserObject = node;
		}
示例#38
0
文件: World.cs 项目: sladen/openbve
		internal static void RotateUpDown(ref Vector3Df Vector, double dx, double dy, double cosa, double sina) {
			double x = (double)Vector.X, y = (double)Vector.Y, z = (double)Vector.Z;
			double u = dy * x - dx * z;
			double v = dx * x + dy * z;
			Vector.X = (float)(dy * u + dx * v * cosa - dx * y * sina);
			Vector.Y = (float)(y * cosa + v * sina);
			Vector.Z = (float)(-dx * u + dy * v * cosa - dy * y * sina);
		}
示例#39
0
		void setupCameraProperties()
		{
			const double deg2rad = Math.PI / 180;

			Vector3Df p = new Vector3Df();
			p.X = (float)(radius * Math.Cos(inclination * deg2rad) * Math.Cos(azimuth * deg2rad));
			p.Y = (float)(radius * Math.Sin(azimuth * deg2rad));
			p.Z = (float)(radius * Math.Sin(inclination * deg2rad) * Math.Cos(azimuth * deg2rad));

			camera.Position = p + target;
			camera.Target = target;
		}
示例#40
0
		public void Draw(uint time, Vector3Df cameraPosition)
		{
			if (time > nextUpdateAt)
			{
				// animation

				transformation.Rotation = rotationVector * time;

				// recalculate current LOD

				currentLOD = meshLODs.Count - 1;
				float distanceSQ = (transformation.Translation - cameraPosition).LengthSQ;
				for (int i = 0; i < lodDistanceSQ.Length - 1; i++)
				{
					if (distanceSQ < lodDistanceSQ[i])
					{
						currentLOD = i;
						break;
					}
				}

				// next line assigns new time for LOD to be recalculated in future,
				// we do not use same value for all LODs here, because we don't want all the LODItems
				// to be recalculated in the same time (same frame). So we assign a value
				// which higher when current LOD is higher - which also means that for now we are
				// a distant object and it is less possible that we will need to change LOD at all;
				// but close objects (with small LOD value, like 0, 1 or 2) we need to pick quite short time.
				// This is OK if it will be really short, because this objects are too close and indeed may
				// change their LOD value very soon, however, we also understand, that in general all the objects
				// takes very large area, so in general we will have something like less than 2% with LOD level 0, 1 or 2,
				// all other will get higher LOD, and about more than 50% will have maximum LOD value -- they take more time to recalc
				// their LOD than to draw them, so we need to calc their LOD less frequent.
				// p.s.: we also uses that fact, that we do not give ability to user to reach oposite side of our world in 1 frame,
				// the speed which user uses for movement is slow in general.

				nextUpdateAt = time + updateIntervals[currentLOD];
			}

			// drawing

			// we do no set material here, because we draw all LODItems with the same material, we set material in main rendering loop

			driver.SetTransform(TransformationState.World, transformation); // this is also very time consuming operation; we can optimize it
			// to make something like 100 calls (instead of 5000 - the number of LODItems) - we need to group LODItems all this we increase FPS up on
			// 10%, BUT it that case we will not be able to move independent LODItems, becase they will not need (and will not have) own transformation
			// matrix (only LODGroup will has it). So grouping is really greate for some completly static objects like trees, shrubs, stones, etc.

			// we draw single 16-bit meshbuffer
			driver.DrawMeshBuffer(meshLODs[currentLOD].GetMeshBuffer(0));

			if (LabelPositions != null && currentLOD <= 4)
			{
				Vector2Di p = device.SceneManager.SceneCollisionManager.GetScreenCoordinatesFrom3DPosition(transformation.Translation);

				// now we filter here results which will not be visible; we know that:
				// - GetScreenCoordinatesFrom3DPosition() returns {-10000,-10000} for behind camera 3d positions
				// - we do not need to draw out small text if its out of the screen
				// p.s.: without this filtering we will have about 200-300 labels to draw (instead of about 10-20 which are trully visible)
				if (p.X > -200 && p.X < screenSize.Width + 200 &&
					p.Y > -100 && p.Y < screenSize.Height + 100)
				{
					int t = meshLODs[currentLOD].GetMeshBuffer(0).IndexCount / 3;
					int d = (int)(transformation.Translation - cameraPosition).Length;

					LabelPositions.Add(p);
					LabelTexts.Add(
						"LOD: " + currentLOD.ToString() +
						"\nTrinagles: " + t.ToString() +
						"\nDistance: " + d.ToString());
				}
			}
		}
示例#41
0
		public void Load(string filename)
		{
			Clear();

			XDocument d = XDocument.Load(filename);

			Center.X = Convert.ToSingle(d.Root.Element("center").Attribute("x").Value);
			Center.Y = Convert.ToSingle(d.Root.Element("center").Attribute("y").Value);
			Center.Z = Convert.ToSingle(d.Root.Element("center").Attribute("z").Value);

			FrontColor.ARGB = Convert.ToUInt32(d.Root.Element("frontColor").Value);
			BackColor.ARGB = Convert.ToUInt32(d.Root.Element("backColor").Value);

			foreach (XElement e in d.Root.Elements("point"))
			{
				Vector3Df p = new Vector3Df(
					Convert.ToSingle(e.Attribute("x").Value),
					Convert.ToSingle(e.Attribute("y").Value),
					Convert.ToSingle(e.Attribute("z").Value));

				AddPoint(p);
			}
		}
示例#42
0
		static public LODItem Create(IrrlichtDevice device, List<Mesh> meshLODs, Matrix transformation, Vector3Df rotationVector)
		{
			LODItem n = new LODItem();
			n.device = device;
			n.meshLODs = meshLODs;
			n.transformation = transformation;
			n.rotationVector = rotationVector;
			n.currentLOD = meshLODs.Count - 1;

			// we cache some really frequently accessed values (which will never get changed anyway)
			n.driver = device.VideoDriver;
			n.screenSize = device.VideoDriver.ScreenSize;

			return n;
		}
示例#43
0
文件: World.cs 项目: sladen/openbve
			internal MeshFaceVertex(int Index, Vector3Df Normal) {
				this.Index = (ushort)Index;
				this.Normal = Normal;
			}
示例#44
0
		static void Main(string[] args)
		{
			// Initialize device.
			
			DriverType driverType;
			if (!AskUserForDriver(out driverType))
				return;

			IrrlichtDevice device = IrrlichtDevice.CreateDevice(driverType, new Dimension2Di(640, 480));
			if (device == null)
				return;

			// Add event handling.

			device.OnEvent += new IrrlichtDevice.EventHandler(device_OnEvent);

			// Save important pointers.

			VideoDriver driver = device.VideoDriver;
			SceneManager smgr = device.SceneManager;
			Logger logger = device.Logger;

			// Initialize joysticks and print info about them.

			List<JoystickInfo> joystickList = device.ActivateJoysticks();
			if (joystickList != null)
			{
				logger.Log("Joystick support is enabled and " + joystickList.Count.ToString() + " joystick(s) are present.");

				foreach (JoystickInfo j in joystickList)
				{
					logger.Log("Joystick " + j.Joystick.ToString() + ":");
					logger.Log("\tName: \"" + j.Name + "\"");
					logger.Log("\tAxisCount: " + j.AxisCount.ToString());
					logger.Log("\tButtonCount: " + j.ButtonCount.ToString());
					logger.Log("\tPovHat: " + j.PovHat.ToString());
				}
			}
			else
			{
				logger.Log("Joystick support is not enabled.");
			}

			device.SetWindowCaption("Mouse and joystick - Irrlicht Lime - " + joystickList.Count.ToString() + " joystick(s)");

			// Create an arrow mesh and move it around either with the joystick axis/hat,
			// or make it follow the mouse pointer (when no joystick movement).

			SceneNode node = smgr.AddMeshSceneNode(
				smgr.AddArrowMesh(
					"Arrow",
					new Color(255, 0, 0),
					new Color(0, 255, 0),
					16, 16,
					2.0f, 1.3f,
					0.1f, 0.6f
				)
			);

			node.SetMaterialFlag(MaterialFlag.Lighting, false);

			CameraSceneNode camera = smgr.AddCameraSceneNode();
			camera.Position = new Vector3Df(0, 0, -10);

			// As in example #4, we'll use framerate independent movement.
			uint then = device.Timer.Time;
			const float MovementSpeed = 5.0f;

			// Run main cycle.

			while (device.Run())
			{
				// Work out a frame delta time.
				uint now = device.Timer.Time;
				float frameDeltaTime = (float)(now - then) / 1000.0f; // in seconds
				then = now;

				bool movedWithJoystick = false;
				Vector3Df nodePosition = node.Position;

				if (joystickList.Count > 0)
				{
					float moveHorizontal = 0.0f; // range is -1.0 for full left to +1.0 for full right
					float moveVertical = 0.0f; // range is -1.0 for full down to +1.0 for full up

					// We receive the full analog range of the axes, and so have to implement our own dead zone.
					// This is an empirical value, since some joysticks have more jitter or creep around the center
					// point than others. We'll use 5% of the range as the dead zone, but generally you would want
					// to give the user the option to change this.
					float DeadZone = 0.05f;

					moveHorizontal = joystickState.Axis[0] / 32767.0f; // "0" for X axis
					if (Math.Abs(moveHorizontal) < DeadZone)
						moveHorizontal = 0.0f;

					moveVertical = joystickState.Axis[1] / -32767.0f; // "1" for Y axis
					if (Math.Abs(moveVertical) < DeadZone)
						moveVertical = 0.0f;

					// POV will contain 65535 if POV hat info no0t supported, so we can check its range.
					ushort povDegrees = (ushort)(joystickState.POV / 100);
					if (povDegrees < 360)
					{
						if (povDegrees > 0 && povDegrees < 180)
							moveHorizontal = +1.0f;
						else if (povDegrees > 180)
							moveHorizontal = -1.0f;

						if (povDegrees > 90 && povDegrees < 270)
							moveVertical = -1.0f;
						else if (povDegrees > 270 || povDegrees < 90)
							moveVertical = +1.0f;
					}

					// If we have any movement, apply it.
					if (Math.Abs(moveHorizontal) > 0.0001f || Math.Abs(moveVertical) > 0.0001f)
					{
						float m = frameDeltaTime * MovementSpeed;
						nodePosition = new Vector3Df(moveHorizontal * m, moveVertical * m, nodePosition.Z);
						movedWithJoystick = true;
					}
				}

				// If the arrow node isn't being moved with the joystick, then have it follow the mouse cursor.
				if (!movedWithJoystick)
				{
					// Create a ray through the mouse cursor.
					Line3Df ray = smgr.SceneCollisionManager.GetRayFromScreenCoordinates(mouseState.Position, camera);

					// And intersect the ray with a plane around the node facing towards the camera.
					Plane3Df plane = new Plane3Df(nodePosition, new Vector3Df(0, 0, -1));
					Vector3Df mousePosition;
					if (plane.GetIntersectionWithLine(ray.Start, ray.Vector, out mousePosition))
					{
						// We now have a mouse position in 3d space; move towards it.
						Vector3Df toMousePosition = mousePosition - nodePosition;
						float availableMovement = frameDeltaTime * MovementSpeed;

						if (toMousePosition.Length <= availableMovement)
							nodePosition = mousePosition; // jump to the final position
						else
							nodePosition += toMousePosition.Normalize() * availableMovement; // move towards it
					}
				}

				node.Position = nodePosition;

				// Turn lighting on and off depending on whether the left mouse button is down.
				node.SetMaterialFlag(MaterialFlag.Lighting, mouseState.IsLeftButtonDown);

				// Draw all.
				driver.BeginScene(true, true, new Color(113, 113, 133));
				smgr.DrawAll();
				driver.EndScene();
			}

			// Drop the device.

			device.Drop();
		}
示例#45
0
		public void Draw(uint time, Vector3Df cameraPosition, AABBox cameraViewBox)
		{
			if (cameraViewBox.IsInside(d1) ||
				cameraViewBox.IsInside(d2) ||
				cameraViewBox.IsInside(d3) ||
				cameraViewBox.IsInside(d4) ||
				cameraViewBox.IsInside(d5) ||
				cameraViewBox.IsInside(d6) ||
				cameraViewBox.IsInside(d7) ||
				cameraViewBox.IsInside(d8))
			{
				for (int i = 0; i < lodItems.Count; i++)
				{
					lodItems[i].Draw(time, cameraPosition);
				}
			}
		}
示例#46
0
文件: World.cs 项目: sladen/openbve
			internal MeshFaceVertex(int Index) {
				this.Index = (ushort)Index;
				this.Normal = new Vector3Df(0.0f, 0.0f, 0.0f);
			}
示例#47
0
文件: World.cs 项目: sladen/openbve
		internal static void RotatePlane(ref Vector3Df Vector, double cosa, double sina) {
			double u = (double)Vector.X * cosa - (double)Vector.Z * sina;
			double v = (double)Vector.X * sina + (double)Vector.Z * cosa;
			Vector.X = (float)u;
			Vector.Z = (float)v;
		}
示例#48
0
 /// <summary>
 /// Elmozdítani a modellt A pontból B pontba.
 /// </summary>
 /// <param name="anim">SceneNodeAnimator</param>
 /// <param name="smgr">SceneManager</param>
 /// <param name="from">A pont</param>
 /// <param name="to">B pont</param>
 /// <param name="node">Mozgatni kívánt modell</param>
 /// <param name="loop">Végtelen ismétlés?</param>
 public static bool moveFromTo(SceneNodeAnimator anim, SceneManager smgr, Vector3Df from, Vector3Df to, SceneNode node, bool loop)
 {
     isAtTo = false;
     anim = smgr.CreateFlyStraightAnimator(from, to, 3.5f, loop);
     node.AddAnimator(anim);
     if (node.Position == to)
     {
         isAtTo = true;
     }
     else
     {
         isAtTo = false;
     }
     return isAtTo;
 }
示例#49
0
		static bool device_OnEvent(Event e)
		{
			// Escape swaps Camera Input
			if (e.Type == EventType.Key && !e.Key.PressedDown && OnKeyUp(e.Key.Key))
				return true;

			if (e.Type == EventType.GUI)
			{
				guiID id = (guiID)e.GUI.Caller.ID;
				GUIEnvironment env = device.GUIEnvironment;

				switch (e.GUI.Type)
				{
					case GUIEventType.MenuItemSelected:
						// a menu item was clicked
						OnMenuItemSelected(e.GUI.Caller as GUIContextMenu);
						break;

					case GUIEventType.FileDialogFileSelected:
						// load the model file, selected in the file open dialog
						loadModel((e.GUI.Caller as GUIFileOpenDialog).FileName);
						break;

					case GUIEventType.ScrollBarChanged:
						if (id == guiID.SkinTransparency)
						{
							// control skin transparency
							int p = (e.GUI.Caller as GUIScrollBar).Position;
							setSkinTransparency(p, env.Skin);
						}
						else if (id == guiID.SkinAnimationFPS)
						{
							// control animation speed
							int p = (e.GUI.Caller as GUIScrollBar).Position;
							if (model.Type == SceneNodeType.AnimatedMesh)
								(model as AnimatedMeshSceneNode).AnimationSpeed = p;
						}

						break;

					case GUIEventType.ComboBoxChanged:
						if (id == guiID.TextureFilter)
							// control anti-aliasing/filtering
							OnTextureFilterSelected(e.GUI.Caller as GUIComboBox);

						break;

					case GUIEventType.ButtonClicked:
						switch (id)
						{
							case guiID.ButtonSetScale:
								// set scale
								GUIElement r = env.RootElement;
								Vector3Df s = new Vector3Df(
									Convert.ToSingle(r.GetElementFromID((int)guiID.XScale, true).Text),
									Convert.ToSingle(r.GetElementFromID((int)guiID.YScale, true).Text),
									Convert.ToSingle(r.GetElementFromID((int)guiID.ZScale, true).Text));

								if (model != null)
									model.Scale = s;

								updateScaleInfo(model);
								break;

							case guiID.ButtonScaleMul10:
								if (model != null)
									model.Scale *= 10;

								updateScaleInfo(model);
								break;

							case guiID.ButtonScaleDiv10:
								if (model != null)
									model.Scale *= 0.1f;

								updateScaleInfo(model);
								break;

							case guiID.ButtonOpenModel:
								env.AddFileOpenDialog("Please select a model file to open");
								break;

							case guiID.ButtonSelectArchive:
								env.AddFileOpenDialog("Please select your game archive/directory");
								break;

							case guiID.ButtonShowAbout:
								showAboutText();
								break;

							case guiID.ButtonShowToolbox:
								createToolBox();
								break;
						}

						break; // case GUIEventType.ButtonClicked:
				}
			}

			return false;
		}
示例#50
0
		void buildShadowVolume(List<Vector3Df> shadowVertices, MeshBuffer meshbuffer, Matrix matrix, Vector3Df light)
		{
			ushort[] indices = meshbuffer.Indices as ushort[];

			if (indices == null)
				throw new ArgumentException();

			Triangle3Df t123 = new Triangle3Df();

			for (int i = 0; i < indices.Length; i += 3)
			{
				Vector3Df v1 = meshbuffer.GetPosition(indices[i]);
				Vector3Df v2 = meshbuffer.GetPosition(indices[i + 1]);
				Vector3Df v3 = meshbuffer.GetPosition(indices[i + 2]);

				matrix.TransformVector(ref v1);
				matrix.TransformVector(ref v2);
				matrix.TransformVector(ref v3);

				t123.Set(v1, v2, v3);

				Vector3Df v1Dir = v1 - light;

				if (!t123.IsFrontFacing(v1Dir))
					continue;

				Vector3Df v2Dir = v2 - light;
				Vector3Df v3Dir = v3 - light;

				// calc near points

				Vector3Df v1near = v1 + v1Dir * shadowNearMultiplier;
				Vector3Df v2near = v2 + v2Dir * shadowNearMultiplier;
				Vector3Df v3near = v3 + v3Dir * shadowNearMultiplier;

				// calc infinity points

				Vector3Df v1inf = v1 + v1Dir.Normalize() * shadowInfinityRange;
				Vector3Df v2inf = v2 + v2Dir.Normalize() * shadowInfinityRange;
				Vector3Df v3inf = v3 + v3Dir.Normalize() * shadowInfinityRange;

				// top
				shadowVertices.Add(v1near);
				shadowVertices.Add(v2near);
				shadowVertices.Add(v3near);

				// bottom
				shadowVertices.Add(v3inf);
				shadowVertices.Add(v2inf);
				shadowVertices.Add(v1inf);

				// side1

				shadowVertices.Add(v1inf);
				shadowVertices.Add(v2near);
				shadowVertices.Add(v1near);

				shadowVertices.Add(v1inf);
				shadowVertices.Add(v2inf);
				shadowVertices.Add(v2near);

				// side2

				shadowVertices.Add(v2inf);
				shadowVertices.Add(v3near);
				shadowVertices.Add(v2near);

				shadowVertices.Add(v2inf);
				shadowVertices.Add(v3inf);
				shadowVertices.Add(v3near);

				// side3

				shadowVertices.Add(v1near);
				shadowVertices.Add(v3near);
				shadowVertices.Add(v1inf);

				shadowVertices.Add(v3near);
				shadowVertices.Add(v3inf);
				shadowVertices.Add(v1inf);
			}
		}
示例#51
0
		static void Main(string[] args)
		{
			int lodItemCount = AskUserForLODItemCount();

			DriverType driverType;
			if (!AskUserForDriver(out driverType))
				return;

			device = IrrlichtDevice.CreateDevice(driverType, new Dimension2Di(800, 600));
			if (device == null)
				return;

			device.OnEvent += new IrrlichtDevice.EventHandler(device_OnEvent);
			device.SetWindowCaption("Simple LOD - Irrlicht Lime");
			device.CursorControl.Visible = false;

			VideoDriver driver = device.VideoDriver;
			SceneManager scene = device.SceneManager;

			// generate all LODs of mesh

			List<Mesh> lodMesh = new List<Mesh>();
			Material meshMaterial = null;
			List<int> lodTriangleCount = new List<int>();

			int[] p = new int[] { 100, 50, 32, 20, 12, 6, 3 };
			for (int i = 0; i < p.Length; i++)
			{
				Mesh m = scene.GeometryCreator.CreateSphereMesh(50, p[i], p[i]);

				MeshBuffer mb = m.GetMeshBuffer(0);
				mb.Material.Type = MaterialType.Solid;
				mb.Material.SetTexture(0, driver.GetTexture("../../media/earth.jpg"));

				m.SetMaterialFlag(MaterialFlag.Lighting, false);
				lodMesh.Add(m);

				if (meshMaterial == null)
					meshMaterial = m.GetMeshBuffer(0).Material;

				lodTriangleCount.Add(mb.IndexCount / 3);
			}

			// generate world,
			// we generate a lot of objects with random positions in huge virtual cube

			int virtualCubeSide = 20000;
			LODItem[] lodItems = new LODItem[lodItemCount];
			Random r = new Random(12345000);
			for (int i = 0; i < lodItemCount; i++)
			{
				Matrix tmat = new Matrix(
					new Vector3Df( // translation
						r.Next(virtualCubeSide) - virtualCubeSide / 2,
						r.Next(virtualCubeSide) - virtualCubeSide / 2,
						r.Next(virtualCubeSide) - virtualCubeSide / 2));

				Vector3Df rvect = new Vector3Df(
					(float)r.NextDouble() / 200.0f,
					(float)r.NextDouble() / 200.0f,
					(float)r.NextDouble() / 200.0f);

				lodItems[i] = LODItem.Create(device, lodMesh, tmat, rvect);
			}

			// split world on virtual sectors (cubes) for faster visibility check

			int lodSectorSide = 6; // total number of sectors will be lodSectorSide^3, so for 6 it is 216
			int lodSectorSize = virtualCubeSide / lodSectorSide;
			LODSector[,,] lodSectors = new LODSector[lodSectorSide, lodSectorSide, lodSectorSide];

			for (int i = 0; i < lodSectorSide; i++)
			{
				for (int j = 0; j < lodSectorSide; j++)
				{
					for (int k = 0; k < lodSectorSide; k++)
					{
						AABBox dimension = new AABBox(
							new Vector3Df(i * lodSectorSize, j * lodSectorSize, k * lodSectorSize),
							new Vector3Df((i + 1) * lodSectorSize, (j + 1) * lodSectorSize, (k + 1) * lodSectorSize));

						dimension.MinEdge -= virtualCubeSide / 2;
						dimension.MaxEdge -= virtualCubeSide / 2;

						LODSector s = LODSector.Create(dimension);
						lodSectors[i, j, k] = s;
					}
				}
			}

			for (int i = 0; i < lodItems.Length; i++)
			{
				Vector3Df pos = lodItems[i].Position;
				pos += virtualCubeSide / 2;
				pos /= lodSectorSize;

				int ix = (int)pos.X;
				int iy = (int)pos.Y;
				int iz = (int)pos.Z;

				if (ix < 0) ix = 0;
				if (ix > lodSectorSide - 1)
					ix = lodSectorSide - 1;

				if (iy < 0) ix = 0;
				if (iy > lodSectorSide - 1)
					iy = lodSectorSide - 1;

				if (iz < 0) iz = 0;
				if (iz > lodSectorSide - 1)
					iz = lodSectorSide - 1;

				lodSectors[ix, iy, iz].AddLODItem(lodItems[i]);
			}

			// camera

			CameraSceneNode camera = scene.AddCameraSceneNodeFPS();
			camera.FarValue = 30000;

			// font, which we are going to use to show any text we need

			IrrlichtLime.GUI.GUIFont font = device.GUIEnvironment.GetFont("../../media/fontlucida.png");

			// render loop

			while (device.Run())
			{
				driver.BeginScene();
				scene.DrawAll();

				if (isLabelMode)
				{
					LODItem.LabelPositions = new List<Vector2Di>();
					LODItem.LabelTexts = new List<string>();
				}
				else
				{
					LODItem.LabelPositions = null;
					LODItem.LabelTexts = null;
				}

				meshMaterial.Wireframe = isWireframeMode;
				device.VideoDriver.SetMaterial(meshMaterial);

				uint timer = device.Timer.Time;
				Vector3Df cameraPosition = camera.AbsolutePosition;
				AABBox cameraViewBox = camera.ViewFrustum.BoundingBox;

				for (int i = 0; i < lodSectorSide; i++)
				{
					for (int j = 0; j < lodSectorSide; j++)
					{
						for (int k = 0; k < lodSectorSide; k++)
						{
							lodSectors[i, j, k].Draw(timer, cameraPosition, cameraViewBox);
						}
					}
				}

				if (isLabelMode)
				{
					for (int i = 0; i < LODItem.LabelPositions.Count; i++)
					{
						driver.Draw2DLine(
							LODItem.LabelPositions[i] - new Vector2Di(10, 0),
							LODItem.LabelPositions[i] + new Vector2Di(50, 0),
							Color.OpaqueGreen);

						driver.Draw2DLine(
							LODItem.LabelPositions[i] - new Vector2Di(0, 10),
							LODItem.LabelPositions[i] + new Vector2Di(0, 50),
							Color.OpaqueGreen);

						font.Draw(LODItem.LabelTexts[i], LODItem.LabelPositions[i], Color.OpaqueGreen);
					}
				}

				if (isStatsMode)
				{
					// show LOD stats

					int[] lodCount = new int[7] { 0, 0, 0, 0, 0, 0, 0 };
					for (int i = 0; i < lodItems.Length; i++)
						lodCount[lodItems[i].CurrentLOD]++;

					string f = "";
					for (int i = 0; i < lodCount.Length; i++)
					{
						int n = lodCount[i];
						f += "LOD" + i.ToString() + ": " + n.ToString() + " [" + ((n * 100) / lodItemCount).ToString() + "%] objects\n";
					}

					string l = "------------------------";

					font.Draw(
						string.Format("Stats\n{0}\n{1}{2}\nTotal: {3} [100%] objects", l, f, l, lodItemCount),
						new Vector2Di(10, 140),
						Color.OpaqueMagenta);
				}

				// show general stats

				font.Draw(string.Format(
					"Camera position: {0}\nTotal LOD 0 triangles: {1}\nTriangles currently drawn: {2}\nDriver: {3}\nFPS: {4}",
					camera.AbsolutePosition,
					lodTriangleCount[0] * lodItemCount,
					driver.PrimitiveCountDrawn,
					driver.Name,
					driver.FPS),
					10, 10, Color.OpaqueYellow);

				// show active keys

				font.Draw(
				    "[S] Toggle stats\n[W] Toggle wireframe\n[L] Toggle labels (only for LODs from 0 to 4)\n[Esc] Exit application",
				    10, driver.ScreenSize.Height - 80, Color.OpaqueCyan);

				driver.EndScene();
			}

			// drop

			device.Drop();
		}