2 * Copyright (c) 1999 Greg Haerr <greg@censoft.com>
4 * 3D Graphics Library for Micro-Windows
6 #define MWINCLUDECOLORS
10 #define USEBLIT 1 /* =1 to use memDC's*/
18 static double Q[5][5];
21 static HBITMAP hbmp, hbmpOrg;
23 /* setup eye, direction, calc observation matrix Q*/
25 look3(vec1 x, vec1 y, vec1 z)
37 init3(HDC hDC, HWND memhwnd)
43 nxpix = hdc->hwnd->clirect.right - hdc->hwnd->clirect.left;
44 nypix = hdc->hwnd->clirect.bottom - hdc->hwnd->clirect.top;
45 xscale = (vec1)(nxpix-1) / nxpix * nxpix/2;
46 yscale = (vec1)(nypix-1) / nypix * nypix/2;
49 hdcMem = CreateCompatibleDC(NULL);
51 hbmp = CreateCompatibleBitmap(hdcMem,
53 hbmpOrg = SelectObject(hdcMem, hbmp);
56 hbr = (HBRUSH)GetClassLong(memhwnd, GCL_HBRBACKGROUND);
57 FillRect(hdc, NULL, hbr);
59 /* create pen for setcolor3() color override*/
60 SelectObject(hdc, CreatePen(PS_SOLID, 1, BLACK));
68 BitBlt(hDC, 0, 0, nxpix, nypix, hdcMem, 0, 0, SRCCOPY);
69 DeleteObject(SelectObject(hdcMem, hbmpOrg));
78 return (int)(x * xscale + nxpix*0.5 - 0.5);
84 return (int)(y * yscale + nypix*0.5 - 0.5);
90 MoveToEx(hdc, fx(pt.x), fy(pt.y), NULL);
94 setcolor3(MWCOLORVAL c)
103 LineTo(hdc, fx(pt.x), fy(pt.y));
107 polyfill(int n, vec2 points[])
116 /* calc window offset*/
117 xoff = hdc->hwnd->clirect.left;
118 yoff = hdc->hwnd->clirect.top;
120 /* only plot non-trivial polygons*/
123 pv[i].x = fx(points[i].x) + xoff;
124 pv[i].y = fy(points[i].y) + yoff;
125 /* fix: floating round error, y intercept difference
128 /*pv[i].x = fx(points[i].x + xoff);*/
129 /*pv[i].y = fy(points[i].y + yoff);*/
131 GdSetForeground(GdFindColor(hdc->pen->color));
132 GdFillPoly(hdc->psd, n, pv);
139 vec2 pt0, pt1, pt2, pt3;
141 pt0.x = -1; pt0.y = 1;
142 pt1.x = -1; pt1.y = -1;
143 pt2.x = 1; pt2.y = -1;
144 pt3.x = 1; pt3.y = 1;
156 vec1 thinc = 2*pi/100;
164 for(i=0; i<100; ++i) {
165 theta = theta + thinc;
173 daisy(vec1 r,int points)
180 /* calculate n points on a circle*/
182 for(i=0; i<points; ++i) {
183 pt[i].x = r*cos(theta);
184 pt[i].y = r*sin(theta);
188 /* join point i to point j for all 0 <= i < j < n */
189 for(i=0; i<points-1; ++i) {
190 for(j=i+1; j<points; ++j) {
198 rose(vec1 r,int levels,int points)
201 vec1 r1, theta, thinc;
210 /* initial inner circle*/
216 /* loop thru m levels*/
217 for(j=1; j<=m; ++j) {
221 /* calc n points on outer circle*/
224 outer[i].x = r1*cos(theta);
225 outer[i].y = r1*sin(theta);
228 /* construct/draw triangles with vertices on
229 * inner and outer circles
232 triangle[0] = outer[i];
233 triangle[1] = outer[(i+1) % n];
234 triangle[2] = inner[i];
236 /* fill triangle in red*/
238 polyfill(3, triangle);
241 /* outline triangle in white*/
243 moveto3(triangle[0]);
244 lineto3(triangle[1]);
245 lineto3(triangle[2]);
246 lineto3(triangle[0]);
250 /* copy points on outer circle to inner arrays*/
256 /* draw a triangle with cordners v0, v1, v2*/
258 triangle(vec2 v0, vec2 v1, vec2 v2)
275 /* draw a quadrilateral with corners v0, v1, v2, v3*/
277 quadrilateral(vec2 v0, vec2 v1, vec2 v2, vec2 v3)
295 /* find intersection of lines v0 to v1 and v2 to v3*/
297 patch(vec2 v0, vec2 v1, vec2 v2, vec2 v3)
303 denom = (v1.x-v0.x)*(v3.y-v2.y) - (v1.y-v0.y)*(v3.x-v2.x);
304 if(fabs(denom) > epsilon) {
305 mu = ((v2.x-v0.x)*(v3.y-v2.y) - (v2.y-v0.y)*(v3.x-v2.x))/denom;
307 /* if intersection between lines v0 to v1 and v2 to v3,
308 * call it v4 and form triangles v0,v2,v4 and v1,v3,v4
310 if(mu >= 0 && mu <= 1) {
311 v4.x = (1-mu)*v0.x + mu*v1.x;
312 v4.y = (1-mu)*v0.y + mu*v1.y;
313 triangle(v0, v2, v4);
314 triangle(v1, v3, v4);
319 /* else find intersection of lines v0 to v2 and v1 to v3*/
320 denom = (v2.x-v0.x)*(v3.y-v1.y) - (v2.y-v0.y)*(v3.x-v1.x);
321 if(fabs(denom) > epsilon) {
322 mu = ((v1.x-v0.x)*(v3.y-v1.y) - (v1.y-v0.y)*(v3.x-v1.x))/denom;
324 /* if intersection between v0 and v1, call it v4
325 * and form triangles v0,v1,v4 and v2,v3,v4
327 if(mu >= 0 && mu <= 1) {
328 v4.x = (1-mu)*v0.x + mu*v2.x;
329 v4.y = (1-mu)*v0.y + mu*v2.y;
330 triangle(v0, v1, v4);
331 triangle(v2, v3, v4);
336 /* there are no proper intersections so form quadrilateral v0,v1,v3,v2*/
337 quadrilateral(v0, v1, v3, v2);
341 /* plotted function*/
343 plotfn(vec1 x, vec1 z)
347 /* y = 4sin(sqrt(x*x+z*z))/sqrt(x*x+z*z) */
349 if(fabs(t) < epsilon)
351 return 4.0 * sin(t) / t;
354 /* draw mathematical function plotfn*/
356 drawgrid(vec1 xmin, vec1 xmax, int nx, vec1 zmin, vec1 zmax, int nz)
365 scale3(1.0/(xmax-xmin)*2, 1.0/(xmax-xmin)*2, 1.0/(zmax-zmin), S);
368 /* grid from xmin to xmax in nx steps and zmin to xmax in nz steps*/
369 xstep = (xmax-xmin)/nx;
370 zstep = (zmax-zmin)/nz;
374 /* calc grid points on first fixed-z line, fine the y-height
375 * and transfrorm the points (xi,yij,zj) into observed
376 * position. Observed first set stored in v[0,1..nx]
378 for(i=0; i<=nx; ++i) {
379 yij = plotfn(xi, zj);
380 v[0][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj;
381 v[0][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj;
385 /* run thru consecutive fixed-z lines (the second set)*/
386 for(j=0; j<nz; ++j) {
390 /* calc grid points on this second set, find the
391 * y-height and transform the points (xi,yij,zj)
392 * into observed position. Observed second set
393 * stored in v[1,0..nx]
395 for(i=0; i<=nx; ++i) {
396 yij = plotfn(xi, zj);
397 v[1][i].x = Q[1][1]*xi + Q[1][2]*yij + Q[1][3]*zj;
398 v[1][i].y = Q[2][1]*xi + Q[2][2]*yij + Q[2][3]*zj;
402 /* run thru the nx patches formed by these two sets*/
404 patch(v[0][i], v[0][i+1], v[1][i], v[1][i+1]);
406 /* copy second set into first set*/
412 /* returns the angle whose tangent is y/x.
413 * all anomalies such as x=0 are also checked
416 angle(vec1 x, vec1 y)
418 if(fabs(x) < epsilon)
419 if(fabs(y) < epsilon)
427 return atan(y/x) + pi;
428 else return atan(y/x);
431 /* calc 3d scaling matrix A giving scaling vector sx,sy,sz.
432 * one unit on the x axis becomes sx units, one unit on y, sy,
433 * and one unit on the z axis becomes sz units
436 scale3(vec1 sx, vec1 sy, vec1 sz, double A[][5])
449 /* calc 3d axes translation matrix A
450 * origin translated by vectdor tx,ty,tz
453 tran3(vec1 tx, vec1 ty, vec1 tz, double A[][5])
467 /* calc 3d axes rotation matrix A. The axes are
468 * rotated anti-clockwise through an angle theta radians
469 * about an axis specified by m: m=1 means x, m=2 y, m=3 z axis
472 rot3(int m, vec1 theta, double A[][5])
492 /* calc the matrix product C of two matrices A and B*/
494 mult3(double A[][5], double B[][5], double C[][5])
503 ab += A[i][k] * B[k][j];
508 /* calc observation matrix Q for given observer*/
512 vec1 alpha, beta, gamma, v, w;
519 /* calc translation matrix F*/
520 tran3(eye.x, eye.y, eye.z, F);
522 /* calc rotation matrix G*/
523 alpha = angle(-direct.x, -direct.y);
526 /* calc rotation matrix H*/
527 v = sqrt(direct.x*direct.x + direct.y*direct.y);
528 beta = angle(-direct.z, v);
531 /* calc rotation matrix U*/
532 w = sqrt(v*v + direct.z*direct.z);
533 gamma = angle(-direct.x*w, direct.y*direct.z);
536 /* combine the transformations to find Q*/