// FILE: draw.c #include #include #include #include "3d\intern.h" #include "3d\compatib.h" #include "3d\globals.h" #include "3d\gdi3D.h" #include "3d\helpers.h" /* PROJECT: GDI3D DLL PROGRAMMER(S): Pasi Paavola COMPILER: Microsoft C/C++ 7.0 ENVIRONMENT: Windows 3.1 running on 386/33/SuperVGA/no 80x87; 386 enhanced mode ROUTINES: Drawing & moving routines */ //////////////////////////////////////////////////////////////////////////// /* G3MoveTo() moves the current position to the position specified by the point pointed by argument lpG3Point. Parameter Description lpG3Point Far pointer to the 3D point Returns: Return value contains the previous position (x in low word, y in high word). The return value is in output window coordinates. Comments */ //////////////////////////////////////////////////////////////////////////// DWORD WINAPI_LIB G3MoveTo(LPG3POINT lpG3Point) { POINT p; p = G3ToViewport(lpG3Point->x, lpG3Point->y, lpG3Point->z); return MoveTo(GhDC, p.x, p.y); } //////////////////////////////////////////////////////////////////////////// /* G3LineTo() draws a line from the current position to the position specified by the point pointed by argument lpG3Point. Parameter Description lpG3Point Far pointer to the destination 3D point Returns TRUE, if successful, otherwise FALSE Comments */ //////////////////////////////////////////////////////////////////////////// BOOL WINAPI_LIB G3LineTo(LPG3POINT lpG3Point) { POINT p; p = G3ToViewport(lpG3Point->x, lpG3Point->y, lpG3Point->z); return LineTo(GhDC, p.x, p.y); } //////////////////////////////////////////////////////////////////////////// /* G3Box() draws a box in 3D. The edges of the box are always parallel to some of the axes. All edges are drawn (no hidden line removal). Parameter Description x1, x2 Limits in x-direction y1, y2 Limits in y-direction z1, z2 Limits in z-direction Returns Comments */ //////////////////////////////////////////////////////////////////////////// VOID WINAPI_LIB G3Box(double x1, double x2, double y1, double y2, double z1, double z2) { POINT c1, c2, c3, c4, c5, c6, c7, c8; // Corner points // Generate 8 corner points c1 = G3ToViewport(x2, y1, z1); c2 = G3ToViewport(x2, y2, z1); c3 = G3ToViewport(x1, y2, z1); c4 = G3ToViewport(x1, y1, z1); c5 = G3ToViewport(x2, y1, z2); c6 = G3ToViewport(x2, y2, z2); c7 = G3ToViewport(x1, y2, z2); c8 = G3ToViewport(x1, y1, z2); // Draw necessary lines // Note that every pixel belonging to the "wire frame" should // be drawn only once. Drawing any pixel twice or more times // will result unwanted results with some ROPs // However, because some lines may overlap in screen coordinates, some // pixels are drawn twice. This produces some unpleasant results // at least with R2_NOT MoveTo(GhDC, c1.x, c1.y); LineTo(GhDC, c2.x, c2.y); LineTo(GhDC, c6.x, c6.y); LineTo(GhDC, c5.x, c5.y); LineTo(GhDC, c1.x, c1.y); LineTo(GhDC, c4.x, c4.y); LineTo(GhDC, c3.x, c3.y); LineTo(GhDC, c7.x, c7.y); LineTo(GhDC, c8.x, c8.y); LineTo(GhDC, c4.x, c4.y); MoveTo(GhDC, c2.x, c2.y); LineTo(GhDC, c3.x, c3.y); MoveTo(GhDC, c6.x, c6.y); LineTo(GhDC, c7.x, c7.y); MoveTo(GhDC, c5.x, c5.y); LineTo(GhDC, c8.x, c8.y); } //////////////////////////////////////////////////////////////////////////// /* G3HIstogram draws a 3D histogram. Parameter Description lpdHeights Pointer to a table containing the bar heights. The data should be organized rowwise in the table. The number of rows in this table should be nCategories and number of columns nItems, respectively (see below). The first bar in a row is drawn nearest the origin. All bar heights should be nonnegative. lpColors Pointer to the table containing color values for various items. The dimension of this array should be nItems. If lpColors is NULL, the current brush is used for all bars. nItems Number of bars in a single bar row (along y-axis) nCategories Number of categories (along x-axis) dBarWidth Bar width in 3D coordinates (along y-axis) dBarDepth Bar depth in 3D coordinates (along x-axis) dDist Distance between rows (categories) in 3D coordinates Returns Nonzero, if OK, otherwise 0 Comments The current viewpoint should be set so that all coordinates (x, y, z) are positive. G3Histogram() uses the current pen selected to device context to draw the edges of the bars. The current ROP mode is also used (for edges and facets). */ //////////////////////////////////////////////////////////////////////////// int WINAPI_LIB G3Histogram(double FAR *lpdHeights, COLORREF FAR * lpColors, int nItems, int nCategories, double dBarWidth, double dBarDepth, double dDist) { register int i; // row index register int j; // category index // Only 3 facets of each bar need to be painted. The following // table presents the viewport coordinates of the corners of these // facets. POINT VPCorners[4]; // double xb, xf; // background and foreground x-coordinates // for the current row (category) double yb, yf; // background and foreground y-coordinates // for the current bar double z; POINT TopL, TopR; // Some temporaries for corners HBRUSH hBrush, hOldBrush; HCURSOR hOldCursor; if (lpdHeights == NULL || nItems <= 0 || nCategories <= 0 || dBarWidth <= 0. || dBarDepth <= 0. || dDist < 0) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_INVPAR); return 0; } hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); for (i = 0; i < nItems; i++) { yb = i*dBarWidth; yf = yb + dBarWidth; if (lpColors) { hBrush = CreateSolidBrush(((COLORREF HUGE *) lpColors)[i]); hOldBrush = SelectObject(GhDC, hBrush); } for (j = 0; j < nCategories; j++) { xb = j*(dBarDepth + dDist); xf = xb + dBarDepth; z = fabs(* ((double HUGE *) lpdHeights + j*nItems + i)); // Draw facet parallel with y-axis: // The first corner is same for all facets VPCorners[0] = G3ToViewport(xf, yf, z); // The "lowest" corner VPCorners[1] = G3ToViewport(xf, yf, 0.); // Continue clockwise... VPCorners[2] = G3ToViewport(xf, yb, 0.); VPCorners[3] = TopL = G3ToViewport(xf, yb, z); if (!Polygon(GhDC, VPCorners, 4)) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_POLYGON); SetCursor(hOldCursor); return 0; } // Draw facet parallel with x-axis: // Only the last two points are different from the previous facet VPCorners[2] = G3ToViewport(xb, yf, 0.); VPCorners[3] = TopR = G3ToViewport(xb, yf, z); if (!Polygon(GhDC, VPCorners, 4)) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_POLYGON); SetCursor(hOldCursor); return 0; } // Draw top facet VPCorners[1] = TopR; // The farthest corner VPCorners[2] = G3ToViewport(xb, yb, z); VPCorners[3] = TopL; if (!Polygon(GhDC, VPCorners, 4)) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_POLYGON); SetCursor(hOldCursor); return 0; } } if (lpColors) DeleteObject(SelectObject(GhDC, hOldBrush)); } SetCursor(hOldCursor); return 1; } //////////////////////////////////////////////////////////////////////////// /* G3WireSurface() draws a surface that is given in the form z = f(x,y) Parameter Description lpfnF Pointer to a function of two double arguments dMinX, dMaxX x range. dMaxX have to be > dMinX dMinY, dMaxY y range. dMaxY have to be > dMinY nXDivs Number of intervals in x direction nYDivs Number of intervals in y direction Returns Nonzero, if successful otherwise 0 Comments */ //////////////////////////////////////////////////////////////////////////// int WINAPI_LIB G3WireSurface(LPFNWIRES lpfnF, double dMinX, double dMaxX, double dMinY, double dMaxY, int nXDivs, int nYDivs) { register int i; // x direction index register int j; // y direction index double xb, xf; // x coordinates of the current "wire loop" double yb, yf; // y coordinates of the current "wire loop" double DeltaX, // Dimensions of one loop DeltaY; POINT pPoints[4]; // Corner points of one "wire loop" HCURSOR hOldCursor; POINT HUGE * pOPns; // Pointer to the table for old round values if (lpfnF == NULL || nXDivs < 1 || nYDivs < 1 || dMinX >= dMaxX || dMinY >= dMaxY) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_INVPAR); return 0; } if ((pOPns = (POINT HUGE *) GlobalAllocPtr(GMEM_MOVEABLE, sizeof(POINT) * (nYDivs + 1))) == NULL ) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_MEM); return 0; } hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); DeltaX = (dMaxX - dMinX) / nXDivs; DeltaY = (dMaxY - dMinY) / nYDivs; xf = dMinX; for (i = 0; i < nXDivs; i++) { xb = xf; xf = dMinX + (i+1)*DeltaX; yf = dMinY; for (j = 0; j < nYDivs; j++) { yb = yf; yf = dMinY + (j+1)*DeltaY; if (i) { pPoints[0] = pOPns[j]; pPoints[1] = pOPns[j + 1]; } else { pPoints[0] = G3ToViewport(xb, yb, lpfnF(xb, yb)); pPoints[1] = G3ToViewport(xb, yf, lpfnF(xb, yf)); } pPoints[2] = G3ToViewport(xf, yf, lpfnF(xf, yf)); pOPns[j] = pPoints[3] = G3ToViewport(xf, yb, lpfnF(xf, yb)); if (!Polygon(GhDC, pPoints, 4)) { (void)GlobalFreePtr(pOPns); SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_POLYGON); SetCursor(hOldCursor); return 0; } } pOPns[nYDivs] = pPoints[2]; } (void)GlobalFreePtr(pOPns); SetCursor(hOldCursor); return 1; } //////////////////////////////////////////////////////////////////////////// /* G3Polygon() draws a polygon in 3D space. Parameter Description lpG3Points Far pointer to the polygon vertexes. The last point is automatically connected to the first. So, don't specify it twice nPoints Number of points in the array Returns The return value is nonzero if the function is successful, otherwise it's 0. Comments */ //////////////////////////////////////////////////////////////////////////// int WINAPI_LIB G3Polygon(LPG3POINT lpG3Points, int nPoints) { POINT HUGE * lpPoints; lpPoints = (POINT HUGE *) GlobalAllocPtr(GMEM_MOVEABLE, sizeof(POINT)* nPoints); if (!lpPoints) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_MEM); return 0; } G3G3ToViewport(lpG3Points, (LPPOINT) lpPoints, nPoints); if (!Polygon(GhDC, (LPPOINT) lpPoints, nPoints)) { SetWindowWord(GhWnd, IERRPOS, (WORD) G3ERR_MEM); return 0; } (void)GlobalFreePtr(lpPoints); return 1; }