Tuesday, 30 July 2013

The Design

Hi again!

   Today I want to share some design principles which I tried to both fulfill and achieve during development of graphics framework. Some of them are more important, some less, others changed during last year or probably will change in the future. But in general this is something I'm trying to keep in mind when I sit down in front of my computer and continue to create the library.
   Here's a list (in no particular order):
  1. Graphics API independence - this the most important rule for me and the one from which everything started. I wanted to create a library that could be independent of the graphics api. Developer should be able to choose the api used for rendering and that's all - no other code specific neither for OpenGL nor for Direct3D should be required in the development process of the program linking to graphics framework.
    Probably I'm not that far in stated api independence as I would like to be (mainly because I don't have too much expirience in D3D) and I'm sure this will come with some sacrifices but I hope it is something I could gradually draw nearer to.
    And I should probably clarify one more thing - my library exposes set of classes which allows to easily develop 3D application but 3D graphics programming knowledge is required when using graphics framework. For example shaders aren't translated from one shading language to another and there's no abstraction layer provided for the shaders. So if one chooses to use OpenGL as the graphics api used for rendering but will provide shader code written in HLSL compilation errors will occur (meaning some objects won't initialize).
  2. Coherent, clean interface - all classes should expose similar set of functions, functions should follow the same naming conventions and the same rules when taking parameters etc. Graphics framework should be easy to use, all objects should be used in similar ways etc. It is quite obvious but when the number of classes gets bigger and bigger such things are not always easy to control. That's why I try to keep interface clean and I don't want to litter it with too many functions and members. To keep it that way I follow next 2 rules.
  3. RAII - "resource acquisition is initialization" is a quite popular design pattern. During development process I have tried different approaches when prototyping classes for my graphics framework. Sometimes it felt natural for a particular class to expose additional functions (i.e. SetShader() for effect class or SetTargetTexture() for render target class) but after testing and during further development it became clear that this approach has more flaws than advantages. Classes that had such functions were harder to maintain. I had to deal with some special cases. And I also had to add functions to other classes that were connected with the ones not following the RAII principle. So I removed all setter functions. Resources can be defined only through constructors or Create() functions (which behave identically to constructors). I'm also thinking about removing all Create() functions so the resources could be created only through constructors and assignment operators.
  4. PIMPL - "pointer to implementation" idiom is something I was considering from the beginning. I wanted to hide all member variables from library clients (to keep api clean) which also allows me to modify all operations that are going inside the class without modifying class's definition (which reduces compile time). And I wanted to learn how to use it properly because I didn't have the opportunity yet. And I still don't know if I want to fully release (meaning open) code of my creation.
  5. Not only graphics - as a framework (not only graphics api wrapper) library should also include some classes that will allow to create application window, manage system messages and drawing loop, measure time or read user input. I have added some helper classes for these tasks. Right now graphics framework supports windowed and fullscreen modes (with default, desktop resolution), reads input from keyboard and mouse (relative and absolute), and has classes which allow to track beginning and end of rendering a frame or changing the size of a window. There are also 2D, 3D and 4D vector and 3D and 4D matrix classes which implement typical linear algebra operations. Probably this list of helper classes or interfaces will evolve in the future.
  6. Windows - as a target platform. I know many of You will hate me for this and will stop reading my blog (if there is anyone) but I have almost no experience writing programs for Linux/Unix systems (not to mention creating and using libraries). I'm windows developer, I'm using Visual Studio, and right now I just don't have time to change that. BUT...
    Most of the classes don't have any OS specific code. I was using some Visual Studio specific C++ language extensions (like "abstract" keyword) but I'm trying to remove most of it. So I think it wouldn't be too hard to migrate it to another operating system. And speaking about C++...
  7. C++11 - I wanted to learn the newest version of a C++ standard. I had to dig into C++11 in my job so it was easier for me to also use it in my private project. Then in November 2012 Visual Studio compiler CTP was released which had better comliance with the standard. So I finally incorporated it into graphics framework. There are many advantages of using C++11 compared to the previous version that made working on graphics framework whole lot easier: delegating constructors, initializer lists, unique and shared smart pointers, variadic templates, scoped or strongly typed enums, r-value references, auto, range-based loops, virtual functions overrides and virtual functions final identifier, nullptr. I've listed only those I'm using in graphics framework library and the ones that are supported by Visual Studio. I think all of them were very usefull. There are even more usefull features like uniform initialization, member initialization or STL C++11 compliance which VS2012 doesn't support (that's why I'm thinking about changing VS2012 to 2013).
  8. Tech demos/small 3D apps - graphics framework is designed to ease the development of small, realtime 3D apps and technological demonstrations. Why?
    Some principles like RAII or graphics api indepence come with a cost. There has to be a tradeoff between flexibility, maintainability, performance and a usability. Not all features from D3D can be exposed if OpenGL doesn't support them and vice versa. If some feature is absent it can be for example simulated. But performance will suffer is such cases. There also has to be some abstraction layer that provides interface for using both graphics libraries. Performance once again will decrease.
    It is against my nature. I've always tried to improve performace. If I could or if I knew how I always wanted my software to work as fast as possible. But I also know my limitations. It is one my biggest projects. I've never used some of the design patterns or principles. So I know that performance won't probably be too high. Maybe it won't also be so bad - I didn't test it in a performance crucial applications. But tech demos feels like a natural fit, like a common usage for a graphics framework.
   What do You think about my list? What would You add, remove or change? (I need to encourage You to post comments ;-)) I know it is too early for You to have Your own thoughts about the project so next time I will post my first sample usage - full code and screenshots of my "Light Shafts" tech demo.
   Till next time. Bye!

No comments:

Post a Comment