GWin3D TM
Freeware*
Real-time 3D Graphics/Networking
/Media
C++ Class library for Windows

Programmer's Manual

Version 1.3
April 2008

GWin3D can be downloaded from http://coderboys.com



IMPORTANT:

* Except for certain portions, GWin3D and this document are Copyright (c) 2008 by Kelly Loum, all rights reserved. GWin3D also contains portions owned and copyrighted by others. You may use GWin3D, and distribute the DLL, without charge as long as you accept and obey the Terms. See http://coderboys.com for Pro version pricing and benefits.

Table of Contents


How to Use This Manual

Simply reading through this manual is not recommended! By far the fastest, most efficient, and least painful way to learn and develop with GWin3D is to read only the Introduction, Installation, and Creating Your First Program sections, take a look at the sample source code (see the samples directory), create a new bare-bones project, and then search the table of contents and this document for the subject of interest (for example, there are sections for getting you started in networking, 3D graphics, media, etc.).

Introduction to GWin3D

GWin3D is a C++ class library that greatly simplifies the development of Windows (Win32) applications that require any combination of high-performance dynamic 3D graphics, media, or network communications.

GWin3D has been designed with the following goals in mind:
For examples, with just a few lines of code you can set up a high-performance peer-to-peer network over the Internet or a LAN, broadcast to many other computers on a LAN, or easily and efficiently share blocks of data with other computers over the Internet or a LAN. You can play media files with a line or two of code. And with a few lines of code you can.load a 3D model file (created, for example, with the Blender freeware modeler) and display, alter, and move that model on the screen while GWin3D silently handles model file parsing, all the OpenGL calls, automatic level-of-detail selection, dynamic depth buffer optimization, out-of-view object culling, object hierarchy management, collision detection, infrequent lower-priority processing, and much more. Yet you can also completely override any part of that default behavior with your own code. So you need only understand something when you want to change, fix, or remove it.

You can use as little or as much of GWin3D as you like. You are not required to follow any application structure except any that might be a requirement of an API you happen to be using. For example, when using 3D graphics, you generally need to draw things in a given window (in a given "rendering context") from within a single thread. So you can use GWin3D along with other libraries that do require a certain program structure.

GWin3D is freeware. You can develop with GWin3D and distribute the DLL without charge as long as you obey and accept the terms. See the terms for complete restrictions, and see http://coderboys.com for current pricing and benefits of a Pro license.

System Requirements


Main Features


Installing the GWin3D SDK

Unzip the delivery if it is zipped. Preserve the directory tree specified in the zip file, if any. Where the tree is placed on your drive is not important.

Be sure you have the latest drivers for your video card. Additional multimedia capabilities are available if you install DirectX.



Creating Your First Program

To create an application, follow these rules:
See the sample VC++ source code in the samples directory.

As was said earlier, there is no required structure for your application except any that might be required by other APIs. For all GWin3D functionality except 3D graphics, this usually means simply creating an object and using it. For 3D graphics, OpenGL requires that all code that draws things in a given window (in a given "rendering context") be restricted to a single thread. (See the next section for discussion on this and an example of a bare-bones 3D graphics application.)

The GWin3D internal debugger is enabled by default. When the debugger detects a probable programming error, it prints a warning to a console window. It is wise to leave warnings enabled during development and fix the warnings as they appear. Even if your program apparently works in spite of an error or warning message from the debugger, note that some platforms are more forgiving than others. See the section on the Debugger.

The debugger also provides a mode that let's a user enter the debug console by using hotkeys. This mode is disabled by default. See the section on debugging for an example of how to enable this feature.

In a release, disable all except fatal debug messages (see gwSetDebug) because there is a very small performance hit when messages are enabled even if none are being printed.

There are some advantages to creating your program as a console application. The console makes a convenient user I/O point and will also be used as the debugger window. For example, if you create your program as a console application and run your program by entering the program name in an existing command shell console window, then any debugger warnings will remain on the screen even after the program terminates. You can also redirect program stdin and stdout with shell piping operators. Even for a console application, you can always close your console window in a release (with the Win32 FreeConsole function), so that the user is not confused by its presence.

It is best to avoid terminating your program with explicit calls to functions like exit() or TerminateProcess(). Some OpenGL and media drivers don't handle this well. Simply allow your top-most function to return. Likewise, a user closing a console window of a console program can cause an ungraceful exit. For example, some Video for Windows (VFW) drivers don't like it when a program exits ungracefully. If you must handle the possibility of a user closing the console window, then install a ctrl-break hook to force the exit to be graceful.


Creating an Application that Displays Dynamic 3D Scenes

There are many ways to design your program to get graphics content to appear in a window.

GWin3D provides a simple method shown by example, below. This method draws the scene periodically in the window even if there was no change in the scene content. This method works efficiently if typically something is changing in the scene every frame--which is usually the case with real-time 3D graphics. Since this can be wasteful when the scene contents are not changing between frames and other threads are in need of CPU, you might consider either setting the priority of the drawing thread lower than other threads (see the Win32 SetThreadPriority function), or adding code that doesn't bother drawing a frame if it is known that there is no reason to (realize that this method involves not only keeping track of whether scene content has changed, but also whether the window has been resized or an obscuring window has been removed).

Instead of using the below simple method to draw frames, you can also use the Windows conventional method to draw frames. The conventional way to update screen graphics in Windows is to place the actual drawing code in a WM_PAINT handler (in MFC, an OnPaint handler) and then let code elsewhere do the things necessary to change what will appear in the scene and then call the Win32 InvalidateRect() function, which causes the system to post a WM_PAINT message, which will cause the WM_PAINT handler to execute, and draw the scene. You can use this method if you like, but note any actual drawing to the window done from other code (like erasing the background of a CDialog object, for example) will conflict with the drawing of the 3D scene, and also that several of the automatic performance enhancements in GWin3D are based on the assumption that frames are being drawn relatively rapidly and periodically. This is because often it can't be known what drawing settings are optimal without having drawn the scene at least once. For example, the auto-LOD code and the auto clipping code calculate optimal values according to the last scene drawn. If you only update the window's contents when a change was made, when the window was resized, or when an obscuring window was moved away, (typical when code for drawing resides in a WM_PAINT handler), then the GWin3D automatic performance functionality will not work correctly. One remedy to this is to forcibly cause a WM_PAINT message to be posted periodically--for example, by calling InvalidateRect from within a periodic WM_TIMER handler. See the gwWindow constructor for more details on using the WM_PAINT approach. Also note that the WM_PAINT approach requires that gwWindow::PrepareForDrawing and gwWindow::FinishDrawing be called in the WM_PAINT handler (those functions are called automatically by GWin3D if the below method is used). Also, make sure the message pump that calls the WM_TIMER and WM_PAINT handlers is the same one that calls any other functions that do OpenGL things with the window--so that only one thread is using a given OpenGL rendering context.

Finally, no matter what drawing method you do choose to use, remember to obey the OpenGL requirement that everything that calls OpenGL functions for a given window (a given rendering context) occur in the same thread.

Below is an example of the simple drawing method provided by GWin3D. This is the entire code for a console program. It displays a spinning 3D object in a window. It requires that a VRML file named MyVrmlFile0.wrl exist in the default directory. See gwSprite::Load and the section on Creating 3D Objects for more information on creating such files. You can use this source as a starting point:

#include "GWin3D.h"

// this function draws one frame. it is called 20 times per second
void __fastcall UpdateFrameFunction( gwWindow *Win)
{
   // create a 3D object from a VRML model file
   // (since this is static, its created only the first time this function is called)
   static gwSprite MySprite("MyVrmlFile");

   // rotate the object
   MySprite.ModifyRotation (10,17,23);

   // draw the object in the window
   MySprite.Draw(Win);
}

void main(void)
{
   // initialize the GWin3D library
   gwInitLib();

   // create a 3D window and specify the frame-drawing function
   gwWindow MyWindow(NULL,UpdateFrameFunction,GW_BLOCK);
}


Finally, before getting heavily into 3D graphics development, be sure to read the short section on 3D Graphics Performance Considerations. Neglecting to tweak the several most important window and sprite variables related to performance can make the difference between a usable program and an unusable program. It certainly isn't necessary to implement what you read in that section into your first program, but it is important to know about them.

Selected Subjects


A Short Glossary of 3D Graphics Terms


Vertex

A point in space. Typically in reference to a point at which the line segments of a polygon meet. That is, a corner of a polygon. A corner of an object. Most visible objects are described as a set of vertices.

Polygon

A visible surface described by a set of vertices that mark its corners. A triangle is a polygon with three vertices, a quad is a polygon with four. One side of a polygon is a "face". Most of the objects you create will be made of polygons, although you can also make lines, points, and other visible things.

Ambient lighting

A 3D scene has one ambient light setting. You configure it with OpenGL commands. GWin3D initially sets the ambient light to a dim gray. The ambient light affects only the ambient material attribute on objects. The intensity of ambient lighting on the surface of a polygon is unrelated to the orientation of the polygon and the camera.

Diffuse lighting

Directional or point source lighting. You can have multiple directional or point light sources. Attach one of OpenGL's lights to a sprite via the gwSprite::Light member. Diffuse lighting affects only the diffuse material attribute on objects. Its intensity depends on the orientation of the polygon relative to the light.

Material

The coloration and shininess of an object and how the colors are affected by ambient and diffuse light sources. This is not to be confused with a texture, which is a 2D image that can be applied onto an object in order to give it apparent detail. An object can have a coloration and shininess without a texture. If a texture is also applied, the material affects the coloration and shininess of the texture. How the material affects the texture is configurable with OpenGL. See gwMaterial for more details.

Texture

A 2D image applied to the surface of an object. For this to work, each vertex of the object must have a texture coordinate associated with it, which is an X,Y coordinate of the 2D bitmap image that should be aligned with that vertex. Pixels across the surface of a polygon are interpolated from the texture coordinates specified for each vertex. GWin3D can automatically create texture coordinates for an object, and it supports dynamic textures and video textures.

Normal

In mathematics, the word "normal" means a vector that is perpendicular to a surface. In 3D graphics, "normal" means a vector that indicates at what direction light will cause a surface to be brightest. Normally they would mean the same thing. However, by defining a normal at some angle other than perpendicular, you can cause the illusion that a surface lies at a different angle. Each vertex of a polygon has a normal vector associated with it and the brightness across the surface of a polygon is interpolated from the normals of its vertices. So a single flat polygon can have a gradient of brightness across it giving the illusion of curvature. In this way an object composed of fewer polygons can still be made to look quite smooth by specifying vertex normals for a surface that really were curved. GWin3D can automatically create vertex normals for a model.

X-axis

The axis that extends right from the origin.

Y-axis

The axis that extends up from the origin.

Z-axis

The axis that extends forward from the origin.

Translation

Movement. The placing of something at a different location from its original location.

Rotation

The circular movement of each vertex of an object about the same axis.

Scale

A change in the width, height, and/or depth of an object.

Shear

A pulling of one side of an object in one direction, and the opposite side in the opposite direction, without rotation, such that the object is distorted rather than rotated.

Yaw

Rotation about the Y-axis

Pitch

Rotation about the X-axis, after any Yaw has been applied.

Roll

Rotation about the Z-axis, after any Pitch has been applied.

Euler angles

The pitch, yaw, and roll of an object, applied in that order.

Matrix

An array of 16 numbers that describes the position and orientation of a sprite. Specifically, a matrix describes a difference, or change, in the orientation (coordinate system) of one object from another. See the section on Introduction to Matrices in 3D Rendering.

Origin

The center of a coordinate system. The point in the coordinate system that is, by definition, untranslated.

Frame

In this document, 'Frame' means a complete still scene. It is analogous to a movie frame. A moving 3D scene is created by drawing successive frames--typically at about 15 to 70 times per second.

Creating 3D Objects for use as Sprites

There are three ways to create a 3D object to be used as a sprite:
The gwSprite::Load function supports a simplified subset of VRML 1.0, VRML97, and VRML 2.0 and ignores everything else it encounters in a VRML file. For performance reasons, individual sprites should be kept fairly simple. Complex objects should be constructed of multiple sprites (sprite trees). However, consider also that modern video cards can often draw thousands of polygons in the time it might take the CPU to execute the overhead of one gwSprite. Ideally we adjust sprite complexity so that neither the CPU nor GPU experiences idle time. Experimentation is recommended.

GWin3D does not accept compressed VRML files (if you have a compressed VRMl file you want to use, simply uncompress it with your favorite decompressor--you might have to temporarily rename the file extension to ".gz" to make this work). GWin3D also has certain VRML file-naming rules. See gwSprite::Load for details.

GWin3D honors texture coordinates that are specified in a VRML file. Some modelers do a poor job of creating texture coordinates or simply don’t output texture coordinates to the VRML file. To overcome this problem GWin3D has some fairly powerful auto-texturing capabilities. You can use certain flags of gwSprite::Load to override the texture coordinates in a VRML file or to generate texture coordinates when they are not present in the VRML file. See gwSprite::Load.

By default GWin3D ignores material, rotate, and translate statements in the VRML file since many modelers place these in a VRML file when it would be better, for performance reasons, to avoid them. You can tell GWin3D to honor these statements by specifying certain flags to the gwSprite::Load function, however you should consider avoiding them, if possible.

Remember that GWin3D sprites are a rather primitive object from a modeling point of view. Your philosophy should be to create only one primitive, single-textured, single material "sub" object per VRML file. In this way you will be more prone to create sprite trees to produce complexity and LODs rather than single complex sprites. This approach is important so that things like out-of-view detection, levels-of-detail, etc. work efficiently. Of course, if your application displays only a few sprites and you are assured that you will always have enough CPU/GPU to spare, then its perfectly OK to create a complex sprite. You also have the option of compiling a sprite tree (see the section on Compiled Sprite Trees ) to increase performance. Note, however, that GWin3D ignores references to texture filenames in the VRML file (you specify the sprite's texture with the Texture member), that a sprite may have only one texture, and that many modelers may not do a good job of saving a complex scene to a VRML file that can be properly parsed by GWin3D.

Of late, the only reasonable option for a freeware modeler is Blender.

Blender is a full-featured modeler. It is the recommended modeler for GWin3D.

Do not attempt to learn the interface by playing with it. The interface is not designed to be easy to learn by being simplistic. It is designed to be efficiently used by someone who has taken the ten minutes to read the quick start section describing the GUI. There are many hot keys not apparent by looking at the GUI. To use Blender you keep one hand on the keyboard and one on the mouse. If you don't know about the hotkeys you will only get frustrated thinking the Blender GUI is broken or poorly designed. Once the hot-keys are learned it is a Cadillac modeler with which you can work quickly and efficiently.

Also, take the time to get whatever documentation is available on the Blender site.

At the time of this writing Blender did not output texture coordinates to a VRML file (this may have changed). This is not a problem since GWin3D's internal texture coordinate generation is as good as or better than what a typical modeler might be capable of (see gwSprite::Load ).

Blender is open source, so it will likely stay current and competitive.

Blender outputs VRML 1.0 and Blender VRML files can be loaded by GWin3D.

Note: As always, be sure you have the latest drivers for your video card.

3D Graphics Performance Considerations

It certainly isn't necessary to implement what you read in this section into your first program, but it is important to know the following points exist.
The following code is an example of a way to limit the CPU/GPU used in your gwWindow 's PeriodicFunction. No more than about 80% of the CPU/GPU is used. You would use this code if you want highest levels of detail to be retained at the expense of frame update rate:

// This is at the top of the gwWindow 's PeriodicFunction:
gwTimer Elapsed;

// main body of the PeriodicFunction is here
...
...

Universe.Draw(Win);

// This code is at the bottom of the PeriodicFunction:

// Adjust the period to be a little more than how long it took this
// function to execute (this assumes Win->MaxElapsedTimeMs
// is very large so that highest LODs are always used):
Win->RealTimeTask->Period = Elapsed.Get()/800;

Introduction to Matrices in 3D Rendering

GWin3D makes it easy to set a sprite's position, orientation, scale, and shear relative to its parent sprite. It is not necessary to read or understand this section to use the GWin3D functions that do that. This section is provided solely for a deeper understanding of how GWin3D and OpenGL manage positioning and orientation of objects and their children.

In the real world, objects often have moving parts attached to them.

Such parts follow the position and orientation of the objects they are connected to, but may have their own position and orientation relative to that "parent" object, which may even change dynamically (from frame to frame).

Every object has a coordinate system that describes its orientation and position. When we say "object's coordinate system", we don't mean the coordinate system in which the object lives. That is the object's parent's coordinate system. Rather, we mean the coordinate system that is defined by the position and orientation of the object. In an object's coordinate system, the object resides at the origin, is undistorted, is pointing down the Z-axis, and its children are positioned relative to that.

The numbers describing an object's coordinate system are really describing how the position and orientation of that object differ from its parent's coordinate system.

There are many mathematical ways to describe such a difference. It could, for example, be described with a set of distances and angles.

We use matrices to describe such differences. A matrix is a set of 16 values that are held in a 4x4 array for mathematical reasons. The matrix holds three axes and a position.

All possible differences in one coordinate system from another can be described by defining the length and direction of the three axes and the position. Nine of the values in a matrix are used to define the three axes (three per axis) and three more entries are used to describe a position (X, Y, Z).

Fortunately, it is not at all necessary for a 3D developer to understand the meanings of the 16 values in the matrix . It is only necessary to understand that a matrix is a description of a difference in position, scale, shear , and rotation of one coordinate system from another, and that you multiply them together to create other matrices.

GWin3D supplies functions that set and alter the position, scale, shear, and rotation attributes of a matrix.

Matrices are used instead of a set of angles and distances because many underlying calculations are simplified and faster.

Multiplying a child's matrix by the parent's matrix yields a matrix that describes the child relative to the grandparent's coordinate system. That is, multiplying matrices collapses the tree of relative coordinate systems. Said another way, one coordinate system can be used to modify another.

Multiply all the matrices in a tree (hierarchy) and the result is a matrix that describes an object's position and orientation relative to the universe. This is needed because, although the application often finds it convenient to manage matrices that describe one object relative to another, the rendering engine can handle only matrices that describe objects relative to the universe. Also, the universe-relative matrix is often of use to the application when the application needs to know the absolute orientation and position of a child object. GWin3D internally collapses the tree of matrices (see gwSprite::Draw ) and also saves-off the absolute matrix (see gwSprite::LastMatrix ) for examination by the application each time the object is drawn.

The order two matrices are multiplied makes a difference. Multiply them one way and you modify a matrix relative to its own coordinate system, multiply them the other way and you modify the matrix relative to its parent's coordinate system.

Every Sprite has a matrix. This matrix describes the sprite's orientation and position relative to its parent sprite. Specifically, the gwSprite class is a child of the gwMatrix class. Other members of gwSprite specify what sprites are children (subsprites) to what. See gwSprite::AddSubSprite and gwSprite::RemoveSubSprite.

When you draw a sprite (see gwSprite::Draw ), the sprite and all its subsprites are drawn. That function first pushes the current matrix onto a stack (called the modelview stack) and then draws the sprite. Next, the gwSprite::Draw function calls the gwSprite::Draw function for each subsprite. After it draws all the subsprites, it pops the matrix and returns. When gwSprite::Draw calls itself recursively, it pushes the default matrix onto a stack and multiplies it by the subsprite's matrix. This new default matrix describes the subsprite relative to the universe.

There may be a time that the application needs to create a coordinate system (a matrix ) to independently modify the current matrix (see the glMultMatrixd OpenGL function) or a sprite's matrix (see gwMatrix::operator*= ). This operation might, for example, be performed in a gwSprite::PreDrawCallback function. Note that matrix multiplication is not commutative--the order it is performed makes a difference.

If all this sounds confusing, see the bare-bones source. Creating a sprite and moving it around is quite simple and just takes a few lines of code.

See the gwMatrix class for more information.

Level of Detail (LOD)

When a sprite is far away, drawing all its details would be a waste of CPU and GPU time, slowing down the entire application. It is better to draw a simplified form of the sprite when it is far away so that none of the CPU and GPU power is wasted drawing complexity that can't be seen, anyway.

Different versions of the same object that vary only in their complexity are called levels of detail (LOD). Which LOD should be drawn depends on the diameter of the object in the window, among other things.

The two ways that GWin3D can manage LODs are discussed below. You can also write your own code to manage LODs or to modify the way GWin3D handles LODs by placing it in a gwSprite:PreDrawCallback function.

Simple LODs

"Simple" LODs allow the distance to an object to vary by a factor of about 2000 and still maintain efficient use of CPU/GPU.

For higher distance ratios, use a combination of simple LODs and sprite tree LODs. Sprite tree LODs are described in the next section.

Simple LODs are implemented in GWin3D by creating a separate OpenGL display list for each LOD and assigning them to elements of the sprite's List array (see gwSprite::List ).

You can create such display lists programmatically by calling the right OpenGL functions. If you do this then be sure to set the gwSprite::Radius member to reflect the visible radius of the object.

You can also just create, using a freeware 3D modeling program like Blender, a set of VRML files (one for each LOD ) and let gwSprite::Load do everything automatically. gwSprite::Load creates OpenGL display lists from the VRML files and distributes them throughout the List array according to the number of polygons in each file. It also automatically loads the gwSprite::Radius member according to the largest VRML LOD loaded. There is also a gwSetDebug option that lets you watch this process.

You should experimentally adjust the gwSprite::LodScale member. gwSprite::LodScale controls at what distance LODs change.

When it comes time to draw the sprite, GWin3D will choose one of the OpenGL display list handles from the List array. This decision is based on the following:
The sprite's List array holds 11 elements. All else being equal, a level of detail in GWin3D increases each time the distance from the viewer to the objects is cut in half. Therefore each level of detail for a sprite should have roughly four times the number of polygons as the next lower level of detail (the goal is to maintain a constant polygon density on the screen for the sprite) up to the maximum number of polygons required to fully draw the object. Element 0 of the array holds the OpenGL display list handle for the highest detail, element 10 holds the handle for the lowest defined level of detail.

For the highest level of detail it is important not to use more polygons than are necessary.

Ideally the lowest level of detail is comprised of 0 polygons. That is, at great distances nothing is drawn of the sprite. If GWin3D decides, at draw time, the List element to use is greater than 10, then GWin3D draws nothing (because there is no List element greater than 10). Ideally element 10 of the List should have an OpenGL display list handle that draws 2 polygons, the next level (element 9 of List) 8 polygons, the next 32 polygons, and so on, but limited by the maximum number of polygons needed to fully draw the object. At this rate with the available 11 levels of detail you might make your highest LOD (element 0) with up to 2097152 polygons if the object were complex enough to merit it. However, you should consider breaking up such a sprite into a sprite tree when the polygon count of the LOD exceeds 2000.

Ideally you should create a separate version of the sprite for each level of detail up to the maximum detailed version. Creating LODs with a modeler that has a decimate function (like Blender) makes this easy. Once you have created your highest LOD, repeatedly decimate it to roughly one-fourth the polygons and save each as a VRML file until you have just a few polygons left.

If you aren't quite as concerned about saving CPU and GPU power, or you know you will always have power to spare (because, for example, you will never draw more than a few sprites), then you might use the same version of the object for several contiguous levels of detail, or just use one VRML file for all of them (the easiest and the least efficient way).

For example, if you have an object that can be fully described with 340 polygons and are not terribly concerned that you might waste a little CPU and GPU power, then you might create just three versions of the object. (If you use gwSprite::Load , then it will automatically distribute them optimally). The numbers of polygons for each level of detail might resemble those shown in the following table (Note: In this table, LOD 0 is the highest and 10 is the lowest defined display list, and the fictional "element 11" and beyond is the lowest LOD. This reverse numbering is done because GWin3D's gwSprite::LodIndex member works this way.)

Level of detail (where 0=highest) Maximum number of polygons Actual number of polygons (example)
0 2097152* 340
1 524288* 340
2 131072* 340
3 32768* 340
4 8192* 340
5 2048 340
6 512 340
7 128 340
8 32 40
9 8 8
10 2 0
(11 and beyond) 0 0

*Typically polygon counts over about 2000 really should be broken up into multiple sprites in a tree (see below).

"Simple" LOD handling has its limits, obviously. There may be objects you want to create that have a greater LOD ratio than 2000. For these you would use a combination of simple LODs and a sprite tree.

Note: it is not necessary for the application to manage texture LODs (mipmaps). These are handled internally by GWin3D, thanks to the GLU and OpenGL functions that do that.

Sprite tree LODs

You can create a sprite tree (see gwSprite::AddSubSprite ) to implement almost any range of LOD.

When the parent sprite is far away the subsprites are not drawn (see gwSprite::SubspriteLodLimit ) and the parent sprite is all that is needed to give the object a large-scale form. When the camera is close to the sprite, however, the subsprites are drawn and each subsprite has its own simple LOD that depends on how close it is to the camera. In this way when the viewer is very close to one part of the whole object, only that part is being drawn in detail and the other more distant parts are drawn with less detail.

Those subsprites, too, can have little subsprites upon their backs, ad infinitum (limited by your OpenGL implementation's modelview matrix stack depth, see below for more on this).

Note: The polygon count rules shown in the table in the " Simple LODs " section above should be applied to sprites individually, whether they are in a sprite tree or not. Do not apply the rule to the total polygons in a sprite tree.

When creating a sprite tree, it is sometimes useful to define the higher levels of detail of the parent sprite as invisible and let only the subsprites define the object when the viewer is very close. You might do this if there is considerable detail over the whole object and the parent sprite needs to be hidden to allow the child sprites to show the detail. When doing this, however, care must be taken so that there is not a range of distances at which both the parent and the subsprites are invisible. That is, when the viewer is approaching the object, the subsprites should appear before the parent sprite disappears. You can accomplish this by assigning the high LOD elements of the gwSprite::List array to zero. Be careful when messing with the List elements if the sprite "owns" them--that is, if the sprite is responsible for freeing them when it is destroyed. See gwSprite::List .

Another option is to design the sprite tree such that the parent sprite is always visible but subsprites add detail to the outside of the parent sprite. In this case, care must be taken to avoid the object appearing to grow in size (because the outer subsprites begin to appear) as one approaches the object.

See gwSprite::SubspriteLodLimit to control at what parent LOD subsprites begin to be drawn.

Remember that the LOD drawn is based in part on the size of the sprite as defined by its Radius member. When implementing a sprite tree as described above, remember that an LOD level of a smaller subsprite of the tree does not correspond to the same distance for the same LOD level of a larger subsprite, or the parent. In other words, you can't say to yourself, "I'll set these small subsprites so they appear at LOD 7, and set the big parent sprite to disappear at LOD 7". Those two LODs occur at different distances because the sprites are different sizes (have different Radius values). Said more succinctly, the level numbers do not correspond to distances, they correspond to the relative size of the sprite on the screen.

Remember also that the Radius member you set for a sprite must just encompass all its subsprites so that the automatic out-of-view detection and LOD selection works correctly in GWin3D.

The depth of a sprite tree is limited to the size of the OpenGL implementation's modelview matrix stack. Pretty much all OpenGL implementations have a modelview matrix stack depth of 32 (although some low-end or older implementations may only have 16). If both simple LODs and sprite tree LODs are used in a fairly efficient way on a system that has a stack depth of 32, this yields an LOD dynamic range of roughly 2^40.

If you want to make a sprite tree deeper than a system supports then you'll have to implement your own matrix stack and call the Draw function for each subsprite, yourself, and not let GWin3D do it. You would do this from within a gwSprite::PreDrawCallback or gwSprite::PostDrawCallback function. See gwSprite::Draw to see how the stack is used and when subsprites should be drawn.

Dynamically Loaded Sprite Trees

By dynamically loading and unloading sprite trees and their subsprites, you can implement infinite levels of detail as well as save system resources. You would need to do this if all the sprites of your virtual reality universe won't fit in memory at the same time.

You can implement sprite tree LODs as described above and also dynamically load and unload subsprites at lower LODs than they are visible, or you can implement dynamically loaded subsprites without sprite tree LODs as described above.

One way to implement dynamically loaded subsprites in a sprite is to specify an EarlyDrawCallback function for the sprite. This function would decide whether the subsprites of that sprite should be loaded or deleted.

Note that all of your sprite destructors should delete the sprite's subsprites.

Do not allow subsprites that will be dynamically loaded and unloaded to have multiple parents.

Do not change any sprite's SubspriteLodLimit from its default value. Doing so would sometimes prevent a sprite's EarlyDrawCallback function from being called, preventing a very low LOD sprite from having a chance to delete its subsprites.

The EarlyDrawCallback code you write should examine the current LodIndex and decide whether to load and add subsprites, remove and delete them, are leave things alone.

Be sure to delete sprites at a much higher LodIndex than their highest visible LodIndex (remember that the higher the LodIndex, the lower the level of detail ). For example, do this especially if you also implemented sprite tree LODs as described in the previous subsection.

You might want to load your subsprites at an LodIndex that is lower than the LodIndex at which you unload, if there is a probability that the camera may return to sprites it recently left (which is typical in many virtual reality games).

Mesh LODs

You can create a sprite tree of a mesh by creating a low-resolution parent, and creating successively higher resolution generations of smaller subsprites.

When creating such a sprite tree, just remember to take into account the fact that when you reduce the resolution of a mesh (for example, when you reduce the resolution of a heightfield image that will be converted to a mesh) that the physical size of the resulting mesh will be less than the size of the original. So you need to include a little extra all around your subsprites. Otherwise there will be seams between them.

For example, if a subsprite's horizontal resolution and vertical resolution are each twice that of the parent (this is the suggested ratio), then you'll need to include at least an extra half a polygon 's worth of mesh all around the child sprite in order to close the seam. Of course, the easiest thing to do is add a whole polygon (yes, they'll overlap a little--which is fine).


Working with Images

Use the gwImage class to load, manipulate, access, and save image files of type BMP, JPG, or JP2.

The gwTexture class let's you specify a gwImage object for use as a texture.

You can also use gwImage to get the pixels of an image for use as raw RGB data or a DIB.


Impostors and Billboards

Both impostors and billboards are objects automatically oriented to face the camera. See gwSprite::LockXOrientationToSprite and friends.

Typically a billboard is simply a flat panel that always faces the camera. It might have a text message on it, for example. There is no reason, however, that you can't make a billboard a 3D model that faces the camera.

To implement a flat billboard, create a panel or disk (see gwSprite::Create ) and make the gwSprite::LockXOrientationToSprite and friends point to the viewpoint sprite. Assign or load the gwSprite::Texture member to whatever you want on the billboard. Be sure gwSprite::ImpostorLodIndex is zero (it is by default) so the sprite points at the viewpoint even when it is close to the viewpoint.

An impostor is the same as a billboard except that it is a special form of a low level of detail (see the section on Levels of Detail ). It appears only beyond some distance from the camera and its purpose is to mimic at a great distance the appearance or at least the general coloration of the sprite's higher LODs.

An impostor can have the same texture as the higher LODs of the object, or it can have a separate texture (see gwSprite::ImpostorTexture ) that might be a dynamically created 2D snapshot of the object it is imitating, or it might just be a non-descript hazy image with generally the same coloring as the higher LOD texture.

You control at what LOD and beyond the impostor appears with the gwSprite::ImpostorLodIndex member.

The low LODs of a sprite that will become an impostor are typically flat surfaces, while the higher LODs are the 3D model. See the gwSprite::List array member, which holds the OpenGL display list handles for each LOD.

You might make a separate panel or disk sprite (see gwSprite::Create ) and use its low LOD List element values to assign to the low LOD elements of the sprite you want to use impostors at low LODs . When assigning gwSprite::List elements, remember to keep track of which sprite owns what display list handles. gwSprite::Load and gwSprite::Create set a flag internal to the sprite object telling it to free any handles in the gwSprite::List array when the gwSprite destructor is called. Assigning List elements without thought can result in some handles being freed when they shouldn't be and other handles neglecting to be freed when they should be. It often helps to instantiate separate sprites which are never destroyed and that own their display lists, and other sprite's List elements are assigned from the List elements of those template sprites.

A true impostor texture can be generated on the fly by telling OpenGL to render a view of the 3D object to a RAM buffer, and then that buffer is used as a texture. One may even create on the fly an alpha channel for the texture so that the impostor is transparent except where the texture depicts the object. This texture would be assigned to gwSprite::ImpostorTexture. GWin3D does not automatically generate such textures. Impostors that simply use a predefined texture for gwSprite::ImpostorTexture, or even the same texture that the high LODs of the sprite use (in which case it is not necessary to load or assign gwSprite::ImpostorTexture ) are often convincing at great distances and certainly easier to implement and less CPU/GPU intensive.


Textures

A texture is a 2D image applied to the surface of a sprite.

For textures to work, a texture image must be assigned to the sprite (see the gwSprite::Texture member) and each vertex of each polygon of the sprite must have a texture coordinate assigned to it (accomplished by assuring texture coordinates exist in the VRML file, by causing coordinates to be automatically generated by passing certain flags to gwSprite::Load, or by assigning them, yourself, with certain calls to OpenGL). Otherwise no texture will appear.

The advantages of textures are:
The disadvantage of textures is that they use up RAM in your graphics card. GWin3D does, however, internally create and manage mipmaps for far more efficient use of texture memory (via an internal call to gluBuild2DMipmaps). Therefore it is not necessary for the application to manage simpler textures for distant objects.

Textures can also be compressed to save GPU memory.

By default, GWin3D allows you to specify one texture per sprite (see gwSprite::Texture ), but you can put multiple texture commands in the sprite's display lists (see gwSprite::List ).

GWin3D can load texture coordinates from VRML files. It can also generate texture coordinates automatically. See gwSprite::Load.

Still textures are typically specified as a gwImage object. Textures that play a video are also easily created. See gwTexture::CreateFromDib, gwTexture::CreateFromRgb , and gwAvi.


Networking

The gwNetStreamClient class let's you connect to a standard server such as an HTTP, telnet, or FTP server. Such connections use the reliable but relatively slow SOCK_STREAM protocol. These connections are based on a server-client model.

Use the gwNetPackets and gwNetData classes to implement high-performance peer-to-peer communication over a LAN and across NAT routers (over the Internet).

The gwNetPackets class makes it easy to send and receive fast raw Ethernet packets between any two computers on a LAN or the Internet. You can also use this class to broadcast to multiple computers on a LAN.

The gwNetData class is a higher-level networking class that handles all the performance and reliability issues of sharing variables and blocks of data with other computers on a LAN or the Internet. The gwNetData class uses an existing gwNetPackets object to perform the data transfers. See the descriptions for the gwNetPackets and gwNetData classes for more information.

For performance, gwNetPackets uses raw UDP "datagram" packets instead of a TCP "stream" connection.

There is no question that networked real-time games (and many other applications that require low-latency networking) should use datagrams instead of stream connections. Datagrams have far greater performance. You should, however, be aware of three drawbacks of using datagram packets:
  1. Datagram packets sent in quick succession over the Internet may sometimes arrive in a different order than they were sent. However, this is not the case on a LAN because there is typically only one path packets can take between computers. (The gwNetData class solves this problem.)
  2. Sometimes datagram packets do not make it to the destination computer. This is because of packet collisions. (The gwNetData class solves this problem.)
  3. No single data chunk can be sent larger than 1448 bytes, and on dialup interfaces you should keep packet size (and thus maximum data block size) just below about 520 bytes so that your application is sure to work efficiently on ISPs that use a small MTU (of 576 bytes). (The gwNetData class makes it easy to work around this problem.)
The gwNetPackets class also allows you to broadcast packets to all computers on a LAN subnet--by specifying the last IP byte as 255. You cannot, however, broadcast packets on the Internet (because no sane Internet gateway would allow it!), nor does this class support multicast, simply because multicast is still not widely supported by ISPs and routers even in 2008.

A single gwNetPackets object opens a specified local interface (local network adapter) to receive packets destined to a certain port number. It also lets you send packets to any IP address and any port number using that interface.

It is easy to implement peer-to-peer communication over a LAN using gwNetPackets and gwNetData. However, there are certain things you must know in order to implement peer-to-peer communications over NAT routers (i.e. across the Internet). These things are addressed below.

Routing basics and Internet connections

All Ethernet packets contain the source IP address, source port number, destination IP address, and destination port number. You can find out what these are in a received packet (see gwNetPackets::Receive ).

Of course, the destination IP address and port number are necessary in the packet to let routers know where to send the packet, and once the packet has arrived in the destination computer, the destination port number tells that computer which application code to send it to (which open socket).

The source IP address, of course, let's the receiver know where the packet came from.

But what is the purpose of the source port number in the packet? Its purpose is to tell the destination computer what port the source computer is listening on for responses to that packet.

Whenever you receive a packet and then want to send a packet back along that same "channel", you should send them using the source port number and IP address you recently saw in packets received via that channel.

You may think that you can ignore the source port (or even IP address, in some cases) in incoming packets and simply send any responses to the IP address and port you know the application on that remote computer was really suppose to be using and listening on (what the application on that computer told it to listen to). This is actually OK when both computers are on the same LAN.

However, many routers will alter the source port and the source IP address in outgoing packets, expect incoming responses to that connection to use those values as their destination, and the router then translates them back to the correct values for the local network. NAT routers do this so that all the computers behind the NAT router will appear as just different ports on the same computer to other computers external to the LAN. In this way all the computers on a LAN can have Internet access, yet only one public IP address need be purchased (public IP addresses are not cheap).

For this reason, the standard is that all applications that receive packets for which they want to respond, should use both the source IP address and source port number they saw in recent incoming packets.

This also means that an application must at least partly keep track of other computers by a combination of their IP address and source port number seen in incoming packets. IP address, alone, is not sufficient to discriminate networked computers. Thus a game server or peer-to-peer game network must use both IP address and source port number to discriminate other players.

Hole punching (peer-to-peer over the Internet)

When a computer on a LAN sends a packet through a NAT router to a computer on the Internet, the NAT router notes the destination computer so that it knows to allow packets from that computer back into the LAN. Only packets from that destination computer (IP address) with a correct destination port number (the source port that was in the outgoing packet) are allowed to enter the LAN. This is one way NAT routers maintain security. Unsolicited packets are not allowed into the LAN.

Unfortunately, when a computer on the Internet needs to legally send the first packet to a computer behind a NAT router, the NAT router must assume the packet is malicious (it has no evidence to the contrary) and so it discards the packet.

If, however, the local computer were to first send at least one packet to that other computer, then the NAT router would know that remote computer is a friend of the local computer and therefore packets from that remote computer (to the correct port number) should be allowed into the LAN.

So both computers need simply start sending packets to the other so that any NAT routers between them will realize they are friends. The first packet or two will be lost, but none after that (except, of course, for the random loss of packets caused by network flakeyness and collisions--which the application must handle anyway, when using UDP packets).

This is the basis of hole punching. It makes it possible to have peer-to-peer connections over the Internet. The rest is details.

The details are that there must be a mechanism to arrange the peer-to-peer meeting and there must be a mechanism for each computer to find out the other's public IP address and public source port numbers--so that each can start sending packets to the other using the right IP address and destination port number.

Arranging the meeting can be done any way you like. It can be manual (user's exchange information via an email or instant message and then must click buttons and type IP addresses and port numbers into their applications), or it can be automatic. For example, all participating programs can publish their public IP address and source port numbers on an encrypted web page--so you'll just need a simple PHP script running on a cheap, low-bandwidth HTTP host (you could use the gwNetStreamClient class for implementing the client side).

Finding out your public IP address and the public source port number that your NAT router is putting in outgoing packets requires a special server on the Internet called a STUN server. There are several free STUN servers and will likely be more in the future. Fortunately a large majority of NAT routers will use the same source port value even when the destination computer is changed. So the source port value reported by the STUN server will likely be the one your NAT router uses when you send a packet to another computer (but use the same local source port). You can contact a STUN server and get this information by using the gwGetPublicNetInfo() function.

For more information, see gwNetPackets, gwNetData, and gwGetPublicNetInfo().


Playing audio and video files

Use the gwMedia class to play audio and video files. This lets you play WAV and AVI files in a window and, if DirectX is installed, let's you play MP3s and MPEG files, among others. See gwMedia .

To access individual frames of an AVI file for use as an animated texture, for example, see the gwAvi class.

To play, record, and access individual sound data samples, see gwWaveInDevice and gwWaveOutDevice.


Overriding GWin3D's Functionality

One way to override how GWin3D draws a sprite and its subsprites is to add your own gwSprite::EarlyDrawCallback, gwSprite::PreDrawCallback, or gwSprite::PostDrawCallback function to the sprite object. In these functions you can make the OpenGL calls you want to prepare OpenGL for drawing the sprite or actually draw the sprite or sprite tree.

Any OpenGL state variables you change in an EarlyDrawCallback or PreDrawCallback should be restored to their previous value via a PostDrawCallback function. This may even involve saving of previous OpenGL states in the EarlyDrawCallback or PreDrawCallback functions before those settings are changed so that they can be restored in the PostDrawCallback function.

Another example of overriding gwSprite functionality is supporting multiple textures or multi-texturing in a sprite by creating the additional textures separately and referring to them specifically in your display list (see gwSprite::List ) or drawing code (see gwSprite::PreCallDrawback).

You may also find it useful to create a child class of gwSprite in order to overload certain functionality. In a pinch you could even overload the gwSprite::Draw function, itself, although intimate (read "undocumented") knowledge of that function might be necessary.

Similarly, the functionality of gwWindow can be changed by use of a child class. For example, you may find a need to change how the gwWindow constructor creates a rendering context. See the gwWindow::RC member.

Almost all member functions in GWin3D are virtual. This assures that code given a parent class pointer in place of a child class pointer, or vice versa, will still call the proper member function for that class.


Translucency

An easy form of translucency is implemented by setting the GW_TRANSPARENT flag in sprites that should be translucent (see gwSprite::Flags ) and by drawing all translucent sprites after all solid sprites with a separate call to gwSprite::Draw. For example:

gwSprite MySprite("MyVrmlFile");

MySprite.Flags |= GW_TRANSPARENT;

Universe.AddSubSprite (&MySprite);

...
...

// first draw non-translucent sprites
Universe.Draw(Win,0,GW_TRANSPARENT);

// then draw translucent sprites
Universe.Draw(Win,GW_TRANSPARENT,GW_TRANSPARENT);


In the above method, low R, G, and B values in the sprite's texture and material are more translucent and high R, G, and B values are more opaque. This simple method works moderately well when the background is dark, but gives a strange effect when the background is light .

More complex and realistic methods of implementing translucency can be achieved by use of the alpha channel (see gwSprite::Material and gwImage::CopyComponent ) and other blending algorithms (see gwSprite::BlendSrcFunc and gwSprite::BlendDstFunc). Search the internet for "glBlendFunc" and "alpha channel".


The Debugger

GWin3D contains a simple debug monitor that lets you monitor execution, monitor program faults (debugger "warnings"), and pause the tasks performed by GWin3D.

Debugger output is sent to a console window. If there is no console window attached to the program when the debugger attempts to print a message, then a console window is created. It is highly recommended that you always build your application as a console application. You can always hide the console window in a release, if you like (see the Win32 FreeConsole function).

The debugger also accepts commands entered into the console window by a user.

You can manually activate the debugger prompt by enabling debug hotkeys in your code, and then when your program runs, setting focus to any 3D window ( gwWindow ) and then holding down the G, W, D, and P keys simultaneously. By default, debug hotkeys are disabled.

You can programmatically control the enabling of debug hokeys and debugger output messages with the gwSetDebugfunction. For example, the following code enables warnings and the ability to use hotkeys to enter the debug console, but only when you build your code for debug:

void main(void)
{
#ifdef _DEBUG
   // enable warnings and dbg console hotkeys
   gwSetDebug(GW_ENABLE_GWDP_DBG | GW_WARN_DBG | GW_FATAL_DBG);
#else
   // enable only fatal error messages
   gwSetDebug (GW_FATAL_DBG);
#endif
...


By default, the hotkeys are disabled and debugger warning messages are enabled (equivalent of calling gwSetDebug(GW_WARN_DBG | GW_FATAL_DBG)).

It is wise to leave warnings and hotkeys enabled during development and fix them as they appear. Consider that what might seem a harmless warning on your development system might be an indicator of a failure on a less forgiving OpenGL implementation, or of a future failure when the execution timing or uninitialized RAM is different.

There may, however, be cases in which a warning can be ignored. For example, debug warnings will sometimes display at program shutdown because of various threads, objects, resources, etc. being destroyed (and their destructors being called) in no particular order by the compiler's termination code. It may be OK to ignore some of these warnings because it seems the compiler's termination code should certainly make sure all threads have been suspended before calling destructors of static objects. Let's hope it does. For example, you may see a warning during shutdown saying something like "Subsprite destroyed while it still has a parent". If you see this warning other than during program termination, then there is a possibility that drawing the parent will cause an attempt to draw the subsprite even though the memory of the subsprite object is freed.

If you do want to pay attention to warnings during shutdown (a wise choice), you may want to create your program as a console application. Then you can open a command console window and run your program from the command line. In that way warnings will remain on the screen in that console window after the program terminates and you can redirect the stdout to a file if you want. You can always close the console in a final release (see the Win32 FreeConsole function) so that the user is not confused by the presence of an extra window.

When the debugger "DBG>" command prompt is visible (get to it by pressing G, W, D, and P keys when a 3D window has focus), you can enter any of several commands.

Enter 'h' for a list of valid commands.

When you are at the DBG> prompt, the owning thread is paused. You can cause the thread to continue execution by entering 'g' at the prompt. You need to enter 'g' after you enable new debugger output messages (see below) because they certainly won't display if the thread isn't running.

To enable text messages that describe certain operations performed by the GWin3D library as they happen, use the 'b' command or the 'sf' command. The 'sf' command lets you configure messages describing the drawing of certain sprites. The 'b' command lets you enable other messages. (Also see gwDumpSprite.)

You can filter output messages further by use of the 'f' command. Use the 'f' command to specify a text fragment that must exist in a message before it will be displayed in the console. You might, for example, specify the name of a sprite (see gwSprite::Name ) that should be monitored.

You can also cause the thread to pause, and the DBG> prompt to appear in the debug console window, when a certain text fragment appears in a message displayed on the console window. Use the 'w' command to specify such a text fragment. With the 'b', 'sf', 'f', and 'w' commands you can fairly well control what messages are displayed while the program is running and which operation will stop thread execution at the DBG> prompt.

Here are the commands that can be entered at the DBG> prompt:


Command: Examples: Meaning:
h H Help. Displays a list of these commands.
g G Go. Continue thread execution.
s[<n>] s (run till next msg)
s12 (run till 12 msgs display)
Step. Run the thread until this many debug messages have been displayed, after which execution will stop at the DBG> prompt.
sf<HexVal> sfFFFFFFFFFFFFFFFF (show all sprites)
sf0000004800410600 (show certain sprites)
When a sprite with any of the specified Flags bits set is drawn, display a line of text describing the sprite. See gwSprite::Flags. Also see NOTE 1.
b<HexVal> b20 (showVRML parsing)
b4 (show level of detail statistics)
Set deBug map to the specified HEX value. See table of bits below. Also see NOTE 1.
f<String> fMySprite (don't show dbg messages unless they contain the string "MySprite")
f (Remove string filtering and allow all enabled dbg messages to appear)
Filter messages. Display only messages that contain the specified string (Message must still have been enabled with the 'b' command)
w<String> wMySprite (Stop execution when a dbg message containing the string "MySprite" appears)
w (disable watch mode)
Watch. If <String> is present in a displayed message, then pause execution at the DBG> prompt.
x X eXit the program. NOTE: This forces an ungraceful exit and will likely cause program errors to occur.


NOTE 1: Enabling some messages will use a substantial amount of CPU--especially many sprite messages. This may cause the auto- LOD (see gwWindow::MaxElapsedTimeMs member) to lower the level of detail, likely causing some sprites, and their subsprites, not to be drawn at all. When debugging , it may be necessary to programmatically set gwWindow::MaxElapsedTimeMs to zero and specify a gwWindow::LodFactor value to control level of detail. This may, of course, cause a single frame to take a long time to draw.

The 'b' command takes a hexadecimal bit map that can enable non-sprite messages. (To enable sprite messages, use the 'sf' command). The following bit maps can be bitwise ORed to form the value specified with the 'b' command. These are the same flags that can be passed to the gwSetDebug function. (Note that the preprocessor symbol shown is usable only programmatically with gwSetDebug. When using the 'b' command you must enter the numerical value):

Bit map: Preprocessor Symbol (if gwSetDebug is used): Message Type:
1 GW_FATAL_DBG Really bad errors
2 GW_WARN_DBG Non-fatal, possible programming mistakes
4 GW_LOD_STATS_DBG Dynamic level-of-detail statistics (not yet implemented)
0x20 GW_VRML_DBG High-level VRML parsing (by gwSprite::Load )
0x40 GW_VRML_PARAMETERS_DBG VRML keyword parameters (by gwSprite::Load)
0x80 GW_VRML_TOKENS_DBG VRML keywords (by gwSprite::Load )
0x400 GW_SCANCODE_DBG Keystrokes in a 3D window.
0x800 GW_VIEWPOINT_DBG Camera position and orientation.
0x1000 GW_OPENGL_DBG OpenGL calls
0x2000 GW_TASK_DBG Show thread IDs
0x4000 GW_SOUND_DBG Sound commands
0x8000 GW_CHECK_MATRIX_STACK_DBG Checks for invalid elements in the OpenGL modelview and projection matrix stacks. NOTE: This checks the stack by emptying it and then refilling it. If another thread needs the matrix stack during this time, a failure will occur. In other words, use this only in applications that have only one thread.
0x10000 GW_NET_DBG Network activity ( gwNetPackets and gwNetData )

After the debugger prompt has been enabled, entering the X (exit) command or closing the console will cause a warning window to display saying the program may be terminated ungracefully. This window is displayed because exiting a program via the console may not guarantee application shutdown code will be executed normally, which may cause a crash.

The debugger cannot work well in programs that already use a console and perform input and output to and from that console. This happens when multiple threads attempt to input from the same console. You can resolve this by preventing any of your own threads from attempting to get input from the console when you want the debugger to work. Using the GW_BLOCK flag to the gwWindow constructor helps in this.

If for some reason you don't want to use the GW_BLOCK flag to the gwWindow constructor, here is a kludgy way to allow an 'x' to be pressed to terminate the program yet still allow other threads to access the console (e.g. allow debug prompts):

printf("Press x to terminate.\n");

// we do it this way so the GWin3D debug prompt can be used if desired
while(1)
{
   Sleep(500);

   if(kbhit())
   if(getchar() == 'x')
       break;
}

Compiling a Sprite Tree

You should be familiar with LODs (see the section on Levels of Detail ) and with sprite trees (see gwSprite introduction and gwSprite::AddSubSprite ) before studying this section.

In certain special cases you can convert an entire sprite tree, or a portion of it, to an OpenGL display list. Then place that display list handle in the List[] members of a gwSprite so that it will be drawn when the sprite is drawn.

When there are many subsprites in a tree, converting it to an OpenGL display list will allow it to be drawn much faster. However, note that LODs will not be automatically chosen per each subsprite, since converting a tree to a display list effectively makes it a single sprite.

Create an OpenGL display list handle with glGenLists. Then compile the tree by calling gwSprite::Draw within a glNewList and a glEndList call. You can then assign the display list handle to element(s) of another sprite's List array, or draw it directly with a call to glCallList.

Note that no functionality of the gwSprite or gwWindowclasses is compiled. Only OpenGL commands are compiled. So, for the sprites in a compiled sprite tree, you cannot change the current LODs, material, or texture (you must also assure that any textures used in the tree remain in existence--that is, don't delete the subsprites of the tree). Also, you cannot change the position or orientation of a subsprite in the tree relative to its parent in the tree. For this reason, you must make sure all the gwSprite and gwWindow settings are the way you want them when you compile the tree. The OpenGL commands that are used to draw the tree in the window are recorded in the compilation. Note that this means settings that control the LODs chosen for each subsprite must be the way you want.

By assigning the display list handle of a compiled sprite tree to another sprite's List element(s) (see gwSprite::List ), you make that LOD of that sprite become the entire tree.

There are two main approaches to using compiled sprite trees:temporary compiled sprite trees and sprite tree LODs. Theses are discussed in the following two sections.

Temporary Compiled Sprite Trees

A temporary sprite tree is created and destroyed every several frames. You compile all non-moving and very distant sprites in one frame so that they can be drawn more quickly for the next several frames. Since the compilation process does take time, it is logical to recompile only a portion of the non-moving sprites every frame. For example, you might maintain twenty compiled sprite trees, each encompassing one-twentieth of all non-moving and very distant sprites, and re-compile only one of them each frame.

Since one typically includes all sprites as subsprites in a Universe sprite, and only the more distant, non-moving sprites should be compiled, you'll still need to draw the Universe so that nearby moving sprites are drawn. This means you'll need a method to control which of the Universe sprites are compiled and which are drawn when the Universe sprite is drawn. This can be accomplished with the gwSprite::Flags member.

Compiled Sprite Tree LODs

You may want to create separate compilations of a tree for each LOD of the tree. You would assign each display list created to separate element(s) of the destination sprite's List array.

You would create these separate compiled LODs of the tree by compiling the tree in a window with different gwWindow::ApertureAnglevalues. As always, the entire tree must be visible when you compile it so that the proper OpenGL commands get compiled. To create the highest LOD, place the tree to be compiled at some rather high distance from the camera but adjust gwWindow::ApertureAngle so that the tree still fills the entire window (but no portion of the tree is outside the window). You might also be able to force certain LODs to be drawn by manipulating the SubspriteLodLimit and LodScale members of each sprite before the tree is drawn. Also, the window should be maximized. These steps assure that GWin3D will display a reasonably high LOD for each subsprite in the tree. Note that if you place the tree very close to the camera when you compile it for the highest LOD of the tree (even if ApertureAngle still allows the whole tree to be visible), you might cause the farther subsprites of the tree to draw a lower LOD than the nearer subsprites during compilation, which is undesirable--this is why you place the tree some distance from the viewpoint, and adjust ApertureAngle to encompass it when compiling the highest LOD of the tree. Lower LODs of the tree are compiled by drawing the tree when it is half the diameter in the window, one-fourth the diameter, etc..

You can also use sprite tree compilation to speed displaying of an entire scene. In this case you periodically compile everything in the scene that will not change for the next few frames so that you need only draw the compiled version for those successive frames.

Compiling sprites whose position or orientation (relative to its parent), material, texture, or view status (out of view) changes from one frame to the next is not logical. However, sprites that do not undergo any of these changes from one frame to the next can be compiled.

You can compile all the unchanging sprites in a scene and use that compiled tree to display them until they must change. Recompilation of the tree is necessary when there is a substantial movement or change in orientation of the camera or the aperture angle (zoom). This is because such changes in the camera change which sprites are out of view and also changes the LODs that should be displayed.

The gwSprite::Draw function allows parameters to be passed that limit which sprites are drawn. Using these parameters you can cause the Draw function to only draw the unchanging sprites when you compile the display list, and draw only the changing sprites when you draw the tree directly. With this method, however, there is some overhead in the Draw function even for sprites that are not drawn. Another way is to create a separate sprite tree comprised only of unchanging sprites and another tree composed of changing sprites and of any unchanging sprites that have changing subsprites. The unchanging tree can be compiled once (until the camera angle or zoom changes notably) and the tree of changing sprites can still be drawn each frame .

See the OpenGL glGenLists, glNewList, glEndList, and glCallList functions. Also see the section on Levels of Detail, the gwSprite introduction , and gwSprite::AddSubSprite.

Possible Future Improvements

The following features are not yet supported in GWin3D but probably should be. Note that many of them can currently be implemented by the application. This list doesn't mean they are impossible--it just means GWin3D doesn't do them internally, yet:

Troubleshooting FAQ

(Note: Also see the Possible Future Improvements section)

QUESTION: Crashes and Weird Stuff

GWin3D crashes my system or makes weird stuff appear on the screen.

ANSWER:
This can be caused by GWin3D, your application, your hardware, or the OpenGL drivers on your system.

First, make sure you have the latest versions of all software and drivers.

Some crashes and problems not associated with 3D graphics can be attributed to mismatched run-time libraries. Normally it is safe for different components of an application (DLLs, static libs, application modules) to use different run-time libraries. Problems arise, however, when certain resource handles are shared between different run-time libraries, like FILE pointers, thread handles, etc. and when different memory heaps are used. See gwSprite::Save for more discussion on this.

If the problem is 3D graphics related, make sure GWin3D debugger warning and error messages are enabled (they are enabled by default) and resolve all of the warnings and errors that are displayed.

Next, try your program on another brand of video card.

If that fails with the same symptom, too, then the problem is either GWin3D or your application. See the section on Debugging. If using another brand card fixes the problem, then it is your OpenGL driver or hardware.

QUESTION: I can't see my sprite

I created a sprite but I can't see it.

ANSWER:
There are several things you can try:

Make sure the sprite was created successfully by checking function return values and class members. You might also temporarily replace its creation code with a GW_SPHERE sprite.

If a GW_SPHERE sprite is visible but one created from your VRML file is not, remember that only a subset of VRML is supported (many VRML keywords are ignored). See the gwSprite::Load function. Experiment first with an extremely simple VRML file. Also note the many options in loading a VRML file.

If a GW_SPHERE sprite is not visible, either, you might temporarily forcing all window and sprite settings to those that will most probably let you see your sprite so that you can more easily find out what is otherwise preventing it from appearing. The below settings can be used to force visibility. Please note that many of the values shown below are not reasonable for efficient operation:

Win->BackClip = 10000000;
Win->FrontClip = .001;
Win->BottomBorder =0;
Win->LeftBorder = 0;
Win->LodFactor =100;
Win->MaxElapsedTimeMs =0;
Win->RightBorder = 0;
Win->TopBorder = 0;
Win->ApertureAngle =150;

Sprite->Emission[0]=1;
Sprite->Emission[1]=1;
Sprite->Emission[2]=1;
Sprite->Emission[3]=1;


Make sure the Sprite's Radius is set to a reasonable value.

Make sure the visible size of the sprite is not infinitesimal or astronomical. You might try radically scaling it up and down as an experiment. See gwMatrix::SetScale (inherited by gwSprite ).

Try different background colors in case the sprite has the same color as the background (use glClearColor).

Make sure you aren't looking at the backside of one-sided polygons. See the GW_FLIP_POLYGONS flag. (Actually, by default, GWin3D sets all polygons to two-sided with an OpenGL call, so this shouldn't make a difference unless you've changed it away from that.)

As an experiment, do not override the default material and background colors, and do not enable translucency.

Take a close look at the position and orientation of your viewpoint, and the position, orientation, scale, shear , etc. of the sprite you are suppose to see. You may need to try different values for these. If you don't change gwWindow::ViewPointSprite, then it will point to the default viewpoint sprite, which looks down the negative Z-axis from a distance of a few hundred.

Enable sprite debug messages to see what the position and radius of the sprite actually is (see the section on The Debugger ), call gwDumpSprite, or just put printfs in your periodic code to show the values of interest (assuming yours is a console application).

You may want to place the following code in your periodic function so you can pan the camera pitch and yaw using the arrow keys, in search of your object:

if(Win->KeyStatus [GW_KEY_DOWN_ARROW] & GW_KEY_DOWN_NOW)
   Win->ViewpointSprite ->ModifyRotation (-2,0,0);
if(Win->KeyStatus [GW_KEY_UP_ARROW] & GW_KEY_DOWN_NOW)
   Win->ViewpointSprite ->ModifyRotation (2,0,0);
if(Win->KeyStatus [GW_KEY_RIGHT_ARROW] & GW_KEY_DOWN_NOW)
   Win->ViewpointSprite ->ModifyRotation (0,-2,0);
if(Win->KeyStatus [GW_KEY_LEFT_ARROW] & GW_KEY_DOWN_NOW)
   Win->ViewpointSprite ->ModifyRotation (0,2,0);


The above code pans the camera at its current position. To move the camera in "examine" mode (so that the camera rotates around the origin, continually pointing at the origin), use the ModifyWithRotation function instead of the ModifyRotation function in the above code.

QUESTION: Incorrect depths of sprites

I see any of the following: ANSWER:
See the question about jagged intersections.

QUESTION: Polygons flicker at a distance

The polygons of my sprite flicker different colors when I am far away from them.

ANSWER:
See the question about jagged intersections.

QUESTION: Jagged intersections of surfaces

I see any of the following:
ANSWER:
All of these can be depth buffer artifacts. They are indications of OpenGL's limited ability to keep track of how far away a fragment is.

As objects are being drawn in a frame, OpenGL keeps track of the distance (from the camera) to each pixel on the screen. That way when another object is drawn over a first object, for each pixel OpenGL can know whether the second object's pixel is in front of or behind that of the first object.

As with any stored value in a computer, there is only so much precision. Most modern OpenGL drivers use 32 bits to hold the distance value of each pixel. The units of this value are not meters. If it were, much of the resolution would be wasted because many scenes span millimeters while other scenes may span parsecs. Rather, the units of the depth buffer are described by two separate variables elsewhere. These are the front clipping value and the back clipping value. These tell OpenGL what distance is meant by a depth buffer value of zero, and what distance is meant by a depth buffer value of 4294967296 (maximum value for a 32-bit number).

On a side note, the value of a depth buffer entry is a non-linear representation of a distance. Low depth buffer values represent finer increments in distance than high depth buffer values. This improves the performance of the depth buffer--we care more about accurate depth calculation for near objects than we do far objects.

Pixels beyond the back clip value or closer than the front clip value are simply not drawn by OpenGL because there is no way to keep track of how far away they are.

OpenGL requires that the front clip and back clip values be specified by the application. GWin3D automatically calculates optimal clipping values and tells OpenGL, but only if you have correctly specified sprite radii, among other things.

In some cases there is nothing you can do about depth buffer artifacts because you have simply pushed the depth buffer precision to the limit. For example, you are displaying a very near sprite and a very far sprite at the same time. You might, however, be able to increase this precision--See the Pfd parameter of the gwWindow constructor. But often these artifacts indicate the various GWin3D parameters that control the auto-clipping values given to OpenGL have been poorly chosen.

If you are experiencing any of the abovementioned artifacts and suspect you shouldn't be seeing them considering the distances of your sprites, then do the following:

QUESTION: Periphery disappearance/flashing

My sprite sometimes shows up OK but suddenly disappears or flashes as I turn away from it (that is, it disappears when it is near the edge of the window) or it suddenly disappears when I get close to it.

ANSWER:
Remember that a sprite's Radius member must reflect the size of the sprite with all its sub sprites so that GWin3D can correctly and automatically handle certain drawing attributes without you having to worry about them. A common mistake is to set the Radius member of a sprite to a value indicating the size of the visible part of the parent sprite even though the sub sprites extend beyond that radius.

To save CPU and GPU, GWin3D stops drawing a sprite every frame when it is out of view. This means the sprite's sub sprites will also not be drawn very frequently if the value of the sprite's Radius member does not include them and the parent sprite is out of view.

QUESTION: I change a sprite's position and it disappears for a few frames

ANSWER:
See gwSprite::InfrequentRecalcMask.

QUESTION: A newly created sprite doesn't immediately appear

I create a sprite but I don't see it for a few frames immediately after I created it.

ANSWER:
See gwSprite::InfrequentRecalcMask.

Reference

This section describes all of the classes and their members, global functions, global variables, and defined symbols.

Class member functions are always virtual where possible, and many use the __fastcall calling convention. Since these attributes are taken care of automatically according to the function prototypes in the gwin3d.h file, they are not listed in the function descriptions herein.

The performance overhead for virtual functions is negligible, and they assure that the right function will be called when mixing object pointers in the same class hierarchy.

Every class contains a SizeOf function. SizeOf on a class should be used in place of the C standard function 'sizeof', because sizeof is not virtual and SizeOf is. In fact, when you create a child class of a GWin3D class, you should implement a SizeOf function for all inherited classes. At the time of this writing, only the gwMesh and gwSprite class's SizeOf() function is called by any GWin3D library code, but this may change in the future.

Class gwWindow

The gwWindow class manages everything to do with a 3D window.

You must create a gwWindow object for each 3D window you want displayed.

You can either pass the handle of an existing window to the constructor, or not pass a handle so that the gwWindow constructor creates and displays a simple window for you.

Sprite creation and drawing code for this window must all be executed in the same thread. This approach is necessary because OpenGL places certain restrictions on the thread context in which OpenGL calls are made. If you obey this rule you won't have to worry about these restrictions. Creation of sprites from VRML files, drawing of sprites, creation of textures, and direct calls to OpenGL functions must be executed in the same thread. See the gwWindow constructor for more information.

Note: In theory there is a way to allow openGL objects and textures created for one window to be used in other windows using the Win32 wglShareLists function. Unfortunately it causes problems for many graphics drivers, so GWin3D does not attempt it. To implement multiple windows displaying the same objects, you will either need to create separate instances of those objects for each rendering context (gwWindow instantiation), or separate single gwWindow into regions and write your own codse to manage them as separate regions.

If you want to create your own 3D display window, but you want it created from within the same thread that runs the UpdateFrame function, then create a child class of the gwWindow class that has an override of the WrapInitFunc. Below is the existing code to gwWindow::WrapInitFunc. As you can see, you can alter this code in your child class's version of the function to change how the window is created:

GW_FUNCTIONPREMOD unsigned int GW_FUNCTIONINMOD WrapInitFunc( gwRealTimeTask *Task)
{
   // Get the gwWindow object
   gwWindow *Win=(gwWindow *)Task->Context;

   // Create a window if no handle was passed
   if(!Win->Wnd)
   {
       Win->Wnd=CreateWindow
       (
           "GW3DWIN",
           "GWin3D",
           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           NULL,
           (HMENU)NULL,
           0,//hInstance,
           NULL
       );

       if(!Win->Wnd)
           SERRCHECK;

       Win->MyWindow=1;
   }

   Win->DC=GetDC(Win->Wnd);

   // Initialize the rendering context
   Win->Select();

   return 0;
}


MEMBERS:

gwWindow::gwWindow

gwWindow
(
   HWND WinHandle=NULL,
   void (__fastcall *PeriodicFunctionIn)(gwWindow *)=GW_MEMBER_FRAME_UPDATE,
   __int64 Flags=0,

   int PeriodIn=50,
   void *ContextIn=NULL,

   long TimeoutForInitDone=60000,
   PIXELFORMATDESCRIPTOR *Pfd=NULL

)

gwWindow ( gwWindow *Win)


See the introduction to the gwWindow class, and the section on Creating an Application that Displays Dynamic 3D Scenes, for more information.

For the first constructor:

If PeriodicFunction is not NULL, then it points to an application-defined function that contains the code to update the window contents for each frame. A new thread is created which periodically calls PeriodicFunction (passing the address of the gwWindow object) at the rate specified by Period.

You can pass NULL for the PeriodicFunction if you don't need the precise timing it supplies and you plan on doing your drawing elsewhere. In that case no thread is created. Just remember that all code that directly or indirectly calls OpenGL functions for this window must be performed in the same thread. If you do not pass a PeriodicFunction, please note that currently no OpenGL functions are called when the gwWindow object is created. Rather, the OpenGL functions to set up the window are called the first time PrepareForDrawing is called on a new gwWindow . Future releases of GWin3D may perform some OpenGL calls in the constructor, so you should still try to call the constructor in the same thread that does the drawing.

If no PeriodicFunction is specified, then each time you draw a frame you must explicitly call PrepareForDrawing before drawing the frame, and call FinishDrawing after drawing the frame. (These are automatically called only if you use a PeriodicFunction to draw each frame). Also, you will probably want to disable auto-LOD in this case (see MaxElapsedTimeMs) if you won't be drawing at some constant, rather fast, rate.

A typical approach without a PeriodicFunction is to set up and draw in the 3D window from within a window's message handler functions. For example you might set up the window in your WM_INITDIALOG handler, update sprite positions in a WM_TIMER handler, and draw the sprites in a WM_PAINT handler. There are other issues when using this approach, so see the section on Creating an Application that Displays Dynamic 3D Scenes for a discussion of these issues. Also remember that PrepareForDrawing and FinishDrawing must be called in the WM_PAINT handler. In fact, since the window is not really initialized and ready for use until after the first time PrepareForDrawing is called, then your WM_INITDIALOG handler must also call PrepareForDrawing and FinishDrawing simply to assure the window is properly initialized before creating sprites, etc. for that window. For example, here is a typical chunk of code you might have in a WM_INITDIALOG handler (remember, this only applies if you chose not to put everything in a PeriodicFunction):

    Win3D=new gwWindow(m_hWnd,NULL,0);

    // disable auto-LOD because we're not drawing at any constant rate
    Win3D->MaxElapsedTimeMs=0;
    Win3D->LodFactor=1;

    Win3D->PrepareForDrawing();

    Floor=new gwSprite("floorplan");

    Win3D->FinishDrawing();


If you specified a PeriodicFunction, any application-level one-time initialization must, of course, be executed in that function (because that function is called by a unique thread). So you must place any one-time initialization application code for your window in a conditional block that executes only the first time the periodic function is called. Likewise, declaration of static variables within the function body can be used to assure the variables are created and their constructors called in the same thread context. Permanent sprites can be created in this way. Of course, you can also just dynamically create sprites with the 'new' operator.

You can change a sprite's attributes (position, orientation, material, flags, etc.) from other threads and functions because such does not involve OpenGL calls (The OpenGL calls are performed when the sprite is drawn, not when the sprite's position information is changed). This can be done as long as only one thread accesses these members at a time. For example, you shouldn't allow one thread to call gwSprite::Draw while another is updating the sprite's matrix . See the gwSprite::Lock() and gwSprite::Unlock() functions.

WinHandle is an optional handle to a window. It can be the handle to an existing window that you want to use as the 3D display, or NULL if you want GWin3D to create a window for the 3D display and destroy it when the gwWindow object is destroyed. If you let the constructor create a window, then the window's icon and mouse cursor will be that specified by GW_INIT_LIB.

If PeriodicFunction is not NULL, then by default GWin3D runs a message pump in the new thread in between calls to the periodic function. This pump processes all messages in the queue each time it is called. Thus any windows owned by the thread (such as the one automatically created if WinHandle is NULL and any windows you might create from within your periodic function) will be serviced. You can disable this with the GW_NO_MSG_PUMP flag. Note that if you did pass a WinHandle then it is up to the thread that owns that window to pump its messages.

PeriodicFunction can also be GW_MEMBER_FRAME_UPDATE, which indicates the gwWindow object's FrameUpdate member function is to be used as the periodic function. This is useful when you want to inherit from gwWindow and allow all the class's members to be available from within your periodic function.

The Flags parameter is copied to the Flags member of the gwWindow object. All bits of the Flags member can be altered on the fly. Flags can be a bitwise OR of any of the following:

GW_NO_MSG_PUMP tells GWin3D not to run a message pump in the same thread and in between calls to your PeriodicFunction (if one was specified). You would use this flag if you want to code your own message pump in your periodic function or you know you won't need a message pump. It doesn't hurt to run the message pump when one isn't needed--the overhead is negligible. Note: a message pump should certainly be implemented (by not passing this flag, or by coding your own message pump in your periodic function) if you passed a NULL WinHandle to the constructor or you created other windows from within your periodic function. This flag has meaning only if WinHandle is NULL and PeriodicFunction is not NULL.

GW_BLOCK causes the window to be destroyed when it is closed and the constructor to block until the window is destroyed. This flag has meaning only if WinHandle is NULL and PeriodicFunction is not NULL.

GW_HIDE_ON_CLOSE causes the window to only be hidden when it receives a WM_CLOSE message. This flag has meaning only if WinHandle is NULL and PeriodicFunction is not NULL.

GW_DESTROY_ON_CLOSE causes the window to be destroyed when it receives a WM_CLOSE message. This flag has meaning only if WinHandle is NULL and PeriodicFunction is not NULL.

If none of the above flags are passed and no WinHandle was passed, then WM_CLOSE messages are ignored.

For more control of what happens to the window when it receives various messages, create your own window with its own message handler.

GW_NO_FINISH_DRAWING
GW_NO_PREPARE_FOR_DRAWING
If a PeriodicFunction was specified, then these flags tell GWin3D whether to perform the various tasks necessary in preparing to draw a new frame just before the window's period function is called and whether to perform the various tasks necessary after a new frame has been drawn. You would typically set and clear these flags on the fly from within your periodic function. These are useful, for example, when you want to use the periodic function to perform other tasks at a faster rate than frames need to be drawn. In that case, you would code your periodic function to draw only every several frames. Your periodic function should set the GW_NO_PREPARE_FOR_DRAWING flag to indicate that the next call of the periodic function will not be drawing anything. Set the GW_NO_FINISH_DRAWING flag to indicate the current call of the periodic function has not drawn anything. Be sure to clear the flags, otherwise. These flags have no effect if PeriodicFunction was NULL, in which case your drawing code is responsible for explicitly calling PrepareForDrawing and FinishDrawing .

Context is not used for anything by GWin3D, but it is copied to the Context member of the gwWindow object. Your code can then use it to uniquely identify the gwWindow object to the PeriodicFunction if, for example, the PeriodicFunction is written to handle multiple windows.

The TimeoutForInitDone causes the constructor to fail if the window's PeriodicFunction takes longer than this many microseconds the first time it is called.

If the Pfd parameter is not NULL, then it points to the pixel format descriptor that should be used in creating the device context for the window. This structure will be passed to the Win32 ChoosePixelFormat function in order to find the closest matching available pixel format on the current platform. If you want to know for sure you have selected one of the exact pixel formats available on the current platform, then first call the Win32 GetPixelFormat function for each pixel format index in order to enumerate all available pixel formats, pick the one that best satisfies your needs, and pass that structure to the gwWindow constructor. If Pfd is NULL, then a default pixel format descriptor is used which has the following contents:
{
   sizeof(PIXELFORMATDESCRIPTOR),
   1, // Version
   PFD_DRAW_TO_WINDOW|
   PFD_SUPPORT_OPENGL|
   PFD_DOUBLEBUFFER|
   PFD_GENERIC_ACCELERATED, // dwFlags
   PFD_TYPE_RGBA, // iPixelType - RGBA context
   24, // cColorBits - 24 Bit Color
   0, 0, 0, 0, 0, 0, // RGB Bits & Shifts
   0, 0, // Alpha buffer
   0, 0, 0, 0, 0, // Accumulator
   32, // cDepthBits - Z Buffer
   0, // Stencil Bits
   1, // Auxiliary Buffers
   PFD_MAIN_PLANE, // Layer type
   0, // Reserved
   0, // Layer Mask
   0, // Visible Mask
   0 // Damage Mask
}


For the second constructor:

The constructor may be used to create a "secondary" gwWindow object that shares the same window as a primary gwWindow object. For example, you might call the other constructor first, then call this constructor to make another gwWindow object that uses the same window.

If you use this constructor, then it should be called by the same thread that draws in the window. For examples, if you are using a PeriodicFunction, then it should be called from within that PeriodicFunction. If you are drawing with a WM_PAINT handler, this constructor should be called from the thread pumping messages for that WM_PAINT handler. This is an OpenGL requirement.

Multiple gwWindow objects can be used to manage multiple cameras for the same window. This is necessary because the gwWindow object holds many parameters that are dependent on both the current camera and the state of the window.

gwWindow objects that were created with this constructor do not update their KeyStatus array. Use the KeyStatus array in the primary gwWindow object.

gwWindow objects created with this constructor do not need their PrepareForDrawing or FinishDrawing functions called. In fact, they should never be called.

For primary gwWindow objects, gwSprite::InfrequentRecalcMask is tested against FrameCount to decide when to perform the infrequent calculations. For secondary gwWindow objects, gwSprite::InfrequentRecalcMask is tested against ViewpointDrawCount because FrameCount is never incremented (because PrepareForDrawing is never called). This means that for secondary windows, you should either not draw the viewpoint sprite more than once during a single frame, or you should directly set the secondary window's ViewpointDrawCount to reflect the frame count. That way sprites drawn in a secondary window will still have their infrequent code executed periodically.

gwWindow::FrameUpdate

void FrameUpdate()

If GW_MEMBER_FRAME_UPDATE is passed as the PeriodicFunction parameter to the gwWindow constructor, then this function is used as the periodic function. See the description of the gwWindow constructor for more information.

gwWindow::PrepareForDrawing

PrepareForDrawing()

Performs the OpenGL tasks necessary before drawing a new frame. This is automatically called if you passed the address of a PeriodicFunction to the gwWindow constructor. You must call this explicitly before starting the drawing of a new frame when you draw frames outside of a periodic function. See the gwWindow constructor for more information.

gwWindow::FinishDrawing

FinishDrawing()

Performs the OpenGL tasks necessary after drawing a new frame. This is automatically called if you passed the address of a PeriodicFunction to the gwWindow constructor. You must call this explicitly after you are done drawing a frame if you did not specify the PeriodicFunction parameter to the gwWindow constructor. See the gwWindow constructor for more information.

gwWindow::FrameCount

gwWindow::ViewpointDrawCount

long gwWindow::FrameCount
long gwWindow::ViewpointDrawCount

FrameCount is incremented for each frame (by PrepareForDrawing ).

ViewpointDrawCount is incremented every time the ViewpointSprite is drawn (by gwSprite::Draw, if the sprite is the ViewpointSprite).

These variables are used by the gwSprite::Draw function to decide when to perform the infrequent drawing calculations. See gwSprite::InfrequentRecalcMask .

gwWindow::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy.

gwWindow::Flags

__int64 gwWindow::Flags

This holds the flags that had been passed to the gwWindow constructor (see the gwWindow constructor for descriptions of those flags). All of the flag bits can be changed on the fly.

gwWindow::RC

HGLRC gwWindow::RC

The OpenGL rendering context for the window. This is created the first time PrepareForDrawing is called. See PrepareForDrawing .

gwWindow::DC

HDC gwWindow::DC

The device context for the window. This is created the first time PrepareForDrawing is called. See PrepareForDrawing .

gwWindow::ViewpointSprite

gwSprite * gwWindow::ViewpointSprite

Points to the sprite whose position and orientation define the position and orientation of the camera (viewpoint).

By default, this is set equal to DefaultViewpointSprite member of the gwWindow object, which points to an internally created sprite with no visible attributes and whose position and orientation are initialized to point down the negative Z-axis and backed away by about 200, so that sprites positioned at the origin are visible from their front side.

When the ViewpointSprite is drawn, GWin3D positions the OpenGL viewpoint.

You can alter the orientation and position of DefaultViewpointSprite to move the camera, or you can set ViewpointSprite to be the address of some other sprite.

If your periodic function code is not bothering to draw the viewpoint sprite, then GWin3D recognizes this and draws the viewpoint sprite each time just before it calls the periodic function. If the viewpoint sprite is being drawn by your periodic function, then GWin3D does not draw it.

ViewpointSprite can also be the address of a subsprite in a sprite tree. However, in that case do not let GWin3D draw the ViewpointSprite (that is, be sure your own code draws it), because then it won't be oriented relative to its parents. This is because when GWin3D draws the viewpoint sprite (because your code isn't drawing it), it is drawn as if it is a topmost sprite.

You might point this member to a spaceship sprite that was created and is updated by your PeriodicFunction. Another option is to simply add DefaultViewpointSprite as a subsprite to the spaceship. That way the orientation of DefaultViewpointSprite can be adjusted relative to the spaceship, which is equivalent to allowing the pilot to be oriented and moved relative to the ship.

If you do not draw the viewpoint sprite before all other sprites in the frame, then you will experience a lag in the movement of the viewpoint. For example, if the ViewPointSprite is a child of a spaceship, then the viewpoint will appear to be pulled behind the spaceship when it is moving. This is because the previous frame 's viewpoint position is still in effect until the viewpoint is moved. So it may be necessary to code a separate call to gwSprite::Drawin your periodic function simply to draw the viewpoint sprite first, before you draw all other sprites. If the viewpoint sprite is deeply nested in a sprite tree then all the parent sprites will have to be drawn once with a Flag bit to prevent them from appearing (to save GPU), then the tree will have to be drawn again with Flag bits allowing them to appear. See gwSprite::Flags.

Here is an example. This code would be in your gwWindow 's PeriodicFunction:

// the app is allowed to use sprite flags below bit 32
#define MY_VIEWPOINT_SPRITE 0x10000

// create a spaceship (must be declared within PeriodicFunction body
// so that the constructor is called in the right thread context)
static gwSprite Spaceship(...);

// do stuff that need be done only once
static int FirstTime=1;
If(FirstTime)
{
   FirstTime=0;

   // put the pilot in the spaceship
   Spaceship.AddSubSprite (Win->ViewpointSprite );

   // set a flag bit in the viewpoint so the Draw function
   // can recognize it for drawing separately
   Win->ViewpointSprite ->Flags |= MY_VIEWPOINT_SPRITE;

   // Add the spaceship to the universe.
   Universe.AddSubSprite (&Spaceship);
}

... (update sprite positions as needed here)


// draw the spaceship separately, relative to the origin. This works as long
// as the spaceship is a direct child of the Universe, or nobody's child.
// This way we don't have to draw the entire universe twice.
Spaceship.Draw(Win, MY_VIEWPOINT_SPRITE, MY_VIEWPOINT_SPRITE);

// draw all sprites (spaceship is drawn again here because we didn't bother
// specifying flags criteria).
Universe.Draw(Win);

gwWindow::RealTimeTask

gwRealTimeTask * gwWindow::RealTimeTask

Controls the PeriodicFunction for the window, if a PeriodicFunction had been specified in the constructor. See gwRealTimeTask.

gwWindow::ApertureAngle

double gwWindow::ApertureAngle

This controls the camera zoom. It is the visible angle (zoom, magnification) seen in the window, in degrees.

gwWindow::AspectRatio

double gwWindow::AspectRatio

Aspect ratio in the window.

If this is zero, then pixels are presumed square and no distortion of the scene occurs no matter what the window width and height, and the image width is kept proportional to the width of the window.

If this is non-zero, then the view aspect ratio is made equal to this, and the view is distorted to fit in the aspect ratio of the window.

Also see gwSprite::ApertureAngle.

gwWindow::ViewPort

gwWindow::ViewX

gwWindow::ViewY

gwWindow::ViewWidth

gwWindow::ViewHeight

union
{
   long ViewPort [4];
   struct
   {
       long ViewX;
       long ViewY;
       long ViewWidth ;
       long ViewHeight ;
   };
};


This read-only member is the current OpenGL viewport extents, in pixels.

gwWindow::KeyStatus

unsigned int gwWindow::KeyStatus[0x160]

This array reflects the state and history of all keyboard keys and mouse buttons pressed while the window has focus.

Note: child windows (buttons, checkboxes, etc.) on a window will grab the focus from the main window and can prevent keyboard and mouse messages from being sent to the main window. In that case the KeyStatus array will not be updated.

The index into the array is the key code. See GWin3D.h for preprocessor symbols for each key code. The following preprocessor symbols are bitmaps of the bits of a KeyStatus element that have meaning:

GW_KEY_DOWN_NOW - indicates the key is currently pressed. Use this for "level" sensitive code.

GW_KEY_WAS_DOWN - indicates the key was pressed since the last time this flag was cleared. It is up to the application to clear this bit when the key is finally processed. Use this for "edge" sensitive code.

GW_KEY_WAS_DOUBLE_CLICKED - indicates a mouse key was double clicked. It is up to the application to clear this bit when the key is finally processed. Use this for "edge" sensitive code.

You may also notice that two of the keys defined in GWin3D.h are GW_KEY_LBUTTON and GW_KEY_RBUTTON. These are "key codes" (indexes into the KeyStatus array) for the mouse buttons. The GW_KEY_DOWN_NOW, GW_KEY_WAS_DOWN, and GW_KEY_WAS_DOUBLE_CLICKED bits in these elements of the KeyStatus array indicate the state and recent history of the corresponding mouse button.

Also see the MouseX and MouseY members.

Example:

// this code is sensitive to the level (current state) of the left shift button
if(Win->KeyStatus [GW_KEY_LEFT_SHIFT] & GW_KEY_DOWN_NOW) Pitch ++;

// this code is sensitive to the down-going edge of the left mouse button
if(Win->KeyStatus [GW_KEY_LBUTTON] & GW_KEY_WAS_DOWN)
{
   // clear the history bit
   Win->KeyStatus [GW_KEY_LBUTTON] &= ~GW_KEY_WAS_DOWN;

   printf("LBUTTON %d %d\n",Win->MouseX,Win->MouseY);
}

See LastKeyCode, MouseX , MouseY .

gwWindow::MouseX

gwWindow::MouseY

unsigned long gwWindow::MouseX
unsigned long gwWindow::MouseY

These are the current X and Y coordinates of the mouse cursor in the window client area. The origin is in the lower left corner. These values and the gwSprite::ViewX and gwSprite::ViewY values use the same units (pixels) and exist in the same 2D coordinate system.

Note: If the mouse has left the client area of the window, then these members reflect the last known mouse location in the window.

See also gwWindow::KeyStatus, gwSprite::ViewX, gwSprite::ViewY.

gwWindow::LastKeyCode

unsigned int gwWindow::LastKeyCode

This is the key code of the last key pressed. Note that if two keys were pressed before your code looks at this, the first key press will be lost. Use the KeyStatus array for proper keyboard input handling. See GWin3D.h for preprocessor symbols for each keycode.

gwWindow::Print

void Print
(
   gwColor Color,
   unsigned long FontHandle,
   double X,
   double Y,
   long FontHeight,
   const char *String
)

void _cdecl Printf
(
   gwColor Color,
   unsigned long FontHandle,
   double X,
   double Y,
   long FontHeight,
   const char *fmt,
   ...
)

Prints text to the window.

FontHandle can be gotten from a call to MakeFont. If FontHandle is NULL, then a default font is used.

FontHeight should be specified if there are carriage returns in the text. This specifies how many pixels to move down for each carriage return. If FontHeight is zero, then the height of the window's default font is used.

Currently the length of the printed text must not exceed 2000 characters.

The second form uses printf style optional parameters.

Unlike using gwSprite::Text or gwSprite::TextHandle, this function is unassociated with a sprite.

gwWindow::MakeFont

unsigned long MakeFont
(
   int nHeight,
   int nWidth,
   int nEscapement,
   int nOrientation,
   int fnWeight,
   DWORD fdwItalic,
   DWORD fdwUnderline,
   DWORD fdwStrikeOut,
   DWORD fdwCharSet,
   DWORD fdwOutputPrecision,
   DWORD fdwClipPrecision,
   DWORD fdwQuality,
   DWORD fdwPitchAndFamily,
   LPCTSTR lpszFace
)

Creates a font for use by Print, Printf, gwSprite::TextLabel , and DestroyFont.

nHeight - logical height of font
nWidth - logical average character width
nEscapement - angle of escapement
nOrientation - base-line orientation angle
fnWeight - font weight
fdwItalic - italic attribute flag
fdwUnderline - underline attribute flag
fdwStrikeOut - strikeout attribute flag
fdwCharSet - character set identifier
fdwOutputPrecision - output precision
fdwClipPrecision - clipping precision
fdwQuality - output quality
fdwPitchAndFamily -pitch and family
lpszFace - pointer to typeface name string

For details, see the Win32 function CreateFont. You must call DestroyFont to free the resources allocatred by this function.

gwWindow::DestroyFont

void DestroyFont(long FontHandle)

Destroys a font created by MakeFont.

gwWindow::MaxElapsedTimeMs

int gwWindow::MaxElapsedTimeMs

Use this member to control the auto-level-of-detail. See the sections on level of detail and the gwSprite::Load function for more information on level of detail.

If you want the gwWindow to automatically adjust its scene detail for a target frames-per-second, then set this a tad lower than the period of your frame update code (that is, the Period value you gave to the gwWindowconstructor). Default is twice the period of the periodic function, which will probably be excessively high in most cases, but at least increases the probability everything will be visible when you first start program development.

Specifically, the time it takes your periodic function to execute is compared with the MaxElapsedTimeMs value. If it took longer than that, then LodFactor is lowered. If it took less than that, then LodFactor is raised. The auto-LOD algorithm will not set LodFactor over a value of 1.

It is impossible for auto-LOD to make sure MaxElapsedTimeMs is never exceeded. This is because it can't be known how long it will take to draw everything at a certain LOD until it is attempted. Therefore there will be times that MaxElapsedTimeMs is exceeded, in some situations by as much as twice the value of MaxElapsedTimeMs.

A side effect of this will be that any periodic code in the same thread will be slowed down. It is usually OK if drawing frame rate sometimes slows down, but it may be unacceptable if the entire application (such as the game/play rate) slows down.

A simple solution to this is to set MaxElapsedTimeMs to a value notably lower than the period of your periodic function.

Other solutions involve multiple threads running at different thread priorities (the game play thread should be higher priority than the drawing thread), or neglecting to draw any more sprites after the allotted frame time has expired.

See the Performance section for an example of how you can reduce the frame update rate instead of LOD if you are running out of CPU/GPU.

See the LodFactor member.

gwWindow::LodFactor

double gwWindow::LodFactor

This is the current global level of detail being used in the window. This is updated dynamically by GWin3D according to CPU and GPU usage, if MaxElapsedTimeMs is non-zero (auto-LOD is enabled). If MaxElapsedTimeMs is zero (disabling auto-LOD), you should set this yourself to adjust the global level of detail. A value of 1 is nominal, and means detail is high quality. In that case sprite LODs will be chosen which show just barely the best detail visible at its given distance--assuming the LOD images assigned to sprites follow the rules of polygon count described in the section on Level of Detail (LOD) and that each sprite's gwSprite::LodScale member is correct. LodFactor values less than 1 reduce the detail and likewise the CPU and GPU usage. Values of more than 1 can be used to force higher LOD images to be displayed at high distance. This may be done only if you are sure you have the CPU and GPU power to waste and there are some sprites that do not have a low-LOD image defined.

Note that different machines will be able to handle different LodFactor values. Using auto- LOD by setting MaxElapsedTimeMs is recommended over setting this member explicitly.

If you are using auto-LOD and are managing multiple windows, you should enable auto- LOD in only one window (as long as its visible and not minimized). Then in the top of your periodic code read the LodFactor value from that one window and assign it to the LodFactor members of all the other windows. This is necessary because the pipeline latency of many modern video cards would otherwise cause the LodFactor values of each window to oscillate over multiple frames (each at a different phase), or allow metastable states to exist in which one window hogs all the CPU/GPU power over all the others.

Even when only one window exists, the LodFactor may oscillate because of the graphics pipeline latency and the latency induced by large values for gwSprite::InfrequentRecalcMask. This oscillation is not very apparent unless the system is being taxed, causing excessively low sprite LOD images to be displayed even when the sprites are fairly close to the viewer. A PID loop was considered for the design of GWin3D to dampen the oscillation, but because the integration and differentiation constants would need to be radically different for different systems, the idea was dropped (constant values not matched to a system could make the problem far worse). The application programmer can still implement a PID loop to control LodFactor ( gwTimer would come in handy for this), but it is highly recommended that the PID constants be adjusted individually for each system on which the application runs. Also, you can try lowering the gwSprite::InfrequentRecalcMask value in your sprites and increasing your window's MinLodFactor if you are having auto- LOD oscillation problems--or just disable auto-LOD. This oscillation problem may be improved in later versions of GWin3D (i.e. with a generic PID loop that was tested on many systems).

Also see the MaxElapsedTimeMs and RealTimeTask members.

gwWindow::MinLodFactor

double gwWindow::MinLodFactor

When auto-LOD is enabled (see MaxElapsedTimeMs ), the LodFactor value is changed dynamically. The MinLodFactor member defines the lowest allowed value of LodFactor when auto- LOD is enabled.

gwWindow::FrontClip

double gwWindow::FrontClip

This tells OpenGL not to render anything that is closer to the viewpoint than this.

GWin3D does, however, still execute all sprite code every frame for sprites that are closer than FrontClip even though OpenGL will not actually render their images on the screen.

If this value is zero, then an auto-clipping algorithm will be used which sets front clipping somewhat closer than the closest sprite (considering, and including, its Radius ) that is included in distance calculations (see gwSprite::Flags ) and is within the field of view.

Also see the MinFrontClip member.

The default is 0 (use auto-clipping).

If you choose not to use auto-clipping by setting this to a non-zero value, it should be as large as is acceptable. This is because the larger it is the less likely depth artifacts will appear.

You may wonder why anyone would want FrontClip anything other than a very small value and BackClipanything other than a very large value. The reason is that OpenGL (or any 3D rendering system, for that matter) maintains a depth value of the nearest object for every pixel on the screen as objects are being drawn. Just before drawing a new frame, the depth value for each pixel is set to the deepest (furthest from the camera) value. When OpenGL sees a need to draw something at a pixel position, it first checks the depth value for that pixel to find out if there is already something closer to the camera. If there is (and it isn't translucent ) then OpenGL doesn't bother to change the pixel color. Otherwise OpenGL changes the pixel and updates the depth value for that pixel. This block of memory that holds depths for all pixels is called the depth buffer. Since depth values are integers (not floating point values) and the range of depth values for a pixel is limited, the smaller the range between FrontClip and BackClip the more accurate is depth processing, and the fewer depth artifacts will appear. A depth artifact can appear as a jagged intersection between two planes or an object appearing in front of another when it shouldn't do so.

gwWindow::MinFrontClip

double gwWindow::MinFrontClip

Whether the FrontClip member is set to zero (enabling auto-front-clipping) or not, front clipping will never fall below the value of MinFrontClip.

Default is .02

Without MinFrontClip, when auto-clipping is enabled and the viewpoint is inside a sprite (within its Radius ), front clipping would be set to zero--causing probable undesirable depth buffer artifacts.

gwWindow::MaxBackClip

double gwWindow::MaxBackClip

Whether the BackClip member is set to zero (enabling auto-back-clipping) or not, back clipping will never rise above the value of MaxBackClip.

Setting MaxBackClip to a non-zero value also causes the sprite drawing code to be executed less frequently for sprites that are beyond MaxBackClip.

MaxBackClip should be used in dense scenes in which distant sprites, likely obscured by closer sprites, should be neglected for the sake of performance, and to correct depth testing artifacts.

Default is 1e7.

gwWindow::BackClip

double gwWindow::BackClip

This tells OpenGL not to draw anything that is further from the viewpoint than this.

If this value is zero, then an auto-clipping algorithm will be used which sets back clipping somewhat farther than the farthest sprite that is included in distance calculations (see gwSprite::Flags ) and is within the field of view.

The default is 0 (use auto-clipping).

If you choose not to use auto-clipping by setting this to a non-zero value, it should be as small as is acceptable. This is because the smaller it is the less likely depth artifacts will appear.

See FrontClip for more detailed information on this subject.

gwWindow::WinWidth

gwWindow::WinHeight

long gwWindow::WinWidth
long gwWindow::WinHeight

These read-only members reflect the client window's current width and height, in pixels.

gwWindow::LeftBorder

int gwWindow::LeftBorder

Prevents drawing within this many pixels of the left edge of the window. Some drivers may still erase this area.

gwWindow::RightBorder

int gwWindow::RightBorder

Prevents drawing within this many pixels of the right edge of the window. Some drivers may still erase this area.

gwWindow::TopBorder

int gwWindow::TopBorder

Prevents drawing within this many pixels of the top edge of the window. Some drivers may still erase this area.

gwWindow::BottomBorder

int gwWindow::BottomBorder

Prevents drawing within this many pixels of the bottom edge of the window. Some drivers may still erase this area.

Class gwSprite

You create one gwSprite object for every 3D object you want displayed. The gwSprite class manages everything having to do with the object.

GWin3D currently requires that a sprite be created in the same thread that will be displaying it. The simplest way to create a sprite is by declaring the gwSprite object as a static variable within the function body of your frame drawing code (like the gwWindow 's periodic function), and passing the name of a VRML file to the constructor. Then draw the sprite from within the gwWindow 's periodic function by calling the sprite's Draw member function. See the simple code example in the Creating Your First Program section.

An object of the gwSprite class (a sprite) can display a 3D object from a VRML file, a programmatically created OpenGL display list, a tree of subsprites, can call user-defined drawing code (via a callback function) at draw time, or any combination of these.

A sprite object can have sub-sprites associated with it. These are also gwSprite objects. Subsprites are drawn along with the parent sprite and will follow the parent sprite's position, orientation, scale, etc., but may have their own modifications of position, orientation, scale, etc. relative to the parent and affecting all their subsprites. Subsprites are added to a sprite by using its AddSubSprite member function.

A sprite tree (a sprite and all its subsprites, and all their subsprite, etc.) is drawn by calling the parent sprite's gwSprite::Draw function typically from within the window's PeriodicFunction (see gwWindow ) or your WM_PAINT handler. If you are drawing with a WM_PAINT handler, then don't forget to call gwWindow::PrepareForDrawing and gwWindow::FinishDrawing for each frame that is drawn.

The terms "subsprite" and "child sprite" are used interchangeably in this document and mean the same things.

Typically subsprites represent physical parts of a parent sprite that move relative to the parent, although you might, for example, make a parent sprite that draws nothing simply to better control the orientation, positioning, etc., and encapsulation, of several subsprites.

Subsprites can also be used to create infinite range of level of detail. See the Level of Detail (LOD) section and the SubspriteLodLimit member.

Typically, you would create one master, or 'universe', sprite, and add all topmost parent sprites of the universe to the universe sprite using its AddSubSprite member function. When it comes time to draw all the sprites, you call the gwSprite::Draw function for the universe sprite, which will draw the entire sprite tree.

The depth of a sprite tree is limited to the modelview stack size of the OpenGL driver. Typical modern drivers support at least 32 levels.

Sprites can have multiple parents. This is accomplished by calling the AddSubSpritefunction of each parent and passing the address of the sprite. There are advantages and disadvantages to this. See AddSubSprite for more information.

gwSprite is a child class of gwMatrix, whose functionality manages the sprite's position, orientation, scale, and shear properties relative to its parent. See the gwMatrix class for descriptions of the functions that control the sprite's orientation.

You can also assign sprites (see the operator= member).

MEMBERS:

gwSprite::gwSprite

gwSprite
(
   char *FileName=NULL,
   __int64 InFlags =
       GW_CREATE_SMOOTH_NORMALS
       |
       GW_CENTER,
   double OverWrap=0,
   unsigned long (*EnumVerticesFunc)(int LOD, gwVertex &)=NULL
)

gwSprite
(
   unsigned long Type,
   __int64 InFlags,
   double P1=8,
   double P2=1,
   double P3=0,
   double P4=1
)

gwSprite ( gwSprite & InSprite)


For the first constructor shown above, if a FileName parameter is passed, then all the parameters are passed to the Load function.

For the second constructor shown above, the parameters are all passed to the Create function. See those functions for more information.

The third constructor creates an empty sprite and then copies the contents of InSprite to this sprite using operator=.

If no parameters are passed to the constructor then an empty sprite is created. You might do this, for example, if you want to use the sprite solely to hold subsprites, you want to call the Load or Create function later, you want to add your own drawing code as a gwSprite::PreDrawCallback, or you want to create your own OpenGL display lists and place their handles in the gwSprite::List array.

Because Load and Create call OpenGL functions, they must be executed in the same thread that all other OpenGL functions are being called for a given window (like in your gwWindow 's PeriodicFunction, if you are using that) because OpenGL requires it.

One way to construct a permanent sprite in a periodically called function is to declare it as a static variable within the function body. Your C++ compiler should then cause the constructor to be executed in the context of that thread when the thread is created.

If the Load or Create function is called, then an internal flag is set which will cause the display list handles found in the List array to be destroyed by the gwSprite destructor when the sprite is destroyed. If the Load or Create function is not called, then any display list handles found in the List array will not be destroyed when the gwSprite object is destroyed.

See the Load and Create functions for more details.

gwSprite::CreateHeightFieldLods

long CreateHeightFieldLods
(
   gwImage *Image,
   __int64 Flags=0,
   double ResolutionFactor=1;
   double WaterLevel=-1e28
)


(Note: this function is not yet implemented)

CreateHeightFieldLods converts the supplied image into a heightfield with all its LODs, normal vectors, and texture coordinates.

Image is the heightfield image.

ResolutionFactor resizes the image before it is processed.

For the highest LOD, CreateHeightFieldLods uses all of the pixels in the image. A good rule of thumb is to limit the polygons in the highest LOD to a few thousand. Any more than that and you will probably waste GPU power. If Image has more than a few thousand pixels, then you should consider specifying a ResolutionFactor to resize it to a few thousand pixels before it is processed.

CreateHeightFieldLods causes each LOD to contain 1/4 the polygons of the next higher LOD. See the section on Levels of Detail for a discussion on this.

If the GW_WRAP_SPHERICAL bit is set in Flags then a geospherical mesh is created. Otherwise a Cartesian mesh is created.

Note that this function does not in any way alter the vertices passed according to whether a Cartesian or geospherical mesh was specified--that is up to the caller. The GW_WRAP_SPHERICAL flag simply causes the normals calculation to correctly wrap at the poles and latitude seam, and controls whether polygons are created across a wrapping seam.

Scale scales the X, Y, and Z magnitudes in each vertex. It does not reduce or increase the number of vertices.

Xoffset, Yoffset, and Zoffset are added to the corresponding vertex coordinates.

WaterLevel cause CreateHeightFieldLods to not create polygons whose Y coordinates are less than this values. For example, you might have a mesh, like a heightfield, that has a substantial number of polygons on the same plane (for example, at the water level), and it would be a waste of CPU to draw all these polygons when one large quad (see GW_PANEL) would suffice.

Also see gwMesh and the section on Levels of Detail.

gwSprite::LoadMesh

long LoadMesh
(
   gwMesh *Mesh,
   double WaterLevel=-1e28,
   __int64 Flags=0,
   double Scale=1,
   double Xoffset=0,
   double Yoffset=0,
   double Zoffset=0
)

long LoadMesh
(
   gwVector3 *Coord,
   long NumYaws,
   long NumPitches,
   __int64 Flags=0,
   double Scale=1,
   double Xoffset=0,
   double Yoffset=0,
   double Zoffset=0,
   double WaterLevel=-1e28
)


When CreateHeightFieldLods is implemented in GWin3D (it isn't, yet) call it where possible instead of this function because CreateHeightFieldLods accomplishes the same thing as this function but with LODs. This function does not create LODs. It loads all elements of the List array with the same high-resolution display list--which can be an enormous waste of GPU.

LoadMesh creates an OpenGL display list from the mesh, including normals and texture coordinates, and loads all elements of the List array with that same display list handle.

The first form of the function lets you use a gwMesh object. For example, you would use this form when creating a height field. See gwMesh for more information. Use the second form of the function if you prefer more direct control of the vertices. The first form of the function simply calls the second form by simply passing the gwMesh 's Mesh, NumXs, and NumYs members as the first three parameters.

Coord is a one-dimensional array used as a 2-dimensional array as follows:

Vertex [Xnum,Ynum] = Coord[Xnum + Ynum * NumXs]

NumYaws is either the number of latitudes or the number of X elements in the array, and NumPitches is either the number of longitudes or the number of Y elements in the array.

If the GW_WRAP_SPHERICAL bit is set in Flags then a geospherical mesh is created. Otherwise a Cartesian mesh is created.

Note that this function does not in any way alter the vertices passed according to whether a Cartesian or geospherical mesh was specified--that is up to the caller. The GW_WRAP_SPHERICAL flag simply causes the normals calculation to correctly wrap at the poles and latitude seam, and controls whether a seam of polygons is created from the lowest Yaw /X coordinates to the highest.

Scale scales the X, Y, and Z magnitudes in each vertex. It does not reduce or increase the number of vertices.

Xoffset, Yoffset, and Zoffset are added to the corresponding vertex coordinates.

WaterLevel cause LoadMesh to not create polygons whose Y coordinates are less than this values. For example, you might have a mesh, like a heightfield, that has a substantial number of polygons on the same plane (for example, at the water level), and it would be a waste of CPU to draw all these polygons when one large quad (see GW_PANEL) would suffice.

Also see gwMesh and the section on Levels of Detail.

gwSprite::Save

long Save(FILE *F)

Saves the entire object to a file, assuming F was created by MSVCRT's fopen function--which will be the case in Visual C++ if you build your application in Release mode and you specified the release multi-threaded DLL in Project/Settings/C++/Code Generation.

Unfortunately, Visual C++ ignores your specification to use MSVCRT.LIB for a debug build. When building in debug mode, MSVCRTD.LIB is always used. In that case, calls to fopen() made by your application will return a FILE pointer suitable only for MSVCRTD. If you pass that FILE pointer to this function (which uses the MSVCRT version of fwrite), bad things will happen.

For this reason GWin3D provides some wrapper functions to a small subset of the most useful of the MSVCRT file functions so that you can at least do basic file accesses along with this Save() function. See gwFileOpen and friends. Again, this is only absolutely necessary when you build your application in debug mode, and pass FILE handles to or from the GWin3D library.

This function uses SizeOf. Child classes of gwSprite should always implement a SizeOf function so this function can save child objects.

Note that structure packing is also an issue here. The Save function does a raw save of the object. The packing of class members may vary between builds of your application and builds of the GWin3D library. See the MSVC 'pack' pragma and the MSVC /Zp command line switch.

Although this saves all member variables, the Load(FILE *) function only loads those variables that are not pointers or resource handles or variables related to those things. See Load(FILE *) for more information.

gwSprite::Load (FILE *F)

long Load(FILE *F)

Loads all members of the sprite from a file, except for members that are pointers or resource handles.

Use this function in conjunction with Save.

See the Save description for important information on limitations on using these functions.

At the time of this writing, the following gwSprite members were not affected by a call to Load(FILE*) (Note: some of these members are not documented):

SpriteOwnsDisplayLists;
SpriteOwnsVertexArrays;
OneSpriteRecord;
HeadSubSpriteRecord ;
AlwaysDrawCallback ;
EarlyDrawCallback ;
PreDrawCallback ;
PostDrawCallback ;
Name;
Text;
TextLabel ;
LockPositionToSprite ;
LockXOrientationToSprite;
LockYOrientationToSprite;
LockZOrientationToSprite;
RC;
NumParentSprites;
Mutex;
List[]

This function uses SizeOf. Child classes of gwSprite should always implement a SizeOf function so this function can load child objects. Of course, for child classes, you'll probably want to overload this function so that any additional pointer and resource handle variables held in the child class are also unaffected by this function. For example, your overloaded Load(FILE *) function would first save the current member variables that should be unaffected, then call the gwSprite::Load (FILE *) function, and then restore those variables.

See Save.

gwSprite::Load

int Load
(
   char *FileName=NULL,
   __int64 InFlags =
       GW_CREATE_SMOOTH_NORMALS
       |
       GW_CENTER,
   double OverWrap=0,
   unsigned long (*EnumVerticesFunc)(int LOD, gwVertex &)=NULL
)


Call the Load function to load VRML file(s) that describe the sprite's appearance.

Specifically, OpenGL display lists (one for each level of detail) will be automatically created from the VRML file(s) and put in the List array. See the List member and see the sections on level of detail. When gwSprite::Draw is called, it will choose which level of detail to draw and then draw the corresponding display list.

You have the options of defining your sprite by calling the Load function, loading the List elements directly with some OpenGL display list handles you created separately, leaving the List array empty and leaving the drawing work up to subsprites, writing your own code to perform the drawing or other work each time the sprite is drawn (see EarlyDrawCallback, PreDrawCallback and PostDrawCallback members), or any combination of these.

You can also copy the elements of one sprite's List array to the elements of another sprite's List array, but not if the destination sprite thinks it owns its current List (see the comment on this in the constructor section). See operator=.

If a sprite's Load function is called, then an internal flag is set in the object which will cause the display list handles found in the List array to be destroyed (via glDeleteLists) by the gwSprite destructor when the sprite is destroyed. If the Load or Create member functions are never called for a sprite, then any display list handles found in the List array will not be destroyed when the gwSprite object is destroyed--it is presumed they were copied there and are thus owned by another sprite or application code.

Display lists are bound to the gwWindow that was "active" when they were created, and there must be an active window when the Lists are created, and thus when this function is called. A sprite that has display lists (non-zero elements of the List array) or textures can only be drawn in the window that had most recently been drawn in (or for which the most recent gwWindow::PrepareForDrawing was called) when the sprite was created. For more information see the description for gwWindow, the sample sources, the gwWindow constructors, gwSprite::Draw, and gwSprite::List.

Also, remember that all OpenGL calls associated with a given window (including creation of display lists) must be performed the same thread. See gwWindow for more information on this.

One VRML file is enough to create a sprite. In that case only one OpenGL display list is created by the Load function and its handle will be copied to the higher LOD elements of the List array. Lower LOD elements will be zero, indicating nothing should be drawn at great distances.

There can be, however, multiple VRML files where each file is a different level of detail (LOD) of the sprite. However many VRML files there are, their display list handles will be distributed through the List array according to the number of polygons in each.

There are automated ways to create a reduced level of detail model. Check out Blender's decimate function.

Be sure to limit the number of polygons of your highest level of detail to only those that are needed to draw it with good detail. A common mistake is to create an object with more polygons than are needed.

You will also likely want to tweak the LodScale member for the sprite to control at what distance LODs appear. Different models can require radically different LodScale values.

Each level of detail VRML file name (even if there is only one file) should be appended with a zero-based number, where zero is the highest level of detail and higher numbers are lower levels of detail.

The FileName parameter you pass is simply the file name without a number following it and without the 'wrl' extension. All level of detail files found that start with that name will be loaded.

EXAMPLE:

Using your favorite 3D modeler (in other words, using Blender along with its decimate function for each level of detail), you make three level of detail VRML files:

spaceship0.wrl
spaceship1.wrl
spaceship2.wrl

(where spaceship0.wrl is the highest resolution version of the
spaceship, spaceship1.wrl the second highest, etc..)

You pass "spaceship" as the FileName parameter to the gwSprite::Load function (or the constructor that calls Load).

You can also include a path name in the FileName parameter. For example:

gwSprite MySprite1("MyObjectsDir//spaceship");

Even if you have only one VRML file, the file name must still have a "0" appended to it, and the FileName parameter you pass should still not include that "0".

Only a subset of VRML is supported. Here are the VRML functions supported:

Rotation (if enabled--see below flags)
Translation (if enabled--see below flags)
Materials (less 'transparency' setting. if enabled--see below flags)
Meshes (Indexed face sets of n-gons)
Normals (indexed)
Texture coordinates (indexed)

All other VRML functions are ignored, including:

Primitives (spheres, etc.)
Nesting of objects (children)
Texture file names (the image file name is ignored, but texture coordinates are honored)

VRML file formats can be VRML 1.0, VRML97, or VRML 2.0. VRML files must be uncompressed (text format, only).

The GWin3D VRML parser does not fully comply with the VRML standard and will likely have trouble with some VRML files. Some modelers let you convert a complex model to a single mesh before exporting. Try this if you are having any problems.

Some editing of VRML text is possible even if you don't understand much about VRML syntax. You might, for example, remove a section that is making the GWin3D parser choke. You might also edit the Material statements in the VRML file (their syntax is very straightforward).

You can watch GWin3D load the VRML file and assign the LODs. Do this by calling, before the load is performed, gwSetDebugwith any combination of several flags that enable different VRML messages. See gwSetDebug and the Debug section for more information.

Flags:

The following paragraphs describe values that may be bitwise ORed into the Flags parameter of the Load function. The Flags parameter is not to be confused with the Flags member of a gwSprite object, and is not associated with it in any way.

The GW_CREATE_SMOOTH_NORMALS flag causes any normals in the VRML file to be ignored and per-vertex normals to be created for the object. These cause the object to appear smooth. Note that this will even make sharp corners appear smoothed, which may not be what you want. Proper normals for objects that have both smooth curved surfaces and sharp corners can only be generated correctly by the modeler or by creating separate sprites (and including them in the same sprite tree) for the different surfaces. The GW_CREATE_SMOOTH_NORMALS flag is enabled by default.

The GW_CREATE_FACE_NORMALS flag causes any normals in the VRML file to be ignored and per-face normals to be created for the object. These cause the object to appear faceted.

Note: If the VRML file contains no normals and neither of the above flags is specified, then no normals are generated. OpenGL can handle polygons without normals in different ways. See OpenGL's glPolygonMode.

The GW_FLIP_POLYGONS flag may be specified to flip the normal and vertex order of each polygon so that its visibility is switched to the other side of the polygon. You might use this, for example, to make the inside of an object visible instead of the outside, or vice versa, depending on how the polygons had originally been defined in the VRML file. (When GWin3D initializes a gwWindow, it sets the glPolygonMode to GL_FRONT_AND_BACK, which causes OpenGL to show polygons from both sides no matter what. By disabling this for the window and specifically orienting your polygons correctly with, for example, this flag, you might increase rendering speed.) See OpenGL's glPolygonMode for more information.

The GW_HONOR_MATERIALS flag causes the Load function to honor Material statements in the VRML file.

If all material attributes are specified in the VRML file, and you have specified the GW_HONOR_MATERIALS flag, then you can increase performance by disabling the sprite's material by clearing its Material's gwMaterial::Enabled flag.

If you have a need to dynamically change the sprite's material, then you should not specify the GW_HONOR_MATERIALS flag so that you can use the gwSprite::Material member.

The GW_HONOR_TRANSLATES flag causes the Load function to honor Translate statements in the VRML file. Honoring a Translate statement slows down the drawing of the object. Use GW_MULTMATRIX_ON_LOAD as an alternative.

The GW_HONOR_ROTATES flag causes the Load function to honor Rotate statements in the VRML file. Honoring a Rotate statement slows down the drawing of the object. Use GW_MULTMATRIX_ON_LOAD as an alternative.

The GW_HONOR_SCALES flag causes the Load function to honor Scale statements in the VRML file. Honoring a Scale statement slows down the drawing of the object. Use GW_MULTMATRIX_ON_LOAD as an alternative.

The GW_CENTER flag moves the model so it is centered about the origin. This is done only to the vertexcoordinates in the VRML file without regard to any translates or scales that may also appear in the file. You would typically use this flag when translates are being honored (when you do not specify the GW_HONOR_TRANSLATES flag). This flag is enabled by default.

If the GW_MULTMATRIX_ON_LOAD flag is specified, then the vertices in the VRML file are each multiplied with the sprite's current matrix, and then the sprite's matrix is Reset (see gwMatrix::Reset ) after the file(s) are loaded. This makes it possible to rotate, translate, scale, and/or shear the object as it is loaded so that it need not be done at run-time, wasting CPU and GPU time. Note: The sprite's Radius member may not be correct if the matrix scales the object. In that case the application should set the Radius member to the correct value. See gwSprite::Radius . Later releases of GWin3D may set Radius automatically when this flag is used.

Flags controlling autotexturing:

For a texture to appear on the sprite, texture coordinates must be present either in the VRML file or by use of one of the below flags, and you must load the gwSprite::Texture member.

If you want the sprite to have a texture and you don't like the texture coordinates in the VRML file, or there aren't any texture coordinates in the VRML file, then you can pass one of the following flags to generate texture coordinates:

GW_TEXCOORDS_PROJ_X
GW_TEXCOORDS_PROJ_Y
GW_TEXCOORDS_PROJ_Z
Project the texture down the given axis.

GW_TEXCOORDS_CYL_X
GW_TEXCOORDS_CYL_Y
GW_TEXCOORDS_CYL_Z
Cylindrically wrap the texture around the given axis and overwrap it according to the OverWrap parameter.

GW_TEXCOORDS_SPHER_X
GW_TEXCOORDS_SPHER_Y
GW_TEXCOORDS_SPHER_Z
Spherically wrap the texture around the given axis and overwrap it according to the OverWrap parameter.

GW_TEXCOORDS_FOLD_ZY
GW_TEXCOORDS_FOLD_ZX
GW_TEXCOORDS_FOLD_YX
GW_TEXCOORDS_FOLD_YZ
GW_TEXCOORDS_FOLD_XY
GW_TEXCOORDS_FOLD_XZ
Project the right half of the texture image onto one side of the object and the left half of the texture onto the opposite side. The first axis in the symbol name indicates the fold axis and the second axis indicates the projection direction.

Any texture coordinates already in the VRML file will be ignored if one of the above GW_TEXCOORDS_xxx flags is passed.

The texture flags are mutually exclusive. Bitwise ORing multiple texture flags causes undefined behavior.

If, in the VRML file, the object is not centered at the origin, then you should use the GW_CENTER flag to center it before generating texture coordinates. This will assure that the texture is well fitted to the object.

The OverWrap parameter should always be zero unless one of the GW_TEXCOORDS_CYL_x or GW_TEXCOORDS_SPHER_x flags is specified. For these flags, textures may need to be overwrapped to overcome a deficiency in OpenGL that does not correctly handle a texture seam. A texture seam is the line at which the right and left edges of the texture meet when wrapped around a closed mesh.

Without overwrapping, a texturing artifact is caused by OpenGL interpolating, across the polygon that the seam traverses, a high texture coordinate near the right side of the image back down to a low texture coordinate near the left side of the image when really we wanted OpenGL to interpolate off the right edge of the texture image (over the "seam") and onto the left edge of the image as if it were tiled in texture memory. Direct3D has a mode that does this but OpenGL does not.

Typically in OpenGL, meshes to be textured must be designed so that the texture seam follows polygon boundaries and two vertices must be defined at each vertex along the seam--one for defining the right edge of the texture for the previous polygon and one defining the left edge of the texture for the next polygon. Since the automatic texture coordinate generating feature of GWin3D will often be applied to meshes that aren't designed this way (meshes created by a modeler and loaded from a VRML file), overwrapping is needed. See figure 1.

<a href=
Figure 1. The wrapping artifact is the thin jagged line that looks like a crack on this geosphere. See how all the colors of the texture are densely packed in the line. (This uses the texture from figure 2). A close examination shows that the entire texture is squeezed into the crack. (Note: This sphere, loaded from a VRML file, is shown only for an example because it makes the artifact clear. If you want spheres in your program then use the gwSprite::Create function to produce a stock object sphere with all its LODs, and which won't have a texture wrapping problem)

This wrapping artifact appears when the OverWrap value is too small. It is a strip on the object which contains most of the entire texture (left to right inverted) but notably narrower than it should be. For objects with lots of polygons the strip will typically be quite thin yet still contain the entire texture with all its fine detail when you look closely. The strip may even be somewhat jagged.

The best approach to find out what OverWrap value you should use for a particular model is to experiment. Start by loading your VRML file with an OverWrap of zero. If you don't see the above artifact (very unlikely) then you are done. If you do see the artifact then try a slightly higher OverWrap value. Continue until the artifact is gone. Ideally, you want the OverWrap value that is just barely high enough to fix the problem.

Note that whether the OverWrap value is set well or not, you will still see a poorly matched seam because the texture has not yet been designed to be tiled according to whatever OverWrap value you are trying. Ignore this for the moment. Watch only for the artifact described above. You will correct the seam mismatch problem in your final texture only after you've chosen an optimal OverWrap value.

You want OverWrap to be fairly small so that not much of the texture is wasted wrapping, but large enough so no wrapping artifact is visible, at least in the higher LODs.

Also be sure the highest LOD is displayed while you are experimenting. Otherwise you will be adjusting the OverWrap value for low LODs.

Once you've chosen an OverWrap value, you must edit the final texture image that will be wrapped around the object so that its right edge can overlap the left edge by the specified amount and still match up the pixels that overlap.

The units of the OverWrap value are in fractions of a full circle. For example, an OverWrap of 0.25 means the texture should be overlapped an extra 90 degrees on the object. This also means that the texture image should have a copy of its left one-fourth tacked on to its right side so that it can be wrapped an extra 25% (0.25) of its original width so the pixels match where the texture overlaps.

For another example, let's say you have a horizontally tile-able texture with a width of 128. See figure 2.

tileable <a href=
Figure 2. A 128x128 texture that can be horizontally wrapped onto an object such that the left edge and right edge of the image smoothly connect. That is, it is a "tile-able" texture suitable for wrapping on an object. This image would be fine if there were no wrapping problem.

Let's also say that your OverWrap experiment showed that an OverWrap value of 0.2 was needed. This means a 20% wrap should be used. But now your texture doesn't align because it is being overlapped by 20% and wasn't designed to be. You must now copy 20% of the left side of the texture image, which is 26 pixels wide, and tack in on the right side. See figure 3.

overwrappable <a href=
Figure 3. The texture from figure 2 extended by 20% by copying the left 20% and adding it to the right so that it can be wrapped an extra 20% onto an object.

Note that the texture dimensions must still be powers of two (to comply with OpenGL requirements, unless you know you'll be using a later OpenGL release) and by adding the extra 20% more width you have violated this rule. So you now need to resize the image so that its width and height are again each a power of 2 and the aspect ratio still roughly matches the height/circumference ratio of the object being wrapped (so that neither horizontal nor vertical texture resolution is wasted in a severe difference in the aspect ratios of the texture and the object).

Now you can load your mesh and specify an OverWrap value of 0.2. Then you can call the gwTexture::Load function of the sprite's Texture member to get the texture to appear on the sprite.

EnumVerticesFunc:

The EnumVerticesFunc parameter to the gwSprite::Load function can be the address of a user-defined function to be called by the Load function as it loads the VRML files.

The Load function will call your EnumVerticesFunc function for each vertex of each triangle in each VRML file as they are loaded. All vertices of the highest LOD file are loaded first, then those of the next highest, etc.. Every three calls of EnumVerticesFunc represent a single triangle. (GWin3D converts all polygons in the VRML file to triangles. The EnumVerticesFunc is called after this conversion).

You can use EnumVerticesFunc to find out the exact details of every triangle, normal, and texture coordinate that will be drawn for the object. Note: If specified, the GW_MULT_MATRIX_ON_LOAD flag causes the current matrix to be applied to the vertices before they are passed to the application's EnumVerticesFunc.

When EnumVerticesFunc is called by the Load function, it is passed the following parameters:

LOD - Which level of detail VRML file is being loaded (starts with 0).
Vertex - Vertex that was just loaded. See gwVertex.

Example:

// define the callback function
unsigned long MyEnumVerticesFunc
(
   int LOD,
   gwVertex & Vertex
)
{
   // process this vertex however we want
   ...
   ...
   return 0;
}

...
...
...

// create a sprite from VRML files...

gwSprite MySprite1;

// load the model (and call MyEnumVerticesFunc() for each vertex )
MySprite1.Load("MyVrmlObjectFile",0,1,1,1, MyEnumVerticesFunc);

After a call to the Load function, the sprite's NumPolygons member will contain the number of triangles (each polygon in the VRML file is converted to as many triangles as is needed) in the highest level of detail, and the Radius member contains the distance to the furthest vertex from the origin of the sprite.

Example:

gwSprite MySprite1;

...
...

MySprite1.Load("MyObjectsDir//MyVrmlObjectFile",GW_NO_SMOOTH | GW_FLIP_POLYGONS);

gwSprite::Create

int Create
(
   unsigned long ObjectType,
   __int64 Flags,
   double P1=8,
   double P2=1,
   double P3=0,
   double P4=1
)


The Create function causes the sprite to become a stock object with texture coordinates and all its levels of detail. There is a gwSprite constructor that calls this, also.

Flags should be zero.

If ObjectType is GW_SPHERE, then a sphere object, with all its levels of detail, is created. Spherical texture coordinates are also created for the sphere. P1 is detail (roughly number of slices or stacks), P2 is radius. P3 can be the GLU normal orientation code GLU_OUTSIDE or GLU_INSIDE, if 0 is passed for P3 then GLU_OUTSIDE is used. Note: The lower the detail, the more blank (empty) LODs there will be and the sooner the object will disappear as distance increases.

(see If ObjectType is GW_PANEL, then a single square quad, with texture coordinates, is created. This can be used, for examples, as a sign, wall, banner, or impostorgwSprite::LockXOrientationToSprite and friends). P1 is width and P2 is height.

(see If ObjectType is GW_DISK, then a disk with all its levels of detail and with texture coordinates is created. This can be used, for example, as a banner or impostorgwSprite::LockXOrientationToSprite and friends). P1 is detail (number of slices) and P2 is radius. Note: The lower the detail, the more blank (empty) LODs there will be and the sooner the object will disappear as distance increases.

If ObjectType is GW_CYLINDER, then a cylinder/cone (anything varying between a cylinder and cone, inclusive) with all its levels of detail and with texture coordinates is created. P1 is detail (number of slices), P2 is top radius, P3 is bottom radius, and P4 is height. Note: The lower the detail, the more blank (empty) LODs there will be and the sooner the object will disappear as distance increases.

If ObjectType is GW_BOX, then a box, with texture coordinates, is created. P1 is width, P2 is height, and P3 is depth.

gwSprite::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy. When you inherit from the gwSprite class, you must implement a SizeOf function.

gwSprite::Lock

gwSprite::Unlock

long Lock(long Timeout=-1,unsigned long Flags=0)
void Unlock(void)


The Lock and Unlock functions need be used only by another thread that is modifying the sprite members directly. Call Lock before modification and call Unlock when modification is complete. This prevents other threads from accessing the sprite members at the same time.

Timeout is how long to wait while the sprite is currently locked by another thread, in milliseconds. If Timeout is -1, then the timeout is gwSprite::DefaultLockTimeout, whose default value is 5000. This is the value used by most functions that access sprite members, except for gwSprite::Draw (see below).

If Flag & 1, then a warning message is displayed if a timeout occurs.

Lock returns non-zero if there is a timeout, otherwise it returns zero.

Many functions that modify a sprite already call Lock and Unlock internally. For example, the AddSubSprite and RemoveSubSprite functions call them (and all of these functions use the default lock timeout, except for gwSprite::Draw ). Application code need call Lock and Unlock directly only when it modifies sprite members directly by a thread other than the main drawing thread.

The gwSprite::Draw function calls Lock when it begins and Unlock when it is done. The Timeout it passes is zero. If there is a timeout (after zero milliseconds) then Draw immediately returns.

Note that the thread priorities you choose will change the operation. For example, if your drawing thread is higher priority than the other thread that is modifying the sprite (recommended), then drawing will always occur at the expense of delaying the modifying thread. If your modifying thread is higher priority, then the sprite will not be drawn if the modifying thread currently has a lock on the sprite, and you may see the sprite disappear for a frame or two.

If a thread calls Lock more than once, then the sprite will not be unlocked until it calls Unlock as many times.

To avoid deadlock, no thread should lock more than one sprite at a time. For an example of deadlock: thread A locks sprite A, thread B locks sprite B, then thread A blocks waiting for sprite B, and thread B blocks waiing for sprite A.

gwSprite::operator=

operator=( gwSprite &InSprite)

Assigns the sprite from another sprite.

If this sprite (the destination sprite) currently "owns" its display lists (see the Load member function) then this ->Unload() is first called.

If present, the Texture and ImpostorTexture are also unallocated.

Everything else is assigned from the InSprite to this sprite using the SizeOf function except the subsprites are left alone.

If InSprite.SizeOf() is smaller than SizeOf(), then an error message is displayed.

Name is also copied. Note that this means that if Name had pointed to allocated space, then you must make sure that space is eventually freed.

Note that this function calls Lock for both this sprite and InSprite, so if multiple threads are using this function in certain (rather unreasonable) ways, then deadlock is possible. For example, it could happen if one thread is assigning sprite A to sprite B, and another is assigning sprite B to sprite A.

gwSprite::LastMatrix

gwMatrix gwSprite::LastMatrix

Each time a sprite is drawn (see gwSprite::Draw ), a matrix must be internally calculated that describes the sprite's position and orientation relative to the universe (i.e. its absolute position and orientation) to be given to the rendering engine. This matrix is also saved in the LastMatrix member so that it can be examined by the application.

For example, your application code might call LastMatrix.GetZAxis to get the absolute direction that the sprite is pointing, or your application might call LastMatrix.GetPosition to get the absolute position of the sprite.

This is a read-only member. Any alteration made to LastMatrix will be overwritten the next time the sprite is drawn.

See gwMatrix.

gwSprite::List

int gwSprite::List[GW_MAX_LODS]

Array of OpenGL display list handles, where each handle represents a single level of detail. The gwSprite::Draw function will choose one of the List elements and draw it. Element zero is the handle of the display list of the highest LOD. Element GW_MAX_LODS-1 is the handle of the display list of the lowest LOD. An element with value zero means no object is drawn for that LOD.

GWin3D uses the next lower LOD each time the distance doubles. The first LOD threshold depends on the value of the gwWindow::LodFactor member, which is changed dynamically, according to CPU and video adapter usage, if the gwWindow::MaxElapsedTimeMs member is non-zero.

The gwSpriteLoad function can automatically create display lists and load this array with their handles.

Please note that if the Load function is called (or called indirectly by the gwSprite constructor), then the display list handles found in the List array will be destroyed by the gwSpritedestructor when the sprite is destroyed. If the Load function was never called, then any display list handles found in the List array will not be destroyed when the gwSprite object is destroyed.

Display lists are bound to the gwWindow that was "active" when they were created. A sprite can only be drawn in the window that had most recently been drawn in (or for which gwWindow::PrepareForDrawing was called) when the sprite was created. See the description for gwWindow, sample sources, the gwWindow constructors and the PeriodicFunction parameter of the main gwWindow constructor for more information.

See the sections on levels of detail for more information and other ways to manage levels-of-detail.

gwSprite::Draw

double Draw
(
   gwWindow *Win,
   __int64 Map=0x0FFFFFFFFFFFFFFF,
   __int64 Mask=0,
   __int64 InheritFlagsIn=0,
   double MinViewWidth=0,
   double MaxViewWidth =1e300
)


The Draw function draws a sprite and all its subsprites (a sprite tree).

The Win parameter is which gwWindow object the sprite should be drawn in.

A sprite that has non-zero display List elements can only be drawn in the window and from the thread that was active when the List elements were created. See the gwSprite List member and the Load function.

The other parameters of this function are criteria controlling which sprites in the sprite tree should be drawn by the call. The default values for these parameters cause all sprites in the tree to be drawn. By setting these parameters to certain values, you can limit which sprites are drawn in a single call to Draw. In this way Draw can be called multiple times with different parameters to control the order subsprites are drawn.

For example, the first time Draw is called it might be made to draw all non-transparent sprites and the second time it is called it might be made to draw all transparent sprites (see the section on Translucency for more information).

There are really several approaches to controlling the order sprites are drawn, and combinations of these are possible:
  1. You can call Draw once for the top-most sprite and not worry about drawing order.
  2. You can call Draw individually for different parent sprites without using the criteria parameters.
  3. You can Draw the same top sprite multiple times with different criteria parameters controlling which subsprites are drawn in each call.
  4. You can control the drawing order of all the subsprites of any single parent sprite by adding those subsprites (via gwSprite::AddSubSprite ) to the parent in the reverse order you wish them drawn, or even manipulating the order of the SpriteRecords in the linked list (see HeadSubSpriteRecord ). This method of controlling drawing order doesn't require multiple calls of Draw, but is less powerful because it only orders the drawing of the subsprites of the particular parent sprite being drawn.
  5. You can leave a sprite's Enable flag cleared except when the call to Draw is made within which you want the sprite to be drawn.
The MinViewWidth and MaxViewWidth parameters limit drawing of sprites in the tree only to those of certain visible widths on the screen. Only sprites within this range of screen widths (in pixels) and that also pass the tests performed with the Map and Mask parameters (see below) will be drawn. A sprite's screen width is calculated according to its Radius member, among other things.

The Map and Mask parameters can be used to specify what state certain bits of the bitwise OR of the sprite's Flags and InheritFlags members must be to draw the sprite. These parameters only control the drawing of the sprite, not its subsprites.

Specifically, bits that are set in the Mask parameter specify which sprite flag bits should be examined. The corresponding bits in the Map parameter specify what the states of those flag bits must be for the sprite to be drawn. If the flag bits defined by Mask are not all equal to the states defined by the corresponding bits in Map, then the sprite will not be drawn. A sprite is drawn if (Flags & Mask)==(Map & Mask).

"Flags" in the above expression means the bitwise OR of the sprite's Flags member, InheritFlags member, along with all the InheritFlags members of all its ancestors.
The application may define bits in the lower 32 Flags bits, the upper 32 bits are predefined by GWin3D and include flags such as GW_TRANSPARENT, GW_NO_DEPTH_TEST, etc..

The Draw function draws the sprite using the sprites matrix modified by the current modelview matrix. After a call to gwWindow::PrepareForDrawing (which, by the way, is called automatically when you are using a gwWindow::PeriodicFunction), the modelview matrix is the unity matrix. So you typically would only call Draw for topmost sprites. You can also call Draw from within another sprite's callback function (such as PreDrawCallback ). In that case the current modelview matrix is the coordinate system of the parent sprite.

Avoid calling this multiple times if it isn't necessary because there is some CPU overhead per sprite even when a sprite is not drawn.

It is also an easy mistake to allow a sprite to be drawn multiple times with multiple calls to Draw. If this happens you may never realize that CPU and graphics power is being wasted.

See gwWindow::ViewpointSprite. Ideally, the ViewpointSprite should be drawn first in your frame update code with a call to Draw, then other sprites are drawn with subsequent calls to Draw.

Also ideally, light sprites should be drawn before other sprites within a given frame update. If you don't do this, lighting may be off a little when there is movement of objects from one frame to the next.

The Draw function performs the following operations in the order shown:
  1. If Flags say don't draw, then just return
  2. Call AlwaysDrawCallback if there is one.
  3. If OutOfView and InfrequentRecalcMask say so, then just return
  4. Push the modelview matrix onto the OpenGL modelview matrix stack
  5. Call EarlyDrawCallback if there is one
  6. Multiply the sprite's matrix with the modelview matrix
  7. Adjust sprite's orientation according to LockXOrientationToSprite, etc.
  8. Adjust sprite's position according to LockPositionToSprite
  9. If this is the viewpoint sprite, then update viewpoint
  10. Perform distance/out of view/screen position/ LOD calculations infrequently according to InfrequentRecalcMask
  11. Dump sprite debug info, if enabled
  12. Apply GW_NO_DEPTH_TEST and GW_TRANSPARENT flags if present
  13. Set the Material (if its enabled)
  14. Bind the Texture (if there is one)
  15. Call PreDrawCallback if there is one
  16. Draw the display list for the current LOD (if there is one)
  17. Draw text if text is attached
  18. Unapply GW_NO_DEPTH_TEST and GW_TRANSPARENT flags
  19. Call PostDrawCallback if there is one
  20. Draw subsprites
  21. Pop the modelview matrix off the OpenGL modelview matrix stack
The following are examples of the drawing code you might place in your PeriodicFunction or WM_PAINT handler (note that you must also explicitly call gwWindow::PrepareForDrawing and gwWindow::FinsihDrawing when drawing within code other than the gwWindow::PeriodicFunction):

Example 1:

// Draw all sprites
Universe.Draw(Win);


Example 2:

// Draw the ViewpointSprite.
// Note: If the viewpoint sprite is a subsprite in a sprite tree, the entire
// parent sprite tree of the ViewpointSprite must be drawn so that its
// position is correct.
Win->ViewPointSprite ->Draw(Win);

// Draw all solid sprites
Universe.Draw(Win,0,GW_TRANSPARENT);

// Draw all transparent sprites
Universe.Draw(Win,GW_TRANSPARENT,GW_TRANSPARENT);

Example 3:

// Draw all solid sprites that use depth testing
Universe.Draw(Win,0,GW_TRANSPARENT | GW_NO_DEPTH_TEST);

// Draw all transparent sprites that use depth testing
Universe.Draw(Win,GW_TRANSPARENT,GW_TRANSPARENT | GW_NO_DEPTH_TEST);

// Draw all solid sprites that don't use depth testing
Universe.Draw(Win,GW_NO_DEPTH_TEST,GW_TRANSPARENT | GW_NO_DEPTH_TEST);

// Draw all transparent sprites that don't use depth testing
Universe.Draw(Win,GW_NO_DEPTH_TEST | GW_TRANSPARENT,GW_TRANSPARENT | GW_NO_DEPTH_TEST);

Example 4:

// Draw all sprites that have their flag bit 6 clear and bit 8 is set
Universe.Draw(Win,0x100,0x140);

gwSprite::EnumSubSprites

double EnumSubSprites
(
   gwSpriteRecord **SpriteRecord=NULL,
   __int64 Map=0x0FFFFFFFFFFFFFFF,
   __int64 Mask=0,
   double NearestDistSqr=0,
   double FurthestDistSqr=-1,
   bool IncludeThisSize=1,
   bool IncludeOtherSize=1
)


A parent sprite keeps track of its subsprites by maintaining a linked list of gwSpriteRecords. Each gwSpriteRecord points to a child sprite. See gwSpriteRecord , AddSubSprite, and RemoveSubSprite.

The EnumSubSprites function lets the caller enumerate all the gwSpriteRecords of this sprite's list.

Note that this does not enumerate a tree of sprites. It only searches the immediate children of this sprite.

Parameters can be passed that limit the subsprite records found to only those whose associated sprite is within a certain distance range and/or has certain Flag bits set or clear.

To use the function, create a gwSpriteRecord pointer and load it with NULL. Then pass its address as the SpriteRecord parameter. When the EnumSubSprites function returns, the SpriteRecord variable will be pointing to the first gwSpriteRecord whose sprite passed the criteria described by the other parameters of the function. Do not change the contents of the SpriteRecord variable. Call the function again to get the next gwSpriteRecord whose sprite passes the criteria. When, after a call, the contents of the gwSpriteRecord pointer is NULL or the return value is -1, then all gwSpriteRecords have been searched.

More specifically, each time the function is called, it starts its search of the linked list of gwSpriteRecords at the current gwSpriteRecord (address) being passed. A NULL value in the variable pointed to by the gwSpriteRecord parameter means start at the HeadSubSpriteRecord of this sprite.

As a general rule, do not call AddSubSprite or RemoveSubSprite for this sprite while the function is being used to iterate the list--for example, another thread should not call AddSubSprite or RemoveSubSprite for this sprite. You might want to use the Lock and Unlock functions in such a case. It is possible, however, for the code doing the enumeration to add or remove subsprites in the list during the enumeration if it is done in a way that does not confuse the next call of EnumSubSprites . One of the common reasons you might enumerate a list of subsprites is to decide which ones should be removed from the list.

If FurthestDistSqr > 0 then FurthestDistSqr is the square of the distance (from this sprite) within which you are looking for sprites. Only sprites within this distance (and passing the other criteria) will be returned.

If FurthestDistSqr > 0 then the return value will be the distance between this sprite and the found sprite squared, if a sprite is found. If FurthestDistSqr <= 0 (the default), then no distance check is performed (in order to save CPU) and the return value is zero when a sprite was found. In any case, -1 return value indicates no other sprite was found and the end of the list was encountered.

NearestDistSqr is the square of the distance (from this sprite) beyond which you are looking for sprites. Only sprites beyond this distance (and passing the other criteria) will be returned.

If IncludeOtherSize is non-zero, then the nearest edge of the other sprite is used in the distance calculation instead of its center. Note that the actual sprite shape is not considered, this is just as if the sprite were a sphere with a radius equal to its Radius member.

If IncludeThisSize is non-zero, then the distance calculation is from the edge of this sprite, also, where the "edge" is simply the value of the Radius member from the center.

The Mask and Map parameters further qualify sprites to find. A sprite must also pass a test in which the sprite's Flag bits specified by the Mask parameter are equal to those bits in the Map parameter. Specifically, the following statement must be true: ( gwSprite::Flags & Mask) == (Map & Mask).

The application may define the lower 32 Flags bits, the upper 32 bits are defined by GWin3D and include flags such as GW_TRANSPARENT, GW_NO_DEPTH_TEST, etc..

gwSprite::Update

long Update( gwWindow *Win, gwSprite *Universe);

This function does nothing in the gwSprite class but return zero. It was included because typically most child classes of gwSprite will have something like an Update function which is called periodically by the gwWindow::PeriodicFunction, which implements the particular sprite's unique behavior in an application. Thus this virtual function in gwSprite may save having to make child classes for some types of sprites.

gwSprite::Name

char *gwSprite::Name

Can be pointed to any string you like. Normally it should describe the sprite. Its only use is during debug. See the section on Debugging.

gwSprite::AddSubsprite

int AddSubSprite( gwSprite *Sprite);

Use this to add a subsprite to this sprite. The subsprite will appear along with the parent, following its orientation and position, and can be oriented and positioned relative to the parent. SubspriteLodLimit controls within what LodIndex subsprites are drawn. You may want to change SubspriteLodLimit to allow subsprites to be drawn at further distances, or to prevent them from being drawn until the parent sprite is very close.

You can add as many subsprites to a parent sprite as will fit in the system.

A sprite can also have multiple parents.

Currently GWin3D, when a sprite is destroyed, will automatically remove it from its parent if it has exactly one parent. A sprite that has multiple parents must be removed from them before it is destroyed. An error message will appear if debug warnings are enabled and a sprite is destroyed that still has a parent. If that happens, when the parent is drawn it will attempt to access the memory associated with the sprite object that had been freed. See RemoveSubSprite.

The advantage of giving a sprite multiple parents is that the visible "copies" of that sprite all obey any changes the application makes to that sprite. For example, you might create a single "wheel" sprite and attach that single sprite to multiple vehicle parent sprites. The visible wheels all turn by rotating only that one wheel sprite. For another example, you might create a single rotating radar dish sprite and attach it to many sprites. The application need only rotate one sprite.

There are two disadvantages to giving a sprite multiple parents:
  1. When a sprite has only one parent, GWin3D can avoid performing certain time-consuming calculations every time the sprite is drawn (see InfrequentRecalcMask ). When a sprite has multiple parents, these calculations must be performed every time the sprite is drawn because the results of one calculation cannot be used for the next several times it is drawn. GWin3D automatically ignores InfrequentRecalcMask in sprites that have multiple parents and makes the calculations every time it is drawn.
  2. Certain members of a sprite object reflect the sprite's state when it was last drawn. Since the sprite is now drawn multiple times in a single frame, these variables reflect only the state of the sprite for the last time it was drawn. Some of these members include LodIndex, LastMatrix, and the Viewxxx members.
You may find it better to make multiple sprites even though they display the same object. This can still be done fairly efficiently by sharing the same display lists among those sprites. See the List member.

Returns zero if success, non-zero if failure.

gwSprite::RemoveSubSprite

int RemoveSubSprite( gwSprite *Sprite);

Use this to remove a subsprite from this sprite's list of subsprites. Sprite must be the address of a sprite that was previously added.

A Sprite must be removed from all its parents before it is destroyed. See AddSubSprite.

gwSprite::HeadSubSpriteRecord

gwSpriteRecord * gwSprite::HeadSubSpriteRecord

Head of the linked list of subsprite records (see AddSubSprite ).

This is documented because you may want to manipulate the linked list of subsprites directly, for example, to sort them in distance order to implement true translucency. See the section on Translucency and gwSpriteRecord.

gwSprite::Text

char * gwSprite::Text

If this is non-zero, then it is the address of a text string to be displayed along with the sprite, using the Texture member as a font.

This variable differs from the TextLabel variable in that you can create your own font as a bitmap--although since it uses the Texture member, you probably would not want a texture on the sprite that is a bunch of letters and number. Typically you would dedicate this sprite strictly for text.

The only ASCII control character that has meaning is the carriage return--which works as expected. Tabs, line feeds, etc. will display undefined characters.

Text display is also limited by MaxTextLodIndex. See that member.

The TextLabel member can also display text using any font available in the system and without using the Texture member.

gwSprite::MaxTextLodIndex

long gwSprite::MaxTextLodIndex

Any text attached to the sprite (see the Text member) will be drawn only if the LodIndex is less than or equal to this value.

Default is [TBD]

gwSprite::TextLabel

gwSprite::TextLabelColor

gwSprite::TextLabelFont

gwSprite::TextLabelXOffset

gwSprite::TextLabelYOffset

gwSprite::TextLabelHeight

gwSprite::TextLabelLod

char * gwSprite:: TextLabel
gwColor gwSprite:: TextLabelColor
unsigned long gwSprite:: TextLabelFont
double gwSprite:: TextLabelXOffset
double
gwSprite:: TextLabelYOffset
long gwSprite:: TextLabelHeight
long gwSprite:: TextLabelLod

If TextLabel is not NULL, then these variables are passed as parameters to the gwWindow 's Print function when the sprite is drawn, except that the offset values are in units of the sprite's ViewRadius. This is similar to the way the Text member function works, but this method does not occupy the Texture member and it can use any font available in the system.

If LodIndex > TextLabelLod, then the text is not drawn.

See gwWindow::Print

gwSprite::Lock...OrientationToSprite

gwSprite *LockXOrientationToSprite
gwSprite *LockYOrientationToSprite
gwSprite *LockZOrientationToSprite


If not NULL, then the this sprite's absolute (relative to the universe) rotation for the specified axis is made equal to the absolute (relative to the universe) rotation on that axis of the sprite pointed to by this member, but only if the LodIndex of the sprite is equal to or greater than the ImpostorLodIndex value.

One might lock a sprite to the viewpoint sprite (see gwWindow::ViewpointSprite ) to make the sprite a billboard sprite or impostor. Notice that this is one of two methods of implementing billboard/impostor sprites. This method is the fastest because it requires virtually no internal mathematical calculations, but causes the locked sprite to rotate as the viewpoint sprite rotates. It is often acceptable to use this for smoke/cloud and impostor sprites, but may not be best for true billboard sprites. Ideally, a billboard sprite should simply orient itself to point to the position of the viewpoint, rather than copy its rotation. If that is what you want, you'll have to implement it in your application using the appropriate gwMatrix functions (see the gwMatrix::...Axis functions).

You typically use this only when you want orientation to follow that of another sprite, but not position. If you want orientation about all axis' and position (and shear and scale, for that matter) to follow another sprite, then simply make the sprite a subsprite of that other sprite and don't use this member.

See ImpostorLodIndex, and the section on Impostors and Billboards.

gwSprite::ImpostorTexture

gwTexture gwSprite::ImpostorTexture

This is the impostor texture.

This texture is applied instead of the Texture member when the LodIndex value is equal to or greater than ImpostorLodIndex.

Leave this texture unloaded (invalid) if you do not want to implement impostors, or you want your impostor to have the same texture as the object.

See the section on Impostors.

gwSprite::ImpostorLodIndex

long gwSprite::ImpostorLodIndex

This is used to help implement impostors. It works in conjunction with the LockXOrientationToSprite, etc., and ImpostorTexture members.

When the current LodIndex of the sprite is equal to or exceeds the value of ImpostorLodIndex, then the LockxxxOrientationToSprite members are honored and ImpostorTexture is applied to the sprite if it is valid.

If you want to use the LockxxxOrientationToSprite members simply for a billboard, then set this value to zero and do not load the ImpostorTexture member with a texture. That will cause the LockxxxOrientationToSprite members always to have an effect no matter how far the sprite is from the camera, and the Texture member will always be applied, if it is valid.

See the section on Impostors.

Default is zero.

gwSprite::LockPositionToSprite

gwSprite *gwSprite::LockPositionToSprite

If this is not NULL, then the sprite's position will follow that of the sprite pointed to by this member, but its orientation ( rotation, scale, shear ) will not follow that of the other sprite.

Use this only when you want position to follow another sprite, but not orientation. A sky box, for example, would use this. If you want both orientation and position (and scale and shear, for that matter) to follow another sprite, then simply make this sprite a subsprite of that other sprite and don't use this member.

gwSprite::AlwaysDrawCallback

long (*AlwaysDrawCallback)( gwSprite *Sprite, gwWindow Win);

If this is not NULL, then the function it points to is called each time the sprite's Draw member is called, but only if the Flags check merits drawing the sprite.

See the Draw function for a detailed timeline of operations performed each time a sprite is drawn.

The function is passed the address of the sprite and the address of the gwWindow in which the sprite is being drawn. The function should return zero.

Also see the sections on Implementing Levels of Detail and Textures .

gwSprite::EarlyDrawCallback

long (*EarlyDrawCallback)( gwSprite *Sprite, gwWindow Win);

If this is not NULL, then the function it points to is called each time the sprite is drawn, but just before preparations are made to draw the sprite.

See the Draw function for a detailed timeline of operations performed each time a sprite is drawn.

The function is passed the address of the sprite and the address of the gwWindow in which the sprite is being drawn. The function should return zero.

Also see the sections on Implementing Levels of Detail and Textures .

gwSprite::PreDrawCallback

long (*PreDrawCallback)( gwSprite *Sprite, gwWindow Win);

If this is not NULL, then the function it points to is called each time the sprite is drawn, just after everything is prepared to draw the sprite and its subsprite's, but before they are actually drawn.

See the Draw function for a detailed timeline of operations performed each time a sprite is drawn.

The function is passed the address of the sprite and the address of the gwWindow in which the sprite is being drawn. The function should return zero.

Your PreDrawCallback function may, for example, draw more detail for the sprite depending on the LodIndexor the DistanceCentermembers. The function might also update various members of the sprite to further control its appearance. For example the function might set the LodIndex member to force a certain display list to be drawn, or alter the Material member according to the distance from the viewpoint, or change the texture to, for example, animate it..

You might use this function to override various OpenGL settings by calling functions like glEnable, glDisable, glMaterial, glBindTexture, etc..

You might also use this function to actually draw the object, or draw more detail on the object, depending on the LodIndex member.

If you place any drawing code in PreDrawCallback, you may want to specify the GW_FORCE_DISTANCE_CALC_ON flag (see the Flags member). Also, you should remember to make sure the sprite's Radius member always correctly reflects the visible radius.

Also see the sections on Implementing Levels of Detail and Textures .

gwSprite::PostDrawCallback

long (*PostDrawCallback)( gwSprite *Sprite, gwWindow Win);

If this is not NULL, then the function it points to is called each time the sprite is drawn after the sprite and its subsprites are drawn.

The function is passed the address of the sprite and the address of the gwWindow in which the sprite is being drawn. The function should return zero.

You might use this function to restore any settings (such as OpenGL states) altered by the EarlyDrawCallback or PreDrawCallback functions.

See the section on Implementing Levels of Detail.

gwSprite::DistanceSqrd

double DistanceSqrd
(
   gwSprite *Sprite,
   bool IncludeThisSize=0,
   bool IncludeOtherSize=0
);


Call this to get the square of the distance between this sprite and another sprite. The square of the distance between the centers is returned, unless the distance from one or both sprite's edges (assuming a sprite is a sphere with radius gwSprite::Radius) is requested by setting the IncludeThisSize and/or IncludeOtherSize parameters.

gwSprite::DistanceCenter

double gwSprite::DistanceCenter

For a visible sprite, this read-only member is the distance from the viewpoint to the center of the sprite. This is calculated as frequently as InfrequentRecalcMask dictates. This has no meaning if the sprite is out of view.

gwSprite::ViewX

gwSprite::ViewY

double gwSprite::ViewX
double gwSprite::ViewY

These read-only members are the current window coordinates of the center of the sprite, in pixels. They are the values returned by a call to gluProject, which is made every InfrequentRecalcMask times the sprite is drawn.

gwSprite::ViewZ

double gwSprite::ViewZ

This is the WinZ value returned by a call to gluProject, which is made as frequently as InfrequentRecalcMaskdictates. This is not simply the depth of the object. It is related to the clipping planes. See ThisFrontClip, ThisBackClip, and the OpenGL gluProject function.

gwSprite::ViewRadius

double gwSprite::ViewRadius

This read-only member reflects the diameter of the sprite in the window, in pixels, assuming the Radius member is correct.

gwSprite::Radius

double gwSprite::Radius

The radius of the sprite is used in various distance calculations and by the auto-level-of-detail algorithm. This member does not change the visible size of the sprite. It should certainly reflect the visible size of the sprite, however, including all its subsprites. That is its purpose.

The Load function (or a constructor that calls Load) automatically loads this with the size of the VRML object loaded, or if a stock object is created then with the size of that object.

Your application should specifically set the Radius member to an accurate value if:
  1. You add subsprites that are outside the parent sprite.
  2. You scale or severely shear the sprite.
  3. You load the List array with your own OpenGL display list handles.
  4. You have your own drawing code in the sprite's PreDrawCallback, which may change its size.
It is important that you load the Radius member with a fairly accurate estimate of the visible radius of the sprite with all its subsprites. Otherwise certain important functions like Auto-LOD , Auto-clipping, and field of view will not work right. Also see InfrequentRecalcMask , gwSprite::Draw, and the section on Level of Detail .

gwSprite::InfrequentRecalcMask

gwSprite::FramePhase

unsigned long gwSprite::InfrequentRecalcMask
unsigned long gwSprite::FramePhase

Some GWin3D code that draws a sprite need not be executed every frame for sprites that are beyond the BackClip distance (if BackClip is non-zero) or are outside the field of view.

Also, there are certain internal, rather time-consuming, calculations that need not be performed every frame even for sprites that are visible. These include the calculations that update the LodIndex, DistanceCenter, and the Viewxxx variables.

InfrequentRecalcMask controls how often these calculations are performed.

Typically, InfrequentRecalcMask is limited to values that are equal to (2^n)-1, where n is an integer. That is, InfrequentRecalcMask is limited to the values 0, 1, 3, 7, 15, 31, etc. In that case InfrequentRecalcMask is simply the number of frames to skip between the infrequent calculations.

You can, however, cause the infrequent calculations to be performed in a more complex fashion. Specifically, the calculations are performed when ( FramePhase & InfrequentRecalcMask ) == ( gwWindow::FrameCount & InfrequentRecalcMask). (However, when a sprite is drawn in a window created by the gwWindow copy constructor, ViewpointDrawCount is used instead of FrameCount in the above expression.)

As you can see, FramePhase is which frame to perform the calculations. You normally don't need to change FramePhase. The gwSprite constructor automatically sets FramePhase to be one more than what was used for the previously created sprite. This generally distributes CPU evenly among frames. However certain applications may need to alter FramePhase to redistribute CPU among frames after certain sprites have been destroyed, for example.

Scenery that quickly changes may cause a noticeable latency in updating sprite visibility, LOD , and read-only gwSprite members in general if InfrequentRecalcMask is large. The larger the value of InfrequentRecalcMask, the longer (more frames) it will take for GWin3D to realize a sprite has moved in the viewport and to update certain members (like DistanceCenter ). The smaller this value, the more CPU will be used but the faster GWin3D will recognize the changes in the object and act accordingly.

In your application code you may want to temporarily set a sprite's InfrequentRecalcMask to 0 if you know it will be needed for that sprite. A classic example is using gwSprite::DistanceCenter to detect a collision with the viewpoint. Once a collision is detected it might be necessary to temporarily set InfrequentRecalcMask = 0 while critical collision code is active for several frames. Once the collision is handled, InfrequentRecalcMask can be set back to a reasonable value (like 3).

If a sprite has multiple parents, then GWin3D automatically ignores InfrequentRecalcMask for that sprite so that the time-consuming calculations will be performed each time the sprite is drawn. This is necessary because the results of those calculations can no longer be used over the next several frames. See AddSubSprite .

Default for InfrequentRecalcMask is 3.

gwSprite::NumPolygons

long gwSprite::NumPolygons

This read-only member is loaded by the Load function. It contains the total number of polygons in the highest LOD VRML file that was loaded. You can also enable certain debug flags (see gwSetDebug ) to see more statistics about VRML files loaded.

gwSprite::Flags

gwSprite::InheritFlags

__int64 gwSprite::Flags
__int64 gwSprite::InheritFlags

The gwSprite::Draw function draws a tree of sprites. When each sprite in the tree is drawn, these two members are bitwise ORed together along with all the InheritFlags of all the sprite's ancestors in the tree. The result of this OR operation serves two purposes:

First, the sprite is drawn only if the flag bits specified by set bits in the Mask parameter passed to the initial gwSprite::Draw function all match the corresponding bits in the Map parameter that was passed. See gwSprite::Draw.

Second, there are several flag bits which control how the sprite is drawn.

The application may use the lower 32 Flag bits such that the Map and Mask parameters passed to gwSprite::Draw can control whether a sprite is drawn. The upper 32 bits are reserved to control specific drawing attributes of the sprite. Several of these bits are defined below.

GW_NO_DEPTH_TEST
If this bit is set, then the sprite is drawn without regard to any other object being in front of it. Specifically, OpenGL's GL_DEPTH_TEST attribute is disabled when the sprite is drawn.

GW_TRANSPARENT
If this bit is set, then the sprite is drawn with blending enabled (glEnable(GL_BLEND)). Blending mixes the current pixels on the window with the object being drawn. Therefore transparent objects should be drawn after solid objects (see gwSprite::Draw ). The BlendSrcFunc and BlendDstFunc members control the exact blending operation. See those members for more information. Also see the section on Translucency.

GW_FORCE_DISTANCE_CALC_ON
GW_FORCE_DISTANCE_CALC_OFF
GWin3D automatically adjusts the OpenGL front clip and back clip parameters (see gwWindow::FrontClip, etc.) according to the nearest and farthest sprites. If neither of these bits is set in the Flags member, then a sprite is included in these calculations only if its List[0] or its Text[0] is non-zero--that is, if it is known to be a visible object.

You may want to force a non-visible sprite to be used in the clipping calculations. Use GW_FORCE_DISTANCE_CALC_ON for this. For example, you might have your own drawing code in the PreDrawCallback function.

You may want to cause a visible sprite to be neglected from distance calculations if, for example, its parent sprite is included and that is sufficient (thus saving CPU cycles) or the viewpoint will frequently be inside the sprite (like a sky box, or the topmost 'universe' sprite). Use GW_FORCE_DISTANCE_CALC_OFF for this.

GW_FORCE_DISTANCE_CALC_ON overrides GW_FORCE_DISTANCE_CALC_OFF.

Default value is 0.

gwSprite::BlendSrcFunc

gwSprite::BlendDstFunc

int gwSprite::BlendSrcFunc
int gwSprite::BlendDstFunc

If transparency is enabled for the sprite (see Flags variable, specifically the GW_TRANSPARENT flag), then blending is enabled when the sprite is drawn. The BlendSrcFunc and BlendDstFunc control how the current frame buffer (where the scene is constructed) pixel and the sprite pixel are combined to form the new frame buffer pixel. Specifically, these members are the two values passed to the OpenGL glBlendFunc function just before the sprite is drawn. See the OpenGL documentation on that function for more information.

There are several ways to implement translucency in OpenGL. Each has advantages and disadvantages.

The default values for BlendSrcFunc and BlendDstFunc are those necessary to implement the "poor man's" translucency that works best when the original view color (background) is typically fairly dark. These values are:

BlendSrcFunc =GL_ONE;
BlendDstFunc =GL_ONE;

This says that the final screen color for a pixel should be the sprite pixel color (the "source" color) multiplied by 1 added to the current screen color (the "destination" color) multiplied by 1.

This simply adds the current screen pixel color with the sprite pixel color. With these settings, black in the sprite is considered transparent and lighter colors more opaque. Note that the final screen value for each color component (R, G, or B) is still limited to 1. So, for example, if the current screen red component is .6 and the sprite pixel red component is .8, then the final screen red component for that pixel will be 1. Such saturation should be avoided, if possible.

Another form of poor man's translucency can simulate a translucent object that absorbs some of the light that goes through it, such as is done by a sheet of dark glass. In this case a dark sprite pixel will appear dark and opaque. A light sprite pixel will appear transparent.

The values for BlendSrcFunc and BlendDstFunc for this method should be:

BlendSrcFunc=GL_ZERO;
BlendDstFunc=GL_SRC_COLOR;

For better forms of translucency, materials and textures must have an alpha value less than one. GWin3D supports this.

See OpenGL glBlendFunc for more information on possible settings for these variables and what your material and texture alpha values should be. Also see the Texture member, gwImage::CopyComponents, and the Material member.

gwSprite::LodIndex

long gwSprite::LodIndex

This is an index into the List array specifying which display list to use to display the sprite.

If auto-LOD is enabled (see MaxElapsedTimeMs member), then this member is internally calculated and set when the sprite is drawn. It can be read, and overridden if desired, from within your EarlyDrawCallback and PreDrawCallback functions.

If auto-LOD is disabled, the application must set this as desired.

gwSprite::SubspriteLodLimit

long gwSprite::SubspriteLodLimit

By default, subsprites of a sprite are always drawn.

If you would like subsprites to only be drawn when the parent sprite is within a certain distance of the viewpoint (specifically when it is above a certain LOD ), then set this member to that threshold LOD.

When the current LodIndex is greater than SubspriteLodLimit, subsprites are not drawn. This saves CPU/GPU power when the sprite is far away. If the purpose of the subsprites is to add only finer detail to the parent sprite, then you may want to override the default value (which causes subsprites to always be drawn).

Subsprites are drawn if LodIndex is this value or lower (i.e. higher LODs ).

Default is GW_MAX_LODS (subsprites are always drawn).

gwSprite::LodScale

double gwSprite::LodScale

This should be adjusted for each sprite model. Set it such that the levels-of-detail appear at the distances you want. Different models often require radically different LodScale values. LodScale can typically range from .01 to 8 depending on personal preferences, model geometry, and texture detail.

To adjust this, assure there is enough CPU/GPU available by slowing down the frame rate. Then adjust this value so that the appearance of lower LODs of the sprite as the camera moves away is just on the threshold of being noticeable.

If this is set too high, then high LODs will be drawn when not needed. If this is set too low then a low LOD will be drawn when really a higher LOD should have been drawn.

gwSprite::Material

gwMaterial gwSprite::Material

Material of the sprite.

You can also cause the sprite material to vary smoothly between Material and NearMaterial depending on the distance from the viewpoint. This is accomplished by setting the HalfFadeDistance to a value other than zero.

To prevent the gwSprite::Draw function from applying the material, clear its gwMaterial::Enabled member. You would typically disable a material only if the sprite's display list specified all material attributes or you want it to take on the material of its parent sprite (all subsprites must have their material disabled for this to work). Material attributes will be undefined that are neither specified in the sprite's display list nor set in the sprite's display list.

Any material specifications in the sprite's display list(s), or executed by a PreDrawCallback function, will override this.

See Load, HalfFadeDistance, FullFadeDistance , and NearMaterial.

gwSprite::NearMaterial

gwMaterial gwSprite::NearMaterial

This member has meaning only if HalfFadeDistance is non-zero.

If HalfFadeDistance is non-zero, then the material used for the sprite varies smoothly between Material and NearMaterial depending on the distance from the viewpoint and the values of HalfFadeDistance and FullFadeDistance.

To prevent the gwSprite::Draw function from applying this material , clear its gwMaterial::Enabled member. You would typically disable a material only if the sprite's display list specified all material attributes. Material attributes will be undefined that are neither specified in the sprite's display list nor set in the sprite's display list.

Any material specifications in the sprite's display list(s), or executed by a PreDrawCallback function, will override this.

See Load, Material, HalfFadeDistance, and FullFadeDistance

gwSprite::HalfFadeDistance

gwSprite::FullFadeDistance

double gwSprite::HalfFadeDistance
double gwSprite::FullFadeDistance

The Material, HalfFadeDistance, FullFadeDistance, and NearMaterial members of the gwSprite class can work together to produce various effects. For example, a smoke or cloud texture can be made to fade as the viewpoint approaches it, giving the illusion of traveling through the smoke or cloud. (One may also want to make the sprite a banner by using the LockXOrientationToSprite, etc. members and the GW_TRANSPARENT flags). For another example, an object can be made to fade as it recedes from view.

If HalfFadeDistance is zero (which is the default), then the material used for the sprite is taken strictly from the Material member no matter what the distance between the viewpoint and the center of the sprite.

If HalfFadeDistance is non-zero, then the material used for the sprite varies smoothly between Material and NearMaterial depending on the distance from the viewpoint and the values of HalfFadeDistance and FullFadeDistance.

When the distance between the viewpoint and the center of the sprite is equal to or less than FullFadeDistance, then the material used for the sprite is fully taken from the NearMaterial member.

As distance from the viewpoint increases from FullFadeDistance, the material is proportionally taken more from the Material member and less from the NearMaterial member.

When the distance between the viewpoint and the center of the sprite has reached HalfFadeDistance , then the material used is half taken from the NearMaterial and half taken from the Material members.

As distance continues to increase beyond HalfFadeDistance, the material used for the sprite is taken more and more from the Material member.

HalfFadeDistance should be larger or equal to FullFadeDistance. Otherwise the behavior is undefined.

Some of the calculations used in implementing material fading are performed infrequently according to the InfrequentRecalcMask member. For sprites that use material fading, you might want to set their InfrequentRecalcMask to a low value so that the material fading is smooth as the camera distance changes.

gwSprite::Light

int gwSprite::Light

You can connect a light to a sprite with this.

Light can be set to GL_LIGHT0, GL_LIGHT1, etc.. Set this member to -1 for no light (which is the default).

Note: This is only for lights that have a definite position and possibly direction, like regular lights and spotlights. If you want a directional light (a light that has direction but no position) then directly call the OpenGL function to create it.

Light orientation and direction follow the sprite orientation and direction. Other light settings can be controlled by directly calling OpenGL functions that do so. For example:

MySprite.Light =GL_LIGHT0;

glEnable(GL_LIGHT0);

glLightfv(GL_LIGHT0, GL_AMBIENT, gwColorGrey.a);
glLightfv(GL_LIGHT0, GL_DIFFUSE, gwColorGrey.a);
glLightfv(GL_LIGHT0, GL_SPECULAR, gwColorGrey.a);


...
...

glDisable(GL_LIGHT0);
MySprite.Light =-1;


Ideally, in moving scenes, be sure to draw light sprites first so sprites drawn afterward in the same frame reflect any new changes in position since the last frame was drawn.

Not drawing lights at the beginning of a frame update usually won't have noticeable effect unless a bright light is right at the surface of a polygon that is drawn after the light, and the objects or light are moving considerably from one frame to the next. So if its a pain or reduces efficiency to draw light sprites first, you might not want to bother.

gwSprite::Disabled

bool gwSprite::Disabled

If non-zero, then GWin3D ignores this sprite and all of its subsprites.

The Disabled bit is checked by a parent sprite to indicate whether the subsprite should be drawn. This means that a disabled sprite takes fairly little overhead to "draw" because its Draw member isn't even called by the parent (although the overhead isn't always negligible) and it also means that if you call a sprite's Draw member directly, that it will still be drawn even if its Disabled flag is set.

To disable a sprite over an extended period, it is better to simply not include it in the sprite tree drawn by gwSprite::Draw.

The Disabled flag also has some use in the implementation of compiled sprite trees (see that section), and see the GW_REENABLE_SUBSPRITES flag.

gwSprite::Texture

gwTexture gwSprite::Texture

Texture for the sprite. Call the gwTexture::Load function to give the sprite a texture, or directly set the gwTexture::TexID member to a texture handle (for example, the texture handle gotten from another texture object).

The Texture member does not affect subsprites. If subsprites are to be textured, then their Texture members must be set accordingly or texture must be bound in their display lists or callback code.

Note that the gwTexture destructor may free the OpenGL texture handle. See gwTexture for more information.

Texture coordinates must be specified in the object description for this to work, unless text mode is being used. See the Text member.

Only one texture per sprite is supported via the gwTexture member. Objects with multiple textures must be made of multiple subsprites, include texture bind commands in their display lists, or perform special processing in the PreDrawCallback function, or texture commands might be compiled in the display lists (see List member).

If the Text member of the sprite is not empty, then the texture really needs to be a font texture. See the included font picture files to see how font pictures are made.

Mipmaps are automatically generated and handled internally by GWin3D (thanks to certain GLU functions).

You can change the texture dynamically. To do this, do not call the Texture.Load() function of the Texture member. Instead, create other gwTexture objects and assign them to the Texture member as needed, or call gwTexture::CreateFromRgb, for example. See gwTexture for warnings and restrictions on assigning gwTextures.

Class gwMesh

A gwMesh holds an array of vertices.

You can specify a gwImage whose pixels describe the mesh's terrain. You can make a flat or spherical terrain. The gwSprite::LoadMesh function can take a gwMesh object.

MEMBERS:

gwMesh::Mesh

gwVector3 * gwMesh::Mesh

A one-dimensional array used as a two-dimensional array where an element can be accessed as follows:
Mesh[Xnum + Ynum*NumXs]

Each vertex ( gwVector3 ) in the array is considered a corner of a quad. For example, if NumXs is 3 and NumYs is 5, then there are 15 vertices (gwVector objects) describing 8 quads in a 2x4 pattern.

The Mesh member is initialized to NULL. The application can allocate and load it, or the CreateFromHeightField function can be called to allocate and load it.

If Mesh is non-NULL when the destructor is called, then the destructor unallocates it with the MSVCRT free() function. Therefore if the application allocates it, it should do so with the gwAllocRamBlock functions to assure the block was allocated with the MSVCRT malloc function.

Note that the Xnum and Ynum mentioned herein do not correspond to world coordinates along the X-axis and Y-axis. Rather, they are simply array indices.

gwMesh::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy.

gwMesh::GetVectorElem

gwVector3 * GetVectorElem(long Xnum,long Ynum)

Returns Mesh[Xnum + Ynum*NumXs]

Note that Xnum and Ynum do not correspond to world coordinates along the X-axis and Y-axis. Rather, they are simply array indices.

gwMesh::Save

long Save(FILE *F)

Saves the mesh to a file.

F must have been obtained with a call to gwFileOpen or a call to the MSVCRT version of fopen().

gwMesh::Load

long Load(FILE *F)

Loads a mesh from a file.

F must be a FILE * created by the fopen function of the MSVCRT run-time library. FILE pointers created by other run-time libraries will not work. See the Save function for a discussion of this.

gwMesh::GetHeight

double GetHeight(double X,double Y)

Returns the height of the point on the mesh at location X,Y. Where X and Y are converted to an Xnum and Ynum index by offsetting and scaling according to Xoffset, Yoffset, ScaleX, and ScaleY. Also, this function correctly interpolates the height when X and Y describe a point between elements (between vertices in the mesh).

Since the X and Y parameters here are really indicative of array coordinates and not 3D axes, realize that for a horizontal mesh (as is created by CreateFromHeightField by default) the parameters passed to this function would really be the X and Z (the two axes of a horizontal plane) coordinates of an object on the plane. That is, if you created a horizontal height field and you want to know its height at a certain X,Z, then pass X,Z to this function.

Note that if the mesh has been modified by a matrix multiply (see gwMesh::Multiply ) then this function no longer performs as advertised. To avoid such, you may need to retain an original, unmodified, form of the mesh simply so you can use this function.

Note also that different implementations of OpenGL draw quads differently. Pretty much all implementations draw two triangles to create a quad, but which set of vertices is used for the two triangles can vary. Therefore this function does not exactly return the height for points on the quads (because it can't really know how OpenGL drew the two triangles) unless those points are on top of a vertex.

gwMesh::NumBytes

long gwMesh::NumBytes

Total number of bytes in the Mesh block. This is written by the CreateFromHeightField function. It is not used by GWin3D, but the application may use it to know the size of the mesh so it can, for example, be saved to disk. (Although in reality the _msize() heap function could also be used for that).

gwMesh::NumXs

gwMesh::NumYs

long gwMesh::NumXs
long gwMesh::NumYs

Contains the number of X and Y elements in the Mesh array. CreateFromHeightField writes these. If CreateFromHeightField is not being used to create the mesh, then the application should load these members so that various other GWin3D function can know the specifications of the mesh.

gwMesh::Xoffset

gwMesh::Yoffset

gwMesh::Zoffset

gwMesh::Xscale

gwMesh::Yscale

gwMesh::Zscale

gwMesh::Xskip

gwMesh::Yskip

gwMesh::Flags

double gwMesh::Xoffset
double gwMesh::Yoffset
double gwMesh::Zoffset
double gwMesh::Xscale
double gwMesh::Yscale
double gwMesh::Zscale
long gwMesh::Xskip
long gwMesh::Yskip
__int64 gwMesh::Flags

CreateFromHeightField loads these with the parameters it was passed. If CreateFromHeightField is not used to create the mesh, then the application should load these with meaningful values so that various other GWin3D function can know the specifications of the mesh.

gwMesh::Multiply

void Multiply( gwMatrix &M)

Call this to modify every vertex in the mesh according to a matrix. For example, if you called CreateFromHeightField to create the mesh (which, by default, orients the mesh horizontally), but you want it oriented vertically, then you might do something like this:

Mesh.CreateFromHeightField("myimage.jpg");
gwMatrix M;
M.SetRotation (90,0,0);
Mesh.Multiply(M);
gwSprite Q;
Q.LoadMesh(&Mesh);

gwMesh::CreateFromHeightField

long CreateFromHeightField
(
   gwImage *Image,
   double Xscale=1,
   double Yscale=1,
   double Zscale=1,
   double Xoffset=GW_AUTO_OFFSET,
   double Yoffset=GW_AUTO_OFFSET,
   double Zoffset=0,
   long Xskip =1,
   long Yskip =1,
   long LeftX=0,
   long TopY=0,
   long RightX=-1,
   long BottomY=-1,
   __int64 Flags=0 ,
   double RedScale=1./256,
   double BlueScale=1./65536,
   double GreenScale=1.
);

long CreateFromHeightField
(
   char *ImageFileName,
   double Xscale=1,
   double Yscale=1,
   double Zscale=1,
   double Xoffset=GW_AUTO_OFFSET,
   double Yoffset=GW_AUTO_OFFSET,
   double Zoffset=0,
   long Xskip =1,
   long Yskip =1,
   long LeftX=0,
   long TopY=0,
   long RightX=-1,
   long BottomY=-1,
   __int64 Flags=0,
   double RedScale=1./256,
   double BlueScale=1./65536,
   double GreenScale=1.
)


CreateFromHeightField creates a mesh from the pixels in an image. This is often convenient because there are so many image editing programs and functions available that can also be used to create a wide variety of terrains and surface detail.

The two forms of the function are identical except that one takes a gwImage (the Image parameter) and the other takes the filename of the image (ImageFileName parameter).

The X, Y, and Z coordinates of each vertex are multiplied by Xscale, Yscale, and Zscale respectively. Then the Xoffset, Yoffset, and Zoffset are added to each coordinate. The special value GW_AUTO_OFFSET can be specified for Xoffset and Yoffset to cause the mesh's center to be at the origin.

The Xskip and Yskip cause pixels to be skipped when creating the mesh. Thus if Xskip is 4 and Yskip is 4 and the original image has dimensions 64x64, then the mesh created will have dimensions 16x16. Note that "skip" might not be the best word here. The Xskip and Yskip values are actually one more than the number of pixels skipped. Thus an Xskip and Yskip value of 1 means skip zero pixels. Also, when pixels are skipped, they are really averaged. So "skipping" seven pixels really means those seven pixel colors should be averaged to produce the mesh height at the point.

There are two reasons you might want to skip pixels:
  1. To create a lower level of detail mesh.
  2. To overcome the height granularity in an image that only has 256 color levels--averaging several adjacent pixels yields more height resolution.
LeftX, TopY, RightX and BottomY describe the portion of the image that should be used to create the mesh. This can be used, for example, to make subsprites that describe a smaller part of the terrain with higher detail than a parent sprite that describes the whole mesh but with lower detail (see the discussion on LOD Sprite trees).

Flags is currently not used and should be zero.

Images cannot have more than 256 levels of red, levels of green, and levels of blue. This is because the highest color resolution image files use only one byte to store the level for each primary color (red, green, and blue). This does not give much resolution when an image is used as a heightfield. To remedy this, some heightfield image editors can use the different colors in each pixel as different bytes of a 3-byte level value for that pixel. The RedScale, BlueScale, and GreenScale give weight to different colors in the image. So, for example, if you have an image whose green bytes are the most significant bytes, red bytes second most significant, and blue bytes least significant, then the default values for the RedScale, BlueScale, and GreenScale parameters will convert each pixel into a 24 bit height. (To sustain such color level resolution, however, you must use a lossless compression, like bitmap).

The default values for RedScale, BlueScale, and GreenScale cause no problem even when the different colors in the image do not represent bytes of different significance, assuming the image is a grayscale image.

If the image is a single-color image (true grayscale rather than a color image containing only levels of gray), then the green parameters of this function control the heights, and the red and blue parameters are ignored.

Class gwImage

You can load an image file of type BMP, JPG, or JP2 into a gwImage object. The gwImage object stores the pixels of the image in memory.

gwImage has functions that let you access, convert, and process the pixels.

You can also save the pixels to a BMP, JPG, or JP2 file. For JPG and JP2, you can specify compression. In this way gwImage can be used to process and convert image files.

You typically load an image because you want to use it as a texture on a 3D object or as a heightfield. See gwTexture, gwSprite::Texture, gwSprite::LoadMesh, and gwMesh.

Do not assign gwImage objects. There is no reasonable operator= yet.

The gwImage class uses the JasPer and IJG code included in the GWin3D library, neither of which is owned or created by the GWin3D creator/owner. See the JasPer license agreement and GWin3D license agreement elsewhere in this document.

MEMBERS:

gwImage::gwImage

gwImage(char *Filename)
gwImage
(
   long Width,
   long Height,
   long NumComponents=3,
   long NumBits=8
)

The first constructor constructs the object and loads the pixels from the specified BMP, JPG, or JP2 file into memory.

It's a good idea to check the Valid member after construction to make sure the load was successful.

The second constructor constructs a gwImage object without loading its pixels from an image file. This may be desirable if the image will be created programmatically rather than loaded from a file.

gwImage::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy.

gwImage::GetNumComponents

long GetNumComponents(void)

Returns the number of components. For example, a color JPG file has 3 components (R, G, and B) and a grayscale has 1 component (luminance). JP2 files can have more components.

gwImage::GetNumBits

long GetNumBits(long ComponentNum)

Returns the number of bits for the specified component number.

For example, a 24-bit BMP file has 8 bits per component (R, G, and B).

Only JP2 files can have different bits per component.

gwImage::GetWidth

long GetWidth(long ComponentNum)

Returns the width (X dimension) for the specified component (R, G, B, or A). Only JP2 files support different dimensions for different components.

gwImage::GetHeight

long GetHeight(long ComponentNum)

Returns the height (Y dimension) for the specified component (like R, G, B, or A). Only JP2 files support different dimensions for different components.

gwImage::Valid

long gwImage::Valid

If non-zero, indicates the gwImage object contains a valid image. Typically you would check this flag after the object is constructed to make sure the image file loaded successfully.

gwImage::Save

void Save
(
   char *FileName,
   char *Options=NULL,
   char *FormatStr=NULL
)

Creates or overwrites a file of the given name with the pixels in the gwImage object.

Examples:

MyImage.Save("MyImage.jpg");
MyImage.Save("MyImage.jpeg","quality=60.4","jpg");
MyImage.Save("MyImage.jp2");
MyImage.Save("ImageDirectory//MyImage.jp2","rate=.04");
MyImage.Save("MyImage.bmp");

FormatStr can be "jpg", "jp2", or "bmp".

When creating a JPG file, Options can be "quality=<ratio>", where <ratio> is a float value indicating the lossiness of JPG compression, where 0.001 is most lossy and 100 is least lossy.

When creating a JP2 file, Options can be "rate=<ratio>", where <ratio> is a float value indicating the lossiness of JP2 compression, where 0.00001 is most lossy and 1 is least lossy.

FormatStr can be the file type extension. If the extension is included in the FileName, then FormatStr need not be specified.

gwImage::CombineComponents

void *CombineComponents
(
   void *Buf=NULL,
   unsigned long Flags=GW_IM_BOUNDEDROWS,
   long NewWidth = -1,
   long NewHeight = -1,
   long LowestRow=0,
   long LowestCol=0,
   long HighestRow=-1,
   long HighestCol=-1
)


When the gwImage object loads an image file, it is kept internally in the gwImage object in a buffer that is not directly accessible. And even if the buffer were accessible it still isn't compatible with the pixel memory format required by standard functions like gluScaleImage, gluBuild2Dmipmaps, and DrawDibDraw.

CombineComponents allocates (optionally) and copies the pixels to a buffer suitable for passing to functions like those mentioned above.

Buf can be NULL, in which case CombineComponents allocates the buffer, itself, and returns its address. The application is responsible for freeing the buffer. You must use the gwFreeRamBlock function to free the buffer.

Buf can also be a caller-allocated buffer to which the pixels are written. If the caller allocates Buf, then care must be taken to assure it is large enough to hold all the pixels. Remember to allocate extra space if GW_IM_BOUNDEDROWS is specified because the alignment may need to waste up to 3 bytes at the end of each row in order to assure that the next row is aligned.

CombineComponents can also get a portion of the image, and it can scale the image dimensions for the pixels copied to the buffer.

LowestRow, LowestCol, HighestRow, and HighestCol specify the portion of the original image to get. When HighestRow or HighestCol has a value of -1, then that means use the maximum.

A NewWidth and/or NewHeight value can be specified to scale the image. Values of -1 mean do not change that dimension.

CombineComponents internally calls the gluScaleImage function to resize the image. gluScaleImage shrinks a dimension with a box filter algorithm, and grows a dimension with a linear interpolation algorithm.

Since gluScaleImage requires that each row of pixel data start on a long boundary, an error message is printed if resizing is attempted and the GW_IM_BOUNDEDROWS flag was not specified.

There may be some OpenGL drivers that require that a valid rendering context be active when gluScaleImage is called. So as a rule, call CombineComponents from within a thread that has one active, like your gwWindow 's PeriodicFunction.

Flags can be a bitwise OR of any of the following:

GW_IM_BOUNDEDROWS
Align each row of pixels on a long boundary (the abovementioned functions require this, and it is necessary if any resizing is performed).

GW_IM_REVERSE_COMPONENTS
Place the components in the buffer in reverse order (for example, RGB vs. BGR). For example, DrawDibDraw requires this.

See also SeparateComponents.

Example:

gwImage MyImage("flerb.jpg");

if(!MyImage.Valid)
{
   printf("Couldn't load file\n");
   return 1;
}


// Below, we could have let CombineComponents allocate this buffer,
// but one purpose of this example is to show you how
// to do it, yourself, if you have a need.
char *Pixels=(char *)malloc
(
   MyImage.GetHeight(0)
   *
   MyImage.GetWidth(0)
   *
   Image.GetNumComponents()

   // allocate extra space to account for a few wasted bytes at end
   // of each row
   +

   3
   *
   MyImage.GetHeight(0)
);

if(!Pixels)
{
   printf("Out of memory\n");
   return 1;
}

MyImage.CombineComponents (Pixels);


gwImage::SeparateComponents

void *SeparateComponents
(
   void *Buf=NULL,
   unsigned long Flags=GW_IM_BOUNDEDROWS
)


Use this function to copy the pixels of a standard format buffer (as is used by functions like gluScaleImage, gluBuild2Dmipmaps, and DrawDibDraw) into the image object.

Flags can be a bitwise OR of any of the following:

GW_IM_BOUNDEDROWS
Indicates that each row of pixels is aligned on a long boundary.

GW_IM_REVERSE_COMPONENTS
Indicates the components in the buffer are in reverse order (for example, RGB vs. BGR).

To use this function, pass the address of a buffer that contains pixels in the standard format. The function will copy these pixels to the internal, inaccessible, non-standard format of the gwImage object so that the gwImage member functions can operate on them.

The return value is undefined.

See CombineComponents.

gwImage::CopyComponent

void CopyComponent
(
   gwImage *SourceImage,
   long SourceComponentNum,
   long DestComponentNum
)


Copies a single color component from one image to another. With this function and the constructor that creates an image of an arbitrary number of components you can manipulate color and alpha channels in images.

For example, you might create a gwImage object with four components and set the first three to the RGB from another image, then set the fourth to the component from a separate grayscale image. The resulting image can be given to the gwTexture constructor to produce a RGBA texture.

As far as saving a file (see gwImage::Save ), remember that numbers of components other than 1 and 3 are supported only by the JPEG2000 (JP2) file format.

gwImage::GetMinMax

void GetMinMax
(
   double *Min=NULL,
   double *Max=NULL,
   long ComponentNum=-1
)

Gets the minimum and maximum level of a specified component, or of all components if ComponentNum == -1.

For example, to find the brightest green level in an RGB image:

gwImage MyImage("mypicfile.jp2");

double BrightestGreen;

MyImage.GetMinMax(NULL,&BrightestGreen,1);


gwImage::Math

long Math
(
   double Addend,
   double Multiplier=1,
   long ComponentNum=-1,
   long LowerRail=0,
   long UpperRail=255
)


For each pixel in the specified component (if ComponentNum == -1 then do it for all components), the level is altered according to the following equation:

NewPixelLevel = (OldPixelLevel + Addend) * Multiplier

Pixel levels are prevented from falling below LowerRail or rising above UpperRail.

If any pixel hit the lower rail then bit zero is set in the return value.
If any pixel hit the upper rail then bit one is set in the return value.

gwImage::MathMergeComponents

long MathMergeComponents
(
   long DestinationComponentNum,
   double Addend=0,
   double Multiplier=.3333,
   long LowerRail=0,
   long UpperRail=255,
   gwImage *DestinationImage=NULL
)

With this function you can easily create components that are modifications of other components, such as grayscale or mask (for alpha channels) images or components.

For each pixel position, this function first adds the magnitudes of all components (creates a grayscale). To pixel value it then adds the Addend value, multiplies the result by Multiplier, then clips it to LowerRail and UpperRail, and finally places the result into the corresponding pixel position of the destination component--which can be in another gwImage object.

If any pixel hit the lower rail then bit zero is set in the return value.
If any pixel hit the upper rail then bit one is set in the return value.

The destination component must have the same dimensions as the source components.

Example1:

// Create an image from a pic file but with 1 extra component for alpha
gwImage Pic1("MyColorPic.JPG",1);

// make the fourth component an alpha channel which causes dark
// areas in the original picture to be transparent
Pic1.MathMergComponents
(
   4,
   -30, // grayscale mags below 30 are transparent, above 30 opaque
   1000000, // we want alpha values of pretty much only 0 or 1
);

gwImage::GetValue

double GetValue
(
   long ComponentNum,
   long X,
   long Y,
   __int64 Flags,
   double Radius
)

Returns the level of the specified pixel of the specified component, if Radius is zero.

If Radius is greater than zero then an average of the pixels within Radius is returned.

If Flags & GW_WRAP_PIXELS, then when averaging pixels the image will be treated as if it is tiled if Radius includes pixels off the edge of the image.

This is rather slow. For heavy processing of many pixels, use one of the other member functions that perform operations on all the pixels, or convert it to a buffer with CombineComponents(), then you can access the pixel memory directly and then convert it back with SeparateComponents() if needed.

gwImage::SetValue

void SetValue
(
   double NewValue,
   long ComponentNum,
   long X,
   long Y
)


Sets the level of the specified pixel in the specified component.

This is rather slow. For heavy processing of pixels, use one of the other member functions that perform operations on all the pixels, or convert it to a buffer with CombineComponents(), then you can access the pixel memory directly and then convert it back with SeparateComponents().

Class gwSpriteRecord

Each gwSprite object keeps a linked list of its subsprites. Rather than simply add "Next" and "Previous" members to the gwSprite class, a separate class was implemented to add one more level of indirection so that parents could share subsprites. Each parent sprite has its own linked list of subsprite records and each record points to a subsprite. That way gwSpriteRecords in different linked lists can refer to the same sprite as a child.

It is unlikely you will find a need to create your own gwSpriteRecord objects since the gwSprite::AddSubSprite and gwSprite::RemoveSubSprite functions create and destroy gwSpriteRecords as needed.

This class is documented because you might, for example, want to sort subsprite records according to their distance from the camera, in order to implement true translucency. See the section on Translucency. Also, the gwSprite::EnumSubSprites function takes a pointer to one of these.

MEMBERS:

gwSpriteRecord::gwSpriteRecord

gwSpriteRecord( gwSprite *InParent, gwSprite *InSprite);

Constructor takes pointers to the parent sprite to whose linked list this record should be added and to the sprite this record will refer to.

The constructor adds itself to the head of the parent's linked list of subsprite records. See Next, Previous, and gwSprite::HeadSubSpriteRecord.

gwSpriteRecord::~gwSpriteRecord

~gwSpriteRecord();

The destructor removes itself from the parent's linked list of subsprite records.

gwSpriteRecord::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy.

gwSpriteRecord::Sprite

gwSprite * gwSpriteRecord::Sprite

The sprite that this sprite record refers to.

gwSpriteRecord::Parent

gwSprite * gwSpriteRecord::Parent

The parent that owns the linked list of which this object is an element. See gwSprite::HeadSubSpriteRecord

gwSpriteRecord::Next

gwSpriteRecord *gwSpriteRecord::Next

The next gwSpriteRecord object in the linked list.

gwSpriteRecord::Previous

gwSpriteRecord *gwSpriteRecord::Previous

The previous gwSpriteRecord object in the linked list.


Class gwMatrix

A gwMatrix object manages everything having to do with the position and orientation of a sprite.

The gwSprite class is a child of the gwMatrix class, and the functionality it inherits from the gwMatrix class defines the sprite's position, scale, shear, and rotation relative to its parent sprite.

The gwSprite class also has a LastMatrix member, which is a gwMatrix object. This member describes the difference in the sprite's most recently calculated position, scale, shear, and rotation relative to the universe. It is calculated each time the sprite is drawn and is the matrix given to the rendering hardware. It is saved in the LastMatrix member simply so other code can find out the latest absolute (relative to the universe) position and orientation of the sprite. See gwSprite::LastMatrix for more information.

You might also want to instantiate a separate gwMatrix object to store a position, scale, shear, and rotation value that can later be used to modify those of a sprite via matrix multiplication.

You may wish to see the section entitled Introduction to Matrices and 3D Rendering before continuing. Although that section tells you more than you need, It is at least important to understand the definition of coordinate systems in the context of matrix math and that a matrix describes a difference in one coordinate system from another.

The gwMatrix class holds the 16x16 array of values (the matrix) which describes a difference in one coordinate system from another, and also supplies all the functions necessary to alter those matrix values in order to set or modify that difference in position, scale, shear, and rotation . Functions are available that modify these attributes relative to the current coordinate system described by the matrix itself, and functions are available that modify these attributes relative to the "parent" matrix.

The rows and columns of the matrix are arranged in the way OpenGL expects them to be. In math literature describing matrices, the rows and columns are swapped from that.

The gwMatrix class has member functions for performing many of the different matrixoperations typically needed in 3D work. Later releases of GWin3D will hopefully have more (like quaternion and vector classes that work together with gwMatrix objects).

The following table shows the member functions available, along with their descriptions and their latencies on an Athlon 1.7 GHz system.

Function Name: Time to execute on an Athlon 1.7 GHz system (in nanoseconds): Description:
Reset 20 Overrides all settings in the matrix and sets it so that it describes no difference from the parent's coordinate system.
ResetNoPosition 10 Resets the scale, shear, and rotation elements, but leaves the position alone.
CopyNoPosition 20 Overwrites the current scale, shear, and rotate attributes with those of the specified matrix, but leaves the position elements alone.
GetPosition 10 Returns the current position relative to the parent's coordinate system.
GetScale 10 Returns the values of the scale elements. These are meaningful only if there is no rotation .
GetShear 30 Returns the values of the shear elements. These are meaningful only if there is no rotation.
GetRotation 770 to 1100 Returns the Euler angles ( roll, pitch, and yaw ) describing the rotation relative to the parent.
GetXAxis 10 Returns the current X-axis relative to the parent's coordinate system.
GetYAxis 10 Returns the current Y-axis relative to the parent's coordinate system.
GetZAxis 10 Returns the current Z-axis relative to the parent's coordinate system.
GetXAxisWith 10 Returns the current transpose X-axis.
GetYAxisWith 10 Returns the current transpose Y-axis.
GetZAxisWith 10 Returns the current transpose Z-axis.
GetXAxisWith 10 Returns the current transpose X-axis.
SetXAxis 20 Writes the X-axis vector
SetYAxis 20 Writes the Y-axis vector
SetZAxis 20 Writes the Z-axis vector
SetXAxisWith 20 Writes the X transpose axis vector
SetYAxisWith 20 Writes the Y transpose axis vector
SetZAxisWith 20 Writes the Z transpose axis vector
SetPosition 20 Overwrites the matrix elements that describe position relative to the parent. Writing these does not affect the current settings for shear, rotate, or scale.
SetScale 20 Overwrites the matrix elements that describe scale. Writing these will have an adverse effect on any current non-zero rotation setting.
SetShear 30 Overwrites the matrix elements that describe shear. Writing these will have an adverse effect on any current non-zero rotation setting.
SetRotation 270 to 530 Overwrites the matrix elements that describe rotation. Writing these will override any current scale and shear setting, such that there is no scaling or shearing.
ModifyPosition 270 to 530 Modifies the position relative to the matrix 's current coordinate system.
ModifyScale 120 to 210 Modifies the scale relative to the matrix 's current coordinate system.
ModifyShear 140 to 240 Modifies the shear relative to the matrix 's current coordinate system.
ModifyRotation 390 to 660 Modifies the rotation relative to the matrix 's current coordinate system. Note:Roll is applied before pitch and yaw with this function. To implement true relative roll, first rotate the matrix with pitch and yaw specified, then call ModifyRotation with the roll value by itself.
ModifyWithPosition 30 Modifies the current position relative to the parent's coordinate system.
ModifyWithScale 270 to 520 Modifies the current scale relative to the parent's coordinate system.
ModifyWithShear 240 to 500 Modifies the current shear relative to the parent's coordinate system.
ModifyWithRotation 530 to 800 Modifies the current rotation relative to the parent's coordinate system.
ModifyWithScaleNoPosition 160 to 420 Modifies the current scale relative to the parent's coordinate system. Leaves alone the elements that define position.
ModifyWithShearNoPosition 190 to 370 Modifies the current shear relative to the parent's coordinate system. Leaves alone the elements that define position.
ModifyWithRotationNoPosition 420 to 690 Modifies the current rotation relative to the parent's coordinate system. Leaves alone the elements that define position.
Rotate Not measured yet Rotates around the specified vector.
Transpose Not measured yet Swaps values of rows and columns
TransposeNoPosition Not measured yet Swaps values of rows and columns for the first three rows/columns
FromQuaternion Not measured yet Alters the 3x3 elements given a quaternion
operator* 160 to 260 Multiplies the left matrix by the right matrix and returns the result.
operator*= 200 to 320 Multiplies the matrix by another matrix. Specifically, this causes the matrix to be altered relative to its current coordinate system according to the specified matrix.
MultiplyWith 210 to 310 Multiplies another matrix by this matrix and writes the result to this matrix. Specifically, this causes the matrix to be altered relative to the parent's coordinate system according to the specified matrix.
MultiplyNoPosition 80 to 90 Same as operator* except leaves position elements alone.
MultiplyWithNoPosition 130 to 240 Same as MultiplyWith except leaves position elements alone.

Although the above function set may look like a committee developed it, there really is rhyme and reason to it. The nature of a matrix is that the concepts of position, scale, shear, and rotation share certain of the elements of the matrix but not others. The above function set is all that is needed to perform basic operations in the most efficient way possible. More quaternion support, more matrix arithmetic, and vector arithmetic may be available in later releases.

Admittedly, the purpose of some of these functions can be confusing. Therefore experimentation is often the best way to learn which functions should be used to perform a needed task. A simplified rule of thumb is to try the faster functions, or combinations of them, first, and if they don't do what you want, only then resign yourself to using a slower function.

Typically you would update a changing sprite's matrix every frame. This can be done from within the gwWindow 's PeriodicFunction. See gwWindow . A sprite that you don't want changed since the last frame update need not have its matrix altered.

Consider the following examples:

Example 1. Fully define a sprite's orientation relative to its parent:

static gwSprite MySprite("MyVrmlFile");

MySprite.Reset();

MySprite.SetPosition(...)

// we can use SetScale instead of ModifyScale because
// the current rotation is zero
MySprite.SetScale(...)

// we can use SetShear instead of ModifyShear because
// the current rotation is zero
MySprite.SetShear(...)

// We can't use SetRotation because it would override
// the previous scale & shear settings, so we have to
// use ModifyRotation, instead.
MySprite.ModifyRotation(...)



Example 2. Periodically move a sprite relative to its parent:

// set sprite's starting position once, and change it a little each frame
// (this code would be in the gwWindow's PeriodicFunction or WM_TIMER handler)

static gwSprite MySprite("MyVrmlFile");

static int FirstFrame=1;
if(FirstFrame)
{
   FirstFrame=0;

   MySprite.Reset();

   MySprite.SetPosition(12,-80,17);
}

MySprite.ModifyPosition (0,2,3);


Example 3. Create a separate matrix for quickly rotating the sprite by the same amount each frame:

// Create a sprite
static gwSprite MySprite("MyVrmlFile");

// and create a matrix to multiply with the sprite:
static gwMatrix MyRotMatrix;

static int FirstFrame=1;
if(FirstFrame)
{
   // position the sprite once in the initialization code
   MySprite.SetPosition(...);
   MySprite.SetRotation (...);

   // and set the rotation of the modifying matrix
   MyRotMatrix.SetRotation (73,10,32);
}

// now, in the periodic frame update code, rotate the sprite by multiplying
// it with the rotation matrix:
MySprite*=MyRotMatrix;


NOTE: Unfortunately, a disadvantage of repeatedly orienting a sprite relatively (as shown in the last two examples above) is that floating point rounding errors can compound themselves over many such reorientations. GWin3D does not currently supply a matrix function to remove these effects (such a function assumes no shear or other oddities were desired in the matrix, and removes them). To alleviate this problem, periodically Reset the sprite and set its full orientation relative to the parent (as shown in the first example). Typically this need not be done very frequently.

NOTE: You are responsible for updating a sprite's Radius member to reflect its visible size. Many of the gwMatrix member functions change the visible size of the sprite or require a parent's Radius member to be updated (for example, if a subsprite moves further away from a parent). See gwSprite::Radius. It is usually acceptable, however, to make minor changes in a sprite's visible size without updating its Radius member.


MEMBERS:

gwMatrix::gwMatrix

gwMatrix(__int64 Flags);
gwMatrix(double *Data=NULL)

If the first constructor is used and the value GW_CLEAR is passed, then the matrix is created and the Reset function is called for the matrix. See Reset.

If the first constructor is called without the GW_CLEAR flag, or the second constructor is called but no data is specified, then the matrix is created without being initialized. You should afterward call other member functions and be sure all 16 elements of the matrix are initialized before using the matrix. This might be done to save a little time--there are cases you don't need Reset called internally by the constructor.

If you know what you are doing, you can optionally pass an array of 16 doubles to initialize the matrix.

gwMatrix::e[]

gwMatrix::a[]

union
{

   struct
   {
       double e00;
       double e01;
       double e02;

       double e03;

       double e10;

       double e11;

       double e12;

       double e13;
       double e20;

       double e21;
       double e22;

       double e23;

       double e30;

       double e31;

       double e32;

       double e33;

   };

   double a[16];

   double e[4][4];

}


You can access any element of the matrix as a separate variable, an element of a one-dimensional array, or an element of a two dimensional array. These expressions can be read or written (used as an lvalue or rvalue). The following are equivalent:

e13=6.2; // fastest
a[7]=6.2; // slow
e[1][3]=6.2; // slower


Note: you can also access the elements one-dimensionally by following the matrix object's name immediately with brackets, which is the slowest method. See below.

gwMatrix::operator[]

double& operator [](unsigned int n)

You can refer to an element of a gwMatrix object by following the object name with brackets enclosing the one-dimensional index. Such an expression can be used as an lvalue or an rvalue. This is the slowest way to access an element. Use the above union, instead.

gwMatrix::FromQuaternion

void FromQuaternion(double *Quaternion)

Alters the 3x3 portion of the matrix to reflect the orientation described by the quaternion (X, Y, Z, W) pointed to by Quaternion. The position is not altered.

gwMatrix::operator* =

gwMatrix operator*=( gwMatrix &M)

This multiplies the matrix by the specified matrix.

gwMatrix::SizeOf

long SizeOf()

Like the C sizeof command, this returns the size of the object. However, unlike sizeof, this function is virtual--so it will work correctly when mixing pointers to different classes in a class hierarchy.

gwMatrix::Reset

void Reset(void)

Overwrites the matrix with the unity matrix. A unity matrix indicates there is no change in position, scale, shear, or rotation.

gwMatrix::ResetNoPosition

void ResetNoPosition(void)

Overwrites the matrix with the unity matrix, but leaves alone the elements that describe position. The matrix will then describe no change in scale, shear, or rotation but the original position will be retained.

gwMatrix::SetPosition

void SetPosition(double X,double Y,double Z)

Overwrites the position of the matrix with the specified vector. Current rotation , scale, and shear are unaffected. A sprite with this matrix will appear at the specified position within its parent's coordinate system.

You can also use such a matrix to multiply with another matrix in order to translate it.

gwMatrix::SetScale

void SetScale(double ScaleX,double ScaleY,double ScaleZ)

Overwrites the scale of the matrix with the specified dimensions. Position and shear are unaffected. If there is any current rotation in the matrix then the results are undefined. A sprite with this matrix will be scaled by the specified amounts within its parent's coordinate system.

Be sure to update the sprite's Radius member accordingly.

You can also use such a matrix to multiply with another matrix in order to change its scale proportionally.

gwMatrix::SetShear

void SetShear
(

   double ShearXY,

   double ShearXZ,

   double ShearYX,

   double ShearYZ,

   double ShearZX,

   double ShearZY

)

Overwrites the matrix shear with the specified shear values. Position and scale are unaffected. If there is any current rotation in the matrix then the results are undefined. A sprite with this matrix will be sheared by the specified amounts within its parent's coordinate system.

You can also use such a matrix to multiply with another matrix in order to change its shear proportionally.

gwMatrix::SetRotation

void SetRotation(double Pitch,double Yaw,double Roll )

Overwrites the rotation with the specified Euler angles. Position is unaffected. If there is a current shear or scale value, then the results are undefined. A sprite with this matrix will be rotated by the specified amounts within its parent's coordinate system.

You can also use such a matrix to multiply with another matrix in order to change its rotation proportionally.

gwMatrix::SetFlattenMatrix

void SetFlattenMatrix(double Ground[4], double Light [4])

This function creates a matrix that will flatten another matrix onto a plane.

This can be used, for example, to create simple planar shadows. In that case you would make a duplicate sprite, flatten it, place it slightly above the plane upon which it is supposed to be a shadow, and make it translucent.

Simply multiply the matrix to be flattened by this matrix.

The Ground[] array is the variables from the plane equation (Ax + By + Cz + D = 0).

Light is the position of a light, in homogeneous coordinates, for which the shadow is being created. This means that for point light sources the first three values are the X, Y, and Z for the light and the last value should be 1. For directional sources X, Y, Z is the direction vector for the light and the last value is 0.

Currently this is the only shadowing feature available in GWin3D. Shadow maps may be added in a future release. It is doubtful shadow volumes will be implemented in GWin3D because they are so CPU intensive and require a lot of specific tweaking to work well in a given situation. You can, of course, implement any type of shadow in your application code. You might also consider light maps for shadows of non-moving objects. (A light map is simply a texture with a hard-coded shadow on it.)

gwMatrix::Transpose

void Transpose(void)

Swaps row and column values of the matrix.

gwMatrix::TransposeNoPosition

void TransposeNoPosition(void)

Swaps row and column values of the first three rows and columns of the matrix. Use this to convert orientation from parent relative to self-relative, or vice versa.

gwMatrix::ModifyPosition

void ModifyPosition(double X,double Y,double Z)

Modifies the position relative to the matrix 's current coordinate system. Specifically, this multiplies the matrix by a translation matrix of the specified vector.

Be sure to update the parent sprite's Radius member accordingly.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyScale

void ModifyScale ( double ScaleX, double ScaleY, double ScaleZ )

Modifies the scale relative to the matrix 's current coordinate system. Specifically, this multiplies the matrix by a scaling matrix of the specified dimensions.

Be sure to update the sprite's Radius member accordingly.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyShear

void ModifyShear
(
  
double ShearXY,
   double ShearXZ,

   double ShearYX,

   double ShearYZ,

   double ShearZX,

   double ShearZY

)


Modifies the shear relative to the matrix 's current coordinate system. Specifically, this multiplies the matrix by a shearing matrix of the specified vector.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyRotation

void ModifyRotation(double Pitch,double Yaw,double Roll )

Modifies the rotation relative to the matrix 's current coordinate system. Specifically, this multiplies the matrix by a rotation matrix of the specified Euler angles.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithPosition

void ModifyWithPosition(double X,double Y,double Z)

Modifies the position relative to the matrix 's parent's coordinate system. Specifically, this multiplies the matrix with a translation matrix of the specified vector.

Be sure to update the parent sprite's Radius member accordingly.

gwMatrix::ModifyWithScale

void ModifyWithScale ( double ScaleX, double ScaleY, double ScaleZ )

Modifies the scale relative to the matrix 's parent's coordinate system. Specifically, this multiplies the matrix with a scaling matrix of the specified dimensions.

Be sure to update the sprite's Radius member accordingly.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithShear

void ModifyWithShear
(
   double ShearXY,
   double ShearXZ,

   double ShearYX,

   double ShearYZ,
   double ShearZX,
   double ShearZY

)


Modifies the shear relative to the matrix 's parent's coordinate system. Specifically, this multiplies the matrix with a shearing matrix of the specified vector.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithRotation

void ModifyWithRotation(double Pitch,double Yaw,double Roll )

Modifies the rotation relative to the matrix 's parent's coordinate system. Specifically, this multiplies the matrix with a rotation matrix of the specified Euler angles.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithScaleNoPosition

void ModifyWithScaleNoPosition ( double ScaleX, double ScaleY, double ScaleZ )

Modifies the scale relative to the matrix 's parent's coordinate system, but leaves alone the matrix elements that describe position. Specifically, this does a 3x3 multiply of the matrix with a scaling matrix of the specified dimensions.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithShearNoPosition

void ModifyWithShearNoPosition
(
   double ShearXY,

   double ShearXZ,

   double ShearYX,

   double ShearYZ,

   double ShearZX,

   double ShearZY

)


Modifies the shear relative to the matrix 's parent's coordinate system, but leaves alone the matrix elements that describe position. Specifically, this does a 3x3 multiply of the matrix with a shearing matrix of the specified vector.

See the description of the gwMatrix class for performance issues.

gwMatrix::ModifyWithRotationNoPosition

void ModifyWithRotationNoPosition ( double Pitch, double Yaw, double Roll )

Modifies the rotation relative to the matrix 's parent's coordinate system, but leaves alone the matrix elements that describe position. Specifically, this does a 3x3 multiply of the matrix with a rotation matrix of the specified Euler angles.

See the description of the gwMatrix class for performance issues.

gwMatrix::Rotate

void Rotate(double Angle, double X, double Y, double Z)

Rotates the matrix around the specified vector by the specified angle.

gwMatrix::GetPosition

void GetPosition ( double *X=NULL, double *Y=NULL, double *Z=NULL )

Loads the variables pointed to by X, Y, and Z with the position relative to the parent's coordinate system.

gwMatrix::GetScale

void GetScale ( double *SizeX=NULL, double *SizeY=NULL, double *SizeZ=NULL )

Loads the variables pointed to by X, Y, and Z with the scale relative to the parent's coordinate system.

gwMatrix::GetShear

void GetShear
(
   double *ShearXY,
   double *ShearXZ,

   double *ShearYX,

   double *ShearYZ,

   double *ShearZX,

   double *ShearZY

)


Loads the variables pointed to with the shear relative to the parent's coordinate system.

gwMatrix::GetRotation

void GetRotation(double* Pitch,double* Yaw,double* Roll )

Extracts the Euler angles from the matrix and loads the variables pointed to with them, in degrees. Note that the nature of a matrix is that the yaw varies between -90 and +90, and the pitch and roll vary between -180 and +180.

Typically one would want the pitch to be the parameter that varies between -90 and +90.

One way to retrieve Euler angles in which the pitch varies between -90 and +90, and the roll and yaw varying between -180 and +180, is to rotate the matrix about the roll axis (the Z-axis ) by 90 degrees and then extract the Euler angles, swapping the meanings of pitch and yaw . For example, let's say you want to extract the Euler angles from OrigMatrix, but with the pitch varying between -90 and +90:

gwMatrix NewMatrix = OrigMatrix;

NewMatrix.ModifyRotation (0,0,90);

NewMatrix.GetRotation (* Yaw, * Pitch , * Roll );


Notice that the final call to GetRotation has the Yaw and Pitch parameters swapped.

gwMatrix::GetXAxis

void GetXAxis ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the X-axis length and direction of the coordinate system described by the matrix.

gwMatrix::GetYAxis

void GetYAxis ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the Y-axis length and direction of the coordinate system described by the matrix.

gwMatrix::GetZAxis

void GetZAxis ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the Z-axis length and direction of the coordinate system described by the matrix.

gwMatrix::GetXAxisWith

void GetXAxisWith ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the X-axis length and direction of the coordinate system described by the transpose of the matrix.

gwMatrix::GetYAxisWith

void GetYAxisWith ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the Y-axis length and direction of the coordinate system described by the transpose of the matrix.

gwMatrix::GetZAxisWith

void GetZAxisWith ( double *VX=NULL, double *VY=NULL, double *VZ=NULL )

Loads the indicated variables with the Z-axis length and direction of the coordinate system described by the transpose of the matrix.

gwMatrix::SetXAxis

void SetXAxis ( double VX=1, double VY=0, double VZ=0 )

Sets the X-axis length and direction of the coordinate system described by the matrix .

gwMatrix::SetYAxis

void SetYAxis ( double VX=0, double VY=1, double VZ=0 )

Sets the Y-axis length and direction of the coordinate system described by the matrix .

gwMatrix::SetZAxis

void SetZAxis ( double VX=0, double VY=0, double VZ=1 )

Sets the Z-axis length and direction of the coordinate system described by the matrix .

gwMatrix::SetXAxisWith

void SetXAxisWith ( double VX=1, double VY=0, double VZ=0 )

Sets the X transpose axis length and direction of the coordinate system described by the matrix.

gwMatrix::SetYAxisWith

void SetYAxisWith ( double VX=0, double VY=1, double VZ=0 )

Sets the Y transpose axis length and direction of the coordinate system described by the matrix.

gwMatrix::SetZAxisWith

void SetZAxisWith ( double VX=0, double VY=0, double VZ=1 )

Sets the Z transpose axis length and direction of the coordinate system described by the matrix.

gwMatrix::operator*

gwMatrix gwMatrix::operator *(double *M)

Multiplies the left matrix by the right matrix (in the form of an array of doubles) and returns the result matrix.

gwMatrix::operator*

gwMatrix gwMatrix::operator *(gwMatrix &M)

Multiplies the left matrix by the right matrix and returns the result matrix.

gwMatrix::operator*

void gwMatrix::operator *=(gwMatrix &M)

Multiplies the matrix by the right matrix.

gwMatrix::operator=

void gwMatrix::operator =(gwMatrix &M)

Copies the 4x4 matrix elements in the right matrix to the left matrix.

gwMatrix::CopyNoPosition

void CopyNoPosition( gwMatrix &M)

Copies the 3x3 matrix elements in the specified matrix to this matrix.

gwMatrix::MultiplyWith

void MultiplyWith( gwMatrix &M)

Multiplies this matrix by the specified matrix and sets this matrix to the result.

gwMatrix::MultiplyNoPosition

void MultiplyNoPosition( gwMatrix &M)

Performs a 3x3 multiply of this matrix by the specified matrix.

gwMatrix::MultiplyWithNoPosition

void MultiplyWithNoPosition( gwMatrix &M)

Performs a 3x3 multiply of the specified matrix with this matrix and writes the result to this matrix.

Class gwTexture

A gwTexture object holds a 2D image that is applied to the surface of a sprite.

You can create a texture from a bmp, jpg, or jp2 image file. You can also create a texture from a memory resident bitmap in the form of a gwImage object. You can assign the gwTexture object from another gwTexture object, or you can access the TexID member (the OpenGL texture handle) directly (with certain restrictions--see the TexID member).

Each vertex of the sprite mesh must also have been given a texture coordinate for the texture to appear on the sprite. See gwSprite::Load.

The gwSprite 's Texture member holds the texture for the sprite. When a sprite is created, this member is empty. To load an image into the sprite's Texture member, you might do something like this, for example:

gwSprite MySprite("MyVrmlFile");

MySprite.Texture.Load("myimage.jpg");

The Load member function must be called from within your gwWindow 's PeriodicFunction because it calls OpenGL functions, and those functions must be called in the proper thread and rendering context. Note that the gwTexture constructor calls the Load member function if parameters are passed.

When the Load member function is called, an internal flag in the object is set indicating that object is the owner of that OpenGL texture handle. This tells the gwTexture destructor that it should free the OpenGL texture handle. The operator= member function does not copy this internal flag. The operator= function also displays a debug warning if the assigned-to object already owns a texture.

To play a video as a texture, see the CreateFromDib function.

To dynamically change a sprite's texture from a set of several images, do not call the gwSprite::Texture .Load() function repeatedly for each texture. Rather, create other gwTexture objects and assign the sprite's Texture from one of those other textures as needed. For higher speed, you can assign the TexID member directly if you are careful about which gwTexture object 'owns' the handle. For example:

gwTexture MyTex1("tex1.jpg");
gwTexture MyTex2("tex2.jpg");

gwSprite MySprite("MyVrmlFile");
...
MySprite.Texture =Tex1;
...
// dynamically change the sprite's texture
MySprite.Texture=Tex2;


Do not assign another gwTexture object's TexID member to a texture object when that object already "owns" its current texture. Doing so will cause the object's destructor to free the texture handle even though that object wasn't the owner of that handle, and to neglect to free its original handle.

When gwTexture::Load is called, mipmaps are internally generated via gluBuild2DMipmaps. This makes your graphics hardware efficiently manage texture memory. Far objects use a much smaller texture map than near objects and the graphics hardware should cache these maps into texture memory from system memory as needed.

The number of components in the image tells gwTexture what kind of texture it is. One component means its luminance (gray scale), two means its luminance and alpha, three means its RGB, four means its RGBA.

If you don't have an image file that has exactly the components you want, or you want to combine components from multiple files or remove components from a file, gwImage gives you this power. With gwImage you can create an image object with whatever components you want from multiple image files (see the gwImage default constructor and gwImage::CopyComponents) and then you can pass it to the gwTexture constructor or save it as a new file so gwTexture can load it directly, later (see gwImage::Save ).

To tell your GPU to store the texture in compressed form if it is supported (to save GPU memory), pass the GW_TEX_COMPRESS flag.

The width and height of texture images must each be a power of 2. An error message is displayed, otherwise.

You might also want to check out Gimp, which is a downloadable (see its license agreement) image editor that has a nice feature called "make seamless" for making tile-able textures.

See gwSprite::Load for more information.

MEMBERS:

gwTexture::gwTexture

gwTexture()

gwTexture

(

   gwImage *Image,

   long NewWidth,

   long NewHeight,

   unsigned __int64 Flags=0,

   long LowestRow=0,

   long LowestCol=0,

   long HighestRow=-1,

   long HighestCol=-1

)

gwTexture

(

   char *Filename,

   long NewWidth,

   long NewHeight,

   unsigned __int64 Flags=0

)


gwTexture

(

   gwImage *Image,

   double ScaleFactor=1,

   unsigned __int64 Flags=0

)
gwTexture ( char *Filename, double ScaleFactor=1, unsigned __int64 Flags=0 )