Mercurial > ecos
diff packages/services/gfx/mw/current/src/mwin/winlib/graph3d.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/services/gfx/mw/current/src/mwin/winlib/graph3d.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 1999 Greg Haerr <greg@censoft.com> + * + * 3D Graphics Library for Micro-Windows + */ +#define MWINCLUDECOLORS +#include "windows.h" +#include "device.h" +#include "graph3d.h" +#define USEBLIT 1 /* =1 to use memDC's*/ + +static int nxpix; +static int nypix; +static vec1 xscale; +static vec1 yscale; +static vec3 eye; +static vec3 direct; +static double Q[5][5]; +static HDC hdc; +static HDC hdcMem; +static HBITMAP hbmp, hbmpOrg; + +/* setup eye, direction, calc observation matrix Q*/ +void +look3(vec1 x, vec1 y, vec1 z) +{ + eye.x = x; + eye.y = y; + eye.z = z; + direct.x = -eye.x; + direct.y = -eye.y; + direct.z = -eye.z; + findQ(); +} + +void +init3(HDC hDC, HWND memhwnd) +{ + HBRUSH hbr; + + hdc = hDC; + if(hdc) { + nxpix = hdc->hwnd->clirect.right - hdc->hwnd->clirect.left; + nypix = hdc->hwnd->clirect.bottom - hdc->hwnd->clirect.top; + xscale = (vec1)(nxpix-1) / nxpix * nxpix/2; + yscale = (vec1)(nypix-1) / nypix * nypix/2; + + if(memhwnd) { + hdcMem = CreateCompatibleDC(NULL); + if(hdcMem) { + hbmp = CreateCompatibleBitmap(hdcMem, + nxpix, nypix); + hbmpOrg = SelectObject(hdcMem, hbmp); + hdc = hdcMem; + } + hbr = (HBRUSH)GetClassLong(memhwnd, GCL_HBRBACKGROUND); + FillRect(hdc, NULL, hbr); + } + /* create pen for setcolor3() color override*/ + SelectObject(hdc, CreatePen(PS_SOLID, 1, BLACK)); + } +} + +void +paint3(HDC hDC) +{ + if(hdcMem) { + BitBlt(hDC, 0, 0, nxpix, nypix, hdcMem, 0, 0, SRCCOPY); + DeleteObject(SelectObject(hdcMem, hbmpOrg)); + DeleteDC(hdcMem); + } + hdcMem = NULL; +} + +int +fx(vec1 x) +{ + return (int)(x * xscale + nxpix*0.5 - 0.5); +} + +int +fy(vec1 y) +{ + return (int)(y * yscale + nypix*0.5 - 0.5); +} + +void +moveto3(vec2 pt) +{ + MoveToEx(hdc, fx(pt.x), fy(pt.y), NULL); +} + +void +setcolor3(MWCOLORVAL c) +{ + if(hdc) + hdc->pen->color = c; +} + +void +lineto3(vec2 pt) +{ + LineTo(hdc, fx(pt.x), fy(pt.y)); +} + +void +polyfill(int n, vec2 points[]) +{ + int i; + int xoff, yoff; + MWPOINT pv[MAXPOLY]; + + if(!hdc) + return; + + /* calc window offset*/ + xoff = hdc->hwnd->clirect.left; + yoff = hdc->hwnd->clirect.top; + + /* only plot non-trivial polygons*/ + if(n > 2) { + for(i=0; i<n; ++i) { + pv[i].x = fx(points[i].x) + xoff; + pv[i].y = fy(points[i].y) + yoff; + /* fix: floating round error, y intercept difference + * with GdLine + */ + /*pv[i].x = fx(points[i].x + xoff);*/ + /*pv[i].y = fy(points[i].y + yoff);*/ + } + GdSetForeground(GdFindColor(hdc->pen->color)); + GdFillPoly(hdc->psd, n, pv); + } +} + +void +square(void) +{ + vec2 pt0, pt1, pt2, pt3; + + pt0.x = -1; pt0.y = 1; + pt1.x = -1; pt1.y = -1; + pt2.x = 1; pt2.y = -1; + pt3.x = 1; pt3.y = 1; + moveto3(pt0); + lineto3(pt1); + lineto3(pt2); + lineto3(pt3); + lineto3(pt0); +} + +void +circle3(vec1 r) +{ + vec1 theta = 0; + vec1 thinc = 2*pi/100; + int i; + vec2 pt; + + pt.x = r; + pt.y = 0.0; + moveto3(pt); + + for(i=0; i<100; ++i) { + theta = theta + thinc; + pt.x = r*cos(theta); + pt.y = r*sin(theta); + lineto3(pt); + } +} + +void +daisy(vec1 r,int points) +{ + int i, j; + vec1 theta = 0; + vec1 thinc; + vec2 pt[100]; + + /* calculate n points on a circle*/ + thinc = 2*pi/points; + for(i=0; i<points; ++i) { + pt[i].x = r*cos(theta); + pt[i].y = r*sin(theta); + theta += thinc; + } + + /* join point i to point j for all 0 <= i < j < n */ + for(i=0; i<points-1; ++i) { + for(j=i+1; j<points; ++j) { + moveto3(pt[i]); + lineto3(pt[j]); + } + } +} + +void +rose(vec1 r,int levels,int points) +{ + int i, j, m, n; + vec1 r1, theta, thinc; + vec2 inner[100]; + vec2 outer[100]; + vec2 triangle[3]; + + m = levels; + n = points; + thinc = 2*pi/n; + + /* initial inner circle*/ + for(i=0; i<n; ++i) { + inner[i].x = 0.0; + inner[i].y = 0.0; + } + + /* loop thru m levels*/ + for(j=1; j<=m; ++j) { + theta = -j*pi/n; + r1 = r * (vec1)j/m; + + /* calc n points on outer circle*/ + for(i=0; i<n; ++i) { + theta += thinc; + outer[i].x = r1*cos(theta); + outer[i].y = r1*sin(theta); + } + + /* construct/draw triangles with vertices on + * inner and outer circles + */ + for(i=0; i<n; ++i) { + triangle[0] = outer[i]; + triangle[1] = outer[(i+1) % n]; + triangle[2] = inner[i]; + + /* fill triangle in red*/ + setcolor3(RED); + polyfill(3, triangle); + +#if 1 + /* outline triangle in white*/ + setcolor3(WHITE); + moveto3(triangle[0]); + lineto3(triangle[1]); + lineto3(triangle[2]); + lineto3(triangle[0]); +#endif + } + + /* copy points on outer circle to inner arrays*/ + for(i=0; i<n; ++i) + inner[i] = outer[i]; + } +} + +/* draw a triangle with cordners v0, v1, v2*/ +void +triangle(vec2 v0, vec2 v1, vec2 v2) +{ + vec2 poly[3]; + + poly[0] = v0; + poly[1] = v1; + poly[2] = v2; + + setcolor3(GREEN); + polyfill(3, poly); + setcolor3(BLACK); + moveto3(poly[2]); + lineto3(poly[0]); + lineto3(poly[1]); + lineto3(poly[2]); +} + +/* draw a quadrilateral with corners v0, v1, v2, v3*/ +void +quadrilateral(vec2 v0, vec2 v1, vec2 v2, vec2 v3) +{ + vec2 poly[4]; + + poly[0] = v0; + poly[1] = v1; + poly[2] = v2; + poly[3] = v3; + setcolor3(GREEN); + polyfill(4, poly); + setcolor3(BLACK); + moveto3(poly[3]); + lineto3(poly[0]); + lineto3(poly[1]); + lineto3(poly[2]); + lineto3(poly[3]); +} + +/* find intersection of lines v0 to v1 and v2 to v3*/ +static int +patch(vec2 v0, vec2 v1, vec2 v2, vec2 v3) +{ + vec1 denom; + vec1 mu; + vec2 v4; + + denom = (v1.x-v0.x)*(v3.y-v2.y) - (v1.y-v0.y)*(v3.x-v2.x); + if(fabs(denom) > epsilon) { + mu = ((v2.x-v0.x)*(v3.y-v2.y) - (v2.y-v0.y)*(v3.x-v2.x))/denom; + + /* if intersection between lines v0 to v1 and v2 to v3, + * call it v4 and form triangles v0,v2,v4 and v1,v3,v4 + */ + if(mu >= 0 && mu <= 1) { + v4.x = (1-mu)*v0.x + mu*v1.x; + v4.y = (1-mu)*v0.y + mu*v1.y; + triangle(v0, v2, v4); + triangle(v1, v3, v4); + return 0; + } + } + + /* else find intersection of lines v0 to v2 and v1 to v3*/ + denom = (v2.x-v0.x)*(v3.y-v1.y) - (v2.y-v0.y)*(v3.x-v1.x); + if(fabs(denom) > epsilon) { + mu = ((v1.x-v0.x)*(v3.y-v1.y) - (v1.y-v0.y)*(v3.x-v1.x))/denom; + + /* if intersection between v0 and v1, call it v4 + * and form triangles v0,v1,v4 and v2,v3,v4 + */ + if(mu >= 0 && mu <= 1) { + v4.x = (1-mu)*v0.x + mu*v2.x; + v4.y = (1-mu)*v0.y + mu*v2.y; + triangle(v0, v1, v4); + triangle(v2, v3, v4); + return 0; + } + } + + /* there are no proper intersections so form quadrilateral v0,v1,v3,v2*/ + quadrilateral(v0, v1, v3, v2); + return 1; +} + +/* plotted function*/ +static vec1 +plotfn(vec1 x, vec1 z) +{ + vec1 t; + + /* y = 4sin(sqrt(x*x+z*z))/sqrt(x*x+z*z) */ + t = sqrt(x*x + z*z); + if(fabs(t) < epsilon) + return 4.0; + return 4.0 * sin(t) / t; +} + +/* draw mathematical function plotfn*/ +void +drawgrid(vec1 xmin, vec1 xmax, int nx, vec1 zmin, vec1 zmax, int nz) +{ + int i, j; + vec1 xi, xstep, yij; + vec1 zj, zstep; + vec2 v[2][100]; + double S[5][5]; + + /* scale it down*/ + scale3(1.0/(xmax-xmin)*2, 1.0/(xmax-xmin)*2, 1.0/(zmax-zmin), S); + mult3(Q, S, Q); + + /* grid from xmin to xmax in nx steps and zmin to xmax in nz steps*/ + xstep = (xmax-xmin)/nx; + zstep = (zmax-zmin)/nz; + xi = xmin; + zj = zmin; + + /* calc grid points on first fixed-z line, fine the y-height + * and transfrorm the points (xi,yij,zj) into observed + * position. Observed first set stored in v[0,1..nx] + */ + for(i=0; i<=nx; ++i) { + yij = plotfn(xi, zj); + v[0][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj; + v[0][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj; + xi += xstep; + } + + /* run thru consecutive fixed-z lines (the second set)*/ + for(j=0; j<nz; ++j) { + xi = xmin; + zj += zstep; + + /* calc grid points on this second set, find the + * y-height and transform the points (xi,yij,zj) + * into observed position. Observed second set + * stored in v[1,0..nx] + */ + for(i=0; i<=nx; ++i) { + yij = plotfn(xi, zj); + v[1][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj; + v[1][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj; + xi += xstep; + } + + /* run thru the nx patches formed by these two sets*/ + for(i=0; i<nx; ++i) + patch(v[0][i], v[0][i+1], v[1][i], v[1][i+1]); + + /* copy second set into first set*/ + for(i=0; i<=nx; ++i) + v[0][i] = v[1][i]; + } +} + +/* returns the angle whose tangent is y/x. + * all anomalies such as x=0 are also checked + */ +vec1 +angle(vec1 x, vec1 y) +{ + if(fabs(x) < epsilon) + if(fabs(y) < epsilon) + return 0.0; + else + if(y > 0.0) + return pi*0.5; + else return pi*1.5; + else + if(x < 0.0) + return atan(y/x) + pi; + else return atan(y/x); +} + +/* calc 3d scaling matrix A giving scaling vector sx,sy,sz. + * one unit on the x axis becomes sx units, one unit on y, sy, + * and one unit on the z axis becomes sz units + */ +void +scale3(vec1 sx, vec1 sy, vec1 sz, double A[][5]) +{ + int i, j; + + for(i=1; i<5; ++i) + for(j=1; j<5; ++j) + A[i][j] = 0.0; + A[1][1] = sx; + A[2][2] = sy; + A[3][3] = sz; + A[4][4] = 1.0; +} + +/* calc 3d axes translation matrix A + * origin translated by vectdor tx,ty,tz + */ +void +tran3(vec1 tx, vec1 ty, vec1 tz, double A[][5]) +{ + int i, j; + + for(i=1; i<5; ++i) { + for(j=1; j<5; ++j) + A[i][j] = 0.0; + A[i][i] = 1.0; + } + A[1][4] = -tx; + A[2][4] = -ty; + A[3][4] = -tz; +} + +/* calc 3d axes rotation matrix A. The axes are + * rotated anti-clockwise through an angle theta radians + * about an axis specified by m: m=1 means x, m=2 y, m=3 z axis + */ +void +rot3(int m, vec1 theta, double A[][5]) +{ + int i, j, m1, m2; + vec1 c, s; + + for(i=1; i<5; ++i) + for(j=1; j<5; ++j) + A[i][j] = 0.0; + A[m][m] = 1.0; + A[4][4] = 1.0; + m1 = (m % 3) + 1; + m2 = (m1 % 3) + 1; + c = cos(theta); + s = sin(theta); + A[m1][m1] = c; + A[m2][m2] = c; + A[m1][m2] = s; + A[m2][m1] = s; +} + +/* calc the matrix product C of two matrices A and B*/ +void +mult3(double A[][5], double B[][5], double C[][5]) +{ + int i, j, k; + vec1 ab; + + for(i=1; i<5; ++i) + for(j=1; j<5; ++j) { + ab = 0; + for(k=1; k<5; ++k) + ab += A[i][k] * B[k][j]; + C[i][j] = ab; + } +} + +/* calc observation matrix Q for given observer*/ +void +findQ(void) +{ + vec1 alpha, beta, gamma, v, w; + double E[5][5]; + double F[5][5]; + double G[5][5]; + double H[5][5]; + double U[5][5]; + + /* calc translation matrix F*/ + tran3(eye.x, eye.y, eye.z, F); + + /* calc rotation matrix G*/ + alpha = angle(-direct.x, -direct.y); + rot3(3, alpha, G); + + /* calc rotation matrix H*/ + v = sqrt(direct.x*direct.x + direct.y*direct.y); + beta = angle(-direct.z, v); + rot3(2, beta, H); + + /* calc rotation matrix U*/ + w = sqrt(v*v + direct.z*direct.z); + gamma = angle(-direct.x*w, direct.y*direct.z); + rot3(3, -gamma, U); + + /* combine the transformations to find Q*/ + mult3(G, F, Q); + mult3(H, Q, E); + mult3(U, E, Q); +}
