Assignment 3 is a further practice on platform-specific and platform-independent coding. The goal of this assignment is to eliminate the platform-specific code within the Graphics.[platform].cpp files and to change the mesh class and the effect class to be data-driven.
I noticed some small differences between Graphics.d3d.cpp and Graphics.gl.cpp. When initializing and cleaning up, Graphics.d3d.cpp has extra steps for dealing with Views which is platform-specific. And when rendering frames, Graphics.d3d.cpp and Graphics.gl.cpp calls platform-specific functions to clear the image buffer and to swap buffers.
To get rid of the differences within Graphics.cpp, I declared a Canvas class within cCanvas.h as a platform-independent interface to wrap up the platform-specific code. All platform-specific code was being separated into cCanva.d3d.cpp and cCanva.gl.cpp. The Canvas class contains an Initialize(sInitializationParameters& i_initializationParameters) function, which takes care of the difference in initialization. Similarly, the CleanUp() function takes care of the difference in cleaning up. The Clear(Color color) function and the PresentBackBuffer() function take care of the difference in rendering frames.
Specially, the Clear(Color color) declared in my cCanva.h takes a parameter of Color, which is a simple struct of 4 float types that represent the rgba values of a color. By doing it this way, I was able to specify the color of the background where the meshes were drawn on.
A Windows application that renders a square-shaped mesh and a triangle-shaped mesh in a window where a fragment shader changes the color of the triangle continuously over time, and the square stays white.
A static instance of Canvas is created within Graphics.cpp. To clear the back buffer color, simply call the Clear(Color c) function of the Canvas instance. The example below showing how the back buffer color is cleared to red. (s_redColor is a struct instance represents {r=1, g=0, b=0, a=1})
To initialize an effect, the only data needed is two file paths, one for the vertex shader and one for the fragment shader. The initialize function will find the shader files using the paths passed in and initialize shading data accordingly.
An effect instance takes 48 bytes in the x64 implementation and 16 bytes in the x86 implementation. The sizes are different because of two factors. One is that pointers in x86 and x64 have different sizes (4 bytes in x86 and 8 bytes in x64). Another one is the different amount of data being stored. The x86 implementation stores an extra m_programId, and the x86 version of cRenderState only stores a uint8_t type, whereas the x64 version of cRenderState stores three pointers.
I do think the data size in my Effect class can be reduced a bit more for the x64 configuration if I change the m_renderState to a pointer. But I didn’t do it that way because I wasn’t sure if that was good practice, and the x86 implementation wouldn’t get any reduction in size from it.
I defined a MeshData struct inside sMeshData.h for the purpose of temporarily storing vertex and index data for the Mesh class to process upon initialization. Eventually, I’m planning to have all the mesh data to be store inside some local files and have a file processor to convert the local files to MeshData instances. For the sake of time, I didn’t implement the file processor for this assignment, and instances of MeshData were coded within Graphics.cpp as globals.
To initialize a mesh, an instance of MeshData is needed to be passed as a parameter of the Mesh::Initialize(MeshData data) function. The initialize function will initialize the geometry data accordingly.
A mesh instance takes 32 bytes in the x64 implementation and 16 bytes in the x86 implementation. The difference is due to the fact that pointers in x64 are 8 bytes whereas pointers in x86 are 4 bytes.
The data size for the Mesh class should be the smallest since all the pointers stored are still needed after initialization.
Be “const right”: Use const keyword to avoid unexpected modification of data.
This assignment is pushing me to think about how to design a reusable system. The decisions I made are not necessarily the best, but they are the best I can think of right now. I’m looking forward to the future examination, and hopefully I don’t have to change much of my design.