|
| 1 | +using System; |
| 2 | +using System.Diagnostics; |
| 3 | +using System.Windows.Forms; |
| 4 | +using Microsoft.Xna.Framework; |
| 5 | +using Microsoft.Xna.Framework.Content; |
| 6 | +using Microsoft.Xna.Framework.Graphics; |
| 7 | +using Microsoft.Xna.Framework.Input; |
| 8 | + |
| 9 | +namespace SpectroNamespace |
| 10 | +{ |
| 11 | + abstract class CommonScene : GraphicsDeviceControl |
| 12 | + { |
| 13 | + // References to important program level objects. |
| 14 | + public RenderSettings RenderSettings { get; set; } |
| 15 | + public DataManager DataManager { get; set; } |
| 16 | + |
| 17 | + // Some important properties and fields. |
| 18 | + public SceneGraph SceneGraph { get; set; } |
| 19 | + public bool Recompute { get; set; } |
| 20 | + public bool Animate { get; set; } |
| 21 | + |
| 22 | + // General |
| 23 | + protected ContentManager _contentManager; |
| 24 | + protected Effect _effect; |
| 25 | + protected Stopwatch _timer; |
| 26 | + protected Matrix _projectionMatrix; |
| 27 | + protected Matrix _worldMatrix; |
| 28 | + protected double _timeSpentCalculating; |
| 29 | + protected double _timeSpentRendering; |
| 30 | + |
| 31 | + // Sprite related |
| 32 | + protected SpriteBatch _spriteBatch; |
| 33 | + protected SpriteFont _font; |
| 34 | + |
| 35 | + // Set the position of the camera in world space, for our view matrix. |
| 36 | + protected Vector3 _cameraPosition; |
| 37 | + protected Matrix _lookAtMatrix; |
| 38 | + |
| 39 | + public CommonScene() |
| 40 | + { |
| 41 | + _projectionMatrix = Matrix.Identity; |
| 42 | + _worldMatrix = Matrix.Identity; |
| 43 | + _lookAtMatrix = Matrix.Identity; |
| 44 | + } |
| 45 | + |
| 46 | + /// <summary> |
| 47 | + /// Simply loads in content from content files. No other setup logic. |
| 48 | + /// </summary> |
| 49 | + public override void LoadContent() |
| 50 | + { |
| 51 | + try |
| 52 | + { |
| 53 | + // Setup the content manager. |
| 54 | + this._contentManager = new ContentManager(Services, "Content"); |
| 55 | + |
| 56 | + // Setup rendering effect |
| 57 | + this._effect = new BasicEffect(this.GraphicsDevice); |
| 58 | + |
| 59 | + // Populate the scene graph |
| 60 | + this.SceneGraph = new SceneGraph(); |
| 61 | + this.SceneGraph.PopulateScene(_contentManager, this.DataManager.Materials[0]); |
| 62 | + |
| 63 | + // Font. |
| 64 | + _spriteBatch = new SpriteBatch(GraphicsDevice); |
| 65 | + _font = _contentManager.Load<SpriteFont>("hudFont"); |
| 66 | + } |
| 67 | + catch (ContentLoadException e) |
| 68 | + { |
| 69 | + MessageBox.Show(e.Message); |
| 70 | + throw; |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + /// <summary> |
| 75 | + /// Walks through some setup steps to prepare the models etc. for rendering. |
| 76 | + /// </summary> |
| 77 | + virtual public void PrepareForRendering() |
| 78 | + { |
| 79 | + // Setup projection matrix. |
| 80 | + bool orthographic = false; |
| 81 | + |
| 82 | + if (orthographic) |
| 83 | + { |
| 84 | + float projectionHeight = 40f; |
| 85 | + float projectionDepth = 1000f; |
| 86 | + _projectionMatrix = Matrix.CreateOrthographic(GraphicsDevice.Viewport.AspectRatio * projectionHeight, projectionHeight, 1f, projectionDepth); |
| 87 | + |
| 88 | + // From an aesthetic point of view, our camera position is dependent on our projection. |
| 89 | + _cameraPosition = new Vector3(0.0f, 0.0f, 200.0f); |
| 90 | + } |
| 91 | + else |
| 92 | + { |
| 93 | + _projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(30.0f), GraphicsDevice.Viewport.AspectRatio, 1.0f, 500.0f); |
| 94 | + |
| 95 | + // From an aesthetic point of view, our camera position is dependent on our projection. |
| 96 | + _cameraPosition = new Vector3(20.0f, 20.0f, 20.0f); |
| 97 | + } |
| 98 | + |
| 99 | + // Prepare the lookat matrix. |
| 100 | + _lookAtMatrix = Matrix.CreateLookAt(_cameraPosition, Vector3.Zero, Vector3.Up); |
| 101 | + |
| 102 | + // Prepare the scenegraph |
| 103 | + this.SceneGraph.PrepareForRendering(_effect); |
| 104 | + |
| 105 | + // Set renderstates. |
| 106 | + GraphicsDevice.RasterizerState = RasterizerState.CullNone; |
| 107 | + |
| 108 | + // Start the animation _timer. |
| 109 | + _timer = Stopwatch.StartNew(); |
| 110 | + |
| 111 | + // Hook the idle event to constantly redraw our animation. |
| 112 | + Application.Idle += delegate { Invalidate(); }; |
| 113 | + |
| 114 | + // Make sure you compute at the start. |
| 115 | + this.Recompute = true; |
| 116 | + } |
| 117 | + |
| 118 | + /// <summary> |
| 119 | + /// Draws the control. |
| 120 | + /// In our case the control is a scene with ONE complex geometric object. Please remember that this method is NOT |
| 121 | + /// optimized for rendering a hierarchy of elements. It does NOT handle bones system correctly. |
| 122 | + /// </summary> |
| 123 | + protected override void Draw() |
| 124 | + { |
| 125 | + Stopwatch renderTimer = new Stopwatch(); |
| 126 | + renderTimer.Start(); |
| 127 | + |
| 128 | + // Check if any of the scene elements have been changed. |
| 129 | + if (this.Recompute) |
| 130 | + { |
| 131 | + this.RecomputeColorValues(); |
| 132 | + this.Recompute = false; |
| 133 | + } |
| 134 | + |
| 135 | + // Clear |
| 136 | + GraphicsDevice.Clear(Color.Gray); |
| 137 | + |
| 138 | + // Spin the camera around the models. We want to spin by a certain amount every millisecond |
| 139 | + float time = (float)_timer.ElapsedMilliseconds; |
| 140 | + float rotationAmount = this.Animate? time * 0.00007f : 0.0f; |
| 141 | + _timer.Restart(); |
| 142 | + |
| 143 | + _lookAtMatrix = Matrix.Multiply(Matrix.CreateRotationY(rotationAmount), _lookAtMatrix); |
| 144 | + |
| 145 | + // Render the scene graph |
| 146 | + _worldMatrix = Matrix.Identity; |
| 147 | + this.SceneGraph.Render(_worldMatrix, _lookAtMatrix, _projectionMatrix); |
| 148 | + |
| 149 | + renderTimer.Stop(); |
| 150 | + _timeSpentRendering = (_timeSpentRendering + renderTimer.Elapsed.Duration().TotalMilliseconds) / 2; |
| 151 | + |
| 152 | + _spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone); |
| 153 | + _spriteBatch.DrawString(_font, "Color calculations took " + _timeSpentCalculating.ToString() + " milliseconds.", new Vector2(10f, 10f), Color.White); |
| 154 | + // _spriteBatch.DrawString(_font, "Rendering took " + _timeSpentRendering.ToString() + " milliseconds.", new Vector2(10f, 30f), Color.White); |
| 155 | + _spriteBatch.End(); |
| 156 | + |
| 157 | + } // The model has been rendered! |
| 158 | + |
| 159 | + protected void RecomputeColorValues() |
| 160 | + { |
| 161 | + // For brevity |
| 162 | + DataManager dm = this.DataManager; |
| 163 | + RenderSettings rs = this.RenderSettings; |
| 164 | + |
| 165 | + LightSource lightSource = dm.LightSources[rs.ActiveLightSourceIndex]; |
| 166 | + Observer observer = dm.Observers[rs.ActiveObserverIndex]; |
| 167 | + // Material material = dm.Materials[rs.ActiveMaterialIndex]; |
| 168 | + |
| 169 | + Stopwatch colorCalcTimer = new Stopwatch(); |
| 170 | + colorCalcTimer.Reset(); |
| 171 | + colorCalcTimer.Start(); |
| 172 | + |
| 173 | + this.SceneGraph.RecalculateColors(lightSource, observer, rs.ClipInvisible); |
| 174 | + |
| 175 | + colorCalcTimer.Stop(); |
| 176 | + _timeSpentCalculating = colorCalcTimer.Elapsed.Duration().TotalMilliseconds; |
| 177 | + |
| 178 | + // Update light intensity. |
| 179 | + // TODO: in the future, you might want to consider creating a new method that only deals with non-color changes |
| 180 | + // so that we don't have to do all the hairy math required for color for simply light changes. |
| 181 | + _effect.Parameters["LightStrength"].SetValue((float)rs.LightStrength / 100.0f); |
| 182 | + |
| 183 | + // Light RGB |
| 184 | + _effect.Parameters["LightColor"].SetValue(Utilities.GetEquivalentRGB(lightSource)); |
| 185 | + |
| 186 | + // Reinhard tone mapping variables. |
| 187 | + //_effect.Parameters["AverageLogLuminance"].SetValue(); |
| 188 | + //_effect.Parameters["Key"].SetValue(); |
| 189 | + //_effect.Parameters["Lw_a"].SetValue(); |
| 190 | + //_effect.Parameters["LogTerm"].SetValue(); |
| 191 | + } |
| 192 | + |
| 193 | + public ModelNode GetIntersectingModel() |
| 194 | + { |
| 195 | + float titleBarHeight = 30f; |
| 196 | + float frameWidth = 10f; |
| 197 | + |
| 198 | + MouseState mouseState = Mouse.GetState(); |
| 199 | + Vector2 mousePosition = new Vector2(mouseState.X - this.Parent.Bounds.Left - this.Bounds.Left - frameWidth, |
| 200 | + mouseState.Y - this.Parent.Bounds.Top - this.Bounds.Top - titleBarHeight); |
| 201 | + |
| 202 | + return SceneGraph.GetIntersectingModel(this._projectionMatrix, this._lookAtMatrix, this._worldMatrix, this.GraphicsDevice, mousePosition); |
| 203 | + } |
| 204 | + |
| 205 | + public void UpdateSelectedObjectMaterial(string objectName, Material material) |
| 206 | + { |
| 207 | + this.SceneGraph.AssignNewMaterial(objectName, material); |
| 208 | + } |
| 209 | + } |
| 210 | +} |
0 commit comments