home *** CD-ROM | disk | FTP | other *** search
/ Quake++ for Quake / Quake++.iso / quake / qkview / threedq.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-10  |  6.9 KB  |  302 lines

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4.  
  5. // delete this later:
  6. #include <applicat.h>
  7.  
  8. #include "threedq.h"
  9. #include "quake.h"
  10.  
  11. #define Pi 3.141592653589793238
  12.  
  13. inline double MaxOf(double v1, double v2)
  14. {
  15.     return (v1 > v2) ? v1 : v2;
  16. }
  17.  
  18. extern ARRAY<plane_t> planes;
  19. extern ARRAY<dsurface_t> surfaces;
  20.  
  21. extern ARRAY<vertex_t> vertices;
  22. extern ARRAY<edge_t> edges;
  23.  
  24.  
  25. TThreeD::TThreeD()
  26. {
  27.     Vb = VB; Vt = VT;
  28.     Vr = VR; Vl = VL;
  29.  
  30.     A = (Vr -Vl) / 2.0;
  31.     B = Vl + A;
  32.     C = (Vt - Vb) / 2.0;
  33.     D = Vb + C;
  34.  
  35.     // Set default values for FROM, AT, UP
  36.     From.x = 1.0;  From.y = 0.0;  From.z = 0.0;
  37.     At.x   = 0.0;  At.y   = 0.0;  At.z   = 0.0;
  38.     Up.x   = 0.0;  Up.y   = 0.0;  Up.z   = 1.0;
  39.  
  40.     Angle  = 60.0 * Pi / 180.0;   // 60 deg converted to radians
  41. }
  42.  
  43.  
  44. // High-level routine to display wireframe model
  45. void TThreeD::Display(HDC DC, RECT& rect)
  46. {
  47.     // Use isotropic mapping to make sure x and y coordinates are
  48.     // displayed in the same way
  49.     SetMapMode(DC,MM_ISOTROPIC);
  50.  
  51.     SetWindowExt(DC, VR-VL, VB-VT);
  52.  
  53.  
  54.     if (rect.right <= rect.bottom) {
  55.         SetViewportOrg(DC,-(rect.bottom-rect.right)/2,0);
  56.         SetViewportExt(DC,rect.bottom,rect.bottom);
  57.     }
  58.     else {
  59.         SetViewportOrg(DC,0,-(rect.right-rect.bottom)/2);
  60.         SetViewportExt(DC,rect.right,rect.right);
  61.     }
  62.  
  63.  
  64.     SetEye();
  65.     View(DC);
  66. }
  67.  
  68.  
  69. // Convert Clipped coordinates to window coordinates
  70. inline void TThreeD::WORLDtoPC(double xw, double yw, POINT& pc)
  71. {
  72.     pc.x = (int)(A * xw + B);
  73.     pc.y = (int)(C * yw + D);
  74. }
  75.  
  76.  
  77. // Find the minimum/maximum coordinates.
  78. void TThreeD::MinMax()
  79. {
  80.     ObjMinx = Points[1].x; ObjMiny = Points[1].y; ObjMinz = Points[1].z;
  81.     ObjMaxx = Points[1].x; ObjMaxy = Points[1].y; ObjMaxz = Points[1].z;
  82.  
  83.     for (long i=1; i<=Vertices; i++) {
  84.         if (Points[i].x > ObjMaxx) { ObjMaxx = Points[i].x; }
  85.         else if (Points[i].x <ObjMinx) { ObjMinx = Points[i].x; }
  86.  
  87.         if (Points[i].y > ObjMaxy) { ObjMaxy = Points[i].y; }
  88.         else if (Points[i].y <ObjMiny) { ObjMiny = Points[i].y; }
  89.  
  90.         if (Points[i].z > ObjMaxz) { ObjMaxz = Points[i].z; }
  91.         else if (Points[i].z <ObjMinz) { ObjMinz = Points[i].z; }
  92.     }
  93. }
  94.  
  95.  
  96. // Default value for AT
  97. void TThreeD::SetAt()
  98. {
  99.     MinMax();
  100.  
  101.     At.x = (ObjMaxx + ObjMinx) / 2.0;
  102.     At.y = (ObjMaxy + ObjMiny) / 2.0;
  103.     At.z = (ObjMaxz + ObjMinz) / 2.0;
  104. }
  105.  
  106.  
  107. // default value for FROM
  108. void TThreeD::SetFrom()
  109. {
  110.     const double WIDTH = 1.8; // ratio used
  111.     From.x = At.x + (ObjMaxx -ObjMinx) / 2.0 + WIDTH *
  112.                 MaxOf((ObjMaxz-ObjMinz)/2.0, (ObjMaxy-ObjMiny)/2.0);
  113.     From.y = At.y;
  114.     From.z = At.z;
  115. }
  116.  
  117. // Set up parameters in the world to eye transformation.
  118. void TThreeD::SetEye()
  119. {
  120.     VECTOR temp;
  121.  
  122.     DVal = cos(Angle/2.0) / sin(Angle/2.0);
  123.  
  124.  
  125.     Dist = Subtract(At, From);
  126.     double amarkmag = Mag(Dist);
  127.     A3 = Divide(Dist, amarkmag);
  128.  
  129.     temp = Cross(Dist, Up);
  130.     double tempmag = Mag(temp);
  131.     A1 = Divide(temp,tempmag);
  132.  
  133.     temp = Cross(A1, A3);
  134.     tempmag = Mag(temp);
  135.     A2 = Divide(temp,tempmag);
  136.  
  137.     Offsx = -A1.x * From.x - A1.y * From.y - A1.z * From.z;
  138.     Offsy = -A2.x * From.x - A2.y * From.y - A2.z * From.z;
  139.     Offsz = -A3.x * From.x - A3.y * From.y - A3.z * From.z;
  140.  
  141. }
  142.  
  143. const int NOEDGE = 0;
  144. const int LEFTEDGE = 1;
  145. const int RIGHTEDGE = 2;
  146. const int BOTTOMEDGE = 4;
  147. const int TOPEDGE = 8;
  148.  
  149. int TThreeD::Code(double x, double y, double z)
  150. {
  151.     int c = NOEDGE;
  152.  
  153.     if (x < -z) c |= LEFTEDGE;
  154.     if (x > z)  c |= RIGHTEDGE;
  155.     if (y < -z) c |= BOTTOMEDGE;
  156.     if (y > z)  c |= TOPEDGE;
  157.  
  158.     return (c);
  159. }
  160.  
  161. // Clip the line in 3d coordinates
  162. void TThreeD::Clip3D(HDC DC, double x1, double y1, double z1,
  163.                             double x2, double y2, double z2, POINT& pc1, POINT& pc2)
  164. {
  165.     int c, c1, c2;
  166.     double x, y, z, t;
  167.     c1 = Code(x1,y1,z1);
  168.     if (c1 > 16) cout << "ERROR (c1): " << x1 << " " << y1 << " "
  169.                                                     << z1 << " " << c1 << "\n";
  170.  
  171.     c2 = Code(x2,y2,z2);
  172.     if (c2 > 16) cout << "ERROR (c2): " << x2 << " " << y2 << " "
  173.                                                     << z2 << " " << c2 << "\n";
  174.  
  175.     while ((c1 != NOEDGE) || (c2 != NOEDGE)) {
  176.         if ((c1 & c2) != NOEDGE) return; // Not in viewing pyramid
  177.  
  178.         c = c1;
  179.         if (c == NOEDGE) c = c2;
  180.         if (c & LEFTEDGE) {
  181.             t = (z1 + x1) /((x1 - x2) - (z2 - z1));
  182.             z = t * (z2 - z1) + z1;
  183.             x = -z;
  184.             y = t * (y2 - y1) + y1;
  185.         }
  186.         else if (c & RIGHTEDGE) {
  187.             t = (z1 - x1) /((x2 - x1) - (z2 - z1));
  188.             z = t * (z2 - z1) + z1;
  189.             x = z;
  190.             y = t * (y2 - y1) + y1;
  191.         }
  192.         else if (c & BOTTOMEDGE) {
  193.             t = (z1 + y1) /((y1 - y2) - (z2 - z1));
  194.             z = t * (z2 - z1) + z1;
  195.             x = t * (x2 - x1) + x1;
  196.             y = -z;
  197.         }
  198.         else if (c & TOPEDGE) {
  199.             t = (z1 - y1) /((y2 - y1) - (z2 - z1));
  200.             z = t * (z2 - z1) + z1;
  201.             x = t * (x2 - x1) + x1;
  202.             y = z;
  203.         }
  204.  
  205.         if (c == c1) {
  206.             x1 = x;  y1 = y;  z1 = z;
  207.             c1 = Code(x,y,z);
  208.             if (c1 > 16) cout << "ERROR (c1): " << x1 << " " << y1 << " "
  209.                                                             << z1 << " " << c1 << "\n";
  210.  
  211.         }
  212.         else {
  213.             x2 = x;  y2 = y;  z2 = z;
  214.             c2 = Code(x,y,z);
  215.             if (c2 > 16) cout << "ERROR (c2): " << x2 << " " << y2 << " "
  216.                                                             << z2 << " " << c2 << "\n";
  217.         }
  218.     }
  219.     if (z1 != 0) {
  220.         WORLDtoPC(x1 / z1, y1/z1, pc1);
  221.         WORLDtoPC(x2/z2, y2/z2, pc2);
  222.     }
  223.     else {
  224.         WORLDtoPC(x1,y1,pc1);
  225.         WORLDtoPC(x2,y2,pc2);
  226.     }
  227.  
  228.     MoveTo(DC, pc1.x, pc1.y);
  229.     LineTo(DC, pc2.x,pc2.y);
  230. }
  231.  
  232.  
  233. // Transform 3d line to screen coordinates
  234. void TThreeD::TransformSeg(HDC DC, VECTOR& v1, VECTOR& v2, POINT& pc1, POINT& pc2)
  235. {
  236.     double x1, y1, z1, x2, y2, z2;
  237.     x1 = (v1.x * A1.x + A1.y * v1.y + A1.z * v1.z + Offsx) * DVal;
  238.     y1 = (v1.x * A2.x + A2.y * v1.y + A2.z * v1.z + Offsy) * DVal;
  239.     z1 = (v1.x * A3.x + A3.y * v1.y + A3.z * v1.z + Offsz);
  240.  
  241.     x2 = (v2.x * A1.x + A1.y * v2.y + A1.z * v2.z + Offsx) * DVal;
  242.     y2 = (v2.x * A2.x + A2.y * v2.y + A2.z * v2.z + Offsy) * DVal;
  243.     z2 = (v2.x * A3.x + A3.y * v2.y + A3.z * v2.z + Offsz);
  244.  
  245.     Clip3D(DC, x1, y1, z1, x2, y2, z2, pc1, pc2);
  246. }
  247.  
  248. // Go through the POINTS, and draw the object
  249. void TThreeD::View(HDC DC)
  250. {
  251.     long i=1, startOfSide;
  252.     POINT pc1, pc2;
  253.     while (i < Length) {
  254.         startOfSide = i; i++;
  255.         while (Connect[i] != -1) {
  256.             TransformSeg(DC, Points[(long)Connect[i-1]], Points[(long)Connect[i]], pc1, pc2);
  257.             i++;
  258.         }
  259.         // Close off the polygon
  260.  
  261.         // *** CLOSE POLYGON
  262. //        TransformSeg(DC, Points[Connect[i-1]], Points[Connect[startOfSide]], pc1, pc2);
  263.         i++;
  264.     }
  265. }
  266.  
  267.  
  268. int TThreeD::Get3dObject()
  269. {
  270.  
  271. }
  272.  
  273.  
  274. // Read a text file
  275. int TThreeD::Read3DObject(char* filename)
  276. {
  277.     long i, skipNumColors, r, g, b;
  278.     FILE *infile;
  279.  
  280.     if ((infile = fopen(filename, "r")) == NULL)
  281.         return EM_FILEOPENERROR;
  282.     fscanf(infile, "%ld", &skipNumColors);
  283.     // skip colors
  284.     for (i=1; i<=skipNumColors; i++)
  285.         fscanf(infile,"%ld %ld %ld", &r, &g, &b);
  286.  
  287.     fscanf(infile, "%u %u", &Vertices, &Length);
  288.     if ((Vertices > NUMVERTICES) || (Length > NUMCONNECTIONS))
  289.         return EM_FILETOOBIG;
  290.  
  291.     for (i=1; i<= Vertices; i++) {
  292.         fscanf(infile, "%lf %lf %lf", &Points[i].x, &Points[i].y, &Points[i].z);
  293.     }
  294.  
  295.     for(i=1; i<=Length; i++)
  296.         fscanf(infile, "%u", &Connect[i]);
  297.  
  298.     fclose(infile);
  299.  
  300.     return TRUE;
  301. }
  302.