INDEX Frame Buffer
TRIANGLE LIST Init
MATH VIRTUAL GPU Init |
Quark 3D graphic
library for pocket PC
1/ QUICK OVERVIEW Quark 3D is
a compact graphic library for pocket pc. It provide a minimal set of
functions to draw 2D and 3D graphics, and is mainly optimized for
speed. The main
features are: 2D
Drawing: 3D
Drawing: Draw
triangles in following modes: For 3D, an
immediate drawing mode using separate triangles, or some triangle list
using flexible vertex format can be used. Structure
ready to support future 3D hardware. Automatic
detection of blit function to use for compatibility with standard pocket
pc 2003 and previous ppc version ('old' iPaq 36xx to 38xx
serie) Provide a
mimimal set of math/matrix/vector functions working on integers and highly
optimized for speed. Full
documentation included in this page, and 15 tutorials. Use a single
small dll (size is 52kb) and a single header file. Royalties free
for pocket pc applications. 2/ TECHNICAL OVERVIEW Every graphics
are drawn into an offscreen buffer containing z buffer + pixels data. When
the scene drawing is completed, a blit function copy this buffer into
video memory to display a new frame. Frame buffer
size is a linear array on 240*320 32bits unsigned integer
value. Each pixel is
coded on unsigned integer value as follow: b0-b7: 8 bits for base color in
fixed palette The Z buffer
value contain 1/z (z > 0) scaled by 2^INVTBL_SHIFT (INVTBL_SHIFT =
22) Example: if z = -100 in
world 3D coordinate: For this
reason, minimum drawable distance is 64 (-CLIPZ_NEAR) that give (2^22 -
1)/64 = 65535, that is the maximum value that can fit on an unsigned 16
bit. Note: near
pixels have bigger Z buffer value than far objects. For every
graphics, pixels, lines, sprites, and triangles, Quark use a fixed palette
of 256 base colors + 32 intensity shading level for each color. Textures are
used to draw triangles or sprites. A texture
pixel is stored on 8 bits and allow to code 8 base colors on a fixed
palette. For each color there are 32 level of intensity and give at total
256*32 = 8192 color. +y is up, Axis are
oriented direct, (rotating x onto y with trigonometric rotation give
+z). Because floats
values are avoided for speed considerations, all 3D coordinates are stored
on integer values. To obtain a good accuracy in 3D transformations, use
objects with 'big' size. For example, 200 or more units length can be used
for a car. This depend too of complexity of object. 1/ - Get object initial vertex
position. These positions are defined relatively to object local axis. for
example for a sphere, center is at 0,0,0 and vertex are located at radius
distance around center. 2/ - Define a transformation matrix.
This matrix define how to translate/rotate/scale object to desired
location into World 3D coordinates. 3/ - Transform vertex initial
positions into new World 3D positions using the matrix and
Matrix::TransformVector function. 4/ - The visible part of world is
located in view frustrum 3D area. If a bounding
box (BBox) is defined for object (3D box including all vertex), test if it
cross the view frustrum. In not, the object is not in field of view and
there is nothing to display. If it cross,
convert all vertex 3D positions to 2D positions using 3D -> 2D
projection function (use CVGpu::ScrProjection function). Store the
clipping mask m returned by CVGpu::ScrProjection function. This m value
define a binary mask depending of the vertex position relative to view
frustrum. if m = 0 then
vertex is visible into frustrum, else it is not visible and m bits define
relative position as follow note that if
b5 = 1, the CVGpu::ScrProjection function do nothing and do not return 2D
coordinates, this because is is not possible to transform if z=0 (require
a division by 0 or if z to small (1/z become too big and produce
overflow), or if z < 0 (negative distance ?) 5/ For each triangle of object to
draw, check clipping mask. note: if
triangle is visible but one of the vertex have b5 = 1 for clipping mask,
then it is not possible to draw triangle because the 2D coordinates of the
vertex are not available. The solution consist to truncate the triangle
with the near clip plane using 3D world coordinates. note: Step 3
to 5 are done by CVGpu::DrawTriangleList function (including near clip
truncate). At Init, the
CVgpu object allocate about 360k of memory to work (Frame buffer, math
table, etc..). If Triangle
list or Z sort of faces (alpha) is used, then some additional memory must
be allocated. This can be done using CVgpu::SetWorkMemory. 2/ MAIN HEADER Quark 3D use a
unique header file for interfacing with applications. The second
main object is CTriangleList,
that manage triangle list containing some vertex + vertex index (triangle)
and draw command list. 3/ MAIN HEADER DESCRIPTION The following
text describe sequentially every part of quark.h header
file. Cannot be
changed because dll have been compiled with these defined
values. // screen
size Define screen
size. // color
definition for offscreen bitmap (*VGpu.VScreen) GD_BITS define
number of bits used to code intensity for a base color. Current value of 5
allow to code 32 values. (2^5). 0 = dark, 31 = max intensity. Note that it
is the framebuffer coding. The user must normaly use 0..255 range to
define an intensity. RD_BITS = 2
allow to code 4 level of red for each base color // convert RGB
888 to base 8 bits RGB color This macro
allow to convert a RGB value coded on 3 bytes (RGB888 range [0..255]) to a
RGB value coded on 1 byte in RD_BITS GR_BITS BL_BITS format (RGB233). This
define a base color. // convert 8
bits intensity value to VScreen format intensity This macro allow to define an Intensity value that can be combined with a base color to obtain a Color+Intensity value. This value can be written directly into framebuffer. example: to obtain yellow color with intensity = 128 (Intensity range is 0..255), use: int Yellow128 = COLOR_RGB(255, 255, 0) | COLOR_I(128) Note that this function is used only to define a color + intensity for PutPixel function. // max clipping values for near and far clipping planes for rasterization #define
CLIPZ_NEAR -64 These values define max allowed range of z in world coordinate
notes: - Camera in 3D to 2D projections look on -z, then 3D clipping positions are negatives. - Gpu.Init(int NearClp, int FarClp, ..) function must use NearClp and FarClp in this range with NearClp > FarClp. Passed NearClp and FarClp define z position of clipping planes that must be in [CLIPZ_NEAR..CLIPZ_FAR] range. Triangle that are not in this range will be not displayed. - 3D to 2D projections change sign of Z value to work with positive values in raterization functions. // scale of
uv Value used to convert floating point texture coordinates to integer coordinates used by system. example: for origin u value of 0.241 -> use 0.241*256 = 61 note: u + k*256 = u. Texture coordinate loop (same than 1.0 value in floating point system). This rule cannot be applyed for a set of texture coordinates if texture is tiled, and the following rule must be applyed. To draw a textured triangle, uv values must be positive without constant offset. A constant offset is a multiple of 256 common to the 3 u or v of each vertex. exemple of u
value for triange ABC this set of
values have a constant offset of 512, and must be corrected to : This allow to reduce uv values and ensure that no overflow will occur in rasterization. It allow too a more accurate rendering of textures. note: The same thing must be done if one of the texture coordinate is negative, then a positive offset of k*256 (k [1..n]) must be added to obtain 3 positives u and v values. This work is done by ConvertUv() function, and internally done by TriangleList::BuildCmdList function. //
rasterization modes For DRAW_OPAQUE, the frame buffer is always updated if the z buffer test success. For DRAW_KEYED mode, pixel is drawn and z buffer updated only if texture color != color key. Color key define a texel color that must no be drawn. For DRAW_ALPHA and DRAW_ALPHAKEYED keyed mode, z buffer is tested but not updated. DRAW_ALPHAKEYED mix ALPHA and KEYED mode, then draw an alpha pixel if texture color != color key. This mode is available only for sprites. (ex: ghost on demo2.cpp) note: color key can have a different value for each texture, and must be defined in CTexture.Init function. // drawing
mode of triangles Define how to draw triangle. Textured, Textured with perspective correction, untextured, or in wireframe.
// error
code for functions, stored in ErrorCode if error occured These defines are used by CTriangleList object, and CVGpu DrawTriangleList function. Most of CTriangleList functions return 1 if success, else place one of this error code into CTriangleList::ErrorCode and return 0 if fail. This allow to retrieve why error occured. CVGpu::DrawTriangleList function return directly this error code (return ERR_NONE if success). // texture definition int
Init(unsigned char *RGB8, int x, int y, int CKey); Texture
datas are stored on a 8 bit array containing base color of a fixed
palette. Function define DrawMaskX and DrawMaskY (used for rasterization, must be not modifyed). Return 1 if x and y size are power of 2 and in [16..128] range. x can be not equal to y. If 1 returned, texture can be used to draw some triangles, else it can be used only to draw sprites that do not have size constraints. // rasterization states for drawing A
rasterization state is a defined hardware state for rendering. Although
there is no 3D hardware on pocket pc (not yet), this will allow future
compatibility. A specific state initialization must be done every time that: - change
texture to bind on a triangle Setting a
new state require to break triangle rendering process and take some time
to init. So it is good for speed to batch all triangle using same state,
and change states as less as possible. The CVGpu::DrawTriangleList work like that. When building a triangle list (CTriangleList::BuildCmdList), the function batch all faces that can be drawn with same state, and define a command list. (see DrawTriangleList function) There are 3 default rasterisation states defined in CVgpu object for Text/Lines/Sprites. For triangle drawing, a specific rasterisation state must be defined and assigned to CVgpu.TriangleState pointer. (see BuildCmdList and tutorials for more details) TRasterState parameters: - DrawMode - DrawColor - DrawIntensity - TestCulling However, in some case (ex: glass, grid, ..), a face must be visible by the both side (2 sided face). In this case, culling must be disabled. - ZSort When the hole scene using opaque or alphakeyed faces is drawn, then a call to CVgpu::SortDraw function will draw all sorted faces from far to near to ensure correct rendering of alpha. Note: this
is significantly more slow than normal drawing, and must be use with a
small number of faces. - al (3 bytes) - Texture // Vertex format used for direct
rasterization (DrawTriangle function) This is the
vertex format used for direct triangle drawing, using screen
coordinates. x=0, y=0
-> top left of screen m : is visibility mask, value is
used to define if a set of 3 vertex is visible on screen. (see demo5.cpp) Vertex and index format for DrawTriangleList function() // format of
vertex in a vertex list // format of
index to define a triangle in a triangle list These defines allow to specify a flexible vertex format to draw a triangle list. For example, to draw an object that is not lighted and not textured, only vertex position and vertex index (in a vertex list) are required to draw a face. The vertex
format will be: Then the
vertex list will contain only 3 short per vertex, and index list 3
unsigned short per triangle (3 index of vertex in vertex list). To define a custom color for each face, add a color value in index list and define new index format as follow: int
VertexFormat = VF_XYZ; To add intensity for each face (face lightening), define int
VertexFormat = VF_XYZ; Or to define intensity for each vertex (vertex lightening), define int
VertexFormat = VF_XYZ | VF_I; The defined Vertex and index format must be passed to Init function of a CTriangleList object to allocate required memory. Note: The Init function of a CTriangleList object will return error if intensity or uv are defined in both Index and vertex format. class CTriangleList This class used to define a triangle list. short
*VertexList; VertexList contain the vertex list
(VertexListSize * VertexStride short values). To acces to vertex n, use Data = VertexList[n*VertexStride], or use data access function described below. unsigned
short *IndexList; Same coding than vertex list, but contain Index list that define each triangle. IndexList contain the index list
(IndexListSize * IndexStride unsigned short values). A minimal triangle is defined by 3 index of vertex into Vertex List. The following datas are used for internal work of triangle list There are initialized by Init and BuildCmdList functions. // offset to
data into Vertex/Index list, defined by Init function: These variables define offset of datas into a verter or index. Value is 0 if data is not available into index/vertex. (depend of defined format) Example: to
access to color intensity of vertex n into vertex list, use: TRasterState *State; This must contain ptr to a list of rasterization state that will be required to draw the hole triangle list. It can contain only one state if the triangle list use the same rasterization state for all triangles. unsigned
short CmdMin[2]; Command
list: n = unsigned
short 0 n : number
of triangle to draw using same rasterization state For example, to draw an object with 3 opaque textures, the State list will contain at least 3 rasterization states and CmdList will contain at least 3 commands (6 unsigned short). The
CTriangleList::BuildCmdList function batch all faces using same state and
define command list. (and alloc required memory for this command). If the BuildCmdList detect that only one state is used, this list is used instead to alloc a new command list with only 2 unsigned short. eErrorCode ErrorCode; Error code is defined with an eErrorCode enum value if one of the CTriangleList function fail and return 0. CTriangleList functions description: int Init (int VFormat, int VCount, int IFormat, int ICount, TRasterState *StateList) - Alloc
memory to store vertex and index list, depending of defined vertex and
index format. int WeldVertex (int WpDelta, int WiDelta, int WuvDelta) Weld vertex is used to remove redundant vertex. If vertex list contain identical vertex, or small variation in position/intensity/uv, then only one vertex is keeped. This allow to increase speed and may remove some visual defaults. The keeped vertex contain averave value of all welded vertex. The maximum
variations allowed to weld is define by: For example,
to weld vertex strictly identical (strictly same position, i, and uv),
use: To weld
vertex having same position with error max = +/- 1 unit, and strictly same
uv and intensity, use: The function
fail if it cannot allocate temporary working memory. The function update vertex index if some vertex are removed, and realloc allocated memory of vertex list to exact required sieze. Note: To test a list of n vertex, the function use a (n^2)/2 loop, and may require lot of time if n is big (use in precalc only, and if the vertex list is 'dirty'). int BuildCmdList (const unsigned short *StateIdList) This function construct a list of command to draw all faces of the triangle list with a minimal count of rasterization states. - Batch all
faces using same rasterization state. int BuildFNormalList (short *NList, int Stride16) const This
function build a list of vector perpendicular to each face. The vector is
normalized in size. (size of a normalized vector = TRIGO_MUL = 16384). The NList
allocated size must be >= CTriangleList::IndexListSize. int BuildVNormalList (short *NList, int Stride16) const Same use than BuildFNormalList, but built a vector normal list to each to vertex. Vertex normal is defined using neighbour connected faces. (define medium value vector) The NList
allocated size must be >= CTriangleList::VertexListSize. void Delete (void); Free memory
allocated for triangle list Function to access datas into vertex/index list: These functions allow to easily Set/Get datas into Vertex/index list, without taking care of data offset and stride. Write datas functions: void SetABC (int Index, const unsigned
short *ABC) Read datas functions: void GetABC (int Index, int *ABC)
const // angles Definition
of system angles for trigonometric functions result. (float)
-> (system integer) The DEGREE macro convert a degree angle value (2*PI = 360 degree) to system angle without using a division. The exact convertion should be DEGREE(a) = (a*ANGLE2PI)/360 //
sinus/cosinus result Result scaling for trigonometric functions. Used too to normalize length of vector (including matrix vectors) Then SINUS/COSINUS function return [-TRIGO_MUL..TRIGO_MUL] range instead of [-1.0f..1.0f] range. short SINUS (int a) Sinus/cosinus functions. Require system angle at input (ANGLE2PI range angle), return a TRIGO_MUL scaled value. Note: Input angle a is masked internally with ANGLE2PI modulo, and any value can be passed. // usefull math functions int Sqrti (int a) Return square root of a. The result is not very accurate (1-2% error max), but function is very fast, and can be used intensively in run time. (for lightening, normalize vector, detect collisions, etc...) int Atan2i (int x, int y) Compute arc tangent. return result in system angle. Relatively fast, but require one division internally. int Log2 (int a) Return log in base 2 of a number. Not fast, use loop. Usually used in precalc mode. // miscelaneous fonctions void ConvertUv (short *UvSet) Adjust a constant offset for a set of 3uv (6 short values) values to get minimal offset value and some positive values. This is based on the fact that u + UV_MUL(=256) = u. (see UV_MUL constant) This function can be used if direct drawing is used. (Trianglelist BuildCmdList call this function automatically). void Normalize (int *N) This function normalize a vector to get norm of vector = TRIGO_MUL. This function is very fast and do not use divisions, however it is not very accurate, but can be use for lightening calculations. void DefUNormal (const int *A, const int *B, const int *C, int *N) This function define a perpendicular vector to plane defined by ABC 3D positions. Result vector lenght is not normalized (length = TRIGO_MUL), however, size is down scaled if length > 32768. (to avoid overflow if try to compute squared length) The vector is oriented for ABC direct. void Itoa (int a, char *aStr) Convert
number to string. // matrix class
CMatrix; void
LoadIdentity (void); ->
init matrix with identity // get
directions of axis into matrix Classic matrix object. notes: Accessors Pos, Dir, Up, Down allow to access some specific vector into matrix, for position, direction, up and right direction that the matrix is coding. The matrix elements (i,j) into matrix can be accessed directly using mIndex = (i + j*3). 'Virtual' GPU main object class CVGpu // default
drawing states Default rasterization states for text/line/sprites. It allow to define color, intensity, texture, etc... to draw text/lines/sprite. These 3 states are initialize with some default value by CVgpu.Init function. TRasterState *TriangleState -> ptr to state used to draw triangle This pointer must point to a user defined rasterization state that will be used to draw triangle. This can be a state define in a triangle list, or another state. If triangle list used, rasterization will use this state to retrieve default value to use if not defined into vertex/index list. Use of a pointer allow to switch very quickly between states by simply changing ptr value. // triangle
drawing mode Define drawing mode of triangle, it must be a eTriangleMode enum value. (see eTriangleMode) //
fov/clipping parameters This value is used by CVgpu::ScrProjection to transform 3D -> 2D vector. It depend of field of view and is defined by CVgpu::SetFov function. (or CVgpu::Init function that call SetFov internally) It must not be modifyed directly, because clipping plane vectors of frustrum are adjusted depending of this value, or the CVgpu::ClipMsk and CVgpu::CrossFrustrum function will return wrong results. Zoom is defined as follow: with a =
(Fov*ANGLE2PI)/(360*2) : a = (field of view)/2 in system units, with Fov
in degree // clipping parameters Local Near and Far clipping plane positions. must be in [CLIPZ_NEAR..CLIPZ_FAR] range. (see CLIPZ_NEAR) When using triangle list drawing, faces are truncated with position of near clip plane, an face having at least one vertex more far that far clip plane are rejected (not truncated) int NFrustrum[4][3] Contain vector perpendicular (and normalized) to bottom/top/left/right frustrum planes. These vectors are used to define if a vertex is in the view frustrum using directly world 3D coordinates. (using some dot products) These vectors are defines/updated by a call to CVgpu::Init or CVgpu::SetFov functions, and must not be modifyed directly. // transform
matrix Define the matrix that will be used to transform initial coordinates of a vertex to world coordinate. This matrix is used by CVgpu::DrawTriangleList function to transform vertex of triangle list. // frame
counter This value count number of displayed frames since program start. // frame
buffer Contain address of offscreen buffer for the hole screen. (see Frame Buffer description) // inits Init CVgpu object. Alloc memory for frame buffer, math precalc tables, etc (about 360k required). If define too near clip/far clip plane position and field of view. void Delete (void) Free memory allocated by CVgpu::Init + CVgpu::SetWorkMemory functions // memory
init This function allow to reserve once some memory for internal work of DrawTriangleList function and Z sort of faces (use hach table) The MaxVertex parameter must define the size of the biggest list of vertex that will be used in a triangle list when CVgpu::DrawTriangleList function will be called. It not enough memory is reserved, DrawTriangleList function will fail and return ERR_TMEM error code. The MaxFSort parameter must define the maximal count of sorted triangle that could be displayed on a frame. Usually, only faces using alpha transparency must be Z sorted for a correct rendering. (may be not necessary in all cases). For
example: In practize, a big value can be set (ex 1000), even if it is too lot. If value is too low, face that cannot be sorted will be not displayed. // text
drawing Print a
string at xy position. (ascii) void PrintFps (unsigned int Ticks) Print
framerate at top left of screen. // pixel
drawing Draw a pixel
at xy position. note: this is the only function that work directly with color + intensity (No TRasterState defined for pixels) // line
drawing - Draw a
line from A to B, A and B specify xyz screen positions. // sprite drawing void DrawSprite (int x, int y) void DrawSpriteScale (int x, int y, int
Scale) void DrawSpriteScaleZb (const int *ScrTl, const
int *ScrBr, int z) The sprite is scaled to fit in defined top/left Bottom/right positions. Z buffer is updated. Texture/intensity must be defined in CVgpu::SpriteState. // direct
triangle drawing. use screen coordinates Draw a triangle using screen coordinate and valid z buffer values (positive > -CLIPZ_NEAR) TVertex.m must contain a valid clipping mask. The clipping mask is returned by CVgpu::ScrProjection function. It can be defined too using CVgpu::ClipMsk function. note: forcing to 0 the clipping mask of ABC will force drawing of face. But this will decrease speed because of execution of some extra code for faces that are out of screen. // triangle
list. use 3D world coordinates and ViewMatrix Draw a triangle list (CTriangleList object). Note: Face
crossing near clip plane are automatically truncated. Return ERR_NONE if success, else other error code. // Z Sort of triangles for alpha transparency modes void SortReset (void) SortReset must be called once at init to clear hach table. If the hach table is full, new faces requiring Z sort will be ignored and not drawn. void SortDraw (void) This function must be called on time at scene draw end, when all unsorted faces (opaque faces) have been drawn. // frame
buffer Copy virtual screen into video memory, clear z buffer (to 0) and VScreen pixels with ClearColor. // 3D to 2D transform int SetFov (int Fov) - Define
field of view (Fov in degree) int ScrProjection (const int *Pos3D, int *ScrPos) - Transform
3D vertex position into 2D screen position. Note: if Pos3D z value > CLIPZ_NEAR, then the function set bit b5 (32) of clipping mask and do not transform vector. (explained in step 4 of drawing process) // frustrum
clipping Define
position of near and far clipping planes. // clipping
test This function can be used to define a vertex position relativly to frustrum. (clipping mask) Note: For triangle vertex, it is better to use result returned by CVgpu::ScrProjection function, because a more fast algorithm is used if vertex is in frustrum (just compare with screen limits). But ClipMsk() can be used to know if an object that we don't need to draw is in frustrum (ex:Bounding box). In this case, use of CVgpu::ClipMsk function if more fast than using CVgpu::ScrProjection int CrossFrustrum (const int *Box) Return 1 if bounding box of an object cross view frustrum (see demo14.cpp for use). A bounding
box is a virtual box big enough to include in space all vertex of an
object. The bounding box must contain 8 vectors, and have minimal 3D size to contain all vertex of an 3D object. // internal work int ZcErrorMax Drawing with corrected perspective is more slow than without. But sometime distorsion is very low (Low Error for small or far faces). In this case, to increase speed it is better to disable correction. ZcErrorMax define the max allowed error on perspective correction. If Error < ZcErrorMax then perspective correction is disabled. Default value is 0: correction is always applyed, even if not required. It can be modifyed to increase speed. A good range is 200 to 1500 200: low
error allowed An example of use is described in demo14.cpp Pocket PC Quark library is free for pocket pc, it can be downloaded at www.pocketgear.com/software_detail.asp?id=12370 It contain tutorials sources, library and dll, for pocket pc and pc. Project files for Visual c++ and embedded visual c++ are included. The compiled examples (contain .exe only) for pocket pc can be download here. The .zip content must be unzipped in a /Quark3D/ directory on the root of your pocket pc (It will not work in another directory, due to use of absolute path on ppc). Then test Demo0 to Demo14 using the ppc file explorer. Click on screen to exit each demo. The compiled examples for PC can be downloaded here. Unzip the content in a directory and select a demo. Note that on the pc, the framerate is timed to 25fps.
HP Jornada 680/690 Quark library is free for hp Jornada 680/690, it can be downloaded at www.pocketgear.com/software_detail.asp?id=12413 It contain tutorials sources, library and dll, for hpc and pc. Project files for Visual c++ and embedded visual c++ are included. The compiled examples (contain .exe only) for Jornada 680/690 can be download here. The .zip content must be unzipped in a /Quark3D/ directory on the root of your jornada (It will not work in another directory, due to use of absolute path on ppc). Then test Demo0 to Demo14 using the jornada file explorer. Click on screen or press escape to exit each demo. The compiled examples of jornada demos for PC can be downloaded here. Unzip the content in a directory and select a demo. Note that on the pc, the framerate is timed to 25fps. Notes about Jornada 680/690 version: Some of these demos have been targeted to run on
pocket pc having arm cpu. (200-400 mhz cpu) Then, demo 10, 12, 13, 14 are slow. Demo14 is a benchmark and is very slow, and perform an average of 3 fps and bench score of 61. However, some game using low count of triangles and simple geometry should be possible on jornada with a reasonable framerate between 10 to 15 fps. |
AVAILABLE TUTORIALS: |