Răsfoiți Sursa

Graphics3D updated to SDK projects and MG 3.8.*

CartBlanche 1 săptămână în urmă
părinte
comite
d2829d9571
53 a modificat fișierele cu 1645 adăugiri și 1108 ștergeri
  1. 49 0
      Graphics3DSample/.vscode/launch.json
  2. 151 0
      Graphics3DSample/.vscode/tasks.json
  3. 118 128
      Graphics3DSample/Core/Animation/Animation.cs
  4. 78 87
      Graphics3DSample/Core/Buttons/Button.cs
  5. 82 85
      Graphics3DSample/Core/Buttons/Checkbox.cs
  6. 64 72
      Graphics3DSample/Core/Buttons/Clickable.cs
  7. 7 7
      Graphics3DSample/Core/Content/AnimationDef.xml
  8. 0 0
      Graphics3DSample/Core/Content/Buttons/animation_60x60.png
  9. 0 0
      Graphics3DSample/Core/Content/Buttons/animation_60x60.xnb
  10. 0 0
      Graphics3DSample/Core/Content/Buttons/arrow1_left_60x60.png
  11. 0 0
      Graphics3DSample/Core/Content/Buttons/arrow1_left_60x60.xnb
  12. 0 0
      Graphics3DSample/Core/Content/Buttons/arrow1_right_60x60.png
  13. 0 0
      Graphics3DSample/Core/Content/Buttons/arrow1_right_60x60.xnb
  14. 0 0
      Graphics3DSample/Core/Content/Buttons/lamp_60x60.png
  15. 0 0
      Graphics3DSample/Core/Content/Buttons/lamp_60x60.xnb
  16. 0 0
      Graphics3DSample/Core/Content/Buttons/perPixelLight_60x60.png
  17. 0 0
      Graphics3DSample/Core/Content/Buttons/perPixelLight_60x60.xnb
  18. 0 0
      Graphics3DSample/Core/Content/Buttons/textureOnOff.png
  19. 0 0
      Graphics3DSample/Core/Content/Buttons/textureOnOff.xnb
  20. 0 0
      Graphics3DSample/Core/Content/Models/enemy.tga
  21. 0 0
      Graphics3DSample/Core/Content/Models/enemy_0.xnb
  22. 0 0
      Graphics3DSample/Core/Content/Models/spaceship.fbx
  23. 0 0
      Graphics3DSample/Core/Content/Models/spaceship.xnb
  24. 0 0
      Graphics3DSample/Core/Content/Textures/explosionStrip.png
  25. 0 0
      Graphics3DSample/Core/Content/Textures/explosionStrip.xnb
  26. 0 0
      Graphics3DSample/Core/Content/Textures/spaceBG.png
  27. 0 0
      Graphics3DSample/Core/Content/Textures/spaceBG.xnb
  28. 435 347
      Graphics3DSample/Core/GameMain.cs
  29. 8 0
      Graphics3DSample/Core/Graphics3DSample.Core.csproj
  30. 176 188
      Graphics3DSample/Core/Models/Spaceship.cs
  31. 0 110
      Graphics3DSample/Graphics3DSample.MacOS.csproj
  32. 48 0
      Graphics3DSample/Graphics3DSample.sln
  33. 0 16
      Graphics3DSample/Info.plist
  34. 0 45
      Graphics3DSample/Main.cs
  35. 33 0
      Graphics3DSample/Platforms/Android/AndroidManifest.xml
  36. 34 0
      Graphics3DSample/Platforms/Android/Graphics3DSample.Android.csproj
  37. 32 0
      Graphics3DSample/Platforms/Android/MainActivity.cs
  38. 5 0
      Graphics3DSample/Platforms/Android/Resources/drawable/icon.xml
  39. 5 0
      Graphics3DSample/Platforms/Android/Resources/mipmap-hdpi/ic_launcher.xml
  40. 5 0
      Graphics3DSample/Platforms/Android/Resources/mipmap-mdpi/ic_launcher.xml
  41. 5 0
      Graphics3DSample/Platforms/Android/Resources/mipmap-xhdpi/ic_launcher.xml
  42. 5 0
      Graphics3DSample/Platforms/Android/Resources/mipmap-xxhdpi/ic_launcher.xml
  43. 5 0
      Graphics3DSample/Platforms/Android/Resources/mipmap-xxxhdpi/ic_launcher.xml
  44. 8 0
      Graphics3DSample/Platforms/Android/Resources/values/styles.xml
  45. 29 0
      Graphics3DSample/Platforms/Desktop/Graphics3DSample.DesktopGL.csproj
  46. 12 0
      Graphics3DSample/Platforms/Desktop/Program.cs
  47. 32 0
      Graphics3DSample/Platforms/Windows/Graphics3DSample.Windows.csproj
  48. 12 0
      Graphics3DSample/Platforms/Windows/Program.cs
  49. 33 0
      Graphics3DSample/Platforms/iOS/Graphics3DSample.iOS.csproj
  50. 40 0
      Graphics3DSample/Platforms/iOS/Info.plist
  51. 30 0
      Graphics3DSample/Platforms/iOS/Program.cs
  52. 0 23
      Graphics3DSample/Properties/AssemblyInfo.cs
  53. 104 0
      Graphics3DSample/README.md

+ 49 - 0
Graphics3DSample/.vscode/launch.json

@@ -0,0 +1,49 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Launch Windows",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-windows",
+      "program": "${workspaceFolder}/Platforms/Windows/bin/Debug/net8.0-windows/Graphics3DSample.Windows.exe",
+      "args": [],
+      "cwd": "${workspaceFolder}",
+      "console": "internalConsole",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch DesktopGL",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-desktopgl",
+      "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net8.0/Graphics3DSample.DesktopGL.exe",
+      "args": [],
+      "cwd": "${workspaceFolder}",
+      "console": "internalConsole",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch Android",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-android",
+      "program": "${workspaceFolder}/Platforms/Android/bin/Debug/net8.0-android/Graphics3DSample.Android.dll",
+      "args": [],
+      "cwd": "${workspaceFolder}",
+      "console": "internalConsole",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch iOS",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-ios",
+      "program": "${workspaceFolder}/Platforms/iOS/bin/Debug/net8.0-ios/Graphics3DSample.iOS.dll",
+      "args": [],
+      "cwd": "${workspaceFolder}",
+      "console": "internalConsole",
+      "stopAtEntry": false
+    }
+  ]
+}

+ 151 - 0
Graphics3DSample/.vscode/tasks.json

@@ -0,0 +1,151 @@
+{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "label": "build-windows",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "build",
+        "Platforms/Windows/Graphics3DSample.Windows.csproj"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      },
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "build-desktopgl",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "build",
+        "Platforms/Desktop/Graphics3DSample.DesktopGL.csproj"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      },
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "build-android",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "build",
+        "Platforms/Android/Graphics3DSample.Android.csproj"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      },
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "build-ios",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "build",
+        "Platforms/iOS/Graphics3DSample.iOS.csproj"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      },
+      "problemMatcher": "$msCompile"
+    },
+    {
+      "label": "run-windows",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "run",
+        "--project",
+        "Platforms/Windows/Graphics3DSample.Windows.csproj"
+      ],
+      "group": "test",
+      "dependsOn": "build-windows",
+      "presentation": {
+        "echo": true,
+        "reveal": "always",
+        "focus": false,
+        "panel": "new"
+      }
+    },
+    {
+      "label": "run-desktopgl",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "run",
+        "--project",
+        "Platforms/Desktop/Graphics3DSample.DesktopGL.csproj"
+      ],
+      "group": "test",
+      "dependsOn": "build-desktopgl",
+      "presentation": {
+        "echo": true,
+        "reveal": "always",
+        "focus": false,
+        "panel": "new"
+      }
+    },
+    {
+      "label": "clean",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "clean"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      }
+    },
+    {
+      "label": "restore",
+      "type": "shell",
+      "command": "dotnet",
+      "args": [
+        "restore"
+      ],
+      "group": "build",
+      "presentation": {
+        "echo": true,
+        "reveal": "silent",
+        "focus": false,
+        "panel": "shared",
+        "showReuseMessage": true,
+        "clear": false
+      }
+    }
+  ]
+}

+ 118 - 128
Graphics3DSample/Animation/Animation.cs → Graphics3DSample/Core/Animation/Animation.cs

@@ -1,128 +1,118 @@
-#region File Information
-//-----------------------------------------------------------------------------
-// Animation.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace Graphics3DSample
-{
-    class Animation
-    {
-        #region Fields
-        // The texture with animation frames
-        Texture2D animationTexture;
-        // The size and structure of whole frames sheet in animationTexture. The animationTexture could
-        // hold animaton sequence organized in multiple rows and multiple columns, that's why animation 
-        // engine should know how the frames are organized inside a frames sheet
-        Point sheetSize;
-        // Amount of time between frames
-        TimeSpan frameInterval;
-        // Time passed since last frame
-        TimeSpan nextFrame;
-
-        // Current frame in the animation sequence
-        public Point currentFrame;
-        // The size of single frame inside the animationTexture
-        public Point frameSize;
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// Constructor of an animation class
-        /// </summary>
-        /// <param name="frameSheet">Texture with animation frames sheet</param>
-        /// <param name="size">Single frame size</param>
-        /// <param name="frameSheetSize">The whole frame sheet size</param>
-        /// <param name="interval">Interval between progressing to the next frame</param>
-        public Animation(Texture2D frameSheet, Point size, Point frameSheetSize, TimeSpan interval)
-        {
-            animationTexture = frameSheet;
-            frameSize = size;
-            sheetSize = frameSheetSize;
-            frameInterval = interval;
-        }
-        #endregion
-
-        #region Update and Render
-        /// <summary>
-        /// Updates the animaton progress
-        /// </summary>
-        /// <param name="gameTime"></param>
-        /// <param name="progressed">Returns true if animation were progressed; in such case 
-        /// caller could updated the position of the animated character</param>
-        public bool Update(GameTime gameTime)
-        {
-            bool progressed;
-
-            // Check is it is a time to progress to the next frame
-            if (nextFrame >= frameInterval)
-            {
-                // Progress to the next frame in the row
-                currentFrame.X++;
-                // If reached end of the row advance to the next row 
-                // and start form the first frame there
-                if (currentFrame.X >= sheetSize.X)
-                {
-                    currentFrame.X = 0;
-                    currentFrame.Y++;
-                }
-                // If reached last row in the frame sheet jump to the first row again - produce endless loop
-                if (currentFrame.Y >= sheetSize.Y)
-                    currentFrame.Y = 0;
-
-                // Reset interval for next frame
-                progressed = true;
-                nextFrame = TimeSpan.Zero;
-            }
-            else
-            {
-                // Wait for the next frame 
-                nextFrame += gameTime.ElapsedGameTime;
-                progressed = false;
-            }
-
-            return progressed;
-        }
-
-        /// <summary>
-        /// Rendering of the animation
-        /// </summary>
-        /// <param name="spriteBatch">SpriteBatch in which current frame will be rendered</param>
-        /// <param name="position">The position of current frame</param>
-        /// <param name="spriteEffect">SpriteEffect to apply on current frame</param>
-        public void Draw(SpriteBatch spriteBatch, Vector2 position, SpriteEffects spriteEffect)
-        {
-            Draw(spriteBatch, position, 1.0f, spriteEffect);
-        }
-
-        /// <summary>
-        /// Rendering of the animation
-        /// </summary>
-        /// <param name="spriteBatch">SpriteBatch in which current frame will be rendered</param>
-        /// <param name="position">The position of the current frame</param>
-        /// <param name="scale">Scale factor to apply on the current frame</param>
-        /// <param name="spriteEffect">SpriteEffect to apply on the current frame</param>
-        public void Draw(SpriteBatch spriteBatch, Vector2 position, float scale, SpriteEffects spriteEffect)
-        {
-            spriteBatch.Draw(animationTexture, position, new Rectangle(
-                  frameSize.X * currentFrame.X,
-                  frameSize.Y * currentFrame.Y,
-                  frameSize.X,
-                  frameSize.Y),
-                  Color.White, 0f, Vector2.Zero, scale, spriteEffect, 0);
-        }
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// Animation.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Graphics3DSample
+{
+    class Animation
+    {
+        // The texture with animation frames
+        Texture2D animationTexture;
+        // The size and structure of whole frames sheet in animationTexture. The animationTexture could
+        // hold animaton sequence organized in multiple rows and multiple columns, that's why animation 
+        // engine should know how the frames are organized inside a frames sheet
+        Point sheetSize;
+        // Amount of time between frames
+        TimeSpan frameInterval;
+        // Time passed since last frame
+        TimeSpan nextFrame;
+
+        // Current frame in the animation sequence
+        public Point currentFrame;
+        // The size of single frame inside the animationTexture
+        public Point frameSize;
+
+        /// <summary>
+        /// Constructor of an animation class
+        /// </summary>
+        /// <param name="frameSheet">Texture with animation frames sheet</param>
+        /// <param name="size">Single frame size</param>
+        /// <param name="frameSheetSize">The whole frame sheet size</param>
+        /// <param name="interval">Interval between progressing to the next frame</param>
+        public Animation(Texture2D frameSheet, Point size, Point frameSheetSize, TimeSpan interval)
+        {
+            animationTexture = frameSheet;
+            frameSize = size;
+            sheetSize = frameSheetSize;
+            frameInterval = interval;
+        }
+
+        /// <summary>
+        /// Updates the animaton progress
+        /// </summary>
+        /// <param name="gameTime"></param>
+        /// <param name="progressed">Returns true if animation were progressed; in such case 
+        /// caller could updated the position of the animated character</param>
+        public bool Update(GameTime gameTime)
+        {
+            bool progressed;
+
+            // Check is it is a time to progress to the next frame
+            if (nextFrame >= frameInterval)
+            {
+                // Progress to the next frame in the row
+                currentFrame.X++;
+                // If reached end of the row advance to the next row 
+                // and start form the first frame there
+                if (currentFrame.X >= sheetSize.X)
+                {
+                    currentFrame.X = 0;
+                    currentFrame.Y++;
+                }
+                // If reached last row in the frame sheet jump to the first row again - produce endless loop
+                if (currentFrame.Y >= sheetSize.Y)
+                    currentFrame.Y = 0;
+
+                // Reset interval for next frame
+                progressed = true;
+                nextFrame = TimeSpan.Zero;
+            }
+            else
+            {
+                // Wait for the next frame 
+                nextFrame += gameTime.ElapsedGameTime;
+                progressed = false;
+            }
+
+            return progressed;
+        }
+
+        /// <summary>
+        /// Rendering of the animation
+        /// </summary>
+        /// <param name="spriteBatch">SpriteBatch in which current frame will be rendered</param>
+        /// <param name="position">The position of current frame</param>
+        /// <param name="spriteEffect">SpriteEffect to apply on current frame</param>
+        public void Draw(SpriteBatch spriteBatch, Vector2 position, SpriteEffects spriteEffect)
+        {
+            Draw(spriteBatch, position, 1.0f, spriteEffect);
+        }
+
+        /// <summary>
+        /// Rendering of the animation
+        /// </summary>
+        /// <param name="spriteBatch">SpriteBatch in which current frame will be rendered</param>
+        /// <param name="position">The position of the current frame</param>
+        /// <param name="scale">Scale factor to apply on the current frame</param>
+        /// <param name="spriteEffect">SpriteEffect to apply on the current frame</param>
+        public void Draw(SpriteBatch spriteBatch, Vector2 position, float scale, SpriteEffects spriteEffect)
+        {
+            spriteBatch.Draw(animationTexture, position, new Rectangle(
+                  frameSize.X * currentFrame.X,
+                  frameSize.Y * currentFrame.Y,
+                  frameSize.X,
+                  frameSize.Y),
+                  Color.White, 0f, Vector2.Zero, scale, spriteEffect, 0);
+        }
+    }
+}

+ 78 - 87
Graphics3DSample/Buttons/Button.cs → Graphics3DSample/Core/Buttons/Button.cs

@@ -1,87 +1,78 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Audio;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.GamerServices;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Media;
-using Microsoft.Xna.Framework.Input.Touch;
-
-
-namespace Graphics3DSample
-{
-    /// <summary>
-    /// A game component, inherits to Clickable.
-    /// Has associated content.
-    /// Has an integer Value that is incremented by click.
-    /// Draws content.
-    /// </summary>
-    public class Button : Clickable
-    {
-
-        #region Fields
-        readonly string asset;
-        Texture2D texture;
-        int value;
-
-        #region Public accessors
-        public int Value { get { return value; } }
-        #endregion
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// Constructor
-        /// </summary>
-        /// <param name="game">The Game object</param>
-        /// <param name="textureName">Texture Name</param>
-        /// <param name="targetRectangle">Position of the component on the screen</param>
-        /// <param name="initialValue">Initial value</param>
-        public Button (Graphics3DSampleGame game, string textureName, Rectangle targetRectangle, int initialValue)
-            : base(game, targetRectangle)
-        {
-            asset = textureName;
-            value = initialValue;
-        }
-
-        /// <summary>
-        /// Load the button's texture
-        /// </summary>
-        protected override void LoadContent()
-        {
-            texture = Game.Content.Load<Texture2D>(asset);
-            base.LoadContent();
-        }
-        #endregion
-
-        #region Update and render
-        /// <summary>
-        /// Allows the game component to update itself
-        /// </summary>
-        /// <param name="gameTime">Provides a snapshot of timing values.</param>
-        public override void Update(GameTime gameTime)
-        {
-            HandleInput();
-            if (IsClicked)
-                ++value;
-            base.Update(gameTime);
-        }
-
-        /// <summary>
-        /// Allows the game component to update itself.
-        /// </summary>
-        /// <param name="gameTime">Provides a snapshot of timing values.</param>
-        public override void Draw(GameTime gameTime)
-        {
-            var color = IsTouching ? Color.Wheat : Color.White;
-            Game.SpriteBatch.Begin();
-            Game.SpriteBatch.Draw(texture, Rectangle, color);
-            Game.SpriteBatch.End();
-            base.Draw(gameTime);
-        }
-        #endregion
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Media;
+using Microsoft.Xna.Framework.Input.Touch;
+
+
+namespace Graphics3DSample
+{
+    /// <summary>
+    /// A game component, inherits to Clickable.
+    /// Has associated content.
+    /// Has an integer Value that is incremented by click.
+    /// Draws content.
+    /// </summary>
+    public class Button : Clickable
+    {
+
+        readonly string asset;
+        Texture2D texture;
+        int value;
+
+        public int Value { get { return value; } }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="game">The Game object</param>
+        /// <param name="textureName">Texture Name</param>
+        /// <param name="targetRectangle">Position of the component on the screen</param>
+        /// <param name="initialValue">Initial value</param>
+        public Button (Graphics3DSampleGame game, string textureName, Rectangle targetRectangle, int initialValue)
+            : base(game, targetRectangle)
+        {
+            asset = textureName;
+            value = initialValue;
+        }
+
+        /// <summary>
+        /// Load the button's texture
+        /// </summary>
+        protected override void LoadContent()
+        {
+            texture = Game.Content.Load<Texture2D>(asset);
+            base.LoadContent();
+        }
+
+        /// <summary>
+        /// Allows the game component to update itself
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        public override void Update(GameTime gameTime)
+        {
+            HandleInput();
+            if (IsClicked)
+                ++value;
+            base.Update(gameTime);
+        }
+
+        /// <summary>
+        /// Allows the game component to update itself.
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        public override void Draw(GameTime gameTime)
+        {
+            var color = IsTouching ? Color.Wheat : Color.White;
+            Game.SpriteBatch.Begin();
+            Game.SpriteBatch.Draw(texture, Rectangle, color);
+            Game.SpriteBatch.End();
+            base.Draw(gameTime);
+        }
+    }
+}

+ 82 - 85
Graphics3DSample/Buttons/Checkbox.cs → Graphics3DSample/Core/Buttons/Checkbox.cs

@@ -1,85 +1,82 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Audio;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.GamerServices;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Media;
-using Microsoft.Xna.Framework.Input.Touch;
-
-
-namespace Graphics3DSample
-{
-    /// <summary>
-    /// A game component, inherits to Clickable.
-    /// Has associated On and Off content.
-    /// Has a state of IsChecked that is switched by click.
-    /// Draws content according to state.
-    /// </summary>
-    public class Checkbox : Clickable
-    {
-        #region Fields
-        readonly string asset;
-        Texture2D textureOn;
-        bool isChecked;
-
-        #region Public accessors
-        public bool IsChecked { get { return isChecked; } }
-        #endregion
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="game">The Game object</param>
-        /// <param name="textureName">Texture name</param>
-        /// <param name="targetRectangle">Position of the component on the screen</param>
-        /// <param name="isChecked">Initial state of the checkbox</param>
-        public Checkbox(Graphics3DSampleGame game, string textureName, Rectangle targetRectangle, bool isChecked)
-            : base(game, targetRectangle)
-        {
-            asset = textureName;
-            this.isChecked = isChecked;
-        }
-
-        /// <summary>
-        /// Load the texture
-        /// </summary>
-        protected override void LoadContent()
-        {
-            textureOn = Game.Content.Load<Texture2D>(asset);
-            base.LoadContent();
-        }
-        #endregion
-
-        #region Update and render
-        /// <summary>
-        /// Allows the game component to update itself.
-        /// </summary>
-        /// <param name="gameTime">Provides a snapshot of timing values.</param>
-        public override void Update(GameTime gameTime)
-        {
-            HandleInput();
-            isChecked = IsClicked ? !isChecked : isChecked;
-            base.Update(gameTime);
-        }
-
-        /// <summary>
-        /// Allows the game component to update itself.
-        /// </summary>
-        /// <param name="gameTime">Provides a snapshot of timing values.</param>
-        public override void Draw(GameTime gameTime)
-        {
-            Game.SpriteBatch.Begin();
-            Game.SpriteBatch.Draw(textureOn, Rectangle,
-                IsChecked ? Color.Yellow : Color.White);
-            Game.SpriteBatch.End();
-            base.Draw(gameTime);
-        }
-        #endregion
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Media;
+using Microsoft.Xna.Framework.Input.Touch;
+
+
+namespace Graphics3DSample
+{
+    /// <summary>
+    /// A game component, inherits to Clickable.
+    /// Has associated On and Off content.
+    /// Has a state of IsChecked that is switched by click.
+    /// Draws content according to state.
+    /// </summary>
+    public class Checkbox : Clickable
+    {
+        readonly string asset;
+        Texture2D textureOn;
+        bool isChecked;
+
+        public bool IsChecked
+        {
+            get { return isChecked; }
+            set { isChecked = value; }
+        }
+
+        public Rectangle Bounds { get { return Rectangle; } }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="game">The Game object</param>
+        /// <param name="textureName">Texture name</param>
+        /// <param name="targetRectangle">Position of the component on the screen</param>
+        /// <param name="isChecked">Initial state of the checkbox</param>
+        public Checkbox(Graphics3DSampleGame game, string textureName, Rectangle targetRectangle, bool isChecked)
+            : base(game, targetRectangle)
+        {
+            asset = textureName;
+            this.isChecked = isChecked;
+        }
+
+        /// <summary>
+        /// Load the texture
+        /// </summary>
+        protected override void LoadContent()
+        {
+            textureOn = Game.Content.Load<Texture2D>(asset);
+            base.LoadContent();
+        }
+
+        /// <summary>
+        /// Allows the game component to update itself.
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        public override void Update(GameTime gameTime)
+        {
+            HandleInput();
+            isChecked = IsClicked ? !isChecked : isChecked;
+            base.Update(gameTime);
+        }
+
+        /// <summary>
+        /// Allows the game component to update itself.
+        /// </summary>
+        /// <param name="gameTime">Provides a snapshot of timing values.</param>
+        public override void Draw(GameTime gameTime)
+        {
+            Game.SpriteBatch.Begin();
+            Game.SpriteBatch.Draw(textureOn, Rectangle,
+                IsChecked ? Color.Yellow : Color.White);
+            Game.SpriteBatch.End();
+            base.Draw(gameTime);
+        }
+    }
+}

+ 64 - 72
Graphics3DSample/Buttons/Clickable.cs → Graphics3DSample/Core/Buttons/Clickable.cs

@@ -1,72 +1,64 @@
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Input.Touch;
-
-
-namespace Graphics3DSample
-{
-    /// <summary>
-    /// A game component.
-    /// Has an associated rectangle.
-    /// Accepts touch and click inside the rectangle.
-    /// Has a state of IsTouching and IsClicked.
-    /// </summary>
-    public class Clickable : DrawableGameComponent
-    {
-
-        #region Fields
-        readonly Rectangle rectangle;
-        bool wasTouching;
-        bool isTouching;
-
-        #region Protected accessors
-        public bool IsTouching { get { return isTouching; } }
-        public bool IsClicked { get { return (wasTouching == true) && (isTouching == false); } }
-
-        protected Rectangle Rectangle { get { return rectangle; } }
-        protected new Graphics3DSampleGame Game { get { return (Graphics3DSampleGame)base.Game; } }
-        #endregion
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// Constructor
-        /// </summary>
-        /// <param name="game">The Game oject</param>
-        /// <param name="targetRectangle">Position of the component on the screen</param>
-        public Clickable(Graphics3DSampleGame game, Rectangle targetRectangle)
-            : base(game)
-        {
-            rectangle = targetRectangle;
-        }
-        #endregion
-
-        #region Input handling
-        /// <summary>
-        /// Handles Input
-        /// </summary>
-        protected void HandleInput()
-        {
-            wasTouching = isTouching;
-            isTouching = false;
-
-            TouchCollection touches = TouchPanel.GetState();
-
-            if (touches.Count > 0)
-            {
-                var touch = touches[0];
-                var position = touch.Position;
-
-
-                Rectangle touchRect = new Rectangle((int)touch.Position.X - 5, (int)touch.Position.Y - 5,
-                    10, 10);
-
-                if (rectangle.Intersects(touchRect))
-                    isTouching = true;
-            }
-
-        }
-        #endregion
-    }
-}
-
-
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input.Touch;
+
+
+namespace Graphics3DSample
+{
+    /// <summary>
+    /// A game component.
+    /// Has an associated rectangle.
+    /// Accepts touch and click inside the rectangle.
+    /// Has a state of IsTouching and IsClicked.
+    /// </summary>
+    public class Clickable : DrawableGameComponent
+    {
+
+        readonly Rectangle rectangle;
+        bool wasTouching;
+        bool isTouching;
+
+        public bool IsTouching { get { return isTouching; } }
+        public bool IsClicked { get { return (wasTouching == true) && (isTouching == false); } }
+
+        protected Rectangle Rectangle { get { return rectangle; } }
+        protected new Graphics3DSampleGame Game { get { return (Graphics3DSampleGame)base.Game; } }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="game">The Game oject</param>
+        /// <param name="targetRectangle">Position of the component on the screen</param>
+        public Clickable(Graphics3DSampleGame game, Rectangle targetRectangle)
+            : base(game)
+        {
+            rectangle = targetRectangle;
+        }
+
+        /// <summary>
+        /// Handles Input
+        /// </summary>
+        protected void HandleInput()
+        {
+            wasTouching = isTouching;
+            isTouching = false;
+
+            TouchCollection touches = TouchPanel.GetState();
+
+            if (touches.Count > 0)
+            {
+                var touch = touches[0];
+                var position = touch.Position;
+
+
+                Rectangle touchRect = new Rectangle((int)touch.Position.X - 5, (int)touch.Position.Y - 5,
+                    10, 10);
+
+                if (rectangle.Intersects(touchRect))
+                    isTouching = true;
+            }
+
+        }
+    }
+}
+
+

+ 7 - 7
Graphics3DSample/Content/AnimationDef.xml → Graphics3DSample/Core/Content/AnimationDef.xml

@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<Animations>
-  <Definition FrameWidth="128" FrameHeight="128" 
-              SheetRows="1" SheetColumns="6" 
-              Speed="10" 
-              SheetName="Textures/explosionStrip"/>
-</Animations>
+<?xml version="1.0" encoding="utf-8" ?>
+<Animations>
+  <Definition FrameWidth="128" FrameHeight="128" 
+              SheetRows="1" SheetColumns="6" 
+              Speed="10" 
+              SheetName="Textures/explosionStrip"/>
+</Animations>

+ 0 - 0
Graphics3DSample/Content/Buttons/animation_60x60.png → Graphics3DSample/Core/Content/Buttons/animation_60x60.png


+ 0 - 0
Graphics3DSample/Content/Buttons/animation_60x60.xnb → Graphics3DSample/Core/Content/Buttons/animation_60x60.xnb


+ 0 - 0
Graphics3DSample/Content/Buttons/arrow1_left_60x60.png → Graphics3DSample/Core/Content/Buttons/arrow1_left_60x60.png


+ 0 - 0
Graphics3DSample/Content/Buttons/arrow1_left_60x60.xnb → Graphics3DSample/Core/Content/Buttons/arrow1_left_60x60.xnb


+ 0 - 0
Graphics3DSample/Content/Buttons/arrow1_right_60x60.png → Graphics3DSample/Core/Content/Buttons/arrow1_right_60x60.png


+ 0 - 0
Graphics3DSample/Content/Buttons/arrow1_right_60x60.xnb → Graphics3DSample/Core/Content/Buttons/arrow1_right_60x60.xnb


+ 0 - 0
Graphics3DSample/Content/Buttons/lamp_60x60.png → Graphics3DSample/Core/Content/Buttons/lamp_60x60.png


+ 0 - 0
Graphics3DSample/Content/Buttons/lamp_60x60.xnb → Graphics3DSample/Core/Content/Buttons/lamp_60x60.xnb


+ 0 - 0
Graphics3DSample/Content/Buttons/perPixelLight_60x60.png → Graphics3DSample/Core/Content/Buttons/perPixelLight_60x60.png


+ 0 - 0
Graphics3DSample/Content/Buttons/perPixelLight_60x60.xnb → Graphics3DSample/Core/Content/Buttons/perPixelLight_60x60.xnb


+ 0 - 0
Graphics3DSample/Content/Buttons/textureOnOff.png → Graphics3DSample/Core/Content/Buttons/textureOnOff.png


+ 0 - 0
Graphics3DSample/Content/Buttons/textureOnOff.xnb → Graphics3DSample/Core/Content/Buttons/textureOnOff.xnb


+ 0 - 0
Graphics3DSample/Content/Models/enemy.tga → Graphics3DSample/Core/Content/Models/enemy.tga


+ 0 - 0
Graphics3DSample/Content/Models/enemy_0.xnb → Graphics3DSample/Core/Content/Models/enemy_0.xnb


+ 0 - 0
Graphics3DSample/Content/Models/spaceship.fbx → Graphics3DSample/Core/Content/Models/spaceship.fbx


+ 0 - 0
Graphics3DSample/Content/Models/spaceship.xnb → Graphics3DSample/Core/Content/Models/spaceship.xnb


+ 0 - 0
Graphics3DSample/Content/Textures/explosionStrip.png → Graphics3DSample/Core/Content/Textures/explosionStrip.png


+ 0 - 0
Graphics3DSample/Content/Textures/explosionStrip.xnb → Graphics3DSample/Core/Content/Textures/explosionStrip.xnb


+ 0 - 0
Graphics3DSample/Content/Textures/spaceBG.png → Graphics3DSample/Core/Content/Textures/spaceBG.png


+ 0 - 0
Graphics3DSample/Content/Textures/spaceBG.xnb → Graphics3DSample/Core/Content/Textures/spaceBG.xnb


+ 435 - 347
Graphics3DSample/GameMain.cs → Graphics3DSample/Core/GameMain.cs

@@ -1,347 +1,435 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// DemoGame.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Audio;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.GamerServices;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Input.Touch;
-using Microsoft.Xna.Framework.Media;
-#endregion
-
-namespace Graphics3DSample
-{
-    /// <summary>
-    /// This is the main type for your game
-    /// </summary>
-    public class Graphics3DSampleGame : Microsoft.Xna.Framework.Game
-    {
-
-        #region Fields
-        #region Constants
-        const int buttonHeight = 70;
-        const int buttonWidth = 70;
-        const int buttonMargin = 15;
-        #endregion
-
-        GraphicsDeviceManager graphics;
-
-        Spaceship spaceship;
-
-        Checkbox[] lightEnablingButtons;
-        Checkbox perpixelLightingButton;
-        Checkbox animationButton;
-
-        Checkbox backgroundTextureEnablingButton;
-
-        float cameraFOV = 45; // Initial camera FOV (serves as a zoom level)
-        float rotationXAmount = 0.0f;
-        float rotationYAmount = 0.0f;
-        float? prevLength;
-
-        Texture2D background;
-
-        Animation animation;
-        Vector2 animationPosition;
-
-        #region Public accessors
-        /// <summary>
-        /// Provides SporiteBatch to components that draw sprites
-        /// </summary>
-        public SpriteBatch SpriteBatch { get; private set; }
-        #endregion
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// Initialization that does not depend on GraphicsDevice
-        /// </summary>
-        public Graphics3DSampleGame()
-        {
-            Content.RootDirectory = "Content";
-
-            graphics = new GraphicsDeviceManager(this);
-            graphics.IsFullScreen = true;
-            graphics.SupportedOrientations =
-                DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
-            graphics.ApplyChanges();
-        }
-
-        /// <summary>
-        /// Initialization that depends on GraphicsDevice but does not depend on Content
-        /// </summary>
-        protected override void Initialize()
-        {
-            GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
-
-            SpriteBatch = new SpriteBatch(GraphicsDevice);
-
-            CreateSpaceship();
-            CreateLightEnablingButtons();
-            CreateBackgroundTextureEnablingButton();
-            CreatePerPixelLightingButton();
-            CreateAnimationButton();
-
-            //Initialize gestures support - Pinch for Zoom and horizontal drag for rotate
-            TouchPanel.EnabledGestures = GestureType.FreeDrag | GestureType.Pinch | GestureType.PinchComplete;
-
-            base.Initialize();
-        }
-
-        /// <summary>
-        /// Loads content and creates graphics resources.
-        /// </summary>
-        protected override void LoadContent()
-        {
-            background = Content.Load<Texture2D>("Textures/spaceBG");
-
-            animation = CreateAnimation();
-            spaceship.Load(this.Content);
-            base.LoadContent();
-        }
-
-        /// <summary>
-        /// Creates animation
-        /// </summary>
-        /// <returns></returns>
-        private Animation CreateAnimation()
-        {
-            // Load multiple animations form XML definition
-            System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Load("Content/AnimationDef.xml");
-            System.Xml.Linq.XName name = System.Xml.Linq.XName.Get("Definition");
-            var definitions = doc.Document.Descendants(name);
-
-            // Get the first (and only in this case) animation from the XML definition
-            var definition = definitions.First();
-
-            Texture2D texture = Content.Load<Texture2D>(definition.Attribute("SheetName").Value);
-
-            Point frameSize = new Point();
-            frameSize.X = int.Parse(definition.Attribute("FrameWidth").Value);
-            frameSize.Y = int.Parse(definition.Attribute("FrameHeight").Value);
-
-            Point sheetSize = new Point();
-            sheetSize.X = int.Parse(definition.Attribute("SheetColumns").Value);
-            sheetSize.Y = int.Parse(definition.Attribute("SheetRows").Value);
-
-            TimeSpan frameInterval = TimeSpan.FromSeconds((float)1 / int.Parse(definition.Attribute("Speed").Value));
-
-            //Calculate the animation position (in the middle fot he screen)
-            animationPosition = new Vector2((graphics.PreferredBackBufferWidth / 2 - frameSize.X),
-                                            (graphics.PreferredBackBufferHeight / 2 - frameSize.Y));
-
-            return new Animation(texture, frameSize, sheetSize, frameInterval);
-        }
-
-        /// <summary>
-        /// Creates spaceship
-        /// </summary>
-        private void CreateSpaceship()
-        {
-            spaceship = new Spaceship();
-            spaceship.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(cameraFOV),
-                GraphicsDevice.Viewport.AspectRatio, 10, 20000);
-        }
-
-        /// <summary>
-        /// Creates light enabling buttons
-        /// </summary>
-        private void CreateLightEnablingButtons()
-        {
-            lightEnablingButtons = new Checkbox[3];
-            for (int n = 0; n < lightEnablingButtons.Length; n++)
-            {
-                lightEnablingButtons[n] = new Checkbox(this, "Buttons/lamp_60x60",
-                    new Rectangle(GraphicsDevice.Viewport.Width - (n + 1) * (buttonWidth + buttonMargin),
-                        buttonMargin, buttonWidth, buttonHeight), true);
-                this.Components.Add(lightEnablingButtons[n]);
-            }
-        }
-
-        /// <summary>
-        /// Creates per-pixel lighting button
-        /// </summary>
-        private void CreatePerPixelLightingButton()
-        {
-            perpixelLightingButton = new Checkbox(this, "Buttons/perPixelLight_60x60",
-                new Rectangle(GraphicsDevice.Viewport.Width - (buttonWidth + buttonMargin),
-                    GraphicsDevice.Viewport.Height - (buttonHeight + buttonMargin),
-                    buttonWidth, buttonHeight), false);
-            this.Components.Add(perpixelLightingButton);
-        }
-
-        /// <summary>
-        /// Creates animation button
-        /// </summary>
-        private void CreateAnimationButton()
-        {
-            animationButton = new Checkbox(this, "Buttons/animation_60x60",
-                new Rectangle(buttonMargin,
-                    GraphicsDevice.Viewport.Height - (buttonHeight + buttonMargin),
-                    buttonWidth, buttonHeight), false);
-            this.Components.Add(animationButton);
-        }
-
-        /// <summary>
-        /// Create texture enabling button
-        /// </summary>
-        private void CreateBackgroundTextureEnablingButton()
-        {
-            backgroundTextureEnablingButton = new Checkbox(this, "Buttons/textureOnOff",
-                     new Rectangle(buttonMargin, buttonMargin, buttonWidth, buttonHeight), false);
-            this.Components.Add(backgroundTextureEnablingButton);
-        }
-        #endregion
-
-        #region Update
-        /// <summary>
-        /// Updates spaceship rendering properties
-        /// </summary>
-        protected override void Update(GameTime gameTime)
-        {
-            // Handle touch input first
-            HandleInput();
-
-            // Allows the game to exit
-            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
-                this.Exit();
-
-            spaceship.Rotation = GetRotationMatrix();
-            spaceship.View = GetViewMatrix();
-            spaceship.Lights = lightEnablingButtons.Select(e => e.IsChecked).ToArray();
-            spaceship.IsTextureEnabled = true;
-            spaceship.IsPerPixelLightingEnabled = perpixelLightingButton.IsChecked;
-            spaceship.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(cameraFOV),
-                GraphicsDevice.Viewport.AspectRatio, 10, 20000);
-
-            if (animationButton.IsChecked)
-            {
-                animation.Update(gameTime);
-            }
-
-            base.Update(gameTime);
-        }
-
-        private void HandleInput()
-        {
-            while (TouchPanel.IsGestureAvailable)
-            {
-                GestureSample gestureSample = TouchPanel.ReadGesture();
-                switch (gestureSample.GestureType)
-                {
-                    case GestureType.FreeDrag:
-                        rotationXAmount += gestureSample.Delta.X;
-                        rotationYAmount -= gestureSample.Delta.Y;
-                        break;
-
-                    case GestureType.Pinch:
-                        float gestureValue = 0;
-                        float minFOV = 60;
-                        float maxFOV = 30;
-                        float gestureLengthToZoomScale = 10;
-
-                        Vector2 gestureDiff = gestureSample.Position - gestureSample.Position2;
-                        gestureValue = gestureDiff.Length() / gestureLengthToZoomScale;
-
-                        if (null != prevLength) // Skip the first pinch event
-                            cameraFOV -= gestureValue - prevLength.Value;
-
-                        cameraFOV = MathHelper.Clamp(cameraFOV, maxFOV, minFOV);
-
-                        prevLength = gestureValue;
-                        break;
-
-                    case GestureType.PinchComplete:
-                        prevLength = null;
-                        break;
-                    default:
-                        break;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets spaceship rotation matrix
-        /// </summary>
-        /// <returns></returns>
-        private Matrix GetRotationMatrix()
-        {
-            Matrix matrix = Matrix.CreateWorld(new Vector3(0, 250, 0), Vector3.Forward, Vector3.Up) *
-                Matrix.CreateFromYawPitchRoll((float)Math.PI + MathHelper.PiOver2 + rotationXAmount / 100, rotationYAmount / 100, 0);
-            return matrix;
-        }
-
-        /// <summary>
-        /// Gets spaceship view matrix
-        /// </summary>
-        private Matrix GetViewMatrix()
-        {
-            return Matrix.CreateLookAt(
-                new Vector3(3500, 400, 0) + new Vector3(0, 250, 0),
-                new Vector3(0, 250, 0),
-                Vector3.Up);
-        }
-        #endregion
-
-        #region Draw
-        /// <summary>
-        /// Draws the game
-        /// </summary>
-        protected override void Draw(GameTime gameTime)
-        {
-            GraphicsDevice.Clear(Color.CornflowerBlue);
-
-            if (backgroundTextureEnablingButton.IsChecked)
-            {
-                SpriteBatch.Begin();
-                SpriteBatch.Draw(background, Vector2.Zero, Color.White);
-                SpriteBatch.End();
-            }
-
-            var lights = lightEnablingButtons.Select(e => e.IsChecked).ToArray();
-
-            // Set render states.
-            GraphicsDevice.BlendState = BlendState.Opaque;
-            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
-            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
-            GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
-
-            // This draws game components, including the currently active menu screen.
-            // Draw the spaceship model
-            spaceship.Draw();
-
-            if (animationButton.IsChecked)
-            {
-                DrawAnimation();
-            }
-
-            base.Draw(gameTime);
-        }
-
-        /// <summary>
-        /// Draws animation
-        /// </summary>
-        private void DrawAnimation()
-        {
-            float screenHeight = graphics.PreferredBackBufferHeight;
-            float scale = (float)(graphics.PreferredBackBufferWidth / 480.0);
-
-            SpriteBatch.Begin();
-            animation.Draw(SpriteBatch, animationPosition, 2.0f, SpriteEffects.None);
-            SpriteBatch.End();
-        }
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// DemoGame.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Input.Touch;
+using Microsoft.Xna.Framework.Media;
+
+namespace Graphics3DSample
+{
+    /// <summary>
+    /// This is the main type for your game
+    /// </summary>
+    public class Graphics3DSampleGame : Game
+    {
+
+        const int buttonHeight = 70;
+        const int buttonWidth = 70;
+        const int buttonMargin = 15;
+
+        GraphicsDeviceManager graphics;
+
+        Spaceship spaceship;
+
+        Checkbox[] lightEnablingButtons;
+        Checkbox perpixelLightingButton;
+        Checkbox animationButton;
+
+        Checkbox backgroundTextureEnablingButton;
+
+        float cameraFOV = 45; // Initial camera FOV (serves as a zoom level)
+        float rotationXAmount = 0.0f;
+        float rotationYAmount = 0.0f;
+        float? prevLength;
+
+        Texture2D background;
+
+        Animation animation;
+        Vector2 animationPosition;
+
+        // Mouse input tracking
+        private MouseState prevMouseState;
+        private float? prevMouseDragLength = null;
+        /// <summary>
+        /// Applies zoom delta to cameraFOV and clamps the value
+        /// </summary>
+        private void ApplyZoomDelta(float delta)
+        {
+            cameraFOV -= delta;
+            cameraFOV = MathHelper.Clamp(cameraFOV, maxFOV, minFOV);
+        }
+
+        /// <summary>
+        /// Resets gesture/mouse drag state for zoom
+        /// </summary>
+        private void ResetZoomGestureState()
+        {
+            prevLength = null;
+            prevMouseDragLength = null;
+        }
+        /// <summary>
+        /// Applies rotation deltas to the camera
+        /// </summary>
+        private void ApplyRotationDelta(float deltaX, float deltaY)
+        {
+            rotationXAmount += deltaX;
+            rotationYAmount -= deltaY;
+        }
+        /// <summary>
+        /// Toggles checkboxes at a given screen position
+        /// </summary>
+        private void ToggleCheckboxesAt(Point pos)
+        {
+            foreach (var checkbox in lightEnablingButtons)
+            {
+                if (checkbox.Bounds.Contains(pos))
+                    checkbox.IsChecked = !checkbox.IsChecked;
+            }
+            if (perpixelLightingButton.Bounds.Contains(pos))
+                perpixelLightingButton.IsChecked = !perpixelLightingButton.IsChecked;
+            if (animationButton.Bounds.Contains(pos))
+                animationButton.IsChecked = !animationButton.IsChecked;
+            if (backgroundTextureEnablingButton.Bounds.Contains(pos))
+                backgroundTextureEnablingButton.IsChecked = !backgroundTextureEnablingButton.IsChecked;
+        }
+
+        /// <summary>
+        /// Provides SporiteBatch to components that draw sprites
+        /// </summary>
+        public SpriteBatch SpriteBatch { get; private set; }
+
+        const float minFOV = 60;
+        const float maxFOV = 30;
+
+        /// <summary>
+        /// Initialization that does not depend on GraphicsDevice
+        /// </summary>
+        public Graphics3DSampleGame()
+        {
+            Content.RootDirectory = "Content";
+
+            graphics = new GraphicsDeviceManager(this);
+            graphics.IsFullScreen = false;
+            graphics.SupportedOrientations =
+                DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
+            graphics.ApplyChanges();
+
+            IsMouseVisible = true;
+        }
+
+        /// <summary>
+        /// Initialization that depends on GraphicsDevice but does not depend on Content
+        /// </summary>
+        protected override void Initialize()
+        {
+            GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
+
+            SpriteBatch = new SpriteBatch(GraphicsDevice);
+
+            CreateSpaceship();
+            CreateLightEnablingButtons();
+            CreateBackgroundTextureEnablingButton();
+            CreatePerPixelLightingButton();
+            CreateAnimationButton();
+
+            //Initialize gestures support - Pinch for Zoom and horizontal drag for rotate
+            TouchPanel.EnabledGestures = GestureType.FreeDrag | GestureType.Pinch | GestureType.PinchComplete;
+
+            base.Initialize();
+        }
+
+        /// <summary>
+        /// Loads content and creates graphics resources.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            background = Content.Load<Texture2D>("Textures/spaceBG");
+
+            animation = CreateAnimation();
+            spaceship.Load(this.Content);
+            base.LoadContent();
+        }
+
+        /// <summary>
+        /// Creates animation
+        /// </summary>
+        /// <returns></returns>
+        private Animation CreateAnimation()
+        {
+            XDocument doc = null;
+
+            using (var stream = TitleContainer.OpenStream("Content/AnimationDef.xml"))
+            {
+                doc = XDocument.Load(stream);
+            }
+
+            // Load multiple animations form XML definition
+            XName name = XName.Get("Definition");
+            var definitions = doc.Document.Descendants(name);
+
+            // Get the first (and only in this case) animation from the XML definition
+            var definition = definitions.First();
+
+            Texture2D texture = Content.Load<Texture2D>(definition.Attribute("SheetName").Value);
+
+            Point frameSize = new Point();
+            frameSize.X = int.Parse(definition.Attribute("FrameWidth").Value);
+            frameSize.Y = int.Parse(definition.Attribute("FrameHeight").Value);
+
+            Point sheetSize = new Point();
+            sheetSize.X = int.Parse(definition.Attribute("SheetColumns").Value);
+            sheetSize.Y = int.Parse(definition.Attribute("SheetRows").Value);
+
+            TimeSpan frameInterval = TimeSpan.FromSeconds((float)1 / int.Parse(definition.Attribute("Speed").Value));
+
+            //Calculate the animation position (in the middle fot he screen)
+            animationPosition = new Vector2((graphics.PreferredBackBufferWidth / 2 - frameSize.X),
+                                            (graphics.PreferredBackBufferHeight / 2 - frameSize.Y));
+
+            return new Animation(texture, frameSize, sheetSize, frameInterval);
+        }
+
+        /// <summary>
+        /// Creates spaceship
+        /// </summary>
+        private void CreateSpaceship()
+        {
+            spaceship = new Spaceship();
+            spaceship.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(cameraFOV),
+                GraphicsDevice.Viewport.AspectRatio, 10, 20000);
+        }
+
+        /// <summary>
+        /// Creates light enabling buttons
+        /// </summary>
+        private void CreateLightEnablingButtons()
+        {
+            lightEnablingButtons = new Checkbox[3];
+            for (int n = 0; n < lightEnablingButtons.Length; n++)
+            {
+                lightEnablingButtons[n] = new Checkbox(this, "Buttons/lamp_60x60",
+                    new Rectangle(GraphicsDevice.Viewport.Width - (n + 1) * (buttonWidth + buttonMargin),
+                        buttonMargin, buttonWidth, buttonHeight), true);
+                this.Components.Add(lightEnablingButtons[n]);
+            }
+        }
+
+        /// <summary>
+        /// Creates per-pixel lighting button
+        /// </summary>
+        private void CreatePerPixelLightingButton()
+        {
+            perpixelLightingButton = new Checkbox(this, "Buttons/perPixelLight_60x60",
+                new Rectangle(GraphicsDevice.Viewport.Width - (buttonWidth + buttonMargin),
+                    GraphicsDevice.Viewport.Height - (buttonHeight + buttonMargin),
+                    buttonWidth, buttonHeight), false);
+            this.Components.Add(perpixelLightingButton);
+        }
+
+        /// <summary>
+        /// Creates animation button
+        /// </summary>
+        private void CreateAnimationButton()
+        {
+            animationButton = new Checkbox(this, "Buttons/animation_60x60",
+                new Rectangle(buttonMargin,
+                    GraphicsDevice.Viewport.Height - (buttonHeight + buttonMargin),
+                    buttonWidth, buttonHeight), false);
+            this.Components.Add(animationButton);
+        }
+
+        /// <summary>
+        /// Create texture enabling button
+        /// </summary>
+        private void CreateBackgroundTextureEnablingButton()
+        {
+            backgroundTextureEnablingButton = new Checkbox(this, "Buttons/textureOnOff",
+                     new Rectangle(buttonMargin, buttonMargin, buttonWidth, buttonHeight), false);
+            this.Components.Add(backgroundTextureEnablingButton);
+        }
+
+        /// <summary>
+        /// Updates spaceship rendering properties
+        /// </summary>
+        protected override void Update(GameTime gameTime)
+        {
+            // Handle touch/mouse input first
+            HandleInput();
+
+            // Handle keyboard input
+            KeyboardState keyboardState = Keyboard.GetState();
+
+            // Allows the game to exit
+            if (keyboardState.IsKeyDown(Keys.Escape)
+            || GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
+                this.Exit();
+
+            spaceship.Rotation = GetRotationMatrix();
+            spaceship.View = GetViewMatrix();
+            spaceship.Lights = lightEnablingButtons.Select(e => e.IsChecked).ToArray();
+            spaceship.IsTextureEnabled = true;
+            spaceship.IsPerPixelLightingEnabled = perpixelLightingButton.IsChecked;
+            spaceship.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(cameraFOV),
+                GraphicsDevice.Viewport.AspectRatio, 10, 20000);
+
+            if (animationButton.IsChecked)
+            {
+                animation.Update(gameTime);
+            }
+
+            base.Update(gameTime);
+        }
+
+        private void HandleInput()
+        {
+            // Touch input
+            while (TouchPanel.IsGestureAvailable)
+            {
+                GestureSample gestureSample = TouchPanel.ReadGesture();
+                switch (gestureSample.GestureType)
+                {
+                    case GestureType.FreeDrag:
+                        ApplyRotationDelta(gestureSample.Delta.X, gestureSample.Delta.Y);
+                        break;
+
+                    case GestureType.Pinch:
+                        float gestureValue = 0;
+                        float gestureLengthToZoomScale = 10;
+
+                        Vector2 gestureDiff = gestureSample.Position - gestureSample.Position2;
+                        gestureValue = gestureDiff.Length() / gestureLengthToZoomScale;
+
+                        if (prevLength != null) // Skip the first pinch event
+                            ApplyZoomDelta(gestureValue - prevLength.Value);
+
+                        prevLength = gestureValue;
+                        break;
+
+                    case GestureType.Tap:
+                        Point tapPos = new Point((int)gestureSample.Position.X, (int)gestureSample.Position.Y);
+                        ToggleCheckboxesAt(tapPos);
+                        break;
+
+                    case GestureType.PinchComplete:
+                        ResetZoomGestureState();
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+            // Mouse input parity
+            MouseState mouseState = Mouse.GetState();
+
+            // Mouse click for UI elements
+            if (prevMouseState.LeftButton == ButtonState.Released && mouseState.LeftButton == ButtonState.Pressed)
+            {
+                Point mousePos = new Point(mouseState.X, mouseState.Y);
+                ToggleCheckboxesAt(mousePos);
+            }
+
+            // Mouse drag for rotation (left button)
+            if (mouseState.LeftButton == ButtonState.Pressed && prevMouseState.LeftButton == ButtonState.Pressed)
+            {
+                int deltaX = mouseState.X - prevMouseState.X;
+                int deltaY = mouseState.Y - prevMouseState.Y;
+                ApplyRotationDelta(deltaX, deltaY);
+            }
+
+            // Mouse wheel for zoom (FOV)
+            if (mouseState.ScrollWheelValue != prevMouseState.ScrollWheelValue)
+            {
+                float wheelDelta = mouseState.ScrollWheelValue - prevMouseState.ScrollWheelValue;
+                float zoomScale = 0.05f; // Adjust sensitivity as needed
+                ApplyZoomDelta(wheelDelta * zoomScale);
+            }
+
+            // Mouse drag with right button for pinch-like zoom (optional)
+            if (mouseState.RightButton == ButtonState.Pressed && prevMouseState.RightButton == ButtonState.Pressed)
+            {
+                float gestureLengthToZoomScale = 10f;
+                float gestureValue = Vector2.Distance(new Vector2(mouseState.X, mouseState.Y), new Vector2(prevMouseState.X, prevMouseState.Y)) / gestureLengthToZoomScale;
+                if (prevMouseDragLength != null)
+                    ApplyZoomDelta(gestureValue - prevMouseDragLength.Value);
+                prevMouseDragLength = gestureValue;
+            }
+            else if (mouseState.RightButton == ButtonState.Released)
+            {
+                ResetZoomGestureState();
+            }
+
+            prevMouseState = mouseState;
+        }
+
+        /// <summary>
+        /// Gets spaceship rotation matrix
+        /// </summary>
+        /// <returns></returns>
+        private Matrix GetRotationMatrix()
+        {
+            Matrix matrix = Matrix.CreateWorld(new Vector3(0, 250, 0), Vector3.Forward, Vector3.Up) *
+                Matrix.CreateFromYawPitchRoll((float)Math.PI + MathHelper.PiOver2 + rotationXAmount / 100, rotationYAmount / 100, 0);
+            return matrix;
+        }
+
+        /// <summary>
+        /// Gets spaceship view matrix
+        /// </summary>
+        private Matrix GetViewMatrix()
+        {
+            return Matrix.CreateLookAt(
+                new Vector3(3500, 400, 0) + new Vector3(0, 250, 0),
+                new Vector3(0, 250, 0),
+                Vector3.Up);
+        }
+
+        /// <summary>
+        /// Draws the game
+        /// </summary>
+        protected override void Draw(GameTime gameTime)
+        {
+            GraphicsDevice.Clear(Color.CornflowerBlue);
+
+            if (backgroundTextureEnablingButton.IsChecked)
+            {
+                SpriteBatch.Begin();
+                SpriteBatch.Draw(background, Vector2.Zero, Color.White);
+                SpriteBatch.End();
+            }
+
+            var lights = lightEnablingButtons.Select(e => e.IsChecked).ToArray();
+
+            // Set render states.
+            GraphicsDevice.BlendState = BlendState.Opaque;
+            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
+            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
+            GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
+
+            // This draws game components, including the currently active menu screen.
+            // Draw the spaceship model
+            spaceship.Draw();
+
+            if (animationButton.IsChecked)
+            {
+                DrawAnimation();
+            }
+
+            base.Draw(gameTime);
+        }
+
+        /// <summary>
+        /// Draws animation
+        /// </summary>
+        private void DrawAnimation()
+        {
+            float screenHeight = graphics.PreferredBackBufferHeight;
+            float scale = (float)(graphics.PreferredBackBufferWidth / 480.0);
+
+            SpriteBatch.Begin();
+            animation.Draw(SpriteBatch, animationPosition, 2.0f, SpriteEffects.None);
+            SpriteBatch.End();
+        }
+    }
+}

+ 8 - 0
Graphics3DSample/Core/Graphics3DSample.Core.csproj

@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+  </ItemGroup>
+</Project>

+ 176 - 188
Graphics3DSample/Models/Spaceship.cs → Graphics3DSample/Core/Models/Spaceship.cs

@@ -1,188 +1,176 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// Spaceship.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-using Graphics3DSample;
-using System;
-#endregion
-
-namespace Graphics3DSample
-{
-    /// <summary>
-    /// Helper class for drawing a spaceship model with animated wheels and turret.
-    /// </summary>
-    public class Spaceship
-    {
-        #region Fields
-        // The XNA framework Model object that we are going to display.
-        Model spaceshipModel;
-
-        // Array holding all the bone transform matrices for the entire model.
-        // We could just allocate this locally inside the Draw method, but it
-        // is more efficient to reuse a single array, as this avoids creating
-        // unnecessary garbage.
-        Matrix[] boneTransforms;
-
-        // Spaceship drawing parameters
-        private Matrix projection;
-        private Matrix rotation;
-        private Matrix view;
-        private bool[] lights;
-        bool isTextureEnabled;
-        bool isPerPixelLightingEnabled;
-        #endregion
-
-        #region Initialization
-        /// <summary>
-        /// Loads the spaceship model.
-        /// </summary>
-        public void Load(ContentManager content)
-        {
-            // Load the spaceship model from the ContentManager.
-            spaceshipModel = content.Load<Model>("Models/spaceship");
-
-            // Allocate the transform matrix array.
-            boneTransforms = new Matrix[spaceshipModel.Bones.Count];
-        }
-        #endregion
-
-        #region Public accessors
-        /// <summary>
-        /// Gets or sets the projection matrix value.
-        /// </summary>
-        public Matrix Projection
-        {
-            get { return projection; }
-            set { projection = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets the rotation matrix value.
-        /// </summary>
-        public Matrix Rotation
-        {
-            get { return rotation; }
-            set { rotation = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets the rotation matrix value.
-        /// </summary>
-        public bool IsTextureEnabled
-        {
-            get { return isTextureEnabled; }
-            set { isTextureEnabled = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets the view matrix value.
-        /// </summary>
-        public Matrix View
-        {
-            get { return view; }
-            set { view = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets the lights states.
-        /// </summary>
-        public bool[] Lights
-        {
-            get { return lights; }
-            set { lights = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets the per pixel lighting preferences
-        /// </summary>
-        public bool IsPerPixelLightingEnabled
-        {
-            get { return isPerPixelLightingEnabled; }
-            set { isPerPixelLightingEnabled = value; }
-        }
-        #endregion
-
-        #region Draw
-        /// <summary>
-        /// Draws the spaceship model, using the current drawing parameters.
-        /// </summary>
-        public void Draw()
-        {
-            // Set the world matrix as the root transform of the model.
-            spaceshipModel.Root.Transform = Rotation;
-
-            // Look up combined bone matrices for the entire model.
-            spaceshipModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
-
-            // Draw the model.
-            foreach (ModelMesh mesh in spaceshipModel.Meshes)
-            {
-                foreach (BasicEffect effect in mesh.Effects)
-                {
-                    effect.World = boneTransforms[mesh.ParentBone.Index];
-                    effect.View = View;
-                    effect.Projection = Projection;
-
-                    SetEffectLights(effect, Lights);
-                    SetEffectPerPixelLightingEnabled(effect);
-
-                    effect.TextureEnabled = IsTextureEnabled;
-                }
-
-                mesh.Draw();
-            }
-        }
-
-        /// <summary>
-        /// Sets effect's per pixel lighting preference
-        /// </summary>
-        /// <param name="effect"></param>
-        private void SetEffectPerPixelLightingEnabled(BasicEffect effect)
-        {
-            effect.PreferPerPixelLighting = isPerPixelLightingEnabled;
-        }
-
-        /// <summary>
-        /// Sets effects lighting properties
-        /// </summary>
-        /// <param name="effect"></param>
-        /// <param name="lights"></param>
-        private void SetEffectLights(BasicEffect effect, bool[] lights)
-        {
-
-            effect.Alpha = 1.0f;
-            effect.DiffuseColor = new Vector3(0.75f, 0.75f, 0.75f);
-            effect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
-            effect.SpecularPower = 5.0f;
-            effect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);
-
-            effect.DirectionalLight0.Enabled = lights[0];
-            effect.DirectionalLight0.DiffuseColor = Vector3.One;
-            effect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(1, -1, 0));
-            effect.DirectionalLight0.SpecularColor = Vector3.One;
-
-            effect.DirectionalLight1.Enabled = lights[1];
-            effect.DirectionalLight1.DiffuseColor = new Vector3(0.5f, 0.5f, 0.5f);
-            effect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(-1, -1, 0));
-            effect.DirectionalLight1.SpecularColor = new Vector3(1f, 1f, 1f);
-
-            effect.DirectionalLight2.Enabled = lights[2];
-            effect.DirectionalLight2.DiffuseColor = new Vector3(0.3f, 0.3f, 0.3f);
-            effect.DirectionalLight2.Direction = Vector3.Normalize(new Vector3(-1, -1, -1));
-            effect.DirectionalLight2.SpecularColor = new Vector3(0.3f, 0.3f, 0.3f);
-
-            effect.LightingEnabled = true;
-        }
-        #endregion
-
-    }
-}
+//-----------------------------------------------------------------------------
+// Spaceship.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Graphics3DSample;
+using System;
+
+namespace Graphics3DSample
+{
+    /// <summary>
+    /// Helper class for drawing a spaceship model with animated wheels and turret.
+    /// </summary>
+    public class Spaceship
+    {
+        // The XNA framework Model object that we are going to display.
+        Model spaceshipModel;
+
+        // Array holding all the bone transform matrices for the entire model.
+        // We could just allocate this locally inside the Draw method, but it
+        // is more efficient to reuse a single array, as this avoids creating
+        // unnecessary garbage.
+        Matrix[] boneTransforms;
+
+        // Spaceship drawing parameters
+        private Matrix projection;
+        private Matrix rotation;
+        private Matrix view;
+        private bool[] lights;
+        bool isTextureEnabled;
+        bool isPerPixelLightingEnabled;
+
+        /// <summary>
+        /// Loads the spaceship model.
+        /// </summary>
+        public void Load(ContentManager content)
+        {
+            // Load the spaceship model from the ContentManager.
+            spaceshipModel = content.Load<Model>("Models/spaceship");
+
+            // Allocate the transform matrix array.
+            boneTransforms = new Matrix[spaceshipModel.Bones.Count];
+        }
+
+        /// <summary>
+        /// Gets or sets the projection matrix value.
+        /// </summary>
+        public Matrix Projection
+        {
+            get { return projection; }
+            set { projection = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the rotation matrix value.
+        /// </summary>
+        public Matrix Rotation
+        {
+            get { return rotation; }
+            set { rotation = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the rotation matrix value.
+        /// </summary>
+        public bool IsTextureEnabled
+        {
+            get { return isTextureEnabled; }
+            set { isTextureEnabled = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the view matrix value.
+        /// </summary>
+        public Matrix View
+        {
+            get { return view; }
+            set { view = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the lights states.
+        /// </summary>
+        public bool[] Lights
+        {
+            get { return lights; }
+            set { lights = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the per pixel lighting preferences
+        /// </summary>
+        public bool IsPerPixelLightingEnabled
+        {
+            get { return isPerPixelLightingEnabled; }
+            set { isPerPixelLightingEnabled = value; }
+        }
+
+        /// <summary>
+        /// Draws the spaceship model, using the current drawing parameters.
+        /// </summary>
+        public void Draw()
+        {
+            // Set the world matrix as the root transform of the model.
+            spaceshipModel.Root.Transform = Rotation;
+
+            // Look up combined bone matrices for the entire model.
+            spaceshipModel.CopyAbsoluteBoneTransformsTo(boneTransforms);
+
+            // Draw the model.
+            foreach (ModelMesh mesh in spaceshipModel.Meshes)
+            {
+                foreach (BasicEffect effect in mesh.Effects)
+                {
+                    effect.World = boneTransforms[mesh.ParentBone.Index];
+                    effect.View = View;
+                    effect.Projection = Projection;
+
+                    SetEffectLights(effect, Lights);
+                    SetEffectPerPixelLightingEnabled(effect);
+
+                    effect.TextureEnabled = IsTextureEnabled;
+                }
+
+                mesh.Draw();
+            }
+        }
+
+        /// <summary>
+        /// Sets effect's per pixel lighting preference
+        /// </summary>
+        /// <param name="effect"></param>
+        private void SetEffectPerPixelLightingEnabled(BasicEffect effect)
+        {
+            effect.PreferPerPixelLighting = isPerPixelLightingEnabled;
+        }
+
+        /// <summary>
+        /// Sets effects lighting properties
+        /// </summary>
+        /// <param name="effect"></param>
+        /// <param name="lights"></param>
+        private void SetEffectLights(BasicEffect effect, bool[] lights)
+        {
+
+            effect.Alpha = 1.0f;
+            effect.DiffuseColor = new Vector3(0.75f, 0.75f, 0.75f);
+            effect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
+            effect.SpecularPower = 5.0f;
+            effect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);
+
+            effect.DirectionalLight0.Enabled = lights[0];
+            effect.DirectionalLight0.DiffuseColor = Vector3.One;
+            effect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(1, -1, 0));
+            effect.DirectionalLight0.SpecularColor = Vector3.One;
+
+            effect.DirectionalLight1.Enabled = lights[1];
+            effect.DirectionalLight1.DiffuseColor = new Vector3(0.5f, 0.5f, 0.5f);
+            effect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(-1, -1, 0));
+            effect.DirectionalLight1.SpecularColor = new Vector3(1f, 1f, 1f);
+
+            effect.DirectionalLight2.Enabled = lights[2];
+            effect.DirectionalLight2.DiffuseColor = new Vector3(0.3f, 0.3f, 0.3f);
+            effect.DirectionalLight2.Direction = Vector3.Normalize(new Vector3(-1, -1, -1));
+            effect.DirectionalLight2.SpecularColor = new Vector3(0.3f, 0.3f, 0.3f);
+
+            effect.LightingEnabled = true;
+        }
+
+    }
+}

+ 0 - 110
Graphics3DSample/Graphics3DSample.MacOS.csproj

@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{C3D02EFA-1C48-415C-8811-56D20434FD68}</ProjectGuid>
-    <ProjectTypeGuids>{948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Graphics3DSample</RootNamespace>
-    <AssemblyName>Graphics3DSample</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <CodeSigningKey>Mac Developer</CodeSigningKey>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <LinkMode>Full</LinkMode>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <CodeSigningKey>Mac Developer</CodeSigningKey>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\AppStore</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PackageSigningKey>3rd Party Mac Developer Installer</PackageSigningKey>
-    <IncludeMonoRuntime>True</IncludeMonoRuntime>
-    <LinkMode>Full</LinkMode>
-    <EnablePackageSigning>True</EnablePackageSigning>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>True</EnableCodeSigning>
-    <CreatePackage>True</CreatePackage>
-    <CodeSigningKey>3rd Party Mac Developer Application</CodeSigningKey>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="MonoMac" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Main.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="GameMain.cs" />
-    <Compile Include="Animation\Animation.cs" />
-    <Compile Include="Buttons\Button.cs" />
-    <Compile Include="Buttons\Checkbox.cs" />
-    <Compile Include="Buttons\Clickable.cs" />
-    <Compile Include="Models\Spaceship.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Info.plist" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
-  <ItemGroup>
-    <Folder Include="Content\" />
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\Buttons\animation_60x60.xnb" />
-    <Content Include="Content\Buttons\arrow1_left_60x60.xnb" />
-    <Content Include="Content\Buttons\arrow1_right_60x60.xnb" />
-    <Content Include="Content\Buttons\lamp_60x60.xnb" />
-    <Content Include="Content\Buttons\perPixelLight_60x60.xnb" />
-    <Content Include="Content\Buttons\textureOnOff.xnb" />
-    <Content Include="Content\Models\enemy_0.xnb" />
-    <Content Include="Content\Models\spaceship.xnb" />
-    <Content Include="Content\Textures\explosionStrip.xnb" />
-    <Content Include="Content\Textures\spaceBG.xnb" />
-    <Content Include="Content\AnimationDef.xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\ThirdParty\Lidgren.Network\Lidgren.Network.MacOS.csproj">
-      <Project>{AE483C29-042E-4226-BA52-D247CE7676DA}</Project>
-      <Name>Lidgren.Network.MacOS</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.MacOS.csproj">
-      <Project>{36C538E6-C32A-4A8D-A39C-566173D7118E}</Project>
-      <Name>MonoGame.Framework.MacOS</Name>
-    </ProjectReference>
-  </ItemGroup>
-</Project>

+ 48 - 0
Graphics3DSample/Graphics3DSample.sln

@@ -0,0 +1,48 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics3DSample.Core", "Core\Graphics3DSample.Core.csproj", "{E3D02EFA-1C48-415C-8811-56D20434FD72}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics3DSample.Windows", "Platforms\Windows\Graphics3DSample.Windows.csproj", "{C3D02EFA-1C48-415C-8811-56D20434FD68}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics3DSample.DesktopGL", "Platforms\Desktop\Graphics3DSample.DesktopGL.csproj", "{B3D02EFA-1C48-415C-8811-56D20434FD69}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics3DSample.Android", "Platforms\Android\Graphics3DSample.Android.csproj", "{A3D02EFA-1C48-415C-8811-56D20434FD70}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics3DSample.iOS", "Platforms\iOS\Graphics3DSample.iOS.csproj", "{D3D02EFA-1C48-415C-8811-56D20434FD71}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E3D02EFA-1C48-415C-8811-56D20434FD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E3D02EFA-1C48-415C-8811-56D20434FD72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E3D02EFA-1C48-415C-8811-56D20434FD72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E3D02EFA-1C48-415C-8811-56D20434FD72}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C3D02EFA-1C48-415C-8811-56D20434FD68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C3D02EFA-1C48-415C-8811-56D20434FD68}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C3D02EFA-1C48-415C-8811-56D20434FD68}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C3D02EFA-1C48-415C-8811-56D20434FD68}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B3D02EFA-1C48-415C-8811-56D20434FD69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B3D02EFA-1C48-415C-8811-56D20434FD69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B3D02EFA-1C48-415C-8811-56D20434FD69}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B3D02EFA-1C48-415C-8811-56D20434FD69}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A3D02EFA-1C48-415C-8811-56D20434FD70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A3D02EFA-1C48-415C-8811-56D20434FD70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A3D02EFA-1C48-415C-8811-56D20434FD70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A3D02EFA-1C48-415C-8811-56D20434FD70}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D3D02EFA-1C48-415C-8811-56D20434FD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D3D02EFA-1C48-415C-8811-56D20434FD71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D3D02EFA-1C48-415C-8811-56D20434FD71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D3D02EFA-1C48-415C-8811-56D20434FD71}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {6F43ACD7-6037-4C12-8FF3-CB49B6E02E0C}
+	EndGlobalSection
+EndGlobal

+ 0 - 16
Graphics3DSample/Info.plist

@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleIdentifier</key>
-	<string>com.yourcompany.Graphics3DSample</string>
-	<key>CFBundleName</key>
-	<string>Graphics3DSample</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSMinimumSystemVersion</key>
-	<string>10.6</string>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
-</dict>
-</plist>

+ 0 - 45
Graphics3DSample/Main.cs

@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-using MonoMac.AppKit;
-using MonoMac.Foundation;
-
-namespace Graphics3DSample
-{
-	static class Program
-	{
-		/// <summary>
-		/// The main entry point for the application.
-		/// </summary>
-		static void Main (string[] args)
-		{
-			NSApplication.Init ();
-			
-			using (var p = new NSAutoreleasePool ()) {
-				NSApplication.SharedApplication.Delegate = new AppDelegate ();
-				NSApplication.Main (args);
-			}
-
-
-		}
-	}
-
-	class AppDelegate : NSApplicationDelegate
-	{
-		Graphics3DSampleGame game;
-
-		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
-		{
-			game = new Graphics3DSampleGame ();
-			game.Run ();
-		}
-		
-		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
-		{
-			return true;
-		}
-	}  
-}
-
-

+ 33 - 0
Graphics3DSample/Platforms/Android/AndroidManifest.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
+          package="com.companyname.graphics3dsample" 
+          android:versionCode="1" 
+          android:versionName="1.0">
+  
+  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
+  
+  <uses-permission android:name="android.permission.INTERNET" />
+  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+  
+  <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+  
+  <application android:allowBackup="true" 
+               android:icon="@mipmap/ic_launcher" 
+               android:label="Graphics3DSample"
+               android:theme="@style/Theme.Splash">
+    
+    <activity android:name="Microsoft.Xna.Framework.AndroidGameActivity"
+              android:label="Graphics3DSample"
+              android:launchMode="singleInstance"
+              android:screenOrientation="fullUser"
+              android:configChanges="orientation|keyboardHidden|keyboard"
+              android:exported="true">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+    
+  </application>
+  
+</manifest>

+ 34 - 0
Graphics3DSample/Platforms/Android/Graphics3DSample.Android.csproj

@@ -0,0 +1,34 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0-android</TargetFramework>
+    <OutputType>Exe</OutputType>
+    <ApplicationId>com.companyname.graphics3dsample</ApplicationId>
+    <ApplicationVersion>1</ApplicationVersion>
+    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <UseShortFileNames>True</UseShortFileNames>
+    <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
+    <AssemblyTitle>Graphics3DSample</AssemblyTitle>
+    <Product>Graphics3DSample</Product>
+    <AndroidManifest>Platforms\Android\AndroidManifest.xml</AndroidManifest>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.Android" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\Graphics3DSample.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\Core\Content\**\*.xml" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 32 - 0
Graphics3DSample/Platforms/Android/MainActivity.cs

@@ -0,0 +1,32 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Android.Views;
+using Microsoft.Xna.Framework;
+
+namespace Graphics3DSample
+{
+    [Activity(
+        Label = "Graphics3DSample",
+        MainLauncher = true,
+        Icon = "@drawable/icon",
+        AlwaysRetainTaskState = true,
+        LaunchMode = LaunchMode.SingleInstance,
+        ScreenOrientation = ScreenOrientation.UserLandscape,
+        ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
+    )]
+    public class MainActivity : AndroidGameActivity
+    {
+        private Graphics3DSampleGame _game;
+
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+
+            _game = new Graphics3DSampleGame();
+            SetContentView((View)_game.Services.GetService(typeof(View)));
+
+            _game.Run();
+        }
+    }
+}

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/drawable/icon.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF6200EE" />
+    <corners android:radius="8dp" />
+</shape>

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/mipmap-hdpi/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF3700B3" />
+    <corners android:radius="12dp" />
+</shape>

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/mipmap-mdpi/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF3700B3" />
+    <corners android:radius="12dp" />
+</shape>

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/mipmap-xhdpi/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF3700B3" />
+    <corners android:radius="12dp" />
+</shape>

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/mipmap-xxhdpi/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF3700B3" />
+    <corners android:radius="12dp" />
+</shape>

+ 5 - 0
Graphics3DSample/Platforms/Android/Resources/mipmap-xxxhdpi/ic_launcher.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#FF3700B3" />
+    <corners android:radius="12dp" />
+</shape>

+ 8 - 0
Graphics3DSample/Platforms/Android/Resources/values/styles.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="Theme.Splash" parent="android:Theme">
+        <item name="android:windowBackground">@drawable/icon</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+    </style>
+</resources>

+ 29 - 0
Graphics3DSample/Platforms/Desktop/Graphics3DSample.DesktopGL.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <AssemblyTitle>Graphics3DSample</AssemblyTitle>
+    <Product>Graphics3DSample</Product>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\Graphics3DSample.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\Core\Content\**\*.xml" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 12 - 0
Graphics3DSample/Platforms/Desktop/Program.cs

@@ -0,0 +1,12 @@
+// DesktopGL entry point
+namespace Graphics3DSample.DesktopGL
+{
+    public static class Program
+    {
+        public static void Main()
+        {
+            using (var game = new Graphics3DSampleGame())
+                game.Run();
+        }
+    }
+}

+ 32 - 0
Graphics3DSample/Platforms/Windows/Graphics3DSample.Windows.csproj

@@ -0,0 +1,32 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <UseWindowsForms>true</UseWindowsForms>
+    <ApplicationIcon />
+    <StartupObject />
+    <AssemblyTitle>Graphics3DSample</AssemblyTitle>
+    <Product>Graphics3DSample</Product>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\Graphics3DSample.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\Core\Content\**\*.xml" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 12 - 0
Graphics3DSample/Platforms/Windows/Program.cs

@@ -0,0 +1,12 @@
+// Windows entry point
+namespace Graphics3DSample.Windows
+{
+    public static class Program
+    {
+        public static void Main()
+        {
+            using (var game = new Graphics3DSampleGame())
+                game.Run();
+        }
+    }
+}

+ 33 - 0
Graphics3DSample/Platforms/iOS/Graphics3DSample.iOS.csproj

@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0-ios</TargetFramework>
+    <OutputType>Exe</OutputType>
+    <ApplicationId>com.companyname.graphics3dsample</ApplicationId>
+    <ApplicationVersion>1</ApplicationVersion>
+    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
+    <SupportedOSPlatformVersion>11.0</SupportedOSPlatformVersion>
+    <AssemblyTitle>Graphics3DSample</AssemblyTitle>
+    <Product>Graphics3DSample</Product>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.iOS" Version="3.8.*" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.*" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\Graphics3DSample.Core.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\Core\Content\**\*.xml" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+
+</Project>

+ 40 - 0
Graphics3DSample/Platforms/iOS/Info.plist

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIdentifier</key>
+	<string>com.companyname.graphics3dsample</string>
+	<key>CFBundleName</key>
+	<string>Graphics3DSample</string>
+	<key>CFBundleDisplayName</key>
+	<string>Graphics3DSample</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>MinimumOSVersion</key>
+	<string>11.0</string>
+	<key>UIDeviceFamily</key>
+	<array>
+		<integer>1</integer>
+		<integer>2</integer>
+	</array>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+	</array>
+	<key>UIStatusBarHidden</key>
+	<true/>
+</dict>
+</plist>

+ 30 - 0
Graphics3DSample/Platforms/iOS/Program.cs

@@ -0,0 +1,30 @@
+using Foundation;
+using UIKit;
+
+namespace Graphics3DSample
+{
+    [Register("AppDelegate")]
+    public class Program : UIApplicationDelegate
+    {
+        private static Graphics3DSampleGame game;
+
+        internal static void RunGame()
+        {
+            game = new Graphics3DSampleGame();
+            game.Run();
+        }
+
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        static void Main(string[] args)
+        {
+            UIApplication.Main(args, null, typeof(Program));
+        }
+
+        public override void FinishedLaunching(UIApplication app)
+        {
+            RunGame();
+        }
+    }
+}

+ 0 - 23
Graphics3DSample/Properties/AssemblyInfo.cs

@@ -1,23 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Graphics 3D Sample")]
-[assembly: AssemblyProduct("Graphics3DSample")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyCompany("Microsoft")]
-[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-[assembly: AssemblyVersion("1.0.0.0")]

+ 104 - 0
Graphics3DSample/README.md

@@ -0,0 +1,104 @@
+# Graphics3DSample
+
+Graphics3DSample is a cross-platform 3D graphics demo built with MonoGame, showcasing animated models, lighting, textures, and interactive UI elements. The project is based on the Microsoft XNA Community Game Platform and demonstrates modern game development techniques using MonoGame.
+
+## Features
+- 3D spaceship model rendering
+- Animation system driven by XML definitions
+- Per-pixel lighting and multiple light sources
+- Interactive UI buttons (checkboxes) for toggling features
+- Touch and gesture support (pinch to zoom, drag to rotate)
+- Mouse support for camera rotation, zoom, and UI interaction
+- Background textures and effects
+
+## Controls
+
+### Mouse (Desktop)
+- **Left Mouse Drag:** Rotate camera (spaceship view)
+- **Mouse Wheel:** Zoom in/out (change camera FOV)
+- **Right Mouse Drag:** Pinch-like zoom (alternative to wheel)
+- **Click UI Buttons:** Toggle lighting, animation, and background texture
+
+### Touch (Mobile)
+- **Free Drag Gesture:** Rotate camera
+- **Pinch Gesture:** Zoom in/out (change camera FOV)
+- **Tap UI Buttons:** Toggle lighting, animation, and background texture
+
+## Project Structure
+- `Core/` — Shared game logic, models, animation, and UI components
+- `Platforms/Windows/` — Windows-specific project files
+- `Platforms/Desktop/` — DesktopGL (cross-platform desktop) project files
+- `Platforms/Android/` — Android project files
+- `Platforms/iOS/` — iOS project files
+- `Content/` — Game assets (textures, models, animations)
+
+## Prerequisites
+- [.NET 8 SDK](https://dotnet.microsoft.com/download)
+- [MonoGame](https://www.monogame.net/)
+- Platform-specific tools (Android SDK, Xcode for iOS, etc.)
+
+## Building and Running
+
+### Windows
+1. Restore dependencies:
+    ```pwsh
+    dotnet restore
+    ```
+2. Build:
+    ```pwsh
+    dotnet build Platforms/Windows/Graphics3DSample.Windows.csproj
+    ```
+3. Run:
+    ```pwsh
+    dotnet run --project Platforms/Windows/Graphics3DSample.Windows.csproj
+    ```
+
+### DesktopGL (Cross-Platform Desktop)
+1. Restore dependencies:
+    ```pwsh
+    dotnet restore
+    ```
+2. Build:
+    ```pwsh
+    dotnet build Platforms/Desktop/Graphics3DSample.DesktopGL.csproj
+    ```
+3. Run:
+    ```pwsh
+    dotnet run --project Platforms/Desktop/Graphics3DSample.DesktopGL.csproj
+    ```
+
+### Android
+1. Restore dependencies:
+    ```pwsh
+    dotnet restore
+    ```
+2. Build:
+    ```pwsh
+    dotnet build Platforms/Android/Graphics3DSample.Android.csproj
+    ```
+3. Deploy/run using your preferred Android deployment method (e.g., Visual Studio, device/emulator).
+
+### iOS
+1. Restore dependencies:
+    ```pwsh
+    dotnet restore
+    ```
+2. Build:
+    ```pwsh
+    dotnet build Platforms/iOS/Graphics3DSample.iOS.csproj
+    ```
+3. Deploy/run using Xcode or your preferred iOS deployment method.
+
+## Cleaning the Project
+To clean all build outputs:
+```pwsh
+dotnet clean
+```
+
+## Notes
+- All platform projects share the core game logic in `Core/`.
+- Content assets are located in `Core/Content/` and referenced by each platform project.
+- For mobile platforms, ensure you have the necessary SDKs and emulators installed.
+
+## License
+This project is based on the Microsoft XNA Community Game Platform sample code.