appendix G
OpenGL for Windows
G.1 OpenGL Auxiliary
Table G.1OpenGL auxiliary function listing
| Name |
Description |
| auxIdleFunc(...) |
Specifies the function to be called whenever no events are pending. |
| auxInitDisplayMode(...) |
Specifies the various characteristics of the display mode that OpenGL and the
auxiliary library will use. |
| auxInitPosition(...) |
Initializes the windows start-up position parameters. |
| auxInitWindow(...) |
Opens a window with the characteristics specified in function calls to
auxInitDisplayMode and auxInitPosition. |
| auxKeyFunc(...) |
Specifies the function that is called whenever a specific key is pressed during
display of an auxiliary model. |
| auxMainLoop(...) |
Specifies the display function that needs to be called whenever the display is to be
updated. |
| auxMouseFunc(...) |
Specifies that this function is called whenever a mouse event occurs during auxiliary
display. |
| auxReshapeFunc(...) |
Specifies the function that will be called whenever the auxiliary windows are resized
or moved. |
| auxSetOneColor(...) |
Loads the index in the color map with the given values. |
| auxSolidCone(...) |
Draws a surfaced three-dimensional cone. |
| auxSolidCube(...) |
Draws a surfaced three-dimensional cube. |
| auxSolidCylinder(...) |
Draws a surfaced three-dimensional cylinder. |
| auxSolidDodecahedron(...) |
Draws a surfaced three-dimensional dodecahedron (similar to a sphere). |
| auxSolidIcosahedron(...) |
Draws a surfaced three-dimensional icosahedron (similar to a sphere). |
| auxSolidOctahedron(...) |
Draws a surfaced three-dimensional octahedron. |
| auxSolidSphere(...) |
Draws a surfaced three-dimensional sphere. |
| auxSolidTeapot(...) |
Draws a surfaced three-dimensional teapot. |
| auxSolidTetrahedron(...) |
Draws a surfaced three-dimensional tetrahedron. |
| auxSolidTorus(...) |
Draws a surfaced three-dimensional solid torus. |
| auxWireCone(...) |
Draws a wireframe three-dimensional cone. |
| auxWireCube(...) |
Draws a wireframe three-dimensional cube. |
| auxWireCylinder(...) |
Draws a wireframe three-dimensional cylinder. |
| auxWireDodecahedron(...) |
Draws a wireframe three-dimensional dodecahedron (similar to a sphere). |
| auxWireIcosahedron(...) |
Draws a wireframe three-dimensional icosahedron (similar to a sphere). |
| auxWireOctahedron(...) |
Draws a wireframe three-dimensional octahedron. |
| auxWireSphere(...) |
Draws a wireframe three-dimensional sphere. |
| auxWireTeapot(...) |
Draws a wireframe three-dimensional teapot. |
| auxWireTetrahedron(...) |
Draws a wireframe three-dimensional tetrahedron. |
| auxWireTorus(...) |
Draws a wireframe three-dimensional solid torus. |
For more specific information on OpenGL auxiliary functions, consult the OpenGL
Programming Guidethe "red book." (See Neider, Jackie.)
G.2 OpenGL functions and extended functions
Table G.2 OpenGL functions
| Name |
Description |
| glAccum(...) |
Performs operations on the accumulation buffer. |
| glAddSwapHintRectWIN(...) |
Specifies a set of rectangles that are to be used and copied by SwapBuffers. |
| glAlphaFunc(...) |
Specifies how alpha blending works by picking a testing function and setting testing
parameters. |
| glArrayElementEXT(...) |
Specifies an index into an array when indexing vertex information. |
| glBegin(...) |
Begins a new primitive or primitive group when rendering a model. |
| glBitmap(...) |
Draws a specified bitmap. |
| glBlendFunc(...) |
Specifies blending function pixel arithmetic. |
| glCallList(...) |
Executes a given display list that has been previously stored. |
| glCallLists(...) |
Executes a roster of display lists that have been previously stored. |
| glClear(...) |
Clears a specified buffer within a given viewport. |
| glClearAccum(...) |
Clears values in an accumulation buffer using specified values. |
| glClearColor(...) |
Specifies the color to use when clearing buffers. |
| glClearDepth(...) |
Specifies the clear value for the depth buffer (z-buffer). |
| glClearlndex(...) |
Specifies the clear value for the color index buffer. |
| glClearStencil(...) |
Specifies the clear value for the stencil buffer. |
| glClipPlane(...) |
Specifies additional planes to be used when clipping a model's geometry. |
| glColor(...) |
Specifies a color when drawing a model. |
| glColorMask(...) |
Enables or disables the writing of frame buffer color components. |
| glColorMaterial(...) |
Causes a material color to track the current color based on various lighting
parameters. |
| glColorPointerEXT(...) |
Defines an array of colors. |
| glCopyPixels(...) |
Copies a set of pixels into the frame buffer. |
| glCullFace(...) |
Specifies whether front and back facing polygon faces can be culled. |
| glDeleteLists(...) |
Deletes a contiguous group of display lists. |
| glDepthFunc(...) |
Specifies the value used for depth buffer comparison. |
| glDepthMask(...) |
Enables or disables writing into the depth buffer. |
| glDepthRange(...) |
Specifies the mapping of z-depth values from normalized coordinates into window
coordinates. |
| glDrawArraysEXT(...) |
Specifies multiple primitives to render. |
| glDisable(...) |
Disables and enables various OpenGL modeling features. |
| glDrawBuffer(...) |
Specifies which color buffers are to be drawn into. |
| glDrawPixels(...) |
Writes a block of pixels into the frame buffer. |
| glEdgeFlag(...) |
Specifies the current edge flag. Edge flags indicate whether the current edge is a
boundary or a nonboundary. |
| glEdgeFlagPointerEXT(...) |
Defines an array of edge flags. |
| glEnable(...) |
Enables or disables various OpenGL capabilities. |
| glEvalCoord(...) |
Evaluates enabled one and two-dimensional maps. |
| glEvalMesh(...) |
Computes one and two-dimensional grids of points or lines. |
| glEvalPoint(...) |
Generates and evaluates a single point in a mesh. |
| glFeedbackBuffer(...) |
Controls the feedback mode by specifying buffer and vertex return information. |
| glEnd(...) |
Ends a glBegin block of primitives. |
| glEndList(...) |
Finishes declaration of a display list. |
| glFinish(...) |
Blocks all operations until GL rendering is completed. |
| glFlush(...) |
Forces execution of GL commands in finite time. |
| glFog(...) |
Specifies various parameters when modeling with fog. |
| glFrontFace(...) |
Defines front and back facing polygons. |
| glFrustum(...) |
Multiplies the current matrix by a perspective transformation matrix that defines the
viewing volume. |
| glGenLists(...) |
Generates a set of empty display lists. |
| glGet(...) |
Returns a parameter from the current model. |
| glGetBooleanv(...) |
Returns the value or values of a given parameter. |
| glGetClipPlane(...) |
Returns the coefficients of the specified clipping plane. |
| glGetDoublev(...) |
Returns the value or values of a given parameter. |
| glGetError(...) |
Returns current error information. |
| glGetFloatv(...) |
Returns the value or values of a given parameter. |
| glGetLight |
Returns the light source parameter values. |
| glGetlntegerv(...) |
Returns the value or values of a given parameter |
| glGetMap(...) |
Returns function evaluator parameters. |
| glGetMaterial(...) |
Returns selected material parameters. |
| glGetPixelMap(...) |
Returns the specified pixel map. |
| glGetPolygonStipple(...) |
Returns the polygon stipple pattern. |
| glGetString(...) |
Returns a string describing the current GL connection. |
| glGetTexEnv(...) |
Returns texture environment parameters. |
| glGetTexGen(...) |
Returns texture coordinate generation parameters. |
| glGetTexImage(...) |
Returns a texture image. |
| glGetTexLevelParameter(...) |
Returns texture parameter values for a specific level of detail. |
| glGetTexParameter(...) |
Returns texture parameter values. |
| glHint(...) |
Specifies a hinting level to assist GL in determining which method to use when
rendering a model. |
| glIndex(...) |
Sets the current color index. |
| glIndexMask(...) |
Controls the writing of individual bits in the color index buffers. |
| glIndexPointerExt |
Defines an array of color indexes. |
| glInitNames(...) |
Initializes the name stack. |
| glIsEnabled(...) |
Tests whether a current capability is enabled. |
| glIsList(...) |
Tests for display list existence. |
| glLight(...) |
Sets up light source parameters. |
| glLightModel(...) |
Sets the lighting model parameters. |
| glLineStipple(...) |
Specifies the current line stipple pattern. |
| glLineWidth(...) |
Specifies the current width of rasterized lines. |
| glListBase(...) |
Sets the display-list base for using the glCallLists function. |
| glLoadIdentity(...) |
Loads the identity matrix into the current matrix. |
| glLoadMatrix(...) |
Replaces the current matrix with an arbitrary user-defined matrix. |
| glLoadName(...) |
Loads a name onto the name stack. |
| glLogicOp(...) |
Specifies a logical pixel operation for color index rendering. |
| glMapl(...) |
Defines a one-dimensional evaluator. |
| glMap2(...) |
Defines a two-dimensional evaluator. |
| glMapGrid(...) |
Defines a one- or two-dimensional mesh. |
| glMaterial(...) |
Specifies material properties used in the lighting model. |
| glMatrixMode(...) |
Specifies which matrix is the current matrix, either Modelview, Projection, or
Texture. |
| glMultMatrix(...) |
Multiplies the current matrix by an arbitrary matrix. |
| glNewList(...) |
Creates or replaces a display list. |
| glNormal(...) |
Sets the current normal vector for lighting calculations. |
| glNormalPointerEXT |
Defines an array of normals. |
| glOrtho(...) |
Multiplies the current matrix by an orthographic matrix that defines a viewing volume.
|
| glPassThrough(...) |
Places a marker in the feedback buffer. |
| glPixelMap(...) |
Sets up pixel transfer maps. |
| glPixelStore(...) |
Sets pixel storage modes. |
| glPixelTransfer(...) |
Sets pixel transfer modes. |
| glPixelZoom(...) |
Specifies the pixel zoom factors which are used during the glDrawPixels and
glCopyPixels operations. |
| glPointSize(...) |
Specifies the diameter of rasterized points. |
| glPolygonMode(...) |
Selects a polygon rasterization mode. |
| glPolygonStipple(...) |
Sets the polygon stippling pattern. |
| glPopAttrib(...) |
Pops attribute sets on the attribute stack. |
| glPopMatrix(...) |
Pops a matrix off of the current matrix stack. |
| glPopName(...) |
Pops a name on the name stack. |
| glPushAttrib(...) |
Pushes attribute sets on the attribute stack. |
| glPushMatrix(...) |
Pushes a matrix off of the current matrix stack. |
| glPushName(...) |
Pushes a name on the name stack. |
| glRasterPos(...) |
Specifies the raster position for pixel operations. |
| glReadBuffer(...) |
Selects a color buffer source for pixels. |
| glReadPixels(...) |
Reads a block of pixels from the frame buffer. |
| glRect(...) |
Draws a rectangle. |
| glRenderMode(...) |
Sets the current rasterization mode. |
| glRotate(...) |
Multiplies the current matrix by a rotation matrix. |
| glScale(...) |
Multiplies the current matrix by a scaling matrix. |
| glScissor(...) |
Defines the scissor box, which is a rectangle in window coordinates. A scissor box
specifies that only pixels drawn in the box may be modified by rendering commands. |
| glSelectBuffer(...) |
Establishes a buffer for selection mode values. |
| glShadeModel(...) |
Specifies either smooth or flat shading. |
| glStencilFunc(...) |
Sets the function and reference value for stencil testing. |
| glStencilMask(...) |
Controls the writing of individual bits in the stencil planes. |
| glStencilOp(...) |
Sets the stencil test actions. |
| glTexCoord(...) |
Sets the current texture coordinates. |
| glTexCoordPointerEXT(...) |
Defines an array of texture coordinates. |
| glTexEnv(...) |
Sets texture environment parameters. |
| glTexGen(...) |
Controls the generation of texture coordinates. |
| glTexImage(...) |
Specifies a texture image. |
| glTexParameter(...) |
Sets texture parameters. |
| glTranslate(...) |
Multiplies the current matrix by a translation matrix. |
| glVertex(...) |
Specifies a vertex. |
| glVertexPointerExt(...) |
Defines an array of vertex data. |
| glViewport(...) |
Sets the current viewport. |
G.2.1 OpenGL utility functions
Table G.3 OpenGL utility functions
| Name |
Description |
| gluBeginCurve(...) |
Delimits a NURBS curve definition. |
| gluBeginPolygon(...) |
Delimits a polygon description. |
| gluBeginSurface(...) |
Delimits a NURBS surface definition. |
| gluBeginTrim(...) |
Delimits a NURBS trimming loop definition. |
| gluBuildldMipmaps(...) |
Creates one and two-dimensional MIP maps. |
| gluCylinder(...) |
Draws a cylinder. |
| gluDeleteNurbsRenderer(...) |
Destroys a NURBS object. |
| gluDeleteQuadric(...) |
Destroys a quadrics object. |
| gluDeleteTess(...) |
Destroys a tessellation object. |
| gluDisk(...) |
Draws a disk. |
| gluErrorString(...) |
Produces an error string from an OpenGL or GLU error code. |
| gluEndCurve(...) |
Completes a NURBS curve definition. |
| gluEndPolygon(...) |
Completes a polygon description. |
| gluEndSurface(...) |
Completes a NURBS surface definition. |
| gluEndTrim(...) |
Completes a trimming loop definition. |
| gluGetNurbsProperty(...) |
Gets a NURBS property. |
| gluGetString(...) |
Gets a string that describes the GLU version number and supported GLU extension calls.
|
| gluGetTessProperty(...) |
Gets a tessellation object property. |
| gluLoadSamplingMatrices(...) |
Loads NURBS sampling and culling matrices. |
| gluLookAt(...) |
Defines a viewing transformation. |
| gluNewNurbsRenderer(...) |
Creates a NURBS object. |
| gluNewQuadric(...) |
Creates a quadrics object. |
| gluNewTess(...) |
Creates a tessellation object. |
| gluNextContour(...) |
Marks the beginning of another contour. |
| gluNurbsCallback(...) |
Defines a callback for a NURBS object. |
| gluNurbsCurve(...) |
Defines the shape of a NURBS curve. |
| gluNurbsProperty(...) |
Sets a NURBS property. |
| gluNurbsSurface(...) |
Defines the shape of a NURBS surface. |
| gluOrtho2D(...) |
Defines a 2D orthographic projection matrix. |
| gluPartialDisk(...) |
Draws an arc of a disk. |
| gluPerspective(...) |
Sets up a perspective projection matrix. |
| gluPickMatrix(...) |
Defines a picking region. |
| gluProject(...) |
Maps object coordinates to window coordinates. |
| gluPwlCurve(...) |
Describes a piecewise linear NURBS trimming curve. |
| gluQuadricCallback(...) |
Defines a callback for a quadrics object. |
| gluQuadricDrawStyle(...) |
Specifies the draw style desired for quadrics. |
| gluQuadricNormals(...) |
Specifies what kind of normals are desired for quadrics. |
| gluQuadricOrientation(...) |
Specifies inside/outside orientation for quadrics. |
| gluQuadricTexture(...) |
Specifies whether or not texturing is desired for quadrics. |
| gluScaleImage(...) |
Scales an image to an arbitrary size. |
| gluSphere(...) |
Draws a sphere. |
| gluTessBeginContour(...) |
Delimits a contour description. |
| gluTessBeginPolygon(...) |
Delimits a polygon description. |
| gluTessCallback(...) |
Defines a callback for a tessellation object. |
| gluTessNormal(...) |
Specifies a normal for a polygon. |
| gluTessProperty(...) |
Sets the property of a tessellation object. |
| gluTessVertex(...) |
Specifies a vertex on a polygon. |
| gluUnProject(...) |
Maps window coordinates to object coordinates. |
G.2.2 Windows implementation OpenGL functions
Table G.4 Windows-specific OpenGL functions
| Name |
Description |
| wglCreateContext(...) |
Creates a new OpenGL rendering context. The rendering context is suitable for drawing
on the device referenced by hdc. The rendering context has the same pixel format as the
device context. |
| wglDeleteContext(...) |
Destroys an OpenGL rendering context that was created with wglCreateContext. |
| wglGetCurrentContext(...) |
Obtains a handle to the calling thread's current OpenGL rendering context. |
| wglGetCurrentDC(...) |
Obtains a handle to the device context that is associated with the calling thread's
current OpenGL rendering context. |
| wglGetProcAddress(...) |
Returns the address of an OpenGL extension function for use with the current OpenGL
rendering context. |
| wglMakeCurrent(...) |
Makes a specified OpenGL rendering context the calling thread's current rendering
context. All subsequent calls made by the thread are drawn on the device identified by the
current device context. This function can also be used to make the calling thread's
current rendering context not current. |
| wglShareLists(...) |
Enables multiple OpenGL rendering contexts to share a single display list. |
| wglUseFontBitmaps(...) |
Creates a set of bitmap display lists based on the glyphs in a device context's
currently selected font for use in the current OpenGL rendering context. These bitmaps can
then be used to draw characters in an OpenGL image. |
| wglUseFontOutlines(...) |
Creates a set of display lists based on the glyphs of the currently selected outline
font of a device context for use with the current rendering context. The display lists are
used to draw 3D characters of TrueType fonts. |
G.2.3 Related Win32 functions
Table G.5 Win32 functions
| Name |
Description |
| ChoosePixelFormat(...) |
Attempts to find the pixel format that is supported by a device context that is the
best match to a given pixel format specification. |
| DescribePixelFormat(...) |
Obtains information about the pixel format identified by the device associated with
the current hdc. |
| GetPixelFormat(...) |
Obtains the index of the specified device context's currently selected pixel format. |
| SetPixelFormat(...) |
Sets the specified device context's pixel format to the format specified by the index.
|
| SwapBuffers(...) |
Exchanges the front and back buffers if the current pixel format for the window
referenced by the specified device context includes a back buffer. |
PIXELFORMATDESCRIPTOR
typedef struct tagPIXELFORMATDESCRIPTOR { // pfd
WORD nSize;
WORD nVersion;
DWORD dwFlags;
BYTE iPixelType;
BYTE cColorBits;
BYTE cRedBits;
BYTE cRedShift;
BYTE cGreenBits;
BYTE cGreenShift;
BYTE cBlueBits;
BYTE cBlueShift;
BYTE cAlphaBits;
BYTE cAlphaShift;
BYTE cAccumBits;
BYTE cAccumRedBits;
BYTE cAccumGreenBits;
BYTE cAccumBlueBits;
BYTE cAccumAlphaBits;
BYTE cDepthBits;
BYTE cStencilBits;
BYTE cAuxBuffers;
BYTE iLayerType;
BYTE bReserved;
DWORD dwLayerMask;
DWORD dwVisibleMask;
DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR;
Table G.6 PIXELFORMATDESCRIPTOR members
| Name |
Description |
| WORD nSize |
Specifies the size of this data structure. |
| WORD nVersion |
Specifies the version of this data structure. |
| DWORD dwFlags |
Set of flags that specify properties of the pixel buffer. |
| BYTE iPixelType |
Specifies the type of pixel data. |
| BYTE cColorBits |
Specifies the number of color bitplanes in each color buffer. |
| BYTE cRedBits |
Specifies the number of red bitplanes in each color buffer. |
| BYTE cRedShift |
Specifies the shift count for red bitplanes in each color buffer. |
| BYTE cGreenBits |
Specifies the number of green bitplanes in each color buffer. |
| BYTE cGreenShift |
Specifies the shift count for green bitplanes in each color buffer. |
| BYTE cBlueBits |
Specifies the number of blue bitplanes in each color buffer. |
| BYTE cBlueShift |
Specifies the shift count for blue bitplanes in each color buffer. |
| BYTE cAlphaBits |
Specifies the number of alpha bitplanes in each color buffer. |
| BYTE cAlphaShift |
Specifies the shift count for alpha bitplanes in each color buffer. |
| BYTE cAccumBits |
Specifies the total number of bitplanes in the accumulation buffer. |
| BYTE cAccumRedBits |
Specifies the total number of red bitplanes in the accumulation buffer. |
| BYTE cAccumGreenBits |
Specifies the total number of green bitplanes in the accumulation buffer. |
| BYTE cAccumBlueBits |
Specifies the total number of blue bitplanes in the accumulation buffer. |
| BYTE cAccumAlphaBits |
Specifies the total number of alpha bitplanes in the accumulation buffer. |
| BYTE cDepthBits |
Specifies the color depth of the buffer. |
| BYTE cStencilBits |
Specifies the depth of the stencil buffer. |
| BYTE cAuxBuffers |
Specifies the number of auxiliary buffers. |
| BYTE iLayerType |
Specifies the type of layer. |
| BYTE bReserved |
Not used. |
| DWORD dwLayerMask |
Specifies the layer mask. |
| DWORD dwVisibleMask |
Specifies the visible mask. |
| DWORD dwDamageMask |
Specifies whether more than one pixel format shares the same frame buffer. |
Following is the pixel descriptor used when developing Partica:
PIXELFORMATDESCRIPTOR pfq = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24 bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32 bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
GLYPHMETRICSFLOAT
typedef struct _GLYPHMETRICSFLOAT { // gmf
FLOAT gmfBlackBoxX;
FLOAT gmfBlackBoxY;
POINTFLOAT gmfptGlyphOrigin;
FLOAT gmfCellIncX;
FLOAT gmfCellIncY;
} GLYPHMETRICSFLOAT;
Table G.7 GLYPHMETRICSFLOAT members
| Name |
Description |
| FLOAT gmfBlackBoxX |
Specifies the width of the smallest rectangle that completely encloses the glyph. |
| FLOAT gmfBlackBoxY |
Specifies the height of the smallest rectangle that completely encloses the glyph. |
| POINTFLOAT gmfptGlyphOrigin |
Specifies the x and y coordinates of the upper left corner of the smallest rectangle
that completely encloses the glyph. |
| FLOAT gmfCellIncX |
Specifies the horizontal distance from the origin of the current character cell to the
origin of the next character cell. |
| FLOAT gmfCellIncY |
Specifies the vertical distance from the origin of the current character cell to the
origin of the next character cell. |
POINTFLOAT
typedef struct _POINTFLOAT { // ptf
FLOAT x;
FLOAT y;
} POINTFLOAT;
Table G.8 POINTFLOAT members
| Name |
Description |
| FLOAT X; |
Specifies the horizontal or (x) coordinate of a point. |
| FLOAT Y; |
Specifies the vertical or (y) coordinate of a point. |
G.3 COpenGLView header
This source code is provided so that the reader can construct his/her own OpenGL-based
classes independently. When you run into problems you can quickly look up the solution
that was used in Partica. This will help speed up development by having a set of working
code available. The following code has been tested and used in the Windows 95/NT
environment.
The first step is to create the interface for the COpenGLView class. We do
that by setting up the primary object and its member variables as follows:
// COpenGLView.h : interface of the COpenGLView class
#include "objects.h"
COpenGLView header
Our implementation has four primary modes of operation. These modes are given the
enumeration type OpenGLTool.
enum OpenGLTool {
Select, NodeSelect, Zoom, Translate
};
The currently selected tool is a global member so that all views will have the same
tool selected to save confusion.
extern OpenGLTool SelectedTool;
class CObjectViewDlg;
class COpenGLDoc;
Our COpenGLView object is an MFC extension and is derived from the MFC CView object.
The critical function members listed here have been discussed in chapter 11. These
functions are intended to be accessed by derived objects from the following base class:
class COpenGLView : public CView
{
protected:
afx_msg void OnContextMenu(CWnd*, CPoint point);
unsigned char ComponentFromIndex(int i, UINT nbits, UINT shift);
void ComputeTessellationLocation();
void SelectField(LField *field);
void DrawModel(RECT &l);
void CreateRGBPalette(HDC hDC);
BOOL bSetupPixelFormat(HDC hDC);
PIXELFORMATDESCRIPTOR pfd;
COpenGLView();
DECLARE_DYNCREATE(COpenGLView)
LPoint3 OldField,
Leye,Lcenter,Lup,
Loldeye,Loldup,center,
trackballaxis;
CPoint LastMouseLocation,
BeginRotatePos,
LastClickPos,
BeginDrag;
RECT oldrect;
CObjectViewDlg *objwin;
CWnd * THISCWND;
CDC *hdc ; // OpenGL Rendering Contexts
HDC hDC;
HGLRC hrc ;
LACEDocument *objectdata;
LField * WorkingField;
HPALETTE ghpalOld, ghPalette;
float DepthScale;
float dtheta;
float theta;
float near_plane, far_plane, aspect, fov;
float radius;
float CubeSize;
float trackballangle;
float LastTessellationTime;
int TimerValue;
int LightModel;
int ModelType; // 0-point 1-plus 2-sphere
BOOL IsFollow,IsMouseInWindow,PausePlay,
IsFrozen,Rotating,IsFullScreen,
KillPlay,KillRotate,SuccessFullDraw,
Tetrahedral,Wireframe,Shading,
ZBuffer,AntiAlias,Backface,
AutoField,rdown,spinmode,
down,CanPaint,IsSplines,
IsLighting,IsTransparent,IsPlaying,
IsWireframe;
LineF_t BeginLine;
GLdouble trackballMatrix[16];
GLdouble starttrackballMatrix[16];
The following are the publicly accessible members. These members may be accessed by any
object in the application. Most of these functions are in-line for use with the virtual
trackball control that is implemented in COpenGLView.
public:
void Center() {
LPoint3 r=objectdata->GetCenter();
Lcenter.x=-r.x;
Lcenter.y=-r.y;
Lcenter.z=-r.z;
if(!(IsPlaying|Rotating))
Invalidate(FALSE);
};
void DisconnectFromCWnd();
void ConnectToCWND(CWnd *wnd);
void StopAnimation();
void AdjustLighting();
void Tessellate();
void NeedViewClose();
virtual BOOL PreTranslateMessage(MSG* pMsg);
COpenGLDoc* GetDocument();
float GetTrackballDistance() {
return VECTORLENGTH(Leye.x,Leye.y,Leye.z);
};
LPoint3 GetSphereIntersection(LineF_t &_l, SphereF_t &_sp) {
LPoint3 result;
result.x=-999999; // Failed Case
LineF_t EO;
EO.vector.x=_sp.center.x-_l.point.x;
EO.vector.y=_sp.center.y-_l.point.y;
EO.vector.z=_sp.center.z-_l.point.z;
EO.point=_l.point;
float m=VECTORLENGTH(_l.vector.x,_l.vector.y,_l.vector.z);
if(m==0) return result;
_l.vector.x/=m;
_l.vector.y/=m;
_l.vector.z/=m;
GLfloat v= EO.vector.x*_l.vector.x+
EO.vector.y*_l.vector.y+
EO.vector.z*_l.vector.z;
GLfloat EOEO= EO.vector.x*EO.vector.x+
EO.vector.y*EO.vector.y+
EO.vector.z*EO.vector.z;
float disc=_sp.r*_sp.r-
(EOEO-v*v);
if(disc<0)
return result;
GLfloat d=sqrt(disc);
result.x=EO.point.x+(v-d)*_l.vector.x;
result.y=EO.point.y+(v-d)*_l.vector.y;
result.z=EO.point.z+(v-d)*_l.vector.z;
return result;
};
void GotoObjectSpace(float x, float y, float z) {
Lcenter.x=-x;
Lcenter.y=-y;
Lcenter.z=-z;
};
LPoint3 WindowToObject(CPoint &t, double z=0 ) {
LPoint3 object;
GLdouble modelMatrix[16];
GLdouble projMatrix[16];
GLint viewport[4];
GLdouble winx,winy,winz,objx,objy,objz;
winx=t.x;
winy=t.y;
winz=z;
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
glGetIntegerv(GL_VIEWPORT,viewport);
gluUnProject(winx,winy,winz,
modelMatrix,projMatrix,viewport,
&objx,&objy,&objz);
object.x=objx;
object.y=objy;
object.z=objz;
return object;
};
LPoint3 ObjectToWindow(LPoint3 &t) {
LPoint3 object;
GLdouble modelMatrix[16];
GLdouble projMatrix[16];
GLint viewport[4];
GLdouble winx,winy,winz,objx,objy,objz;
winx=t.x;
winy=t.y;
winz=t.z;
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
glGetIntegerv(GL_VIEWPORT,viewport);
gluProject(winx,winy,winz,
modelMatrix,projMatrix,viewport,
&objx,&objy,&objz);
object.x=objx;
object.y=objy;
object.z=objz;
return object;
};
LPoint3 IntersectLinePlane(LineF_t &l, LPoint3 &planepoint,
LPoint3 &planenorm) {
LPoint3 Q,P,v,w,result;
Q.x=l.point.x; Q.y=l.point.y; Q.z=l.point.z;
P.x=planepoint.x; P.y=planepoint.y; P.z=planepoint.z;
v.x=planenorm.x; v.y=planenorm.y; v.z=planenorm.z;
w.x=l.vector.x; w.y=l.vector.y; w.z=l.vector.z;
float top,bottom;
top=(P.x-Q.x)*v.x+(P.y-Q.y)*v.y+(P.z-Q.z)*v.z;
bottom=w.x*v.x+w.y*v.y+w.z*v.z;
float mul=top/bottom;
result.x=Q.x+mul*w.x;
result.y=Q.y+mul*w.y;
result.z=Q.z+mul*w.z;
return result;
};
LPoint3 MoveParallelToScreen(LPoint3 &OldPoint, CPoint &oldwin,
CPoint &newwin) {
// Get object coord
LPoint3 OldWin=WindowToObject(oldwin);
LPoint3 NewWin=WindowToObject(newwin);
OldWin.x=(float)oldwin.x/(float)oldrect.right;
OldWin.y=(float)oldwin.y/(float)oldrect.bottom;
OldWin.z=0;
NewWin.x=(float)newwin.x/(float)oldrect.right;
NewWin.y=(float)newwin.y/(float)oldrect.bottom;
NewWin.z=0;
LPoint3 pnorm,ppoint;
ppoint=OldPoint; // Plane at point
// Ray from screen center to eye
pnorm.x=Lcenter.x-Leye.x;
pnorm.y=Lcenter.y-Leye.y;
pnorm.z=Lcenter.z-Leye.z;
float dist=VECTORLENGTH(pnorm.x,
pnorm.y,pnorm.z);
pnorm.x/=dist;
pnorm.y/=dist;
pnorm.z/=dist;
// Plane setup now, find ray
LineF_t ray;
ray.point.x=NewWin.x;
ray.point.y=NewWin.y;
ray.point.z=NewWin.z;
LPoint3 NewWindeltat=WindowToObject(newwin,1);
ray.vector.x=ray.point.x;//-NewWindeltat.x;
ray.vector.y=ray.point.y;//-NewWindeltat.y;
ray.vector.z=ray.point.z-1;//NewWindeltat.z;
dist=VECTORLENGTH(ray.vector.x,
ray.vector.y,ray.vector.z);
ray.vector.x/=dist;
ray.vector.y/=dist;
ray.vector.z/=dist;
LPoint3 result;
result.x=OldPoint.x+(NewWin.x-OldWin.x)*3.0;
result.y=OldPoint.y+(OldWin.y-NewWin.y)*3.0;
result.z=OldPoint.z+(OldWin.z-NewWin.z)*3.0;
return result;
};
void GetTrackballAngle(CPoint oldpos, CPoint newpos) {
GLfloat r2=4;
LineF_t ray0, ray1;
SphereF_t sp;
GLfloat r=r2;
LPoint3 p0,p1;
oldpos.y=oldrect.right-oldpos.y;
newpos.y=oldrect.right-newpos.y;
LPoint3 t=WindowToObject(oldpos);
float enx,eny,enz,em=VECTORLENGTH(Leye.x,Leye.y,Leye.z);
enx=Leye.x/em;
eny=Leye.y/em;
enz=Leye.z/em;
ray0.point.x=t.x; ray0.point.y=t.y; ray0.point.z=t.z;
ray0.vector.x=-enx; ray0.vector.y=-eny; ray0.vector.z=-enz;
t=WindowToObject(newpos);
ray1.point.x=t.x; ray1.point.y=t.y; ray1.point.z=t.z;
ray1.vector.x=-enx; ray1.vector.y=-eny; ray1.vector.z=-enz;
sp.center.x=0; sp.center.y=0; sp.center.z=0;
sp.r=r;
p0=GetSphereIntersection(ray0,sp);
if(p0.x==-999999) return;
p1=GetSphereIntersection(ray1,sp);
if(p1.x==-999999) return;
GLfloat m2=VECTORLENGTH(p1.x,p1.y,p1.z);
if(p0.x==-999999) {
trackballangle=0;
return;
};
if(p1.x==-999999) {
trackballangle=0;
return;
};
LPoint3 V0,V1;
GLfloat m=VECTORLENGTH(
p0.x-sp.center.x,
p0.y-sp.center.y,
p0.z-sp.center.z);
V0.x=(p0.x-sp.center.x)/m;
V0.y=(p0.y-sp.center.y)/m;
V0.z=(p0.z-sp.center.z)/m;
m=VECTORLENGTH(p1.x-sp.center.x,
p1.y-sp.center.y,
p1.z-sp.center.z);
V1.x=(p1.x-sp.center.x)/m;
V1.y=(p1.y-sp.center.y)/m;
V1.z=(p1.z-sp.center.z)/m;
LPoint3 A;
A.x=V0.y*V1.z-V0.z*V1.y;
A.y=V0.z*V1.x-V0.x*V1.z;
A.z=V0.x*V1.y-V0.y*V1.x;
float alpha=asin(VECTORLENGTH(A.x,A.y,A.z));
float test=V0.x*V1.x+V0.y*V1.y+V0.z*V1.z;
if(test<0) {
alpha+=3.141592654/(float)2.0;
};
trackballaxis.x=A.x;
trackballaxis.y=A.y;
trackballaxis.z=A.z;
trackballangle=(alpha*r*10)/(fov/180.0);
int i;
glPushMatrix();
glLoadIdentity();
glLoadMatrixd(starttrackballMatrix);
glRotatef(trackballangle,trackballaxis.x,
trackballaxis.y,trackballaxis.z);
glGetDoublev(GL_MODELVIEW_MATRIX,trackballMatrix);
glPopMatrix();
float ex=trackballMatrix[0]*Leye.x
+trackballMatrix[1]*Leye.y
+trackballMatrix[2]*Leye.z
+trackballMatrix[3];
float ey=trackballMatrix[4]*Leye.x
+trackballMatrix[5]*Leye.y
+trackballMatrix[6]*Leye.z
+trackballMatrix[7];
float ez=trackballMatrix[8]*Leye.x
+trackballMatrix[9]*Leye.y
+trackballMatrix[10]*Leye.z
+trackballMatrix[11];
Leye.x=ex; Leye.y=ey; Leye.z=ez;
ex=trackballMatrix[0]*Lup.x
+trackballMatrix[1]*Lup.y
+trackballMatrix[2]*Lup.z
+trackballMatrix[3];
ey=trackballMatrix[4]*Lup.x
+trackballMatrix[5]*Lup.y
+trackballMatrix[6]*Lup.z
+trackballMatrix[7];
ez=trackballMatrix[8]*Lup.x
+trackballMatrix[9]*Lup.y
+trackballMatrix[10]*Lup.z
+trackballMatrix[11];
Lup.x=ex; Lup.y=ey; Lup.z=ez;
glPushMatrix();
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX,trackballMatrix);
glPopMatrix();
};
void RotateAgain() {
glPushMatrix();
glLoadIdentity();
glLoadMatrixd(starttrackballMatrix);
glRotatef(trackballangle,trackballaxis.x,
trackballaxis.y,trackballaxis.z);
glGetDoublev(GL_MODELVIEW_MATRIX,trackballMatrix);
glPopMatrix();
float ex=trackballMatrix[0]*Leye.x
+trackballMatrix[1]*Leye.y
+trackballMatrix[2]*Leye.z
+trackballMatrix[3];
float ey=trackballMatrix[4]*Leye.x
+trackballMatrix[5]*Leye.y
+trackballMatrix[6]*Leye.z
+trackballMatrix[7];
float ez=trackballMatrix[8]*Leye.x
+trackballMatrix[9]*Leye.y
+trackballMatrix[10]*Leye.z
+trackballMatrix[11];
Leye.x=ex; Leye.y=ey; Leye.z=ez;
ex=trackballMatrix[0]*Lup.x
+trackballMatrix[1]*Lup.y
+trackballMatrix[2]*Lup.z
+trackballMatrix[3];
ey=trackballMatrix[4]*Lup.x
+trackballMatrix[5]*Lup.y
+trackballMatrix[6]*Lup.z
+trackballMatrix[7];
ez=trackballMatrix[8]*Lup.x
+trackballMatrix[9]*Lup.y
+trackballMatrix[10]*Lup.z
+trackballMatrix[11];
Lup.x=ex; Lup.y=ey; Lup.z=ez;
glPushMatrix();
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX,trackballMatrix);
glPopMatrix();
Rotating=TRUE;
};
void Play() {
OnAnimPlay();
};
The following functions are primarily MFC-derived event function declarations and
provide overloaded behavior for the COpenGLView object:
// Operations
public:
// Overrides
//{{AFX_VIRTUAL(COpenGLView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID,
CCreateContext* pContext = NULL);
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD
dwKeyState, CPoint point);
virtual void OnDragLeave();
virtual BOOL IsSelected(const CObject* pDocItem) const;
virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD
dwKeyState, CPoint point);
virtual void OnFinalRelease();
virtual void OnInitialUpdate();
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM
lParam, LRESULT* pLResult);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType
= adjustBorder);
virtual void OnActivateView(BOOL bActivate, CView* pActivateView,
CView* pDeactiveView);
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject*
pHint);
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM
lParam);
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
virtual void DoDataExchange(CDataExchange* pDX);
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM
lParam);
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT*
pResult);
//}}AFX_VIRTUAL
The following functions are the implementation members of the COpenGLView
object. Note the preprocessor definitions for debugging. These members are only included
if the Visual C++ compiler is in debug mode.
// Implementation
public:
virtual ~COpenGLView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
The next section is the message map section from the application frameworks. All of the
functions in this section respond to windows or MFC-based application events.
protected:
//{{AFX_MSG(COpenGLView)
afx_msg void OnCancelEditSrvr();
afx_msg void OnOptionsModelerSettings();
afx_msg void OnZoom();
afx_msg void OnNodeSelect();
afx_msg void OnSelect();
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnMove(int x, int y);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnParticle();
afx_msg void OnSpace();
afx_msg void OnRotate();
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest,
UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnEditCut();
afx_msg void OnUpdateEditCut(CCmdUI* pCmdUI);
afx_msg void OnAddblob();
afx_msg void OnAddfield();
afx_msg void OnUpdateAddblob(CCmdUI* pCmdUI);
afx_msg void OnUpdateAddfield(CCmdUI* pCmdUI);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnCluster();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnCamerasettings();
afx_msg void OnImportascii();
afx_msg void OnCenter();
afx_msg void OnAnimatorsettings();
afx_msg void OnSimulatoroptions();
afx_msg void OnObjectview();
afx_msg void OnAnimEnd();
afx_msg void OnAnimFront();
afx_msg void OnAnimNext();
afx_msg void OnAnimPlay();
afx_msg void OnAnimPrevious();
afx_msg void OnAnimStop();
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnDataadjust();
afx_msg void OnImporthin();
afx_msg void OnTCard(UINT idAction, DWORD dwActionData);
afx_msg void OnImportsim();
afx_msg void OnFullscreen();
afx_msg void OnPmodelStar();
afx_msg void OnPmodelSphere();
afx_msg void OnPmodelPoint();
afx_msg void OnPmodelFastquality();
afx_msg void OnPmodelLighting();
afx_msg void OnPmodelTransparency();
afx_msg void OnPmodelWireframe();
afx_msg void OnPmodelSplines();
afx_msg void OnPmodelSurface();
afx_msg void OnPmodelSlow();
afx_msg void OnPmodelAntialias();
afx_msg void OnParallel();
afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
afx_msg void OnUpdatePmodelAntialias(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelTransparency(CCmdUI* pCmdUI);
afx_msg void OnUpdateAnimPlay(CCmdUI* pCmdUI);
afx_msg void OnUpdateRotate(CCmdUI* pCmdUI);
afx_msg void OnUpdateZoom(CCmdUI* pCmdUI);
afx_msg void OnUpdateNodeSelect(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelWireframe(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelSplines(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelSphere(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelStar(CCmdUI* pCmdUI);
afx_msg void OnUpdatePmodelPoint(CCmdUI* pCmdUI);
afx_msg void OnUpdateTranslate(CCmdUI* pCmdUI);
afx_msg void OnTranslate();
afx_msg void OnUpdateCenter(CCmdUI* pCmdUI);
afx_msg void OnEditCopy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
The following function definition for the GetDocument() member is the inline
version for use in release builds.
#ifndef _DEBUG // debug version in COpenGLView.cpp
inline COpenGLDoc* COpenGLView::GetDocument()
{ return (COpenGLDoc*)m_pDocument; }
#endif
G.3.1 COpenGLView Member Functions
The following functions are implementations of members that were
declared in the COpenGLView object definition. Different functions
call different dialog box members. These dialog boxes are used for
enabling and disabling parameters. In general, these dialog box
members can be set up in whatever manner needed in user applications.
#include "stdafx.h"
#include "OpenGL Space.h"
#include "OpenGL SpaceDoc.h"
#include "COpenGLView.h"
#include "ModelerSettingsDlg.h"
#include "CameraSettingsDlg.h"
#include "AnimatorSettingsDlg.h"
#include "SimulatorSettingsDlg.h"
#include "SpaceSettingsDlg.h"
#include "ParticleSettingsDlg.h"
#include "ClustersDlg.h"
#include "ASCIIImportDlg.h"
#include "ObjectViewDlg.h"
#include "DataAdjustertDlg.h"
#include "ParallelDialogue.h"
#include "objects.h"
#include <fstream.h>
#include "resource.h"
We will use the debug version of the new C++ operator. The debug
version tracks and locates memory leaks and missed deallocations. The
THIS_FILE member specifies a string that is the name of the current
file being compiled. This string can be used in debug strings to point
to the module that caused the problem.
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
The next section declares all of the message map functions for the different OpenGL
command handlers. The Visual C++ ClassWizard inserts and removes these functions. For the
most part, user modification of the components is not recommended.
// COpenGLView Implementation
IMPLEMENT_DYNCREATE(COpenGLView, CView)
BEGIN_MESSAGE_MAP(COpenGLView, CView)
ON_WM_CONTEXTMENU()
//{{AFX_MSG_MAP(COpenGLView)
ON_COMMAND(ID_CANCEL_EDIT_SRVR, OnCancelEditSrvr)
ON_COMMAND(ID_OPTIONS_MODELERSETTINGS, OnOptionsModelerSettings)
ON_COMMAND(ID_ZOOM, OnZoom)
ON_COMMAND(ID_NODE_SELECT, OnNodeSelect)
ON_COMMAND(ID_SELECT, OnSelect)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_MOVE()
ON_WM_SIZE()
ON_COMMAND(ID_PARTICLE, OnParticle)
ON_COMMAND(ID_SPACE, OnSpace)
ON_COMMAND(ID_ROTATE, OnRotate)
ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDBLCLK()
ON_WM_SETFOCUS()
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
ON_COMMAND(ID_ADDBLOB, OnAddblob)
ON_COMMAND(ID_ADDFIELD, OnAddfield)
ON_UPDATE_COMMAND_UI(ID_ADDBLOB, OnUpdateAddblob)
ON_UPDATE_COMMAND_UI(ID_ADDFIELD, OnUpdateAddfield)
ON_WM_TIMER()
ON_COMMAND(ID_CLUSTER, OnCluster)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_COMMAND(ID_CAMERASETTINGS, OnCamerasettings)
ON_COMMAND(ID_IMPORTASCII, OnImportascii)
ON_COMMAND(ID_CENTER, OnCenter)
ON_COMMAND(ID_ANIMATORSETTINGS, OnAnimatorsettings)
ON_COMMAND(ID_SIMULATOROPTIONS, OnSimulatoroptions)
ON_COMMAND(ID_OBJECTVIEW, OnObjectview)
ON_COMMAND(ID_ANIM_END, OnAnimEnd)
ON_COMMAND(ID_ANIM_FRONT, OnAnimFront)
ON_COMMAND(ID_ANIM_NEXT, OnAnimNext)
ON_COMMAND(ID_ANIM_PLAY, OnAnimPlay)
ON_COMMAND(ID_ANIM_PREVIOUS, OnAnimPrevious)
ON_COMMAND(ID_ANIM_STOP, OnAnimStop)
ON_WM_KILLFOCUS()
ON_COMMAND(ID_DATAADJUST, OnDataadjust)
ON_COMMAND(ID_IMPORTHIN, OnImporthin)
ON_WM_TCARD()
ON_COMMAND(ID_IMPORTSIM, OnImportsim)
ON_COMMAND(ID_FULLSCREEN, OnFullscreen)
ON_COMMAND(ID_PMODEL_STAR, OnPmodelStar)
ON_COMMAND(ID_PMODEL_SPHERE, OnPmodelSphere)
ON_COMMAND(ID_PMODEL_POINT, OnPmodelPoint)
ON_COMMAND(ID_PMODEL_FASTQUALITY, OnPmodelFastquality)
ON_COMMAND(ID_PMODEL_LIGHTING, OnPmodelLighting)
ON_COMMAND(ID_PMODEL_TRANSPARENCY, OnPmodelTransparency)
ON_COMMAND(ID_PMODEL_WIREFRAME, OnPmodelWireframe)
ON_COMMAND(ID_PMODEL_SPLINES, OnPmodelSplines)
ON_COMMAND(ID_PMODEL_SURFACE, OnPmodelSurface)
ON_COMMAND(ID_PMODEL_SLOW, OnPmodelSlow)
ON_COMMAND(ID_PMODEL_ANTIALIAS, OnPmodelAntialias)
ON_COMMAND(ID_PARALLEL, OnParallel)
ON_WM_SHOWWINDOW()
ON_UPDATE_COMMAND_UI(ID_PMODEL_ANTIALIAS,
OnUpdatePmodelAntialias)
ON_UPDATE_COMMAND_UI(ID_PMODEL_TRANSPARENCY,
OnUpdatePmodelTransparency)
ON_UPDATE_COMMAND_UI(ID_ANIM_PLAY, OnUpdateAnimPlay)
ON_UPDATE_COMMAND_UI(ID_ROTATE, OnUpdateRotate)
ON_UPDATE_COMMAND_UI(ID_ZOOM, OnUpdateZoom)
ON_UPDATE_COMMAND_UI(ID_NODE_SELECT, OnUpdateNodeSelect)
ON_UPDATE_COMMAND_UI(ID_PMODEL_WIREFRAME,
OnUpdatePmodelWireframe)
ON_UPDATE_COMMAND_UI(ID_PMODEL_SPLINES, OnUpdatePmodelSplines)
ON_UPDATE_COMMAND_UI(ID_PMODEL_SPHERE, OnUpdatePmodelSphere)
ON_UPDATE_COMMAND_UI(ID_PMODEL_STAR, OnUpdatePmodelStar)
ON_UPDATE_COMMAND_UI(ID_PMODEL_POINT, OnUpdatePmodelPoint)
ON_UPDATE_COMMAND_UI(ID_TRANSLATE, OnUpdateTranslate)
ON_COMMAND(ID_TRANSLATE, OnTranslate)
ON_UPDATE_COMMAND_UI(ID_CENTER, OnUpdateCenter)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
As mentioned before, we use a global member to declare the currently selected tool. All
views should have the selected tool working in the same manner. When the tool changes, it
should change for all views. Using a global member value accommodates this. Also note the IsIdleLocked
member. Screen redraws should be done when the system is not doing other tasks. We use the
IsIdleLocked member to accomplish this in combination with the global NumViews
member.
// COpenGLView construction/destruction
OpenGLTool SelectedTool;
int NumViews=0;
BOOL IsIdleLocked=FALSE;
The COpenGLView constructor initializes all of the member variables
to default start up values.
COpenGLView::COpenGLView()
{
DepthScale=1;
CanPaint=TRUE;
SelectedTool=Zoom;
CubeSize=.37;
spinmode=0;
down=0;
rdown=0;
Tetrahedral=FALSE;
Wireframe=FALSE;
Shading=TRUE;
ZBuffer=TRUE;
AntiAlias=FALSE;
Backface=TRUE;
AutoField=TRUE;
WorkingField=NULL;
objwin=NULL;
Rotating=FALSE;
IsPlaying=FALSE;
LightModel=0;
IsIdleLocked=FALSE;
ghPalette = (HPALETTE) 0;
Leye.x=0; Leye.y=0; Leye.z=4;
Lcenter.x=0; Lcenter.y=0; Lcenter.z=0;
Lup.x=0; Lup.y=1; Lup.z=0;
fov=45; aspect=1; near_plane=1; far_plane=1000;
trackballangle=0; trackballaxis.x=1;
trackballaxis.y=0; trackballaxis.z=0;
PIXELFORMATDESCRIPTOR pfq = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24 bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32 bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
pfd=pfq;
IsFullScreen=FALSE;
IsWireframe=FALSE;
IsSplines=FALSE;
IsLighting=TRUE;
IsTransparent=FALSE;
IsFollow=TRUE;
ModelType=0;
NumViews++;
TimerValue=1;
KillPlay=FALSE;
}
The destructor object checks to see if there is a property window open. If so, it makes
sure that it has been destroyed. It also decrements the number of views.
COpenGLView::~COpenGLView()
{
if(objwin!=NULL) {
objwin->DestroyWindow();
delete objwin;
};
NumViews;
}
The AssertValid(), Dump(), and GetDocument() members are
defined for debugging builds of the application. They are not included when the system is
creating a release build.
#ifdef _DEBUG
void COpenGLView::AssertValid() const
{
CView::AssertValid();
}
void COpenGLView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
COpenGLDoc* COpenGLView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COpenGLDoc)));
return (COpenGLDoc*)m_pDocument;
}
#endif //_DEBUG
Following are some example command handlers, such as OnOptionsModelerSettings(),
for command notifications for parameter changes. These command event handlers typically
just create a dialog box and swap the necessary parameters in and out of the view via the
dialog box.
void COpenGLView::OnOptionsModelerSettings()
{
CModelerSettingsDlg dlg;
static int ModelerType=0,Number=20,Fast=0;
static BOOL LightPrim=FALSE;
dlg.m_Center=ModelerType;
dlg.m_Spline=IsSplines;
dlg.m_DetailAmount=CubeSize;
dlg.m_AntiAlias=AntiAlias;
dlg.m_FineDetail=Tetrahedral;
dlg.m_InnerShade=IsLighting;
dlg.m_Wireframe=Wireframe;
dlg.m_LightPrim=LightPrim;
dlg.m_Backface=Backface;
dlg.m_TrackField=AutoField;
dlg.m_Number=Number;
dlg.m_Fast=Fast;
dlg.m_Alpha=IsTransparent;
if(dlg.DoModal()==IDOK) {
AntiAlias=dlg.m_AntiAlias;
IsLighting=dlg.m_InnerShade;
Wireframe=dlg.m_Wireframe;
ModelerType=dlg.m_Center;
IsTransparent=dlg.m_Alpha;
AutoField=dlg.m_TrackField;
if(Wireframe)
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
Fast=dlg.m_Fast;
Backface=dlg.m_Backface;
IsSplines=dlg.m_Spline;
LightPrim=dlg.m_LightPrim;
if(Backface)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
if(IsLighting)
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
if(IsTransparent) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
}
else {
glDisable(GL_BLEND);
};
if(AntiAlias) {
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_POLYGON_SMOOTH);
}
else {
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POINT_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);
};
if(Fast) {
glHint(GL_FOG_HINT,GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
}
else {
glHint(GL_FOG_HINT,GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
};
if( (Tetrahedral!=dlg.m_FineDetail) |
(Number!=dlg.m_Number) |
(CubeSize!=dlg.m_DetailAmount))
Tessellate();
Tetrahedral=dlg.m_FineDetail;
Number=dlg.m_Number;
CubeSize=dlg.m_DetailAmount;
Invalidate(FALSE);
};
}
void COpenGLView::OnParticle()
{
CParticleSettingsDlg dlg;
static BOOL DF=FALSE, Sphe=FALSE, Star=TRUE;
static int ModelType=0;
dlg.m_Slices=p_slices;
dlg.m_Stacks=p_stacks;
dlg.m_ModelType=ModelType;
dlg.m_Transparency=p_transparency;
if(dlg.DoModal()==IDOK) {
switch(dlg.m_ModelType) {
case(0): // Point selected
break;
case(1): // Star Selected
break;
case(2): // Sphere Selected
break;
case(3): // Density Selected
break;
};
p_stacks=dlg.m_Stacks;
p_slices=dlg.m_Slices;
p_transparency=dlg.m_Transparency;
ModelType=dlg.m_ModelType;
objectdata->ForceFullRebuild();
Tessellate();
Invalidate(FALSE);
};
}
void COpenGLView::OnSpace()
{
CSpaceSettingsDlg dlg;
dlg.m_Accuracy=0;
dlg.m_Newton=0;
dlg.m_Normal=0;
if(dlg.DoModal()==IDOK) {
};
}
void COpenGLView::OnCluster()
{
CClustersDlg dlg;
static int BF=0;
static BOOL Connect=FALSE, EveryChange=FALSE, EndToEnd=FALSE;
static int line=0;
dlg.m_BruteForce=BF;
dlg.m_EveryChange=EveryChange;
dlg.m_Line=line;
dlg.m_EndToEnd=EndToEnd;
if(dlg.DoModal()==IDOK) {
BF=dlg.m_BruteForce;
line=dlg.m_Line;
EndToEnd=dlg.m_EndToEnd;
EveryChange=dlg.m_EveryChange;
objectdata->ForceFullRebuild();
Tessellate();
Invalidate(FALSE);
};
}
void COpenGLView::OnCamerasettings()
{
CCameraSettingsDlg dlg;
static int BF=0;
static BOOL Connect=FALSE, EveryChange=FALSE;
dlg.m_Follow=IsFollow;
dlg.m_ZoomScale=DepthScale;
dlg.m_Aspect=aspect;
dlg.m_CenterX=Lcenter.x;
dlg.m_CenterY=Lcenter.y;
dlg.m_CenterZ=Lcenter.z;
dlg.m_EyeX=Leye.x; dlg.m_EyeY=Leye.y; dlg.m_EyeZ=Leye.z;
dlg.m_UpX=Lup.x; dlg.m_UpY=Lup.y; dlg.m_UpZ=Lup.z;
dlg.m_FOV=fov;
dlg.m_ZFar=far_plane;
dlg.m_ZNear=near_plane;
if(dlg.DoModal()==IDOK) {
aspect=dlg.m_Aspect;
Lcenter.x=dlg.m_CenterX;
Lcenter.y=dlg.m_CenterY;
Lcenter.z=dlg.m_CenterZ;
Leye.x=dlg.m_EyeX;
Leye.y=dlg.m_EyeY;
Leye.z=dlg.m_EyeZ;
fov=dlg.m_FOV;
Lup.x=dlg.m_UpX;
Lup.y=dlg.m_UpY;
Lup.z=dlg.m_UpZ;
far_plane=dlg.m_ZFar;
near_plane=dlg.m_ZNear;
DepthScale=dlg.m_ZoomScale;
IsFollow=dlg.m_Follow;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
aspect=1;
gluPerspective( fov, aspect, near_plane, far_plane );
aspect = (GLfloat) oldrect.right / oldrect.bottom;
glMatrixMode( GL_MODELVIEW );
Invalidate(FALSE);
};
}
void COpenGLView::OnAnimatorsettings()
{
CAnimatorSettingsDlg dlg;
static float step=0.10;
dlg.m_TrailLength=ParticleTrails;
if(ParticleTrails==0)
dlg.m_EnableTrails=FALSE;
else
dlg.m_EnableTrails=TRUE;
dlg.m_Type=3;
dlg.m_Step=step;
if(dlg.DoModal()==IDOK) {
objectdata->SetStep(dlg.m_Step);
step=dlg.m_Step;
ParticleTrails=dlg.m_TrailLength;
if(!dlg.m_EnableTrails) ParticleTrails=0;
};
}
void COpenGLView::OnSimulatoroptions()
{
CSimulatorSettingsDlg dlg;
if(dlg.DoModal()==IDOK) {
};
}
void COpenGLView::OnDataadjust()
{
CDataAdjustertDlg dlg;
static BOOL justr=FALSE;
dlg.m_JustR=justr;
float dist=objectdata->GetMostDistant();
if(dist!=0)
dlg.m_Scale=2/dist;
else
dlg.m_Scale=1;
if(dlg.DoModal()==IDOK) {
objectdata->ScaleNumbers(dlg.m_Scale,dlg.m_JustR);
justr=dlg.m_JustR;
Center();
Invalidate(FALSE);
};
}
void COpenGLView::OnParallel()
{
CParallelDialogue dlg;
static int NumberSwitch=0;
dlg.m_NumCPUS=NumberSwitch;
if(dlg.DoModal()==IDOK) {
NumberSwitch=dlg.m_NumCPUS;
NumberCPUS=(int) pow(2,NumberSwitch);
NumberCPUS;
};
}
The next series of functions provides command members for selection and view updates
for the various tools available in the 3D viewing model. These functions disable the
mouse's "left button down" and any of the other mouse status switches that need
to be toggled.
void COpenGLView::OnZoom()
{
down=0;
spinmode=0;
rdown=0;
SelectedTool=Zoom;
}
void COpenGLView::OnUpdateZoom(CCmdUI* pCmdUI)
{
if(SelectedTool==Zoom)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnNodeSelect()
{
down=0;
spinmode=0;
rdown=0;
SelectedTool=NodeSelect;
}
void COpenGLView::OnUpdateNodeSelect(CCmdUI* pCmdUI)
{
if(SelectedTool==NodeSelect)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdateNodeSelect(CCmdUI* pCmdUI)
{
if(SelectedTool==NodeSelect)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnSelect()
{
down=0;
spinmode=0;
rdown=0;
SelectedTool=Select;
}
void COpenGLView::OnRotate()
{
down=0;
spinmode=0;
rdown=0;
SelectedTool=Rotate;
}
void COpenGLView::OnUpdateRotate(CCmdUI* pCmdUI)
{
if(SelectedTool==Rotate)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnTranslate()
{
SelectedTool=Translate;
}
void COpenGLView::OnUpdateTranslate(CCmdUI* pCmdUI)
{
if(SelectedTool==Translate)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
The next set of functions are notifications for various menu and toolbar commands that
can be transmitted.
void COpenGLView::OnPmodelStar()
{
ModelType=1;
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelSphere()
{
ModelType=2;
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelPoint()
{
ModelType=0;
objectdata->NotifyParameter(Lmsg_Points,TRUE);
objectdata->NotifyParameter(Lmsg_Stars,FALSE);
objectdata->NotifyParameter(Lmsg_Spheres,FALSE);
objectdata->NotifyParameter(Lmsg_Density,FALSE);
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelFastquality()
{
glHint(GL_FOG_HINT,GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
switch(p_stacks) {
case(3): p_stacks=2.0; p_slices=2.0; break;
case(4): p_stacks=3.0; p_slices=3.0; break;
case(6): p_stacks=4.0; p_slices=4.0; break;
case(8): p_stacks=6.0; p_slices=6.0; break;
case(10): p_stacks=8.0; p_slices=8.0; break;
case(15): p_stacks=10.0; p_slices=10.0; break;
case(20): p_stacks=15.0; p_slices=15.0; break;
case(30): p_stacks=20.0; p_slices=20.0; break;
default: p_stacks-=1.0; p_slices-=1.0; break;
};
if(p_stacks<2) p_stacks=2;
if(p_slices<2) p_slices=2;
if(p_stacks>100) p_stacks=100;
if(p_slices>100) p_slices=100;
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelLighting()
{
LightModel++;
if(LightModel>5) LightModel=0;
switch(LightModel) {
case(0): glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glDisable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
break;
case(1): glEnable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glDisable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
break;
case(2): glEnable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glEnable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glDisable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
break;
case(3): glDisable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glEnable(GL_LIGHT3);
glDisable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
break;
case(4): glDisable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDisable(GL_LIGHT2);
glDisable(GL_LIGHT3);
glEnable(GL_LIGHT4);
glDisable(GL_LIGHT5);
glDisable(GL_LIGHT6);
break;
case(5): glDisable(GL_LIGHTING);
break;
};
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelTransparency()
{
if(!IsTransparent) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
IsTransparent=TRUE;
}
else {
glDisable(GL_BLEND);
IsTransparent=FALSE;
};
objectdata->SetTransparent(IsTransparent);
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelWireframe()
{
if(!IsWireframe) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
IsWireframe=TRUE;
}
else {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
IsWireframe=FALSE;
};
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelSplines()
{
if(IsSplines) {
IsSplines=FALSE;
}
else {
objectdata->NotifyParameter(Lmsg_DrawSplinePath,TRUE);
IsSplines=TRUE;
};
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelSlow()
{
glHint(GL_FOG_HINT,GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
switch(p_stacks) {
case(2): p_stacks=3.0; p_slices=3.0; break;
case(3): p_stacks=4.0; p_slices=4.0; break;
case(4): p_stacks=6.0; p_slices=6.0; break;
case(6): p_stacks=8.0; p_slices=8.0; break;
case(8): p_stacks=10.0; p_slices=10.0; break;
case(10): p_stacks=15.0; p_slices=15.0; break;
case(15): p_stacks=20.0; p_slices=20.0; break;
case(20): p_stacks=30.0; p_slices=30.0; break;
default: p_stacks+=1.0; p_slices+=1.0; break;
};
if(p_stacks<2) p_stacks=2;
if(p_slices<2) p_slices=2;
if(p_stacks>100) p_stacks=100;
if(p_slices>100) p_slices=100;
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnPmodelAntialias()
{
if(!AntiAlias) {
if(!IsTransparent)
OnPmodelTransparency();
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
AntiAlias=TRUE;
}
else {
glDisable(GL_POINT_SMOOTH);
glDisable(GL_LINE_SMOOTH);
AntiAlias=FALSE;
};
IsIdleLocked=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnCenter()
{
if(IsFollow)
IsFollow=FALSE;
else
IsFollow=TRUE;
Center();
}
void COpenGLView::OnObjectview()
{
if(objwin==NULL) {
objwin=new CObjectViewDlg(this);
objwin->Create(IDD_OBJECTVIEW,this);
objwin->ShowWindow(SW_SHOWNORMAL);
}
else {
objwin->BringWindowToTop();
};
}
void COpenGLView::OnAnimEnd()
{
IsPlaying=FALSE;
objectdata->Frame_Last();
Invalidate(FALSE);
}
void COpenGLView::OnAnimFront()
{
IsPlaying=FALSE;
objectdata->Frame_First();
Invalidate(FALSE);
}
void COpenGLView::OnAnimNext()
{
IsPlaying=FALSE;
objectdata->Frame_Next();
Invalidate(FALSE);
}
void COpenGLView::OnAnimPlay()
{
IsPlaying=TRUE;
Invalidate(FALSE);
}
void COpenGLView::OnAnimPrevious()
{
IsPlaying=FALSE;
objectdata->Frame_Prev();
Invalidate(FALSE);
}
void COpenGLView::OnAnimStop()
{
IsPlaying=FALSE;
}
void COpenGLView::StopAnimation()
{
OnAnimStop();
IsPlaying=FALSE;
}
The following functions are command enablers which toggle whether a button is checked,
or depressed, for the various toolbars and options:
void COpenGLView::OnUpdatePmodelAntialias(CCmdUI* pCmdUI)
{
if(AntiAlias)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdateCenter(CCmdUI* pCmdUI)
{
if(IsFollow)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelTransparency(CCmdUI* pCmdUI)
{
if(IsTransparent)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdateAnimPlay(CCmdUI* pCmdUI)
{
if(IsPlaying)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelWireframe(CCmdUI* pCmdUI)
{
if(IsWireframe)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelSplines(CCmdUI* pCmdUI)
{
if(IsSplines)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelSphere(CCmdUI* pCmdUI)
{
if(ModelType==2)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelStar(CCmdUI* pCmdUI)
{
if(ModelType==1)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
void COpenGLView::OnUpdatePmodelPoint(CCmdUI* pCmdUI)
{
if(ModelType==0)
pCmdUI->SetCheck(1);
else
pCmdUI->SetCheck(0);
}
The following collection of functions implements the example drawing function setup for
the renderer. The wglMakeCurrent() function is called because the application is
an MDI (multiple document interface) application. By selecting the current rendering
thread on redraws, this makes all of the views render well independently.
void COpenGLView::DrawModel(RECT &l)
{
hDC=THISCWND->GetDC()->GetSafeHdc();;
wglMakeCurrent(hDC, hrc );
LPoint3 eyedir;
LPoint3 Leyesave;
Leyesave.x=Leye.x; Leyesave.y=Leye.y; Leyesave.z=Leye.z;
LPoint3 adjcenter;
if(IsFollow) {
LPoint3 r=objectdata->GetCenter();
Lcenter.x=-r.x; Lcenter.y=-r.y; Lcenter.z=-r.z;
};
adjcenter.x=(Lcenter.x-(Leye.x*DepthScale*DepthScale))+Leye.x;
adjcenter.y=(Lcenter.y-(Leye.y*DepthScale*DepthScale))+Leye.y;
adjcenter.z=(Lcenter.z-(Leye.z*DepthScale*DepthScale))+Leye.z;
glLoadIdentity();
glViewport(0, 0, oldrect.right, oldrect.bottom);
gluLookAt(Leye.x,Leye.y,Leye.z,0,0,0,Lup.x,Lup.y,Lup.z );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glMultMatrixd(trackballMatrix);
if(DepthScale<1)
glScaled(.3/DepthScale,.3/DepthScale,.3/DepthScale);
else
glScaled(.3,.3,.3);
glTranslatef(adjcenter.x, adjcenter.y, adjcenter.z);
objectdata->DumpFilled();
glPopMatrix();
glFinish();
Leye.x=Leyesave.x; Leye.y=Leyesave.y; Leye.z=Leyesave.z;
SwapBuffers(hDC);
}
The OnPaint() member is called whenever the system requests a model repaint.
Some repaints are delayed if the system has not entered an idle situation
recently--meaning there is a lot of activity going on. Additionally, there is a KillPlay
switch that is called when the system needs to stop all timed rendering.
void COpenGLView::OnPaint()
{
CPaintDC dc(this);
KillTimer(6);
if(IsIdleLocked) {
SetTimer(6,500,NULL);
ValidateRect(&dc.m_ps.rcPaint);
return;
};
if(KillPlay) {
KillPlay=FALSE;
SetTimer(6,2000,NULL);
ValidateRect(&dc.m_ps.rcPaint);
return;
};
DrawModel(dc.m_ps.rcPaint);
ValidateRect(&dc.m_ps.rcPaint);
if(!CanPaint)
return;
if(Rotating|IsPlaying) {
if(Rotating)
RotateAgain();
if(IsPlaying) {
objectdata->Frame_Play();
pane_time=objectdata->GetCurrentTime();
};
if(OnToolBar) {
OnToolBar=FALSE;
SetTimer(6,10,NULL);
return;
};
Invalidate(FALSE);
};
}
OLE drag and drop support is implemented by applying calls to the OnDragEnter()
and OnDragLeave() member functions. The object does not make use of OLE. We
simply make sure the system is not updating or animating via mouse clicks. If OLE were to
be implemented, you would implement it here.
DROPEFFECT COpenGLView::OnDragEnter(COleDataObject* pDataObject,
DWORD dwKeyState, CPoint point)
{
rdown=0;
down=0;
return CView::OnDragEnter(pDataObject, dwKeyState, point);
}
void COpenGLView::OnDragLeave()
{
rdown=0;
down=0;
CView::OnDragLeave();
hDC=GetDC()->GetSafeHdc();
}
The CalcWindowRect() function is used to determine the size of a window. The
default behavior in this case works well so we leave it as is. The OnSize()
function also provides sizing behavior by telling OpenGL what size the window should be
set to, and setting flags regarding the current rendering size and state.
void COpenGLView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
CView::CalcWindowRect(lpClientRect, nAdjustType);
}
void COpenGLView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
RECT rect;
IsIdleLocked=TRUE;
GetClientRect(&rect);
glViewport(0, 0, rect.right, rect.bottom);
if((oldrect.right != rect.right) ||
(oldrect.bottom != rect.bottom))
Invalidate(TRUE);
oldrect.right = rect.right;
oldrect.bottom = rect.bottom;
hDC=GetDC()->GetSafeHdc();
}
void COpenGLView::OnShowWindow(BOOL bShow, UINT nStatus)
{
CView::OnShowWindow(bShow, nStatus);
IsIdleLocked=TRUE;
}
We also want to know when children are moved so we use the OnChildNotify()
handler to catch WM_SIZE messages. The OnCommand() handler allows us to catch
menu or toolbar events which are also sent. For both of these operations, we use our
delayed repaint.
BOOL COpenGLView::OnChildNotify(UINT message, WPARAM wParam, LPARAM
lParam, LRESULT* pLResult)
{
switch(message) {
case(WM_MOVE): IsIdleLocked=TRUE; break;
default: break;
};
return CView::OnChildNotify(message, wParam, lParam, pLResult);
}
BOOL COpenGLView::OnCommand(WPARAM wParam, LPARAM lParam)
{
IsIdleLocked=TRUE;
return CView::OnCommand(wParam, lParam);
}
The NeedViewClose() command handler is called when the object view needs to be
closed, so we add a handler that destroys the object view window and cleans up.
void COpenGLView::NeedViewClose() {
objwin->DestroyWindow();
delete objwin;
objwin=NULL;
}
OnActivateView() is called whenever the current view is selected or activated.
This command handler enables rendering in the window and sets the necessary switches so
that invalidates behave correctly and quickly when the window is activated. OnSetFocus()
replicates the necessary parts of this behavior when the window is given the focus. The
same is true for the function OnKillFocus() which kills the rendering of an
animation in the window.
void COpenGLView::OnActivateView(BOOL bActivate, CView* pActivateView,
CView* pDeactiveView)
{
if(bActivate) {
CanPaint=TRUE;
TimerValue=1;
KillPlay=FALSE;
Invalidate(FALSE);
}
else {
CanPaint=FALSE;
TimerValue=2000;
};
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
hDC=GetDC()->GetSafeHdc();
}
void COpenGLView::OnSetFocus(CWnd* pOldWnd)
{
CView::OnSetFocus(pOldWnd);
hDC=GetDC()->GetSafeHdc();
SetTimer(6,500,NULL);
}
void COpenGLView::OnKillFocus(CWnd* pNewWnd)
{
KillPlay=TRUE;
CView::OnKillFocus(pNewWnd);
}
Timer functions are used in the view to provide a delayed invalidate
functionality so that the system will only render when it is free. Care should be taken to
kill the timer in order to keep the event from repeating and causing unneccesary invalidates.
void COpenGLView::OnTimer(UINT nIDEvent)
{
CView::OnTimer(nIDEvent);
if(nIDEvent==6) {
KillTimer(6);
Invalidate(FALSE);
};
}
The OnMove() function says that the system needs to pause before it
redraws the window. This allows the user to move the window easily and
promptly without redraw delays.
void COpenGLView::OnMove(int x, int y)
{
CView::OnMove(x, y);
IsIdleLocked=TRUE;
}
The OnSetCursor() function queries to see if the window being set is the
current one. If it is, then it loads the appropriate cursor for the current tool.
BOOL COpenGLView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if(pWnd==this){
switch(SelectedTool) {
case(Select): SetCursor(AfxGetApp()
->LoadCursor(IDC_SELECT));
break;
case(NodeSelect): SetCursor(AfxGetApp()
->LoadCursor(IDC_NODE));
break;
case(Zoom): SetCursor(AfxGetApp()
->LoadCursor(IDC_ZOOM));
break;
case(Translate): SetCursor(AfxGetApp()
->LoadCursor(IDC_TRANSLATE));
break;
};
return 0;
}
else {
return CView::OnSetCursor(pWnd, nHitTest, message);
};
}
The following functions provide the necessary handlers for dealing with the mouse and
virtual trackball. Portions of these functions are examined in detail in section 11.5.
void COpenGLView::OnMouseMove(UINT nFlags, CPoint point)
{
CView::OnMouseMove(nFlags, point);
RECT D;
GetClientRect(&D);
int Width=D.right;
int Height=D.bottom;
float temp;
LastMouseLocation=point;
switch(SelectedTool) {
case(Translate):
if(down) {
Lup.x=0; Lup.y=1; Lup.z=0;
Leye.x=0; Leye.y=0; Leye.z=4;
Invalidate(FALSE);
LPoint3 r=MoveParallelToScreen(Lcenter,
BeginRotatePos,point);
Lcenter.x=r.x; Lcenter.y=r.y; Lcenter.z=r.z;
BeginRotatePos=point;
Invalidate(FALSE);
};
if(rdown) {
Lup.x=0; Lup.y=1; Lup.z=0;
Leye.x=0; Leye.y=0; Leye.z=4;
Lcenter.z+=-(float)((float)BeginRotatePos.y
-point.y)/((float)Height/(float)1);
BeginRotatePos=point;
Invalidate(FALSE);
};
break;
case(Zoom):
if(down) {
float changefac=(((float)LastClickPos.y
-point.y)/(float)Height)*DepthScale;
DepthScale+=(changefac);
if(DepthScale<0.0001) DepthScale=0.0001;
if(DepthScale>999999) DepthScale=999999;
LastClickPos=point;
Invalidate(FALSE);
};
if(rdown) {
GetTrackballAngle(BeginRotatePos,point);
RECT r;
DrawModel(r);
Invalidate(FALSE);
};
break;
case(Select):
if(rdown) {
Invalidate(FALSE);
break;
};
if(down) {
ComputeTessellationLocation();
Invalidate(FALSE);
};
break;
case(NodeSelect):
if(rdown) {
Invalidate(FALSE);
break;
};
if(down) {
ComputeTessellationLocation();
};
break;
default: break;
};
}
void COpenGLView::OnRButtonDblClk(UINT nFlags, CPoint point)
{
CView::OnRButtonDblClk(nFlags, point);
}
void COpenGLView::OnRButtonDown(UINT nFlags, CPoint point)
{
rdown=1;
RECT D;
GetClientRect(&D);
int Width=D.right;
int Height=D.bottom;
BeginRotatePos=point;
int i;
Rotating=FALSE;
trackballangle=0;
if(rdown) {
for(i=0;i<=15;i++)
starttrackballMatrix[i]=trackballMatrix[i];
LastClickPos=point;
};
if((SelectedTool==NodeSelect) | (SelectedTool==Select)) {
center.x = (GLfloat)(Width / 2);
center.y = (GLfloat)(Height / 2);
radius = (Width > Height) ? center.y : center.x;
spinmode=0;
Invalidate(FALSE);
return;
};
CView::OnRButtonDown(nFlags, point);
}
void COpenGLView::OnRButtonUp(UINT nFlags, CPoint point)
{
switch(SelectedTool) {
case(Zoom):
if(rdown) {
if(trackballangle > 1) {
Rotating=TRUE;
Invalidate(FALSE);
break;
};
float ex=trackballMatrix[0]*Leye.x
+trackballMatrix[1]*Leye.y
+trackballMatrix[2]*Leye.z
+trackballMatrix[3];
float ey=trackballMatrix[4]*Leye.x
+trackballMatrix[5]*Leye.y
+trackballMatrix[6]*Leye.z
+trackballMatrix[7];
float ez=trackballMatrix[8]*Leye.x
+trackballMatrix[9]*Leye.y
+trackballMatrix[10]*Leye.z
+trackballMatrix[11];
Leye.x=ex; Leye.y=ey; Leye.z=ez;
ex=trackballMatrix[0]*Lup.x
+trackballMatrix[1]*Lup.y
+trackballMatrix[2]*Lup.z
+trackballMatrix[3];
ey=trackballMatrix[4]*Lup.x
+trackballMatrix[5]*Lup.y
+trackballMatrix[6]*Lup.z
+trackballMatrix[7];
ez=trackballMatrix[8]*Lup.x
+trackballMatrix[9]*Lup.y
+trackballMatrix[10]*Lup.z
+trackballMatrix[11];
Lup.x=ex; Lup.y=ey; Lup.z=ez;
glPushMatrix();
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX,
trackballMatrix);
glPopMatrix();
Invalidate(FALSE);
break;
};
default: break;
};
rdown=0;
if(!Rotating)
CView::OnRButtonUp(nFlags, point);
if(trackballangle<=1) Rotating=FALSE;
}
void COpenGLView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CView::OnLButtonDblClk(nFlags, point);
}
void COpenGLView::OnLButtonDown(UINT nFlags, CPoint point)
{
RECT D;
GetClientRect(&D);
int Width=D.right,Height=D.bottom,i;
LineF_t intline;
SphereF_t sphere;
LField *Field;
LPoint3 C;
down = 1;
switch(SelectedTool) {
case(Zoom): LastClickPos=point;
BeginRotatePos=point;
break;
default: break;
};
down=1;
CView::OnLButtonDown(nFlags, point);
}
void COpenGLView::OnLButtonUp(UINT nFlags, CPoint point)
{
RECT D;
GetClientRect(&D);
int Width=D.right,Height=D.bottom,i;
down=0;
CView::OnLButtonUp(nFlags, point);
}
Section 11.2 details the creation scheme for getting the COpenGLView object
created and enabled. The exact implementation is listed here for your reference.
int COpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
int result = CView::OnCreate(lpCreateStruct);
ConnectToCWND(this);
return result;
}
void COpenGLView::OnDestroy()
{
CView::OnDestroy();
DisconnectFromCWnd();
}
The exact implementation of the ConnectToCWND() function is also shown below.
The key components for OpenGL initialization are listed here. To use OpenGL in your own
rendering engines, the core OpenGL initialization is contained within ConnectToCWnd()
and DisconnectFromCWnd().
void COpenGLView::ConnectToCWnd(CWnd *wnd)
{
THISCWND=wnd;
hdc = wnd->GetDC();
bSetupPixelFormat(hdc->GetSafeHdc());
hrc = wglCreateContext(hdc->GetSafeHdc());
wglMakeCurrent(hdc->GetSafeHdc(), hrc );
float maxObjectSize, aspect;
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glClearDepth( 1.0 );
glEnable(GL_DEPTH_TEST);
glMatrixMode( GL_PROJECTION );
aspect = (GLfloat) oldrect.right / oldrect.bottom;;
gluPerspective( fov, aspect, near_plane, far_plane );
gluLookAt(
Leye.x,Leye.y,Leye.z,
Lcenter.x,Lcenter.y,Lcenter.z,
Lup.x,Lup.y,Lup.z );
GLfloat position[] = { 2, 3, 2, 0.0 };
GLfloat ambient[] = { .5, .5, .5, 1.0 };
GLfloat diffuse[] = { .35, .35, .35, 1.0 };
GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position1[] = { -2, 3, 2, 0.0 };
GLfloat ambient1[] = { .5, .5, .5, 1.0 };
GLfloat diffuse1[] = { .35, .35, .35, 1.0 };
GLfloat specular1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position2[] = { 0, 3, 1, 0.0 };
GLfloat ambient2[] = { .5, .5, .5, 1.0 };
GLfloat diffuse2[] = { .35, .35, .35, 1.0 };
GLfloat specular2[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position3[] = { 0, -3, 1, 0.0 };
GLfloat ambient3[] = { .5, .5, .5, 1.0 };
GLfloat diffuse3[] = { .35, .35, .35, 1.0 };
GLfloat specular3[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat position4[] = { 0, -3, 5, 0.0 };
GLfloat ambient4[] = { .5, .5, .5, 1.0 };
GLfloat diffuse4[] = { .35, .35, .35, 1.0 };
GLfloat specular4[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat exponent[] = { 20.0 };
GLfloat cutoff[] = { 45.0 };
GLfloat ca[] = { 1.5 };
GLfloat la[] = { 0.5 };
GLfloat qa[] = { 0.2 };
GLfloat spotdir[] = { -2.0, -3.0, -2.0 };
glLightfv(GL_LIGHT0,GL_POSITION,position);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glLightfv(GL_LIGHT1,GL_POSITION,position1);
glLightfv(GL_LIGHT1,GL_AMBIENT,ambient1);
glLightfv(GL_LIGHT1,GL_DIFFUSE,diffuse1);
glLightfv(GL_LIGHT1,GL_SPECULAR,specular1);
glLightfv(GL_LIGHT2,GL_POSITION,position2);
glLightfv(GL_LIGHT2,GL_AMBIENT,ambient2);
glLightfv(GL_LIGHT2,GL_DIFFUSE,diffuse2);
glLightfv(GL_LIGHT2,GL_SPECULAR,specular2);
glLightfv(GL_LIGHT3,GL_POSITION,position3);
glLightfv(GL_LIGHT3,GL_AMBIENT,ambient3);
glLightfv(GL_LIGHT3,GL_DIFFUSE,diffuse3);
glLightfv(GL_LIGHT3,GL_SPECULAR,specular3);
glLightfv(GL_LIGHT4,GL_POSITION,position4);
glLightfv(GL_LIGHT4,GL_AMBIENT,ambient4);
glLightfv(GL_LIGHT4,GL_DIFFUSE,diffuse4);
glLightfv(GL_LIGHT4,GL_SPECULAR,specular4);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_FALSE);
GLfloat high_shininess[] = { 100.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, high_shininess);
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX,trackballMatrix);
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX,starttrackballMatrix);
glPopMatrix();
GLfloat lmodel_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
GLfloat local_view[] = { 0 };
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, local_view);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_LIGHTING);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POINT_SMOOTH);
glDisable(GL_POLYGON_SMOOTH);
glHint(GL_FOG_HINT,GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POINT_SMOOTH_HINT,GL_FASTEST);
glHint(GL_POLYGON_SMOOTH_HINT,GL_FASTEST);
hDC=wnd->GetDC()->GetSafeHdc();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
aspect=1;
gluPerspective( fov, aspect, near_plane, far_plane );
aspect = (GLfloat) oldrect.right / oldrect.bottom;
glMatrixMode( GL_MODELVIEW );
Invalidate(FALSE);
}
void COpenGLView::DisconnectFromCWnd()
{
wglDeleteContext(hrc);
}
The implementation of bSetupPixelFormat() is listed here. This function
queries the capabilities of the current device and matches them as closely as possible to
the desired OpenGL rendering context. If no match is possible it notifies the user of that
as well.
BOOL COpenGLView::bSetupPixelFormat(HDC hDC)
{
int pixelformat;
if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 )
{
::MessageBox(NULL, "ChoosePixelFormat failed", "Error",
MB_OK);
return FALSE;
};
if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE)
{
::MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
return FALSE;
};
CreateRGBPalette(hDC);
return TRUE;
}
The bSetupPixelFormat() makes a call to the CreateRGBPalette()
member. This member creates the necessary palette information for OpenGL. The code to
complete this tedious task in conjunction with the other elements in the COpenGLView
object is shown as follows:
unsigned char threeto8[8] = {
0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};
unsigned char twoto8[4] = {
0, 0x55, 0xaa, 0xff
};
unsigned char oneto8[2] = {
0, 255
};
static int defaultOverride[13] = {
0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91
};
static PALETTEENTRY defaultPalEntry[20] = {
{ 0, 0, 0, 0 },
{ 0x80,0, 0, 0 },
{ 0, 0x80,0, 0 },
{ 0x80,0x80,0, 0 },
{ 0, 0, 0x80, 0 },
{ 0x80,0, 0x80, 0 },
{ 0, 0x80,0x80, 0 },
{ 0xC0,0xC0,0xC0, 0 },
{ 192, 220, 192, 0 },
{ 166, 202, 240, 0 },
{ 255, 251, 240, 0 },
{ 160, 160, 164, 0 },
{ 0x80,0x80,0x80, 0 },
{ 0xFF,0, 0, 0 },
{ 0, 0xFF,0, 0 },
{ 0xFF,0xFF,0, 0 },
{ 0, 0, 0xFF, 0 },
{ 0xFF,0, 0xFF, 0 },
{ 0, 0xFF,0xFF, 0 },
{ 0xFF,0xFF,0xFF, 0 }
};
unsigned char
COpenGLView::ComponentFromIndex(int i, UINT nbits, UINT shift)
{
unsigned char val;
val = (unsigned char) (i >> shift);
switch (nbits) {
case 1: val &= 0x1; return oneto8[val];
case 2: val &= 0x3; return twoto8[val];
case 3: val &= 0x7; return threeto8[val];
default: return 0;
};
}
void
COpenGLView::CreateRGBPalette(HDC hDC)
{
PIXELFORMATDESCRIPTOR pfd;
LOGPALETTE *pPal;
int n, i;
n = GetPixelFormat(hDC);
DescribePixelFormat(hDC, n,
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if (pfd.dwFlags & PFD_NEED_PALETTE) {
n = 1 << pfd.cColorBits;
pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED,
sizeof(LOGPALETTE)
+ n * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = n;
for (i=0; i<n; i++) {
pPal->palPalEntry[i].peRed =ComponentFromIndex(i,
pfd.cRedBits, pfd.cRedShift);
pPal->palPalEntry[i].peGreen =ComponentFromIndex(i,
pfd.cGreenBits, pfd.cGreenShift);
pPal->palPalEntry[i].peBlue =ComponentFromIndex(i,
pfd.cBlueBits, pfd.cBlueShift);
pPal->palPalEntry[i].peFlags = 0;
}
if ((pfd.cColorBits == 8) &&
(pfd.cRedBits == 3) && (pfd.cRedShift == 0) &&
(pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) &&
(pfd.cBlueBits == 2) && (pfd.cBlueShift == 6)
) {
for (i = 1 ; i <= 12 ; i++)
pPal->palPalEntry[defaultOverride[i]] =
defaultPalEntry[i];
};
ghPalette = CreatePalette(pPal);
LocalFree(pPal);
ghpalOld = SelectPalette(hDC, ghPalette, FALSE);
n = RealizePalette(hDC);
};
}