Listing 1 3d.c creates a General Dynamics F16 Falcon aircraft
#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*/