March 01, 1993
URL:http://drdobbs.com/three-dimensional-modeling-under-windows/184402682
#include "windows.h" #include <math.h> #include <stdlib.h> //****************************************************************** //Title: 3D.C //Author: Thomas W. Olsen //Version: 1.0 //Compiler: Microsoft C/C++ 7.0 // rc /r 3d. rc // cl /c /AL /Gsw /W3 /Oas /Zpe /Zi /FPi 3d.c // link /CO /NOD 3d,,, libw llibcew win87em, 3d.def // rc 3d.exe //***************************************************************** //********************** Various Constants ************************* #define CENTER 0 #define PI 3.141593 #define RADIANS(a) (a * (PI / 180.0)) #define DEGREES(a) (a * (180.0 / PI)) #define NO_OF_VERTICES 66 #define NO_OF_SURFACES 45 #define NO_OF_SURFACE_VERTICES 220 #define VIEW_RATIO (40 / 10) #define MIN_DEGREES 0 #define MAX_DEGREES 359 #define ROTATE_DEGREES 5 //********************* Structure Definitions ********************** typedef struct tagPOINT3D { double x; double y; double z; } POINT3D; typedef struct tagVERTEX { POINT3D world; // World Coordinates POINT3D eye; // Eye Coordinates POINT screen; // Screen Coordinates } VERTEX; typedef struct tagSURFACE { int mapIndex; // Index Into the Surface Map Array int noOfVertices; // No of Vertices Forming the Surface int depthIndex; // Used in Determining Depth of Surface int brushColor; } SURFACE; typedef struct tagOBJECT { VERTEX vertex [NO_OF_VERTICES]; SURFACE info[NO._OF_SURFACES]; int map[NO_OF_SURFACE_VERTICES]; } OBJECT; //************************* Static Data *************************** OBJECT f16 = { { // Vertex Array { 0.00, 0.00, 0.00 }, //Center { 0.00, -17.00, 9.0 }, { 0.00, -13.00, 9.00 }, //Tail { 0.00, -14.50, 3.00 }, { 0.00, -8.00, 3.00 }, { 0.00, -14.50, 2.00 }, { 0.00, -5.00, 2.00 }, { -0.50, -16.00, 1.00 }, { -1.00, -16.00, 0.00 }, //Exhaust { -0.50, -16.00, -0.50 }, { 0.00, -16.00, -1.00 }, { 0.50, -16.00, -0.50 }, { 1.00, -16.00, 0.00}, { 0.50, -16.00, 1.00 }, { -1.00, -13.00, 2.00 }, { -2.00, -13.00, 0.00 }, //Fuse { -1.50, -13.00, -1.50 }, { 0.00, -13.00, -2.00 }, { 1.50, -13.00, -1.50 }, { 2.00, -13.00, 0.00 }, { 1.00, -13.00, 2.00 }, { -1.00, 7.00, 2.00 }, { -2.00, 7.00, 0.00 }, { -1.50, 7.00, -1.50 }, { 0.00, 7.00, -2.00 }, { 1.50, 7.00, -1.50 }, { 2.00, 7.00, 0.00 }, { 1.00, 7.00, 2.00 }, { 2.00, -8.00, 0.00 }, { 11.00, -8.00, 0.00 }, //Wings { 11.00,-5.00,0.00 }, { 5.00, 0.00, 0.00 }, { 2.00, 7.00, 0.00 }, { -2.00, -8.00, 0.00 }, { -11.00, -8.00, 0.00 }, { -11.00, -5.00, 0.00 }, { -5.00, 0.00, 0.00 }, { -2.00, 7.00, 0.00 }, { 0.50, 2.00, 2.00 }, { -0.50, 2.00, 2.00 }, //Cockpit { 1.00, 5.00, 2.00 }, { 0.50, 5.00, 3.50 }, { -0.50, 5.00, 3.50 }, { -1.00, 5.00, 2.00 }, { 1.00, 8.00, 2.00 }, { 0.50, 8.00, 3.50 }, { -0.50, 8.00, 3.50 }, { -1.00, 8.00, 2.00 ), { 0.50, 11.00, 2.00 }, { -0.50, 11.00, 2.00 }, { 0.00, 7.00, -1.00 }, { -1.00, 11.00, 2.00 }, //Subfuse { -2.00, 11.00, 0.00 }, { 0.00, 11.00, -1.00 }, { 2.00, 11.00, 0.00 }, { 1.00, 11.00, 2.00 }, { 0.00, 11.00, -1.00 }, { 0.00, 17.00, 0.00 }, //Nose { -2.00, -16.00, 0.00 }, { -8.00, -16.00, 0.00 }, //Elevators { -8.00, -14.00, 0.00 }, { -2.00, -10.00, 0.00 }, { 2.00, -16.00, 0.00 }, { 8.00, -16.00, 0.00 }, { 8.00, -14.00, 0.00 }, { 2.00, -10.00, 0.00 } }, { // Surface Info ... (Points to Surface Map) { 0, 5, 60, DKGRAY_BRUSH }, { 5, 5, 64, DKGRAY_BRUSH }, //Elevators { 10, 5, 60, DKGRAY_BRUSH }, { 15, 5, 64, DKGRAY_BRUSH }, { 20, 5, 1, GRAY_BRUSH }, { 25, 5, 4, LTGRAY_BRUSH }, //Tail { 30, 5, 1, GRAY_BRUSH }, { 35, 5, 4, LTGRAY_BRUSH }, { 40, 5, 14, BLACK_BRUSH }, ( 45, 5, 15, DKGRAY_BRUSH }, //Exhaust { 50, 5, 16, BLACK_BRUSH }, ( 55, 5, 17, BLACK_BRUSH }, { 60, 5, 18, DKGRAY_BRUSH }, { 65, 5, 19, BLACK_BRUSH }, { 70, 5, 20, DKGRAY_BRUSH }, { 75, 5, 22, DKGRAY_BRUSH }, { 80, 5, 23, GRAY_BRUSH }, //Fuse { 85, 5, 24, DKGRAY_BRUSH }, { 90, 5, 25, DKGRAY_BRUSH }, { 95, 5, 26, GRAY_BRUSH }, { 100, 5, 27, DKGRAY_BRUSH }, { 105, 5, 20, GRAY_BRUSH, }, { 110, 6, 30, DKGRAY_BRUSH }, ( 116, 6, 35, DKGRAY_BRUSH }, //Wings { 122, 6, 30, DKGRAY_BRUSH }, { 128, 6, 35, DKGRAY_BRUSH }, { 134, 5, 21, LTGRAY_BRUSH }, { 139, 5, 22, LTGRAY_BRUSH }, //Subfuse { 144, 5, 50, LTGRAY_BRUSH }, { 149, 5, 26, LTGRAY_BRUSH }, { 154, 5, 27, LTGRAY_BRUSH }, { 159, 4, 55, GRAY_BRUSH }, { 163, 4, 54, GRAY_BRUSH }, //Nose { 167, 4, 56, GRAY_BRUSH }, { 171, 4, 52, GRAY_BRUSH }, { 175, 4, 51, LTGRAY_BRUSH }, { 179, 5, 41, WHITE_BRUSH }, { 184, 5, 45, WHITE_BRUSH }, //Cockpit { 189, 5, 46, WHITE_BRUSH }, { 194, 4, 41, WHITE_BRUSH }, { 198, 4, 42, WHITE_BRUSH }, { 202, 5, 41, WHITE_BRUSH }, { 207, 5, 46, WHITE_BRUSH }, { 212, 4, 45, WHITE_BRUSH }, { 216, 4, 46, WHITE_BRUSH } }, { // Surface Map ... (Points to Vertex Array) 58, 61, 60, 59, 58, 62, 63, 64, 65, 62, 58, 59, 60, 61, 58, // Elevators 62, 65, 64, 63, 62, 1, 3, 4, 2, 1, 3, 5, 6, 4, 3, 1, 2, 4, 3, 1, // Tail 3, 4, 6, 5, 3, 14, 15, 8, 7, 14, 15, 16, 9, 8, 15, 16, 17, 10, 9, 16, // Exhaust 17, 18, 11, 10, 17, 18, 19, 12, 11, 18, 19, 20, 13, 12, 19, 20, 14, 7, 13, 20, 14, 21, 22, 15, 14, 15, 22, 23, 16, 15, 16, 23, 24, 17, 16, // Fuse 17, 24, 25, 18, 17, 18, 25, 26, 19, 18, 19, 26, 27, 20, 19, 20, 27, 21, 14, 20, 28, 29, 30, 31, 32, 28, 33, 37, 36, 35, 34, 33, 28, 32, 31, // Wings 30, 29, 28, 33, 34, 35, 36, 37, 33, 21, 51, 52, 22, 21, 22, 52, 53, 50, 22, 50, 53, 54, 26, 50, // Subfuse 26, 54, 55, 27, 26, 27, 55, 51, 21, 27, 55, 54, 57, 55, 54, 56, 57, 54, 56, 52, 57, 56, 52, 51, 57, 52, // Nose 51, 55, 57, 51, 41, 42, 39, 38, 41, 45, 46, 42, 41, 45, 48, 49, 46, 45, 48, // Cockpit 40, 41, 38, 40, 42, 43, 39, 42, 44, 45, 41, 40, 44, 46, 47, 43, 42, 46, 48, 45, 44, 48, 49, 47, 46, 49 } }; BOOL wireFrame = FALSE; double distance = 75, thetaDegrees = 90, phiDegrees = 60; //************************** Static Data *************************** LONG FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void DrawObject(HWND hWnd, HDC hDC, OBJECT *object ); int __cdecl compareProc(const void *elem1, const void *elem2 ); //************************** Program Begin ************************* int PASCAL WinMain(HANDLE hInst, HANDLE hPrevInst, LPSTR lpCmdLine, int numCmdShow ) { MSG msg; HWND hWnd; WNDCLASS wc; //************************ Setup Window ************************ wc.style = (UINT) NULL; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon( NULL, IDI_APPLICATION); wc.hCursor = LoadCursor( NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(BLACK_BRUSH); wc.lpszMenuName = (LPSTR) "Menu"; wc.lpszClassName = (LPSTR) "3DClass"; if (!RegisterClass(&wc)) return(FALSE); hWnd = CreateWindow( "3DClass", "3D Modeling Example", WS_OVERLAPPEDWINDOW | WS_SCROLL | WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL ); if (!hWnd) return (FALSE); SetScrollRange( hWnd, SB_HORZ, MIN_DEGREES, MAX_DEGREES, TRUE ); SetScrollRange( hWnd, SB_VERT, MIN_DEGREES, MAX_DEGREES, TRUE ); SetScrollPos( hWnd, SB_HORZ, (int) thetaDegrees, TRUE ); SetScrollPos( hWnd, SB_VERT, (int) phiDegrees, TRUE ); ShowWindow( hWnd, numCmdShow ); while (GetMessage(&msg, NULL, NULL, NULL)) /* Typical Mossage Loop */ { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } LONG FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT paint; HDC hDC; HMENU hMenu; int vPos, hPos; switch (message) { case WM_COMMAND: hMenu = GetMenu( hWnd ); CheckMenuItem( hMenu, wParam, MF_CHECKED); if (wParam == 1) { CheckMenuItem( hMenu, 2, MF_UNCHECKED); wireFrame = TRUE; } else { CheckMenuItem( hMenu, 1, MF_UNCHECKED); wireFrame = FALSE; } InvalidateRect( hWnd, NULL, TRUE ); break; case WM_DESTROY: PostQuitMessage( NULL ); break; case WM_HSCROLL: if (wParam == SB_THUMBTRACK) break; hPos = GetScrollPos( hWnd, SB_HORZ); switch( wParam ) { case SB_TOP: hPos = MIN_DEGREES; break; case SB_BOTTOM: hPos = MAX_DEGREES; break; case SB_LINEUP: case SB_PAGEUP: hPos -= ROTATE_DEGREES; break; case SB_PAGEDOWN: case SB_LINEDOWN: hPos += ROTATE_DEGREES; break; case SB_THUMBPOSITION: hPos = LOWORD(lParam); break; } if (hPos < MIN_DEGREES) hPos = MAX_DEGREES; else if (hPos > MAX_DEGREES) hPos = MIN_DEGREES; SetScrollPos( hWnd, SB_HORZ, hPos, TRUE ); thetaDegrees = (double) hPos; InvalidateRect( hWnd, NULL, TRUE ); break; case WM_VSCROLL: if (wParam == SB_THUMBTRACK) break; vPos = GetScrollPos( hWnd, SB_VERT ); switch( wParam ) { case SB_TOP: vPos = MIN_DEGREES; break; case SB_BOTTOM: vPos = MAX_DEGREES; break; case SB_LINEUP: case SB-PAGEUP: vPos -= ROTATE_DEGREES; break; case SB_PAGEDOWN: case SB_LINEDOWN: vPos += ROTATE_DEGREES; break; case SB_THUMBPOSITION: vPos = LOWORD(lParam); break; } if (vPos < MIN_DEGREES) vPos = MAX_DEGREES; else if (vPos > MAX_DEGREES) vPos = MIN_DEGREES; SetScrollPos( hWnd, SB_VERT, vPos, TRUE ); phiDegrees = (double) vPos; InvalidateRect( hWnd, NULL, TRUE ); break; case WM_SIZE: InvalidateRect( hWnd, NULL, TRUE ); break; case WM_PAINT: hDC = BeginPaint( hWnd, &paint ); DrawObject(hWnd, hDC, &f16); ReleaseDC( hWnd, hDC ); EndPaint( hWnd, &paint ); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } } void DrawObject(HWND hWnd, HDC hDC, OBJECT *object) { double sinTheta, cosTheta, sinPhi, cosPhi; double s1, s2, s3; POINT3D *v1, *v2, *v3; POINT center; RECT rect; POINT points[10]; HBITMAP hBitmap, hOldBitmap; HRGN hRgn; HDC hMemDC; int surface, vertex, mapIndex, vertexIndex, loop; GetClientRect( hWnd, &rect); // Determine Size of Client Area center.x = (rect.right / 2); // Calculate X-Centerpoint center.y = (rect.bottom / 2); // Calculate Y-Centerpoint hRgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ); hMemDC = CreateCompatibleDC( hDC ); hBitmap = CreateCompatibleBitmap( hDC, rect.right, rect.bottom); hOldBitmap = SelectObject( hMemDC, hBitmap ); //********************************************************************** //* Precalculate SIN(x) and COS(x) * //********************************************************************** cosTheta = cos( RADIANS(thetaDegrees) ); sinTheta = sin( RADIANS(thetaDegrees) ); cosPhi = cos( RADIANS(phiDegrees) ); sinPhi = sin( RADIANS(phiDegrees) ); //****************************************************************** //* Calculate Eye and Screen Coordinates * //****************************************************************** for (loop = 1; loop < NO_OF_VERTICES; loop++) { object->vertex[loop].eye.x = (-object->vertex[loop].world.x * sinTheta) + (object->vertex[loop].world.y * cosTheta); object->vertex[loop].eye.y = (-object->vertex[loop].world.x * cosTheta * cosPhi) - (object->vertex[loop].world.y * sinTheta * cosPhi) + (object->vertex[loop].world.z * sinPhi); object->vertex[loop].eye.z = (-object->vertex[loop].world.x * sinPhi * cosTheta) - (object->vertex[loop].world.y * sinTheta * sinPhi) - (object->vertex[loop].world.z * cosPhi) + distance; object->vertex[loop].screen.x = (int) (VIEW_RATIO * (object->vertex[loop].eye.x / object->vertex[loop].eye.z) * center.y + center.x); object->vertex[loop].screen.y = (int) (-VIEW_RATIO * (object->vertex[loop].eye.y / object->vertex[loop].eye.z) * center.y + center.y); } //****************************************************************** //* Draw Object * //****************************************************************** FillRgn( hMemDC, hRgn, GetStockObject(BLACK_BRUSH)); SelectObject( hMemDC, GetStockObject(wireFrame == TRUE ? WHITE_PEN:BLACK_PEN) ); if (wireFrame == FALSE) qsort( object->info, NO_OF_SURFACES, sizeof(SURFACE), compareProc ); for (surface = 0; surface < NO_OF_SURFACES; surface++) { mapIndex = object->info[surface].mapIndex; if (wireFrame == FALSE) // No Hidden Surface Removal For Wire Frame { v1 = &object->vertex[ object->map[ mapIndex ] ].eye; // Setup pointers to three v2 = &object->vertex[ object->map[ mapIndex+1 ] ].eye; // surface vertices v3 = &object->vertex[ object->map[ mapIndex+2 ] ].eye; s1 = v1->x * (v2->y * v3->z - v3->y * v2->z); s1 = (-1) * s1; s2 = v2->x * (v3->y * v1->z - v1->y * v3->z); // Perform dot product on surface s3 = v3->x * (v1->y * v2->z - v2->y * v1->z); // vectors to find normal vector } if (wireFrame == TRUE || s1 - s2 - s3 <= 0.0) { for (vertex = 0; vertex < object->info[surface].noOfVertices; vertex++, mapIndex++) { vertexIndex = object->map[mapIndex]; points[vertex].x = object->vertex[vertexIndex].screen.x; points[vertex].y = object->vertex[vertexIndex].screen.y; } if (wireFrame == TRUE) Polyline( hMemDC, &points[0], vertex; else { SelectObject( hMemDC, GetStockObject(object->info[surface].brushColor) ); Polygon( hMemDC, &points[0], vertex); } } } BitBlt( hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY); SelectObject( hMemDC, hOldBitmap ); DeleteObject( hBitmap ); DeleteObject( hRgn ); DeleteDC( hMemDC ); } int _cdecl compareProc( const void *elem1, const void *elem2 ) { if( f16.vertex[((SURFACE *) elem1)->depthIndex].eye.z > f16.vertex[((SURFACE *) elem2)->depthIndex].eye.z) return -1; if( f16.vertex[((SURFACE *) elem1)->depthIndex].eye.z < f16.vertex[((SURFACE *) elem2)->depthIndex].eye.z) return 1; else return 0; } /* End of File*/
NAME 3D DESCRIPTION '3D Modeling Example' EXETYPE WINDOWS STUB 'WINSTUB.EXE' CODE PRELOAD MOVEABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 2048 STACKSIZE 4096 EXPORTS WindowProc @1
#include "windows.h" Menu MENU { POPUP "&Draw" { MENUITEM "&Wire Frame", 1 MENUITEM "&Solid", 2, CHECKED } }
Thomas writes a variety of Windows and DOS software for a major insurance company. He can be reached on the CompuServe Information Service at (76450,1767).
Nothing communicates an idea better than a picture. It's the defining principle behind the popularity of Microsoft Windows and other graphical environments. Not long ago, though, you might recall serious debate over whether Windows would ever meet the performance demands of a graphical user interface. Much of the trepidation resulted, no doubt, from the tremendous freedom of MS-DOS programs to directly access video hardware. However, faster CPUs, accelerated video adapters, local bus connections, multimedia, and a mature Graphical Display Interface (GDI) have since conspired in favor of Windows.
These changes pose significant opportunities in 3-D modeling software development. Three-dimensional modeling has become increasingly important over time because it mimics elements in the real world. This article focuses on simple strategies for 3-D modeling. The accompanying source code was compiled and linked with the Microsoft C/C++ Optimizing Compiler Version 7.0 and Microsoft Windows 3.1 Software Developer Kit (SDK). Every effort has been made to ensure compatibility with other compilers. Compile instructions are provided in comments at the top of each listing. The bitmaps were created with Microsoft Paintbrush.
This article barely scratches the surface of 3-D graphics. Rendering, shading, ray tracing, and texture mapping get a more thorough treatment from the references in the bibliography. This article will present a building block for such advanced features.
Do not confuse 3-D modeling with Windows metafiles. A metafile is a binary-encoded collection of GDI function calls. You create one by sending the output from various GDI function calls to a special device context. A recorded metafile can be played back by passing its associated resource handle to PlayMetaFile. The resulting picture may look three-dimensional but it's just a two-dimensional facade.
Microsoft Windows derives its characteristic look and feel primarily from raster-based or bitmapped graphics technology. Most fonts, controls, and icons are nothing more than bitmaps two-dimensional blocks of pixels that appear three-dimensional due to varying color gradients. Bitmaps look great but generally experience some kind of image distortion when rotated, stretched, or scaled onto devices of varying resolutions. To address such deficiencies Microsoft incorporated so-called TrueType font technology into Windows 3.1. TrueType is a form of vector-based graphics, in which images are constructed with individual graphical primitives such as lines, points, rectangles, ellipses, and curves rather than bitmaps. Vector graphics are scalable, require less memory than bitmaps, and enable us to model three-dimensional objects with relative ease.
The Windows GDI does not contain explicit support for 3-D modeling, but it is not difficult to build a suitable framework atop existing primitive functions. Nearly any 3-D object can be drawn with a set of interconnected points or vertices. For example, a simple cube has eight vertices (one for each corner) while the General Dynamics F16 Falcon aircraft in 3D.C in Listing 1 (along with the files in Listing 2 and Listing 3) contains literally hundreds of vertices. Of course, a collection of points is worthless without some frame of reference, so they are placed in a domain called the World Coordinate System (WCS). You can change the object's orientation in WCS by multiplying each vertex by a series of transformation matrices. There are distinct transformation matrices for rotation, reflection, shearing, scaling, and translation operations, respectively.
Try to imagine yourself floating in space around a motionless object. As you change position, each WCS vertex is transformed with respect to an Eye Coordinate System (ECS) that emanates from your eye and points toward the object (Figure 1) . To complicate matters even more, the resulting ECS vertices must be transformed from three-dimensional to two-dimensional screen coordinates (SCS) before the object can be displayed. Once these screen positions are known, you can connect-the-dots to produce a transparent wireframe model, or use filled polygons for a more realistic solid model (Figure 2) . Three-dimensional objects are drawn one surface at a time, so vertices are generally grouped in that order.
Hidden-surface removal is one of the more complicated and computation-in-tensive facets of 3-D modeling. The most popular method of hidden-surface removal is called backplane elimination. Basically, it involves computing whether a normal (perpendicular) vector emanating from a given surface points away from or toward the viewer's line of sight. Those surfaces facing away from the viewer cannot be seen and, therefore, need not be drawn. It does have its drawbacks, too. Objects with irregular or overlapping surfaces will not be drawn properly. One quick-and-dirty solution is to sort the surfaces in terms of decreasing distance from the viewer (ECS z-coordinate). Surfaces lying farther away from the viewer are drawn first and subsequently masked by closer surfaces. Depth sorting has its flaws but performance-conscious applications usually don't mind.
3D.C (Listing 1) supports both wireframe and solid models. It first creates a window with horizontal and vertical scroll bars, and uses SetScrollRange to lock the thumb between 0 and 360 degrees. Depressing the scroll bars changes the angular position of the viewer relative to the object. This is especially convenient because the viewer's position is given in spherical coordinates (distance, theta, phi). All measurements are given in device units. The F16 object "database" has been optimized to keep code size to a minimum.
3D.C calls DrawObject whenever the viewer depresses the scroll bars or resizes the window. DrawObject determines the center point of the window and creates a compatible work bitmap. Using an intermediate bitmap prevents the flashing effects that occur while drawing straight to a display context. DrawObject also precalculates sine and cosine values for global variables theta and phi. These values are needed when f16.vertex[].world vertices are transformed to f16.vertex[].eye vertices and, finally, to f16.vertex[].screen coordinates. DrawObject clears the work bitmap and loops through each surface in the f16.info[] array. For solid models, DrawObject performs a depth sort on the f16.vertex[].eye vertices, removes hidden surfaces with backplane elimination, selects a brush color from f16.info[].brushColor, and calls Polygon; otherwise, it calls PolyLine for a wire-frame surface. DrawObject then updates the client area with the completed work bitmap and deletes unused resources.
Floating-point computations incur a considerable amount of overhead even with a math coprocessor installed but you can improve performance significantly by substituting fixed-point integers for floating-point numbers. Fixed-point integers incorporate both the whole and fractional components of floating-point numbers but can be manipulated in single arithmetic operations, such as IMUL and IDIV. For example, it is possible to represent the floating-point number 12.345 with integer 12345 by shifting the decimal place three positions. There are certain problems with this technique, as well. Integers can only represent so many digits before overflowing, so you must strike a balance between the scale and precision of the 3-D model.
NASA's Jet Propulsion Laboratories unveiled a computer-generated film several months ago that depicted the surface topography of some distant planet. JPL had downloaded countless bits of radar imaging data from a distant probe into three Cray super computers and rendered the surreal landscape frame-by-frame over the course of three solid weeks. The resulting bitmaps were finally transferred to videotape and made available for public consumption. There's a lesson hiding behind this madness. Even though real-time 3-D graphics were out of the question, JPL eventually got what it paid for by blending vector and raster technologies.
Adams, Lee. 1986. High-Performance CAD Graphics in C. Blue Ridge Summit, PA: Windcrest/Tab.
Microsoft Corp. 1991. Microsoft Windows Multimedia Authoring and Tools Guide. Redmond, WA: Microsoft Press.
Microsoft Corp. 1991. Microsoft Windows Multimedia Programmer's Reference. Redmond, WA: Microsoft Press.
Microsoft Corp. 1991. Microsoft Windows Multimedia Programmer's Workbook. Redmond, WA: Microsoft Press.
Park, Chan S. 1985. Interactive Microcomputer Graphics. Reading, MA: Addison-Wesley Publishing Company.
Petzold, Charles. 1990. Programming Windows. Redmond, WA: Microsoft Press.
Wilton, Richard. 1987. Programmer's Guide to PC & PS/2 Video Systems. Redmond, WA: Microsoft Press.
Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.