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
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
Place the OpenGL headers and stub libraries within the appropriate location
for your development environment.
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
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
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.
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
- QuesaMemory.h defines the Quesa memory manager - all memory management
within Quesa must go through these routines, rather than accessing
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
- 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
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