- Read the coding standards below.
- Keep PR simple and focused - one PR per feature.
- Make a Pull Request.
- Check back if any revisions are requested.
Feel free to contribute bug fixes or documentation fixes as pull request.
If you are looking for ideas what to work on, head to Issues and checkout out open tickets or start a conversation. It is best to start conversation if you are going to make major changes to the engine or add significant features to get advice on how to approach it.
Try to keep PR focused on a single feature, small PR's are easier to review and will get merged faster. If your PR is too large, we'll want it get broken down to chunks of small features.
Simple code is always better. Write for people not for the machine. The compiler will take care of the tiny optimizations for you.
For example, use "Initialize" instead of "Initialise", and "color" instead of "colour".
glm::vec3 vector{ 1, 1, 1 };
instead of
glm::vec3 vector(1, 1, 1);
//or
glm::vec3 vector = glm::vec3(1, 1, 1);
For example:
// Notice there is no new line before the opening brace
int main() {
return 0;
}
Also use the following style for 'if' statements:
if (true) {
// do something
} else {
// do something else
}
Always use braces, this applies to where braces can be omitted:
// Notice the braces
if (true) {
then();
}
if (condition) { then(); }
else { then2(); }
struct A {} // demonstration only, we shouldn't have empty structs
void Foo() {}
// Assume dots are spaces, WRONG
if (x == 0) {........
then();.....
}.....
// Assume dots are spaces, CORRECT
if (x == 0) {
then();
}
On save, set your text editor to remove trailing white spaces.
int x = 16 + 32 / 4;
int x = RandomNumberBetween(0, 100);
for(auto itr = someIterable.begin(); itr != someIterable.end(); ++itr) {
// do something
}
foo();
bar(1, 2);
while(true);
for (;;)
if (false) {}
int b[5] { 8, 20, 25, 9, 14 };
int a[10];
glm::vec3 vector{ 1, 1, 1 };
Variable declarations should only appear in a function when the variable itself is needed.
Variables should be declared one per line. (This one is permissive, there are times where you can break this rule, left it up to you.)
void foo() {
std::string x = "I'm a string";
cout << x << "\n";
int y = 3;
cout << y << "\n";
}
When checking for nullness, or parameter correctness, exit functions early. Be a never-nester.
// Don't do this
void SomeFunc(int* x) {
if (x != nullptr) {
/*
* Logic
*/
}
};
// Do this
void SomeFunc(int* x) {
if (x == nullptr) { return; }
/*
* Logic
*/
};
Namespaces, global variables are banned. Global functions are preferred over where appropriate.
// Global functions names are PascalCase
void UselessFunction() {}
// Struct names are PascalCase
struct Sample {
...
};
// Member variable names are camelCase.
struct IntArray {
int* arrayOfInts;
};
// Member functions names are PascalCase
struct Foo {
void Bar();
};
// Constant names are PascalCase, separated by underscores.
constexpr int ThisIsAConstant = 5;
int id = 1; // not "ID";
int GetID() { ... }; // not "GetId()"
CRUD *c = new CRUD(); // not "Crud";
If a member should be private and trivial getters and setters are to be provided; we don't do that here. "private" variables with setters are oxymoron and cause confusion, and are to be used with caution.
// DON'T
class Point2D { // this is pointless to do and verbose with no good reason
int GetX() const;
void SetX(int x);
int GetY() const;
void SetY(int y);
private:
int x;
int y;
};
// DO
struct Point2D {
int x;
int y;
};
Users of NeoDoa should not have to browse functionality namespace by namespace. Therefore, namespaces are banned. Any and all functionality of NeoDoa should be declared and defined in the global namespace. Usage of detail
namespaces to hide implementation details are allowed, but should be kept to a minimum.
For the class
keyword, developers should favor the struct
keyword and put the public API to the top of the struct
.
// DON'T
class Something { // class - implicitly private members. usage of public: is mandatory
public:
void DoWork();
void DoWork2();
private:
int data;
int data2;
};
// DO
struct Something { // struct - implicitly public members. usage of public: is redundant
void DoWork();
void DoWork2();
private:
int data;
int data2;
};
If a member function is to be defined in the header, there must be a good reason to do so.
Template functions are an example of a good reason.
Functions marked inline
are an example of a bad reason. They have no positive benefits. They increase compile times.
// hpp file
struct Example {
void DoStuff(); // good
inline void DoMoreStuff() { // go to the cpp file please...
int x = 5;
}
template<typename T>
void DoEvenMoreStuff() { // valid reason to define in hpp
int xxx = 999;
}
};