DarkRadiant coding standards: Difference between revisions
No edit summary |
|||
Line 29: | Line 29: | ||
* All data members should be private, except in data structures which provide no methods (other than constructors). | * All data members should be private, except in data structures which provide no methods (other than constructors). | ||
* Members which need to be accessed externally should be provided with get/set methods. | * Members which need to be accessed externally should be provided with get/set methods. | ||
==Module interface== | |||
The design of DarkRadiant is a modular one. Each module encapsulates a certain amount of functionality, such as the '''entity''' module which provides entity creation and rendering, and the '''model''' module which loads modules from ASE, LWO or MD5 files. Each module implements an interface which is defined in an "i*.h" file in the '''include''' directory (such as "imodel.h" and "ientity.h"). There is also a '''Radiant''' module whose interface is specified in "qerplugin.h". | |||
Modules access each other using inline functions defined in the interface header file, such as '''GlobalRadiant()''' or '''GlobalShaderCache()'''. These functions return a reference (or pointer) to a static instance of the corresponding module. The initialisation order of modules is important, and this is controlled via the use of a '''ModuleRef''' template, which instantiates and maintains a reference to a singleton module instance, and "Dependencies classes" which are empty classes that inherit from a number of ModuleRef templates, thus ensuring that each ModuleRef is constructed before the Dependencies class itself. |
Revision as of 09:50, 28 October 2006
Although DarkRadiant was forked from GTKRadiant, there are new coding standards which should be used for new code, in order to maximise readability for developers.
Naming conventions
- All new code should be in a namespace, such as ui for UI-related code or model for code dealing with models.
- Class names should begin with a capital letter and capitalise each word: RenderablePicoModel, TextMenuItem
- Classes represent "things", therefore they should be named after nouns not verbs: ModuleLoader rather than LoadModule.
- Each new class should be contained within its own file pair: MyClass is contained in MyClass.h and MyClass.cpp. This rule does not apply to tightly-bound local classes, such as a functor class which is used by only a single method in a .cpp file. It is also acceptable to define trivial data structures returned by methods in the header file declaring the method, if that data structure is not used elsewhere.
- Method names and local variables should start with a small letter.
- Member variables should begin with an underscore: _widget. Do not use the "m_name" convention in new code, as this is harder to read.
General code structure
- Always use Object-Oriented design methods wherever possible. Think in terms of objects which define methods to act on those objects, rather than C-style functions that process data structures passed as arguments. Non-member functions are OK for minor tasks, as long as they are within a namespace rather than at global scope.
- Always use STL or Boost objects, rather than home-grown reinventions of the same thing. Use std::string not CopiedString, and std::map in favour of HashedCache. Classes that use these home-grown versions should be modified so as not to use them if at all possible, and eventually they will be removed.
- Never use global variables.
Static variables
If a static variable is required, encapsulate it within a small method that returns a reference to the static, e.g.
MyObject& staticInstance() { static MyObject _instance; return _instance; }
This ensures that the static instance will be initialised when the method is first called, which avoids problems with the undefinability of static initialisation.
Access
- All data members should be private, except in data structures which provide no methods (other than constructors).
- Members which need to be accessed externally should be provided with get/set methods.
Module interface
The design of DarkRadiant is a modular one. Each module encapsulates a certain amount of functionality, such as the entity module which provides entity creation and rendering, and the model module which loads modules from ASE, LWO or MD5 files. Each module implements an interface which is defined in an "i*.h" file in the include directory (such as "imodel.h" and "ientity.h"). There is also a Radiant module whose interface is specified in "qerplugin.h".
Modules access each other using inline functions defined in the interface header file, such as GlobalRadiant() or GlobalShaderCache(). These functions return a reference (or pointer) to a static instance of the corresponding module. The initialisation order of modules is important, and this is controlled via the use of a ModuleRef template, which instantiates and maintains a reference to a singleton module instance, and "Dependencies classes" which are empty classes that inherit from a number of ModuleRef templates, thus ensuring that each ModuleRef is constructed before the Dependencies class itself.