Lite-C for C/C++ programmers

Lite-C is very similar to the C language, but has some differences to make it easier approachable to beginners, and allow for a simpler compiler structure. In most cases - when no particular C++ features, like STL, are used - a C/C++ programm can be easily converted to lite-C. Examples for this are the DirectX samples that come with the lite-C installation; they are just slightly modified versions of the original C++ samples from the DirectX 9 SDK. The differences are listed here:

Pointers

Lite-C supports pointers, but does not require the '->' operator (although it's also supported and can be used if preferred). For addressing struct elements '.' can be used regardless if it's a pointer or not. If a function expects a pointer, lite-C automatically adds the '&' operator if required.

&&, ||

In C/C++, comparisons are early aborted when a && is encountered and the expression left of it evaluated to false, or when a || is encountered and the expression left of it evaluated to true. Lite-C does not early abort expressions. This requires a different syntax when early abort is used for checking the value of a struct pointer and its element in the same expression:
if((ptr != NULL) && (ptr->element == ..)) .. // C/C++
if(ptr != NULL) if(ptr->element == ..) .. // lite-C 

Trinary operators

Lite-C does not support the comparison ? expression : expression; syntax, so an if statement must be used instead.
x = (x<0 ? -1 : 1); // C/C++
if(x<0) x=-1; else x=1;  // lite-C 

Struct member alignment

In lite-C, struct members are always aligned to 1-byte boundaries. This ensures that a char really occupies only 1 byte in a lite-C defined struct, and a short only 2 bytes. For exchanging structs between lite-C and external languages, make sure to set the alignment accordingly (in VC++: Properties / C/C++ / Code Generation / Struct Member Alignment / 1 Byte). For speed reasons, it's recommended to put 4 chars or 2 shorts together in structs, which ensures alignment on 4-byte boundaries.

Struct and array initialization

In C/C++ structs can be initialized just like arrays, by giving a list of member values, like VECTOR myvector = { 0,0,0 };. This is only supported for global arrays in lite-C. Local structs can not be initialized this way, and local initialized arrays automatically get the static property. Lite-C initializes all global arrays and structs automatically to zero; local arrays and structs are normally not initialized and thus contain random content. You can use the zero() macro (defined in acknex.h) for initalizing local structs to zero, and vec_zero() for initializing vectors consisting of 3 vars:
VECTOR speed;
...

vec_zero(speed);	// initializes the VECTOR "speed" to x=0,y=0,z=0

For migration and testing, lite-C can automatically initialize also all local variables to zero with the PRAGMA_ZERO definition. If you add

#define PRAGMA_ZERO   // initialize variables

at the beginning of your script, all uninitialized local variables and structs are set to zero. This slows down function calls a little, so it's preferable not to to use PRAGMA_ZERO in your final version.

Struct copying

In C++, structs can be copied into each other with the '=' operator. In C or lite-C, use memcpy for copying structs:
// C++:
D3DXVector3 vecA, vecB;
...
vecA = vecB;

// lite-C:
D3DXVector3 vecA, vecB;
...
memcpy(vecA,vecB,sizeof(D3DXVector3));

Enums

Enums are not supported and can be replaced by defines:
enum RGB { RED=1; BLUE=2; GREEN=3 }; // C/C++

#define RED 1 // lite-C #define BLUE 2 #define GREEN 3

Unions

Union members of the same type can be substituted by a #define, and union members of different type can be treated as a different members of the struct. Example:
typedef struct S_UNION { 
   int data1;
   union { int data2; float data3; };
   union { int data4; int data5; };
} S_UNION; // C/C++

typedef struct S_UNION { int data1; int data2; float data3; int data4; } S_UNION; // lite-C #define data5 data4

If the struct size must not change, or if for some reason the program requires different variable types to occupy the same place in the struct, a special conversion function can be used to convert the type of a variable without converting the content:

typedef struct S_UNION { 
   int data1;
   union { int data2; float data3; };

} S_UNION; // C/C++
...
S_UNION s_union;
s_union.data3 = 3.14;

typedef struct S_UNION { int data1; int data2; } S_UNION; // lite-C #define data3 data2 ... int union_int_float(float x) { return *((int*)&x); } ... S_UNION s_union; s_union.data3 = union_int_float(3.14);

Function pointers

In C/C++, function pointers are declared like this: int (*foo)(int a, int b);. In lite-C there's no difference between function prototypes and function pointers: int foo(int a, int b);. See details under pointers.

Signed or unsigned variables

In lite-C, var, float, double, long and int variables are always signed, and pointers, char and short are always unsigned, according to the normal way they are used. The signed and unsigned variable modifiers are accepted, but have no effect. The include\litec.h file contains definitions for all usual unsigned variables like DWORD or WORD that are used in Windows functions. Therefore, using unsigned variables normally does not cause any problems. However you need to take care when variables exceed their range. For instance, subtracting 1 from (DWORD)0 results in -1 under lite-C, but in 0xFFFFFFFF in standard C/C++, and would produce different behavior in comparisons.

Prefix operators

Lite-C makes no difference between prefix and postfix operators; they always return the result of the operation. i++ is the same as ++i.

min, max

These often-used macros are replaced by simple functions: minv and maxv for var, and minf and maxf for float. The latter are no engine functions, but defined in include\windows.h.

sin, cos, tan, asin, acos, atan

The trigonometric functions are overloaded with their C-Script counterparts and use degrees instead of radians when called with a var or int argument. For enforcing the use of radians regardless of the argument type, use the (float) cast operator, as in sin((float)1).

printf

This old fashioned DOS output function won't work in normal windows programs, but is supported in lite-C pure mode for convenience reasons. It opens a message box (see printf). Make sure in its argument list to cast a var to (long) or (double), and convert STRING* to char* with the _chr function.

Main() function

In C/C++ the main() function terminates the program on return. In lite-C an explicit sys_exit(NULL) call (or clicking on the close icon) is used to terminate the program. Also, in C the main() function does not open a window; in lite-C the main() function automatically opens a DirectX window in the first frame if this is not explicitely prevented by setting video_screen=0;.

Adding C library functions

Lite-C contains only a subset of all functions from the standard C/C++ libraries, but you can add any function that you need as described under Using the Windows API. Here's a brief instruction of how to add a API function to lite-C:

If you need certain structs or variable types that are not yet contained in include\windows.h or in the other standard include files, just add them from their original file either into your script. If you think that a certain function, struct, or variable type is often needed, suggest its inclusion into api.def on the Gamestudio future forum rather than modifying api.def yourself. Self-modified files are overwritten by lite-C updates.

Converting DirectX programs to lite-c

DirectX and other Windows SDKs use the Component Object Model (COM) as described in the API chapter. For convenience, the Windows interface definitions (like DECLARE_INTERFACE_ and STDMETHOD_) are already contained in the lite-C include\d3d9.h file, and all basic classes are already defined within. So it'is easy to add further interface classes when they are needed. Just copy the class definition from the original d3d9.h or other DirectX header file into it's lite-C counterpart, and add the inherited methods (if any) from the parent class.

Although lite-C can use all DirectC classes and functions, it lacks some advanced C++ features such as operator overloading. Thus, for setting up, adding, subtracting, and multiplying D3DX vectors and matrices, the overloaded =, +, -, and * operators can't be used. Use the DirectX library functions, such as D3DXVec3Add etc. instead. For setting up vectors, the following convenience functions have been added to include\d3d9.h:

D3DXVECTOR3* D3DXVec3Set(D3DXVECTOR3 *pOut,float x,float y,float z,float w);
D3DXVECTOR3* D3DXVec3Set(D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pIn);
D3DXVECTOR3* D3DXVec3Set(D3DXVECTOR3 *pOut, CONST D3DXVECTOR4 *pIn);
D3DXVECTOR4* D3DXVec4Set(D3DXVECTOR4 *pOut,float x,float y,float z,float w);
D3DXVECTOR4* D3DXVec4Set(D3DXVECTOR4 *pOut, CONST D3DXVECTOR3 *pIn);
D3DXVECTOR4* D3DXVec4Set(D3DXVECTOR4 *pOut, CONST D3DXVECTOR4 *pIn);

When converting an engine VECTOR to a D3DXVECTOR3, make sure to swap the y and z coordinates. DirectX uses a different coordinate system.

With the above simple modifications, almost all DirectX examples that you can find on the Internet or in the DirectX SDK can easily be converted in a couple of hours and compiled under lite-c. You can find a converted version of the DirectX tutorial samples in the samples folder.

Compiling a lite-C script with other C++ compilers

As long as you don't use any special lite-C syntax, like global struct initialization or pointer autodetection, you can normally compile a lite-C legacy mode script with any other C++ compiler. Here's an example how to compile the mandelbrot_legacy.c file with Visual Studio 2003:

See also:

Pointers, Structs, Functions, Windows API ► latest version online