using System; using Chernobyl; using Chernobyl.Collections.Generic; using Chernobyl.Collections.Generic.Event; using Chernobyl.Dependency; using Chernobyl.Graphics; using Chernobyl.Graphics.Drawing; using Chernobyl.Graphics.Material.Shader.Parameters; using Chernobyl.Graphics.Material.Shader.Parameters.Semantics; using Chernobyl.Graphics.Polygon; using Chernobyl.Graphics.Polygon.Buffers; using Chernobyl.Graphics.Texture; using Chernobyl.Mathematics; using Chernobyl.Mathematics.Vectors; using Chernobyl.Measures; using Chernobyl.Plugin; using Chernobyl.StateMachine; namespace Sample { /// /// A plug-in to Chernobyl! Here are the steps to creating a plug-in: /// /// 1) Create a type that implements the interface IPlugin. You don't have /// to implement any methods or properties from this interface as it is /// an empty interface (for now). See the documentation on the IPlugin /// interface for more details. /// 2) You must put your library somewhere where the .NET runtime can locate /// it using Assembly.Load(string). This is not a Chernobyl thing but a /// .NET thing. If your unsure of where to put the library, then throw it /// in the appropriate bin directory with the rest of the Chernobyl libraries. /// You can have Visual Studio due this for you automatically by importing /// the file "common.targets" into your Visual Studio file. Just open /// your .csproj sample project and place the import line after the /// property groups that deal with debug/release configurations (open /// this plug-in's .csproj file in a text editor to see an example of this). /// Go here for more information on this topic: /// http://msdn.microsoft.com/en-us/library/92x05xfs.aspx /// For more information on how the .NET runtime locates assemblies, go /// here: http://msdn.microsoft.com/en-us/library/yx7xezcf.aspx /// 3) Add the full name of your assembly to the .config file of the .NET /// executable that runs your project. Chernobyl has project to get it /// (and you) started called "Chernobyl.Run". In this project you should /// see a file called "app.config". Open that file up and locate the /// "appSettings" section. Below that, you should see an "add" element /// with the name of "Chernobyl.Plugins". The value should look like a /// bunch of crazy shit. That crazy shit are the FULL names of each of /// the Chernobyl plug-ins separated by semi-colons (;). For example, /// the Input plug-in forChernobyl looks like this: /// /// Chernobyl.Input, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null /// /// You'll need to add your plug-in to this list. This plug-in is called: /// /// Sample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null /// /// This plug-in should be in that list already. The method for loading /// plug-ins will probably change slightly in the future but, for now, /// use this method. Also, .config files and full assembly names are a /// .NET thing so check out the following for information on them, respectively: /// http://msdn.microsoft.com/en-us/library/1xtk877y%28v=VS.80%29.aspx /// http://msdn.microsoft.com/en-us/library/yfsftwz6.aspx (see the section "Specifying Assembly Names" specifically) /// public class MyChernobylPlugin : IPlugin { /// /// Initializes a new instance of the class. /// Chernobyl plug-ins must have either a constructor that takes no /// parameters or a constructor that takes an /// instance. /// /// The instance that gives out services for use /// by this type and takes services from this type for use by other systems. public MyChernobylPlugin(IEventCollection services) { Services = services; // The inject call ensures that properties marked with an "Inject" // attribute are properly resolved. Basically, the inject call will // go through all of the properties in the class that are marked with // "Inject" or "Provide". Those that are marked with "Inject" will // be given the service that matches their type. It is about the same // as doing this for the ConfigurationState property: // // ConfigurationState = services.OfType().First(); // // I say about because the inject call also ensures that dependencies // are handled correctly. It also ensures the service actually exists // before giving the property anything. If a property is marked with // a "Provide" attribute then that property is being "provided" to // the IEventCollection instance as a service that can be // used by other systems. It is the same as doing this: // // services.Add(this.SomeService); services.Inject(this); } /// /// The that represents the configuration or /// initialization state of the application. /// [Inject] public IConfigurationState ConfigurationState { set { value.Left += ConfigurationEnded; } } /// /// An event handler that is invoked when the state of the application /// has left the configuration state. /// /// The sender of the event. /// The instance /// containing the event data. void ConfigurationEnded(object sender, EventArgs e) { // now that everything has been configured, we can create/load content ////////////////////////////////////////////////////////////////////////// // 2D RENDERING ////////////////////////////////////////////////////////////////////////// // create the sprite. "radiation_warning_symbol" is the name of the // XNA resource. This XNA resource has loaded into the Chernobyl.Xna // project. MySprite = new Sprite(Services, "radiation_warning_symbol"); // move the sprite up and to the right MySprite.Translate(200.0f, 400.0f); // attach the sprite to the draw graph. The Draw2D is just a "marker" // to a location in a main draw graph where we can render MySprite.DrawableParent = TheScene.Draw2D; ////////////////////////////////////////////////////////////////////////// // 3D RENDERING // from: http://www.switchonthecode.com/tutorials/creating-a-textured-box-in-xna ////////////////////////////////////////////////////////////////////////// const float shapeSize = 3; Vector3 shapePosition = Vector3.Zero; // create the points of the cube Vector3 topLeftFront = shapePosition + new Vector3(-1.0f, 1.0f, -1.0f) * shapeSize; Vector3 bottomLeftFront = shapePosition + new Vector3(-1.0f, -1.0f, -1.0f) * shapeSize; Vector3 topRightFront = shapePosition + new Vector3(1.0f, 1.0f, -1.0f) * shapeSize; Vector3 bottomRightFront = shapePosition + new Vector3(1.0f, -1.0f, -1.0f) * shapeSize; Vector3 topLeftBack = shapePosition + new Vector3(-1.0f, 1.0f, 1.0f) * shapeSize; Vector3 topRightBack = shapePosition + new Vector3(1.0f, 1.0f, 1.0f) * shapeSize; Vector3 bottomLeftBack = shapePosition + new Vector3(-1.0f, -1.0f, 1.0f) * shapeSize; Vector3 bottomRightBack = shapePosition + new Vector3(1.0f, -1.0f, 1.0f) * shapeSize; // create the normals Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f) * shapeSize; Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f) * shapeSize; Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f) * shapeSize; Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f) * shapeSize; Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f) * shapeSize; Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f) * shapeSize; // create the texture coordinates Vector2 textureTopLeft = new Vector2(0.5f * shapeSize, 0.0f * shapeSize); Vector2 textureTopRight = new Vector2(0.0f * shapeSize, 0.0f * shapeSize); Vector2 textureBottomLeft = new Vector2(0.5f * shapeSize, 0.5f * shapeSize); Vector2 textureBottomRight = new Vector2(0.0f * shapeSize, 0.5f * shapeSize); // create the cube vertices VertexTextureNormal[] shapeVertices = new VertexTextureNormal[36]; // Front face. shapeVertices[0] = new VertexTextureNormal(topLeftFront, textureTopLeft, frontNormal); shapeVertices[1] = new VertexTextureNormal(bottomLeftFront, textureBottomLeft, frontNormal); shapeVertices[2] = new VertexTextureNormal(topRightFront, textureTopRight, frontNormal); shapeVertices[3] = new VertexTextureNormal(bottomLeftFront, textureBottomLeft, frontNormal); shapeVertices[4] = new VertexTextureNormal(bottomRightFront, textureBottomRight, frontNormal); shapeVertices[5] = new VertexTextureNormal(topRightFront, textureTopRight, frontNormal); // Back face. shapeVertices[6] = new VertexTextureNormal(topLeftBack, textureTopRight, backNormal); shapeVertices[7] = new VertexTextureNormal(topRightBack, textureTopLeft, backNormal); shapeVertices[8] = new VertexTextureNormal(bottomLeftBack, textureBottomRight, backNormal); shapeVertices[9] = new VertexTextureNormal(bottomLeftBack, textureBottomRight, backNormal); shapeVertices[10] = new VertexTextureNormal(topRightBack, textureTopLeft, backNormal); shapeVertices[11] = new VertexTextureNormal(bottomRightBack, textureBottomLeft, backNormal); // Top face. shapeVertices[12] = new VertexTextureNormal(topLeftFront, textureBottomLeft, topNormal); shapeVertices[13] = new VertexTextureNormal(topRightBack, textureTopRight, topNormal); shapeVertices[14] = new VertexTextureNormal(topLeftBack, textureTopLeft, topNormal); shapeVertices[15] = new VertexTextureNormal(topLeftFront, textureBottomLeft, topNormal); shapeVertices[16] = new VertexTextureNormal(topRightFront, textureBottomRight, topNormal); shapeVertices[17] = new VertexTextureNormal(topRightBack, textureTopRight, topNormal); // Bottom face. shapeVertices[18] = new VertexTextureNormal(bottomLeftFront, textureTopLeft, bottomNormal); shapeVertices[19] = new VertexTextureNormal(bottomLeftBack, textureBottomLeft, bottomNormal); shapeVertices[20] = new VertexTextureNormal(bottomRightBack, textureBottomRight, bottomNormal); shapeVertices[21] = new VertexTextureNormal(bottomLeftFront, textureTopLeft, bottomNormal); shapeVertices[22] = new VertexTextureNormal(bottomRightBack, textureBottomRight, bottomNormal); shapeVertices[23] = new VertexTextureNormal(bottomRightFront, textureTopRight, bottomNormal); // Left face. shapeVertices[24] = new VertexTextureNormal(topLeftFront, textureTopRight, leftNormal); shapeVertices[25] = new VertexTextureNormal(bottomLeftBack, textureBottomLeft, leftNormal); shapeVertices[26] = new VertexTextureNormal(bottomLeftFront, textureBottomRight, leftNormal); shapeVertices[27] = new VertexTextureNormal(topLeftBack, textureTopLeft, leftNormal); shapeVertices[28] = new VertexTextureNormal(bottomLeftBack, textureBottomLeft, leftNormal); shapeVertices[29] = new VertexTextureNormal(topLeftFront, textureTopRight, leftNormal); // Right face. shapeVertices[30] = new VertexTextureNormal(topRightFront, textureTopLeft, rightNormal); shapeVertices[31] = new VertexTextureNormal(bottomRightFront, textureBottomLeft, rightNormal); shapeVertices[32] = new VertexTextureNormal(bottomRightBack, textureBottomRight, rightNormal); shapeVertices[33] = new VertexTextureNormal(topRightBack, textureTopRight, rightNormal); shapeVertices[34] = new VertexTextureNormal(topRightFront, textureTopLeft, rightNormal); shapeVertices[35] = new VertexTextureNormal(bottomRightBack, textureBottomRight, rightNormal); // now we put the vertices into a MeshElementBuffer; by doing this // we are giving the vertices to the graphics API (XNA, DirectX, OpenGL, etc) // Note that we could use the MeshElementBuffer constructor here, but // the MeshElementBuffer class has Create methods which simplify the // creation of the buffer. It is important that you try to share // buffers whenever possible as it will help performance (for both // drawing and memory consumption). IBuffer meshElementBuffer = new Mesh(Services, shapeVertices); // now that we have our data, we need to setup up the mesh's draw graph // The draw graph describes how the mesh will be rendered and what data // to use when rendering it. // Here we create a shader parameter, specifically, we create a color // texture shader parameter. A shader parameter is responsible for // setting shader parameters within a draw graph. There are different // types of shader parameters within Chernobyl, all of them set different // parameters. The ColorTextureParameter is responsible for setting the // texture that is used for color (some textures may be used for // other purposes such as a bump/normal map or for shadows). IShaderParameter colorTextureParam = new ColorTextureParameter(Services, new Texture2D(Services, "radiation_warning_symbol")); // Here we create a DrawBuffer. A DrawBuffer is an IDrawable that is // responsible for specifying which buffer to use when a mesh is to // be drawn. Note that we use a factory to create the IDrawBuffer. // It cannot be guaranteed that the factory will return immediately // so this code is not safe but does show the basic idea. // TODO: make this code safer. IDrawBuffer drawBuffer = null; DrawBufferFactory.Create( (factorySender, creationResult) => drawBuffer = creationResult.CreatedInstance, new Pair, IBuffer>(Services, meshElementBuffer)); // Now we create the render which is responsible for telling the // graphics API to render the object with the specified data (textures, // mesh elements, etc). It also tells the graphics API where to render // the object, at what orientation, and the type of primitive to render. IRender render = new Render(Services, PrimitiveType.TriangleList); // now we hook up all of the IDrawables into the draw graph so that they // will be properly rendered Drawable.MakeParentChild(TheScene.Draw3D, colorTextureParam, drawBuffer, render); // rotate the cube to get a better view (note that we rotate the render // which holds transformation information; i.e. it is an ITransform) render.Pitch((Degree)30.0f); render.Yaw((Degree)10.0f); // note that, if you prefer radians you can do something like this: // render.Pitch((Radian)0.523598776); // render.Yaw((Radian)0.174532925); // Chernobyl requires you to cast to the appropriate value in order // to prevent issues arising from the user thinking they are specifying // degrees but are actually specifying radians. This helps prevent // user errors. // now move the cube up 3, to the right 5, and forward 50 render.Translate(3.0f, 5.0f, -50.0f); // One thing to note: the Chernobyl Sprite uses a texture parameter, // draw buffer, and render just like a 3D mesh does. In fact, a sprite is // a mesh in that sense. The differences being that a sprite is added // to the 2D section of drawing, the sprite makes creation of 2D // objects easier, it creates a 2D collision volume for you, and does // a few tricks to make them more performance optimal (such as sharing // the MeshElementBuffer between all Sprites). } /// /// The main used be Chernobyl for rendering. /// [Inject] public Scene TheScene { get; set; } /// /// The instance that we will use to create an . /// [Inject] public IDrawBufferFactory DrawBufferFactory { get; set; } Sprite MySprite { get; set; } IEventCollection Services { get; set; } } }