Building Quesa

Quesa is written in ANSI C, and has been built on a variety of platforms with various development environments. Supported environments are:

  • Metrowerks CodeWarrior Pro 7 or later
  • Microsoft Visual C++ 5.0 or later
  • gcc (Linux/Be)

Building Quesa on Mac OS

OpenGL

Mac OS developers will normally be using CodeWarrior as their development environment. Unfortunately CodeWarrior Pro 7 does not include the OpenGL SDK from Apple, and so this must be installed separately.

The OpenGL 1.0 SDK from Apple can be found here. Place the OpenGL headers and stub libraries within the appropriate location for your development environment.

CodeWarrior Projects

Please note that the CodeWarrior .mcp project files are distributed in Pro 7 format. It may be possible to open hese projects using older versions of CodeWarrior, however typically access path settings will be lost in the conversion.

To build Quesa using older CodeWarriors, you must manually add "::::SDK:Includes" and ":::Source" to Quesa.mcp. To build the Example applications, you must manually add "::Qut" and ":::Includes".

Note that the current CodeWarrior projects include Mac targets only. However, it is also possible to build the Windows version of Quesa with CodeWarrior. Be sure to turn on the "Enums Always Int" option in the C/C++ Language settings.

Building Quesa on other platforms

For other platforms you should also obtain appropriate OpenGL headers and libraries, although these will often be supplied by your compiler vendor.

If you do not have access to OpenGL on your platform, you may want to try the Mesa implementation (which fully supports Quesa).

Porting Quesa

Quesa has been designed to be extremely portable, and all of the platform specific code is contained within a single well defined source area.

Non-portable code is not allowed within any other area of the source tree, except when an API call acts as a wrapper around the platform specific implementation (but these are extremely rare, and it is unlikely that more cases of this sort will be needed).

Typically, only five platform specific files are required for a new platform 'Foo':

  • E3FooDebug.c - debugging support
  • E3FooDrawContext.c - platform specific draw context objects
  • E3FooPrefix.h - platform specific build constants
  • E3FooStorage - platform specific storage objects
  • E3FooSystem.c - system level support (e.g., scanning for plug-ins)

Porting Quesa to a new platform should not involve anything more than providing implementations for the functions in these files.

Coding Notes

Rather than try and put any structure on them, here are a list of coding notes you may find useful when adding code to Quesa:

  • Global state should be avoided if at all possible (it introduces locking requirements for preemptively threaded environments). Any global state which does have to be added should be added through the global data structure in E3Globals.h.

  • QuesaMemory.h defines the Quesa memory manager - all memory management within Quesa must go through these routines, rather than accessing malloc/free directly.

    This gives us an extra level of indirection to add debug code, and allows us to adjust our behaviour on platforms with badly performing C libraries.

  • E3Version.h defines the version for the build. This is reported back by the version API calls, and can also be used for platform specific purposes (e.g., the Mac build uses this to create a 'vers' resource).

  • The initial source tree for Quesa was generated automatically by a Perl script from the QD3D header files.

    This has produced a high degree of consistency between source files - in order to keep the source accessible to as many developers as possible, please make sure you conform to the current framework when adding new source files (e.g., naming conventions, function headers, etc).

  • Always turn on all of the warnings your compiler allows, and make sure that new code does not produce warnings when compiled.

    This is particularly important when writing cross platform code, since compiler warnings often indicate portability problems.

  • Since Quesa is written in ANSI C, be careful not introduce any C++isms inadvertently. Examples would be inlined functions, references, 'and'/'or' keywords, declarations after statements, or declarations within for/while loop containers.

    Note that the one exception to this rule is for platform specific directories, where code may need to be written in other languages (C++, Objective-C, etc) in order to talk to the underlying platform API.

    However, the majority of the code within the platform specific directories should be written in ANSI C if possible.

  • Floating point constants should have an 'f' suffix (e.g., "1.0f" rather than "1.0"). This is because floating point constants are actually doubles under ANSI C, so not providing an explicit type can produce lots of warnings under some compilers.

  • Platform specific types, functions, or #includes should only be used within the appropriate source area for that platform.

  • Quesa functions which call other Quesa functions must always go back out through the Q3xxxx entry points.

    This ensures these functions get the same debugging code that applications enjoy, and that various housekeeping functions get called.

    The only exception to this rule is the E3Math.c routines. For speed, these are allowed to call each other directly without going through the public API.

  • Do not, if possible, put structures in header files. Define an opaque type, and provide accessors to get/set fields within the structure.

    This should be followed for even the simplest of structures - it lets you change the implementation of the module at a later point without breaking any other code within Quesa.

    There are only two exceptions to this at present within Quesa, both of which are required for architectural reasons (and which will be removed in the future).

  • If an object can be inherited, it must look up its instance data by hand - it can not assume that the object it is passed is of the type that it needs.

    For an example, look at the definition of a TQ3SharedObject.

    The methods for this class can be passed any object which is a descendent of TQ3SharedObject, so the instance data for the shared object must be discovered by walking back up through the parents of the supplied object until the shared object is found.

    The exception to this is where you know you're dealing with a leaf class: e.g., a triangle object can use a simple cast to obtain the triangle data since triangle objects can not be inherited.

  • Public functions must have prototypes declared in the appropriate header file for their module, while private functions must be declared as 'static'.

  • Public functions should be named 'E3Module_Function', while private functions should be named 'e3module_function'.

  • Use QD3D types rather than C types, since this allows you to specify the bit range and signed/unsigned-ness of the type (e.g., TQ3Int16 rather than signed short). This will help us in the future when we look at 64-bit architectures.