HelloQuad.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System.Runtime.InteropServices;
  2. using AtomicEngine;
  3. public class Program
  4. {
  5. public static void Main(string[] args)
  6. {
  7. Application.Run<HelloQuad>(args);
  8. }
  9. }
  10. [StructLayout(LayoutKind.Explicit)]
  11. public struct PositionTextureColor
  12. {
  13. // Position
  14. [FieldOffset(0)] public float x;
  15. [FieldOffset(4)] public float y;
  16. [FieldOffset(8)] public float z;
  17. // Texture
  18. [FieldOffset(16)] public float u;
  19. [FieldOffset(20)] public float v;
  20. //Color
  21. [FieldOffset(12)] public uint color;
  22. [FieldOffset(12)] public byte r;
  23. [FieldOffset(13)] public byte g;
  24. [FieldOffset(14)] public byte b;
  25. [FieldOffset(15)] public byte a;
  26. }
  27. public class HelloQuad : AppDelegate
  28. {
  29. // Scene reference kept here so it won't be collected by the GC
  30. Scene scene;
  31. Camera camera;
  32. Graphics graphics;
  33. Viewport viewport;
  34. Texture2D texture;
  35. VertexBuffer vertexBuffer;
  36. public override void Start()
  37. {
  38. // We get the variables we are going to use in this example
  39. Renderer renderer = GetSubsystem<Renderer>();
  40. graphics = GetSubsystem<Graphics>();
  41. viewport = renderer.GetViewport(0);
  42. // We create a new Scene
  43. scene = new Scene();
  44. // The Octree should be added to the root scene node (mandatory?)
  45. scene.CreateComponent<Octree>();
  46. // We tell the current viewport to display the scene we just created
  47. viewport.Scene = scene;
  48. // We create a new camera on the scene, called "Camera"
  49. // - Scene.CreateChild(string name) returns a new Node with that name.
  50. // - Node.CreateComponent<ComponentType>() returns a component attached to that Node
  51. camera = scene.CreateChild("Camera").CreateComponent<Camera>();
  52. // We can access the Node any component is attached to using Component.Node
  53. camera.Node.Position = new Vector3(0.5f, 0.5f, 0.0f);
  54. // Remember, 'camera' is a Camera component, so we access it directly here
  55. camera.Orthographic = true;
  56. camera.OrthoSize = 1.5f;
  57. // We tell the Viewport to use our newly created camera to display our scene
  58. viewport.Camera = camera;
  59. // We create an XML from string so this code is fully self-contained
  60. XMLFile xml = new XMLFile();
  61. xml.FromString("<renderpath><command type=\"sendevent\"/></renderpath>");
  62. // We create a new RenderPath. A Viewport comes by default with some events, and you can use viewport.GetRenderPath().Clone()
  63. // to clone the default RenderPath and Append instructions to it instead (see AtomicBlaster for effects)
  64. RenderPath renderpath = new RenderPath();
  65. renderpath.Append(xml);
  66. // We repace the viewport's default renderpath by the one we just created
  67. viewport.SetRenderPath(renderpath);
  68. // We subscribe to the RenderPathEvent. Here we pass an anonymous function that just absorbs the argument and calls Render()
  69. SubscribeToEvent<RenderPathEvent>(e => { Render(); });
  70. // Here we setup our shaders, here we are using the BasicVColUnlitAlpha and selecting only DIFFMAP (diffuse texture pass)
  71. // See this link: github.com/AtomicGameEngine/AtomicGameEngine/tree/master/Resources/CoreData/Techniques
  72. ShaderVariation pixelShader = graphics.GetShader(ShaderType.PS, "Basic", "DIFFMAP VERTEXCOLOR");
  73. ShaderVariation vertexShader = graphics.GetShader(ShaderType.VS, "Basic", "DIFFMAP VERTEXCOLOR");
  74. graphics.SetShaders(vertexShader, pixelShader);
  75. // This vertex shader parameter just applies no transformation (Identity Matrix means no transformation) so the vertices
  76. // display in world coordinates what allow us to use the camera properly
  77. graphics.SetShaderParameter(ShaderParams.VSP_MODEL, Matrix3x4.IDENTITY);
  78. // We set the pixel shader diffuse color to be white. You can change this to 'tint' the texture similar to vertex colors
  79. // but this applies to the whole material
  80. graphics.SetShaderParameter(ShaderParams.PSP_MATDIFFCOLOR, Color.White);
  81. // We set cull mode to NONE so our geometry won't be culled (ignored), for this example we don't really need any culling
  82. graphics.SetCullMode(CullMode.CULL_NONE);
  83. // We create a texture from literal data so this code is fully self-contained, you can safely skip the lines below
  84. // In your real projects you're most likely going to load textures from the disk using Texture.Load
  85. Image image = new Image();
  86. image.SetSize(16, 16, 3);
  87. Color z = Color.White;
  88. Color M = Color.Blue;
  89. Color k = Color.Black;
  90. Color[,] imageData =
  91. {
  92. { k,k,k,k,k,k,k,k,k,k,k,k,k,k,k,k },
  93. { k,z,z,z,z,z,z,z,z,z,z,z,z,z,M,k },
  94. { k,z,z,z,z,z,z,M,M,z,z,z,z,z,z,k },
  95. { k,z,z,z,z,z,z,M,M,z,z,z,z,z,z,k },
  96. { k,z,z,z,z,z,M,z,z,M,z,z,z,z,z,k },
  97. { k,z,z,z,z,z,M,z,z,M,z,z,z,z,z,k },
  98. { k,z,z,z,z,M,z,z,z,z,M,z,z,z,z,k },
  99. { k,z,z,z,z,M,z,z,z,z,M,z,z,z,z,k },
  100. { k,z,z,z,M,z,z,z,z,z,z,M,z,z,z,k },
  101. { k,z,z,z,M,z,z,z,z,z,z,M,z,z,z,k },
  102. { k,z,z,M,M,M,M,M,M,M,M,M,M,z,z,k },
  103. { k,z,z,M,z,z,z,z,z,z,z,z,M,z,z,k },
  104. { k,z,M,z,z,z,z,z,z,z,z,z,z,M,z,k },
  105. { k,z,M,z,z,z,z,z,z,z,z,z,z,M,z,k },
  106. { k,z,z,z,z,z,z,z,z,z,z,z,z,z,z,k },
  107. { k,k,k,k,k,k,k,k,k,k,k,k,k,k,k,k },
  108. };
  109. for (int x = 0; x < 16; x++)
  110. {
  111. for (int y = 0; y < 16; y++)
  112. {
  113. image.SetPixel(x, 15 - y, imageData[y, x]);
  114. }
  115. }
  116. texture = new Texture2D();
  117. texture.SetData(image);
  118. // We call this function that creates the quad geometry
  119. CreateQuad();
  120. }
  121. // We use unsafe code only to access the vertex buffer data
  122. private unsafe void CreateQuad()
  123. {
  124. // We create a new VertexBuffer object, it holds our vertices and is passed to the GPU
  125. vertexBuffer = new VertexBuffer();
  126. // We set its size and the elements it's containing, the 3rd optional argument (dynamic) should be 'true' if you're planning
  127. // to update the VertexBuffer constantly, that will improve performance in those cases.
  128. vertexBuffer.SetSize(6, Constants.MASK_POSITION | Constants.MASK_TEXCOORD1 | Constants.MASK_COLOR, false);
  129. // Here we lock the vertexBuffer what returns a pointer (IntPtr) to its data (vertexData here), I'm using a code block for clarity
  130. System.IntPtr vertexData = vertexBuffer.Lock(0, 6, true);
  131. {
  132. // We can cast the data pointer to whatever data type we want, here we are only using floats but ideally you will want
  133. // to cast it to an object (struct) with properly offsetted fields and maybe unions for things like colors
  134. //float* vout = (float*)vertexData;
  135. PositionTextureColor* vertex = (PositionTextureColor*) vertexData;
  136. vertex[0] = new PositionTextureColor{ x = 0, y = 0, u = 0, v = 0, r = 255, g = 0, b = 255 };
  137. vertex[1] = new PositionTextureColor{ x = 0, y = 1, u = 0, v = 1, r = 255, g = 255, b = 0 };
  138. vertex[2] = new PositionTextureColor{ x = 1, y = 1, u = 1, v = 1, r = 255, g = 255, b = 255 };
  139. vertex[3] = new PositionTextureColor{ x = 0, y = 0, u = 0, v = 0, r = 255, g = 0, b = 255 };
  140. vertex[4] = new PositionTextureColor{ x = 1, y = 1, u = 1, v = 1, r = 255, g = 255, b = 255 };
  141. vertex[5] = new PositionTextureColor{ x = 1, y = 0, u = 1, v = 0, r = 0, g = 255, b = 0 };
  142. //// Our first vertex, here we set the x position of it
  143. //*vout++ = 0;
  144. //// Here we set the y position
  145. //*vout++ = 0;
  146. //// Here we set the z position (depth in this case, useful for sorting in orthographic projection)
  147. //*vout++ = 0;
  148. //// Here we set it's texture x coordinate, commonly called u;
  149. //*vout++ = 0;
  150. //// Here we set it's texture y coordinate, commonly called v;
  151. //// UVs are simply cartesian coordinates: 0,0 is bottom-left; 1,1 is top-right
  152. //*vout++ = 0;
  153. //// Each of these blocks is a vertex, same concept apply:
  154. }
  155. // Don't forget to unlock the VertexBuffer after you modify it
  156. vertexBuffer.Unlock();
  157. }
  158. void Render()
  159. {
  160. graphics.SetDefaultTextureFilterMode(TextureFilterMode.FILTER_NEAREST);
  161. // We clear the whole screen white before drawing anything
  162. graphics.Clear(Constants.CLEAR_COLOR, Color.White);
  163. // The 3 lines below don't have to be set every frame in this specific example, but you'll most likely be changing the often
  164. viewport.View.SetCameraShaderParameters(camera);
  165. // We set the Texture to be used in the next draw call
  166. graphics.SetTexture((uint)TextureUnit.TU_DIFFUSE, texture);
  167. // We set the VertexBuffer to be used on the next draw call
  168. graphics.SetVertexBuffer(vertexBuffer);
  169. // We finally call Draw passing the primitive type our VertexBuffer uses, TRIANGLE_LIST basically means that each 2 vertex
  170. // in the buffer should have a face (triangle) between them
  171. graphics.Draw(PrimitiveType.TRIANGLE_LIST, 0, 6);
  172. }
  173. }