|
|
1.1 root 1: /*--------------------------------------------------------*\
2: SDRAW.C - 3D to 2D transformations and draw routines
3: \*--------------------------------------------------------*/
4:
5: #include <stddef.h>
6: #include <os2.h>
7: #include <math.h>
8: #include "sstruct.h"
9:
10: extern SHAPE rgshape [];
11:
12: POINT3D pt3FillBuffer [MAX_POINTS];
13:
14: extern INT yPelAdjust;
15:
16:
17: /*
18: * ScalePoint:
19: * - replace destination point by source point after scaling
20: */
21:
22: VOID ScalePoint (
23: POINT3D *ppt3Source,
24: POINT3D *ppt3Dest,
25: LONG iScale )
26: {
27: ppt3Dest->x = (INT) ( ((LONG) ppt3Source->x * iScale) >> 6 );
28: ppt3Dest->y = (INT) ( ((LONG) ppt3Source->y * iScale) >> 6 );
29: ppt3Dest->z = (INT) ( ((LONG) ppt3Source->z * iScale) >> 6 );
30: }
31:
32:
33: /*
34: * ChangeScale:
35: * - to be called after a window changes size
36: * - scales a shape's appropriate variables for the new size
37: * - the centre of the window indicates the new window size
38: */
39:
40: extern VOID ChangeScale (
41: PSV psv )
42: {
43: LONG xScale = psv->ptCentre.x;
44: LONG yScale = (psv->ptCentre.y << 10) / yPelAdjust;
45: LONG iScale = (xScale > yScale) ? yScale : xScale;
46: INIT *pinit = rgshape [psv->iShape].pinit;
47:
48: if (iScale < MIN_SCALE)
49: {
50: /* set lower bound on the scale of a shape */
51:
52: iScale = MIN_SCALE;
53: }
54:
55: /* scale the initial size of the shape */
56:
57: ScalePoint (&pinit->pt3SizeMid, &psv->pt3Size, iScale);
58: psv->pt3SizeMid = psv->pt3Size;
59:
60: /* scale the magnitude of the sinusoidal size change */
61:
62: ScalePoint (&pinit->pt3SizeMag, &psv->pt3SizeMag, iScale);
63:
64: /* scale the viewing distance */
65: /* (so that perspective is independent of window size) */
66:
67: psv->zViewDist = pinit->zViewDist * iScale;
68: }
69:
70:
71: /*
72: * lSin:
73: * - fast integer sine function with granularity of 1 degree
74: * - constraint: -360 <= angle <= 360
75: * - returns the sine of an angle * 16384 (shifted left by 14)
76: */
77:
78: LONG lSin(
79: INT iAngle )
80: {
81: static INT iSinTable [91] =
82: { 0, 286, 572, 857, 1143, 1428, 1713, 1997, 2280, 2563, 2845, 3126,
83: 3406, 3686, 3964, 4240, 4516, 4790, 5063, 5334, 5604, 5872, 6138,
84: 6402, 6664, 6924, 7182, 7438, 7692, 7943, 8192, 8438, 8682, 8923,
85: 9162, 9397, 9630, 9860, 10087, 10311, 10531, 10749, 10963, 11174,
86: 11381, 11585, 11786, 11982, 12176, 12365, 12551, 12733, 12911, 13085,
87: 13255, 13421, 13583, 13741, 13894, 14044, 14189, 14330, 14466, 14598,
88: 14726, 14849, 14968, 15082, 15191, 15296, 15396, 15491, 15582, 15668,
89: 15749, 15826, 15897, 15964, 16026, 16083, 16135, 16182, 16225, 16262,
90: 16294, 16322, 16344, 16362, 16374, 16382, 16384 };
91:
92: if (iAngle < 0)
93: iAngle += 360;
94:
95: if (iAngle < 180)
96: if (iAngle < 90)
97: return( (LONG) iSinTable [iAngle] );
98: else
99: return( (LONG) iSinTable [180 - iAngle] );
100: else
101: if (iAngle < 270)
102: return( (LONG) -iSinTable [iAngle - 180] );
103: else
104: return( (LONG) -iSinTable [360 - iAngle] );
105: }
106:
107:
108: /*
109: * iAngleAdd (macro):
110: * - adds the second angle to first angle
111: * - stores result (which is in range 0 to 359) in the first angle
112: */
113:
114: #define iAngleAdd( iA1,iA2) \
115: if ( ((iA1) += (iA2)) < 0 ) (iA1) += 360; \
116: else if ( (iA1) >= 360 ) (iA1) -= 360;
117:
118:
119: /*
120: * AddToAngle:
121: * - adds the 3D angular velocity to the 3D angle
122: */
123:
124: VOID AddToAngle(
125: POINT3D *ppt3Angle,
126: POINT3D *ppt3AngVel )
127: {
128: iAngleAdd (ppt3Angle->x, ppt3AngVel->x)
129: iAngleAdd (ppt3Angle->y, ppt3AngVel->y)
130: iAngleAdd (ppt3Angle->z, ppt3AngVel->z)
131: }
132:
133:
134: /*
135: * CalcSize:
136: * - calculates the new size for sinusoidal size variation
137: * ie. <size> = <middle> + <magnitude> * SIN (<angle>)
138: */
139:
140: VOID CalcSize(
141: POINT3D *ppt3Size,
142: POINT3D *ppt3SizeMid,
143: POINT3D *ppt3SizeMag,
144: POINT3D *ppt3SizeAng )
145: {
146: ppt3Size->x = ppt3SizeMid->x +
147: (INT) (ppt3SizeMag->x * lSin( ppt3SizeAng->x ) >> 14);
148: ppt3Size->y = ppt3SizeMid->y +
149: (INT) (ppt3SizeMag->y * lSin( ppt3SizeAng->y ) >> 14);
150: ppt3Size->z = ppt3SizeMid->z +
151: (INT) (ppt3SizeMag->z * lSin( ppt3SizeAng->z ) >> 14);
152: }
153:
154:
155: /*
156: * CalcPoints:
157: * - transform the 3D points to 2D points
158: * - transformation includes:
159: * a) scaling points
160: * b) rotating points around x/y/z axis
161: * c) perspective transformation
162: * d) translating to centre of window
163: */
164:
165: VOID CalcPoints (
166: PSV psv,
167: INT cPoints,
168: POINT3D rgpt3 [],
169: POINTL rgpt [] )
170: {
171: LONG sinx = lSin( psv->pt3Angle.x );
172: LONG cosx = lSin((psv->pt3Angle.x + 90) % 360 );
173: LONG siny = lSin( psv->pt3Angle.y );
174: LONG cosy = lSin((psv->pt3Angle.y + 90) % 360 );
175: LONG sinz = lSin( psv->pt3Angle.z );
176: LONG cosz = lSin((psv->pt3Angle.z + 90) % 360 );
177: LONG x, y, z, x2, y2, z2;
178: LONG z0 = psv->zViewDist;
179: INT i;
180: LONG xSize = psv->pt3Size.x;
181: LONG ySize = psv->pt3Size.y;
182: LONG zSize = psv->pt3Size.z;
183:
184: for( i=0; i < cPoints; i++ )
185: {
186: /* scale points relative to x/y/z axis of shape */
187:
188: x = (LONG) rgpt3 [i].x * xSize;
189: y = (LONG) rgpt3 [i].y * ySize;
190: z = (LONG) rgpt3 [i].z * zSize;
191:
192: /* rotate around X axis */
193:
194: y2 = ( y * cosx - z * sinx ) >> 14;
195: z2 = ( z * cosx + y * sinx ) >> 14;
196:
197: /* rotate around Y axis */
198:
199: z = ( z2 * cosy - x * siny ) >> 14;
200: x2 = ( x * cosy + z2 * siny ) >> 14;
201:
202: /* rotate around Z axis */
203:
204: x = ( x2 * cosz - y2 * sinz ) >> 14;
205: y = ( y2 * cosz + x2 * sinz ) >> 14;
206:
207: if (psv->fShaded)
208: {
209: /* store points used for shading */
210: /* (before perspective - light source is at infinity) */
211:
212: pt3FillBuffer [i].x = (INT) (x >> 8);
213: pt3FillBuffer [i].y = (INT) (y >> 8);
214: pt3FillBuffer [i].z = (INT) (z >> 8);
215: }
216:
217: if (psv->fPerspective)
218: {
219: /* avoid overflow when doing perspective */
220:
221: x = (x * (z0 >> 6)) / ((z0 - z) >> 6);
222: y = (y * (z0 >> 6)) / ((z0 - z) >> 6);
223: }
224:
225: /* store translated points in 2D table */
226: /* note: points must be rescaled to fit in window */
227:
228: rgpt [i].x = (x >> 8) + psv->ptCentre.x;
229: rgpt [i].y = (( (y >> 8) * yPelAdjust ) >> 10) + psv->ptCentre.y;
230: }
231: }
232:
233:
234: /*
235: * DrawLines:
236: * - draws a shape using the lines of the object (clipping off)
237: */
238:
239: VOID DrawLines (
240: HPS hps,
241: LINE rgline [],
242: POINTL rgpt [] )
243: {
244: INT i;
245: INT iPoint1, iPoint2 = -1;
246:
247: for( i=0; (iPoint1 = rgline [i].p1) >= 0; i++ )
248: {
249: if (iPoint1 != iPoint2)
250: {
251: GpiSetCurrentPosition( hps, &rgpt [iPoint1] );
252: }
253: iPoint2 = rgline [i].p2;
254: GpiLine( hps, &rgpt [iPoint2] );
255: }
256: }
257:
258:
259: /*
260: * DrawFaces:
261: * - draws a shape using the faces of the object (clipping on)
262: */
263:
264: VOID DrawFaces (
265: HPS hps,
266: FACE rgface [],
267: POINTL rgpt [] )
268: {
269: INT i = 0;
270: INT iEndFace, cSpread;
271: INT iPoint1, iPoint2, iPoint3;
272: LONG xV1, yV1, xV2, yV2;
273: LONG zNormal;
274:
275: iPoint1 = rgface [i++];
276: do
277: {
278: /* get 3 points spread out on surface */
279:
280: iEndFace = i;
281: while (rgface [iEndFace++] >= 0)
282: ;
283: cSpread = iEndFace - i + 1;
284:
285: if (cSpread > 5)
286: {
287: cSpread /= 3;
288: iPoint2 = rgface [i - 1 + cSpread];
289: iPoint3 = rgface [i - 1 + 2 * cSpread];
290: }
291: else
292: {
293: iPoint2 = rgface [i];
294: iPoint3 = rgface [i + 1];
295: }
296:
297: /* calculate z coordinate of normal (using 3 points on surface) */
298:
299: xV1 = rgpt [iPoint3].x - rgpt [iPoint2].x;
300: yV1 = rgpt [iPoint3].y - rgpt [iPoint2].y;
301: xV2 = rgpt [iPoint1].x - rgpt [iPoint2].x;
302: yV2 = rgpt [iPoint1].y - rgpt [iPoint2].y;
303: zNormal = xV1 * yV2 - yV1 * xV2;
304:
305: if (zNormal > 0)
306: {
307: /* face is pointing towards the user */
308:
309: /* draw the perimeter of the face */
310:
311: GpiSetCurrentPosition( hps, &rgpt [iPoint1] );
312: while (( iPoint2 = rgface [i++] ) >= 0)
313: GpiLine( hps, &rgpt [iPoint2] );
314: GpiLine( hps, &rgpt [iPoint1] );
315:
316: while (iPoint2 == -1)
317: {
318: /* draw a pattern associated with the face */
319:
320: iPoint1 = rgface [i++];
321: GpiSetCurrentPosition( hps, &rgpt [iPoint1] );
322: while ((iPoint2 = rgface [i++] ) >= 0)
323: GpiLine( hps, &rgpt [iPoint2] );
324: }
325: }
326: else
327: /* face is not visible - skip over it */
328:
329: while (rgface [i++] >= -1)
330: ;
331: }
332: while (( iPoint1 = rgface [i++] ) >= 0);
333: }
334:
335:
336: /*
337: * ChangeShapePosition:
338: * - calculate 2D points for new position
339: * - blank out old position
340: * - draw in new position
341: */
342:
343: extern VOID ChangeShapePosition (
344: PSV psv )
345: {
346: HPS hps;
347: POINTL *pptTemp;
348: SHAPE *pshape = &rgshape [psv->iShape];
349: OBJECT *pobject = pshape->pobject;
350:
351: if (psv->fVarySize)
352: {
353: /* vary the size */
354:
355: AddToAngle (&psv->pt3SizeAng, &pshape->pinit->pt3SizeVel );
356: CalcSize (&psv->pt3Size, &psv->pt3SizeMid,
357: &psv->pt3SizeMag, &psv->pt3SizeAng );
358: }
359:
360: /* rotate */
361:
362: AddToAngle (&psv->pt3Angle, &psv->pt3AngVel );
363:
364: /* calculate new position */
365:
366: CalcPoints (psv, pobject->cPoints, pobject->rgpt3, psv->rgptNew );
367:
368: hps = psv->hpsClient;
369:
370: /* blank out old position */
371:
372: if (psv->fErased)
373: psv->fErased = FALSE;
374: else
375: {
376: GpiSetColor (hps, CLR_WHITE);
377: if (psv->fClipping)
378: DrawFaces (hps, pobject->rgface, psv->rgptOld );
379: else
380: DrawLines (hps, pobject->rgline, psv->rgptOld );
381: }
382:
383: /* draw at new position */
384:
385: GpiSetColor (hps, CLR_BLACK);
386: if (psv->fClipping)
387: DrawFaces (hps, pobject->rgface, psv->rgptNew );
388: else
389: DrawLines (hps, pobject->rgline, psv->rgptNew );
390:
391: /* swap 2D points buffers - new becomes old */
392:
393: pptTemp = psv->rgptOld;
394: psv->rgptOld = psv->rgptNew;
395: psv->rgptNew = pptTemp;
396: }
397:
398:
399: VOID DrawAndFill (
400: PSV psv )
401: {
402: HPS hps = psv->hpsClient;
403: OBJECT *pobject = rgshape [psv->iShape].pobject;
404: FACE *rgface = pobject->rgface;
405: POINTL *rgpt = psv->rgptNew;
406: INT i = 0;
407: INT iEndFace, cSpread;
408: INT iPoint1, iPoint2, iPoint3;
409: LONG xV1, yV1, zV1, xV2, yV2, zV2;
410: LONG iDiv;
411: LONG xN, yN, zN;
412: LONG zNormal;
413: LONG sinx = lSin( psv->pt2LightAng.x );
414: LONG cosx = lSin((psv->pt2LightAng.x + 90) % 360 );
415: LONG siny = lSin( psv->pt2LightAng.y );
416: LONG cosy = lSin((psv->pt2LightAng.y + 90) % 360 );
417: POINTL pt;
418:
419: CalcPoints (psv, pobject->cPoints, pobject->rgpt3, rgpt );
420:
421: GpiSavePS (hps);
422: GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
423:
424: iPoint1 = rgface [i++];
425: do
426: {
427: /* get 3 points spread out on surface */
428:
429: iEndFace = i;
430: while (rgface [iEndFace++] >= 0)
431: ;
432: cSpread = iEndFace - i + 1;
433:
434: if (cSpread > 5)
435: {
436: cSpread /= 3;
437: iPoint2 = rgface [i - 1 + cSpread];
438: iPoint3 = rgface [i - 1 + 2 * cSpread];
439: }
440: else
441: {
442: iPoint2 = rgface [i];
443: iPoint3 = rgface [i + 1];
444: }
445:
446: /* calculate z coordinate of normal (using 3 points on surface) */
447:
448: xV1 = rgpt [iPoint3].x - rgpt [iPoint2].x;
449: yV1 = rgpt [iPoint3].y - rgpt [iPoint2].y;
450: xV2 = rgpt [iPoint1].x - rgpt [iPoint2].x;
451: yV2 = rgpt [iPoint1].y - rgpt [iPoint2].y;
452: zNormal = xV1 * yV2 - yV1 * xV2;
453:
454: if (zNormal > 0)
455: {
456: /* face is pointing towards the user */
457:
458: /* normalize vectors */
459:
460: xV1 = pt3FillBuffer [iPoint3].x - pt3FillBuffer [iPoint2].x;
461: yV1 = pt3FillBuffer [iPoint3].y - pt3FillBuffer [iPoint2].y;
462: zV1 = pt3FillBuffer [iPoint3].z - pt3FillBuffer [iPoint2].z;
463:
464: xV2 = pt3FillBuffer [iPoint1].x - pt3FillBuffer [iPoint2].x;
465: yV2 = pt3FillBuffer [iPoint1].y - pt3FillBuffer [iPoint2].y;
466: zV2 = pt3FillBuffer [iPoint1].z - pt3FillBuffer [iPoint2].z;
467:
468: iDiv = (LONG) sqrt ((double) (xV1 * xV1 + yV1 * yV1 + zV1 * zV1) );
469: xV1 = (xV1 << 10) / iDiv;
470: yV1 = (yV1 << 10) / iDiv;
471: zV1 = (zV1 << 10) / iDiv;
472:
473: iDiv = (LONG) sqrt ((double) (xV2 * xV2 + yV2 * yV2 + zV2 * zV2) );
474: xV2 = (xV2 << 10) / iDiv;
475: yV2 = (yV2 << 10) / iDiv;
476: zV2 = (zV2 << 10) / iDiv;
477:
478: /* calculate normal to surface */
479:
480: xN = (yV1 * zV2 - zV1 * yV2) >> 10;
481: yN = (zV1 * xV2 - xV1 * zV2) >> 10;
482: zN = (xV1 * yV2 - yV1 * xV2) >> 10;
483:
484: /* rotate normal around X and Y axes */
485:
486: zN = ( zN * cosx + xN * sinx ) >> 14;
487: zN = ( zN * cosy + yN * siny ) >> 14;
488:
489: /* change range of zNormal from [0,1023] to [128,255] */
490:
491: zNormal = zN >> 3;
492: if (zNormal < 0)
493: zNormal = 0;
494: else if (zNormal > 127)
495: zNormal = 127;
496: zNormal += 128;
497:
498: GpiSetColor (hps, zNormal);
499:
500: /* draw the perimeter of the face */
501:
502: GpiBeginArea (hps, BA_NOBOUNDARY | BA_ALTERNATE);
503:
504: GpiSetCurrentPosition( hps, &rgpt [iPoint1] );
505: while (( iPoint2 = rgface [i++] ) >= 0)
506: GpiLine( hps, &rgpt [iPoint2] );
507: GpiLine( hps, &rgpt [iPoint1] );
508:
509: GpiEndArea (hps);
510:
511: GpiSetColor (hps, zNormal << 16 );
512:
513: while (iPoint2 == -1)
514: {
515: /* draw a pattern associated with the face */
516:
517: iPoint1 = rgface [i++];
518: GpiSetCurrentPosition( hps, &rgpt [iPoint1] );
519: while ((iPoint2 = rgface [i++] ) >= 0)
520: GpiLine( hps, &rgpt [iPoint2] );
521: }
522: }
523: else
524: /* face is not visible - skip over it */
525:
526: while (rgface [i++] >= -1)
527: ;
528: }
529: while (( iPoint1 = rgface [i++] ) >= 0);
530:
531: GpiRestorePS (hps, -1L);
532: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.