NC* is written in the ODIN programming language. Before we begin, it is expected you have some knowledge of low-level programming languages, or ideally a basic understanding of ODIN. This guide will not be teaching programming.

The reasons to choose ODIN are multifaceted, but the primary reason is its simplicity and approachable design, certainly far easier to pick up than C or C++. There will be references to things like cstring and string, where you will be expected to know how to use them in what circumstances.

As ODIN has no concept of references, we will do our best to explain best practices as the by-value concept may seem strange initially for those used to using references. You very rarely need to dereference a pointer in ODIN, unlike in C/C++ where it's practically everywhere. In fact, as time moves on, it is unlikely NC* will be dereferencing anything.

Other things to note:

Now this is all said and done, let's move on.

Concepts

There are two different concepts in NC* to understand before we can move onto coding.

When creating our own custom components, understanding these two concepts is vital for the construction of these components and how they are drawn.

Below is the expected dependency chain.

  1. ShapeCompositionComponentDefinitionComponent

As you can see, there is no data involved. That's because we are storing data globally and accessing it per Component.

When creating definitions, we give an identifier which we use to construct with later. Then, Components are added to the global state from these definitions which are used to create our interface. If they hold content, the Content type is used for holding our content and is assigned to the global state and accessed via the integer identifier given to us from the global stack. We can use this to move data around easily, instead of trying to use procedures to pass around our data all the time.

In the case of Content, we take advantage of the union type in ODIN which we use to hold a certain specific number of types we would accept. This is compile-time types which are easy to type-check and less error-prone than using the any type we could have used. Note that when we use Content, basic types are copied by value as usual, but user-defined types will be pointers to an underlying type. Moreover, when dealing with these pointers, we are expecting the underlying types to be heap allocated, not stack allocated.

The main reason to do this is because Content as a type in the global stack is a value type, not a pointer, so if data is considered “complex” (i.e., not a basic type), then heap allocate the data and make a reference to it for the Content to use later. This prevents loss of data or losing data in scopes where we expected a value copy. You can use the temp_allocator when allocating if a memory arena is preferred over a straight heap allocation, or your own allocator. The reason the Content type is a union is we can expand this to store values of any type which you, the user, can type-check manually later if desired.

Structure

Besides the basic structure defined above for building interfaces, everything else is left to the user to define how to structure the Components themselves.

All your member variables, procedures and business logic is done yourself if building components from scratch, and NC* will not care much how that's done, besides one simple caveat:

We try our best to make your life as simple as possible in this regard.

We can move on to the next chapter once you're ready.