URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [mw/] [src/] [mwin/] [winlib/] [graph3d.c] - Rev 1780
Go to most recent revision | Compare with Previous | Blame | View Log
/* * 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); }
Go to most recent revision | Compare with Previous | Blame | View Log