home *** CD-ROM | disk | FTP | other *** search
- /* :ts=8 */ /* Yes some of us still use vi ! */
- /************************************************************************/
- /* */
- /* This file contains code to tesselate the current object. */
- /* */
- /* This is done by iterative evaluation of the splines, and this isn't */
- /* the fastest or best method. */
- /* */
- /* A better method would be some kind of recursive subdivision which */
- /* stops when the surfaces are nearly flat. */
- /* */
- /************************************************************************/
-
- #include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <stdlib.h>
-
- #include "general.h"
- #include "globals.h"
- #include "intui.h"
- #include "spl_math.h"
- #include "tesselate.h"
-
- #define Max_Nbr_Connections 2000
- #define Max_Nbr_Patches 1000
-
- /* Blending functions for cubic polynomials (Bernstein pol.) */
-
- /* Below u1 is (1.0 - u) */
-
- #define B03(u, u1) ((u1) * (u1) * (u1))
- #define B13(u, u1) (3.0 * (u) * (u1) * (u1))
- #define B23(u, u1) (3.0 * (u) * (u) * (u1))
- #define B33(u, u1) ((u) * (u) *(u))
-
- /* Cubic hermite polynomials: */
- #define H03(u, u1) (B03(u, u1) + B13(u, u1))
- #define H13(u, u1) (0.33333 * B13(u, u1))
- #define H23(u, u1) (0.33333 * B23(u, u1))
- #define H33(u, u1) (B23(u, u1) + B33(u, u1))
-
- #define F0(u, u1) H03(u, u1)
- #define F1(u, u1) H33(u, u1)
-
- /* Another possibility for F0 and F1 is: */
- /* #define F0(u, u1) (u1) */
- /* #define F1(u, u1) (u) */
-
- #define Parm(Idx, u, u1) ((Connections[Idx].Dir > 0) ? (u) : (u1))
-
-
- typedef struct {
- short From;
- short To;
- Spline_T *Spline;
- Knot_T *Knot;
- Byte_T Count;
- short Dir;
- } Connection_T;
-
-
- typedef struct {
- short P1, P2, P3, P4;
- } Patch_T;
-
-
- static int Step_S = 10; /* Number of steps (s). */
- static int Step_T = 10; /* Number of steps (t). */
- static Vector_T *Row0 = NULL;
- static Vector_T *Row1 = NULL;
- static Vector_T *Row2 = NULL;
-
- static Connection_T Connections[Max_Nbr_Connections];
- static int Nbr_Connections;
- static Patch_T Patches[Max_Nbr_Patches];
- static int Nbr_Patches;
-
- Boolean_T Face_Is_Ok(Vector_T Point0, Vector_T Point1, Vector_T Point2)
- /************************************************************************/
- /* */
- /* Check if the three points defines a triangle. */
- /* Return TRUE if they do. */
- /* */
- /************************************************************************/
- {
- double X1, Y1, Z1;
- double X2, Y2, Z2;
- double Vx, Vy, Vz;
-
- X1 = Point1[0] - Point0[0];
- Y1 = Point1[1] - Point0[1];
- Z1 = Point1[2] - Point0[2];
-
- X2 = Point2[0] - Point0[0];
- Y2 = Point2[1] - Point0[1];
- Z2 = Point2[2] - Point0[2];
-
- /* Cross product: */
- Vx = Y1 * Z2 - Z1 * Y2;
- Vy = Z1 * X2 - X1 * Z2;
- Vz = X1 * Y2 - Y1 * X2;
-
- if (ABS(Vx) < FTINY &&
- ABS(Vy) < FTINY &&
- ABS(Vz) < FTINY) return(FALSE);
-
- return(TRUE);
-
- } /* Face_Is_Ok */
-
- Compute_Row(double S, register Vector_T *Row, int Step_Size,
- Matrix4_T M1, short C1,
- Matrix4_T M2, short C2,
- Matrix4_T M3, short C3,
- Matrix4_T M4, short C4)
- /************************************************************************/
- /* */
- /* Compute row of values for a given 'S'. */
- /* M1, M2, M3 and M4 is the for precomputed matrices for spline */
- /* generation. C1, C2, C3 and C4 is indices into the connection list */
- /* for the four connections in this patch. */
- /* */
- /* C2 is -1 for 2 spline patch */
- /* C4 is -1 for 2 or 3 spline patch */
- /* */
- /************************************************************************/
- {
- double T, T1, S1;
- double F0s, F0t, F1s, F1t;
- register int i;
- Vector4_T Ps0, Ps1, P0t, P1t;
- Vector4_T P00, P10, P01, P11;
-
- if (S < -FTINY || S > 1.0+FTINY) return;
- S1 = 1.0 - S;
-
- Compute_Position(P00, Parm(C1, 0.0, 1.0), M1);
- Compute_Position(P10, Parm(C1, 1.0, 0.0), M1);
- Compute_Position(P01, Parm(C3, 1.0, 0.0), M3);
- Compute_Position(P11, Parm(C3, 0.0, 1.0), M3);
-
- if (C2 < 0) Compute_Position(P1t, Parm(C1, 1.0, 0.0), M1);
- if (C4 < 0) Compute_Position(P0t, Parm(C1, 0.0, 1.0), M1);
- i = 0;
-
-
- while (i <= Step_Size) {
-
- T = (double) i / Step_Size;
- T1 = 1.0 - T;
-
- /* Compute P(S,T), place in Row[i] */
-
- Compute_Position(Ps0, Parm(C1, S, S1), M1);
- if (C2 >= 0) Compute_Position(P1t, Parm(C2, T, T1), M2);
- Compute_Position(Ps1, Parm(C3, S1, S), M3);
- if (C4 >= 0) Compute_Position(P0t, Parm(C4, T1, T), M4);
-
- F0s = F0(S, S1); /* Precompute these to speed things up */
- F0t = F0(T, T1);
- F1s = F1(S, S1);
- F1t = F1(T, T1);
-
- Row[i][0] = F0s * P0t[0] + F1s * P1t[0] +
- F0t * Ps0[0] + F1t * Ps1[0] -
- F0s * F0t * P00[0] -
- F0s * F1t * P01[0] -
- F1s * F0t * P10[0] -
- F1s * F1t * P11[0];
-
- Row[i][1] = F0s * P0t[1] + F1s * P1t[1] +
- F0t * Ps0[1] + F1t * Ps1[1] -
- F0s * F0t * P00[1] -
- F0s * F1t * P01[1] -
- F1s * F0t * P10[1] -
- F1s * F1t * P11[1];
-
-
- Row[i][2] = F0s * P0t[2] + F1s * P1t[2] +
- F0t * Ps0[2] + F1t * Ps1[2] -
- F0s * F0t * P00[2] -
- F0s * F1t * P01[2] -
- F1s * F0t * P10[2] -
- F1s * F1t * P11[2];
-
-
-
- i++;
-
- } /* while */
-
-
- } /* Compute_Row */
-
- int Tesselate_Patch(Tesselate_Info_T *TI,
- short C1, short C2, short C3, short C4)
- /************************************************************************/
- /* */
- /* Tesselate the patch given by the splines C1, C2, C3 and C4. */
- /* */
- /* C2 is -1 for a 2 spline patch */
- /* C4 is -1 for a 2 or 3 spline patch */
- /* */
- /************************************************************************/
- {
- int i, j;
- Vector_T *Tmp_Row;
- Matrix4_T M1, M2, M3, M4;
- static int Old_Step_S = -1;
- static int Old_Step_T = -1;
-
- if (TI->Patch_Begin != NULL) TI->Patch_Begin();
-
- Step_S = Step_T = Patch_Resolution;
-
- if (Step_T != Old_Step_T ||
- Row0 == NULL || Row1 == NULL || Row2 == NULL) {
-
- if (Row0 != NULL) free(Row0);
- if (Row1 != NULL) free(Row1);
- if (Row2 != NULL) free(Row2);
-
- Row0 = (Vector_T *) malloc( (Step_T+3) * sizeof(Vector_T) );
- if (Row0 == NULL) {
- Display_Error_Message("malloc error");
- CloseStuff();
- exit(9);
- } /* if */
-
- Row1 = (Vector_T *) malloc( (Step_T+3) * sizeof(Vector_T) );
- if (Row1 == NULL) {
- Display_Error_Message("malloc error");
- CloseStuff();
- exit(9);
- } /* if */
-
- Row2 = (Vector_T *) malloc( (Step_T+3) * sizeof(Vector_T) );
- if (Row2 == NULL) {
- Display_Error_Message("malloc error");
- CloseStuff();
- exit(9);
- } /* if */
-
- } /* if */
-
- Old_Step_S = Step_S;
- Old_Step_T = Step_T;
-
- Precompute_Kochanek_Bartels(M1,
- Connections[C1].Spline,
- Connections[C1].Knot);
-
- if (C2 >= 0) Precompute_Kochanek_Bartels(M2,
- Connections[C2].Spline,
- Connections[C2].Knot);
-
- Precompute_Kochanek_Bartels(M3,
- Connections[C3].Spline,
- Connections[C3].Knot);
-
- if (C4 >= 0) Precompute_Kochanek_Bartels(M4,
- Connections[C4].Spline,
- Connections[C4].Knot);
-
- /* Initialize the first rows */
- /* It is not neccessary to initialize Row0, as it is */
- /* computed as the first step in the main loop. */
-
- Compute_Row(0.0, Row1, Step_T, M1, C1, M2, C2, M3, C3, M4, C4);
- Compute_Row(1.0/Step_S, Row2, Step_T, M1, C1, M2, C2, M3, C3, M4, C4);
-
-
- for (i = 0; i < Step_S; i++) {
-
- /* compute next row */
- Tmp_Row = Row0;
- Row0 = Row1;
- Row1 = Row2;
- Row2 = Tmp_Row;
-
- Compute_Row((double)(i + 2) / Step_S, Row2, Step_T,
- M1, C1, M2, C2, M3, C3, M4, C4);
-
- for (j = 0; j < Step_T; j++) {
-
- if ( (i + j) & 1 ) {
-
- TI->Patch_Generate_Face(
- Row0[j], Row1[j], Row0[j+1], Row1[j+1]);
-
- } else {
-
- TI->Patch_Generate_Face(
- Row1[j], Row1[j+1], Row0[j], Row0[j+1]);
-
- }
-
- } /* for */
-
- } /* for */
-
- if (TI->Patch_End != NULL) TI->Patch_End();
-
- } /* Tesselate_Patch */
-
- static
- void Sort4(short *i1, short *i2, short *i3, short *i4)
- /************************************************************************/
- /* */
- /* Sort the four numbers i1, i2, i3 and i4. */
- /* */
- /************************************************************************/
- {
- short t;
-
- if (*i2 < *i1) { t = *i1; *i1 = *i2; *i2 = t; }
- if (*i4 < *i3) { t = *i3; *i3 = *i4; *i4 = t; }
- if (*i3 < *i2) { t = *i3; *i3 = *i2; *i2 = t; }
- if (*i2 < *i1) { t = *i1; *i1 = *i2; *i2 = t; }
- if (*i4 < *i3) { t = *i3; *i3 = *i4; *i4 = t; }
- if (*i3 < *i2) { t = *i3; *i3 = *i2; *i2 = t; }
-
- } /* Sort4 */
-
- static
- Boolean_T Patch_Add(short P1, short P2, short P3, short P4)
- /************************************************************************/
- /* */
- /* Add the patch defined by P1, P2, P3 and P4 to the patch table. */
- /* Return TRUE if the patch already existed in the table. */
- /* */
- /* (Linear search!!! Optimize please :) */
- /* */
- /************************************************************************/
- {
- int i;
-
- Sort4(&P1, &P2, &P3, &P4);
-
- for (i = 0; i < Nbr_Patches; i++) {
-
- if (Patches[i].P1 == P1 &&
- Patches[i].P2 == P2 &&
- Patches[i].P3 == P3 &&
- Patches[i].P4 == P4) return(TRUE);
-
- } /* for */
-
- if (Nbr_Patches < Max_Nbr_Patches-1) {
-
- Patches[Nbr_Patches].P1 = P1;
- Patches[Nbr_Patches].P2 = P2;
- Patches[Nbr_Patches].P3 = P3;
- Patches[Nbr_Patches].P4 = P4;
-
- Nbr_Patches++;
-
- } else {
-
- Display_Error_Message("No more space for patches");
- CloseStuff();
- exit(1);
-
- } /* if .. else .. */
-
- return(FALSE);
-
- } /* Patch_Add */
-
- static
- int Find_From_Connection(short From, short To)
- /************************************************************************/
- /* */
- /* Find a connection starting in 'From' and NOT leading to 'To'. */
- /* */
- /************************************************************************/
- {
- int i;
-
- for (i = 0; i < Nbr_Connections; i++)
- if (Connections[i].Count < 2 &&
- Connections[i].From == From && Connections[i].To != To)
- return(i);
-
- return(-1);
-
- } /* Find_From_Connection */
-
- static
- int Find_From_To_Connection(short From, short To)
- /************************************************************************/
- /* */
- /* Find a connection starting in 'From' and leading to 'To'. */
- /* */
- /************************************************************************/
- {
- int i;
-
- for (i = 0; i < Nbr_Connections; i++)
- if (Connections[i].Count < 2 &&
- Connections[i].From == From && Connections[i].To == To)
- return(i);
-
- return(-1);
-
- } /* Find_From_Connection */
-
- static
- int Find_From_To_Spline_Connection(Spline_T *Spline, short From, short To)
- /************************************************************************/
- /* */
- /* Find a connection starting in 'From' and leading to 'To'. */
- /* The found connection must NOT be given by 'Spline'. */
- /* */
- /************************************************************************/
- {
- int i;
-
- for (i = 0; i < Nbr_Connections; i++)
- if (Connections[i].Spline != Spline &&
- Connections[i].Count < 2 &&
- Connections[i].From == From && Connections[i].To == To)
- return(i);
-
- return(-1);
-
- } /* Find_From_To_Spline_Connection */
-
- static
- void Remove_Connection(int Id)
- /************************************************************************/
- /* */
- /* Increase usage count for the connection given by 'Id'. */
- /* Each connection may be used two times. */
- /* */
- /************************************************************************/
- {
- int Id2;
-
- Id2 = Find_From_To_Connection(Connections[Id].To,
- Connections[Id].From);
-
- Connections[Id].Count++;
-
- if (Id2 >= 0) Connections[Id2].Count++;
-
- } /* Remove_Connection */
-
- int CompareFunc(Connection_T *Con1, Connection_T *Con2)
- /************************************************************************/
- /* */
- /* Compare two connections. This is used by 'qsort'. */
- /* */
- /************************************************************************/
- {
- if (Con1->From < Con2->From) return(-1);
- if (Con1->From > Con2->From) return(1);
- if (Con1->To < Con2->To) return(-1);
- if (Con1->To > Con2->To) return(1);
- return(0);
-
- } /* CompareFunc */
-
- Boolean_T Tesselate_Object(Tesselate_Info_T *TI)
- /************************************************************************/
- /* */
- /* This function is called to tesselate the current object. */
- /* */
- /* This is done by dividing the object into patches, and then tesselate */
- /* these patches. */
- /* */
- /* The argument 'TI' defines what to do with the result. */
- /* */
- /* TI is a structure which contains pointers to 3 functions: */
- /* */
- /* void (*Patch_Begin)(void): */
- /* This function is called before tesselation of a new patch starts*/
- /* It could for instance be used to initialize variables. */
- /* This function pointer may be a NULL pointer. */
- /* */
- /* void (*Patch_Generate_Face)(Vector_T Point0, Vector_T Point1, */
- /* Vector_T Point2, Vector_T Point3): */
- /* This function is called for each found 'rectangle'. */
- /* The rectangle isn't necessarily flat, and may be degenerate, so */
- /* normally, the routine should split it into two triangles and */
- /* test that the triangles isn't degenerate. */
- /* */
- /* void (*Patch_End)(void): */
- /* This function is called after tesselation of a patch is done. */
- /* It can be used to free memory, write data to a file or whatever.*/
- /* This function pointer may be a NULL pointer. */
- /* */
- /* 'Tesselate_Object' will return TRUE in case of error. */
- /* */
- /************************************************************************/
- {
- Spline_T *Spline;
- Knot_T *Knot;
- int j;
- int Patch_Count;
- short P1, P2, P3, P4;
- short C1, C2, C3, C4;
-
- Nbr_Connections = 0;
- Nbr_Patches = 0;
-
- /* Add all splines to the connection list: */
- Display_Status("Adding splines to connection list");
-
- for (Spline = Splines; Spline != NULL; Spline = Spline->Next) {
-
- if (Spline->Nbr_Knots > 1) {
-
- for (j = 1, Knot = Spline->First;
- j < Spline->Nbr_Knots; j++, Knot = Knot->Next) {
-
- if (Is_Hidden(Points[Knot->Point_Id])) continue;
-
- if (Nbr_Connections >= Max_Nbr_Connections-2) {
- Display_Message("No more space for connections");
- return(TRUE);
- }
- Connections[Nbr_Connections].From = Knot->Point_Id;
- Connections[Nbr_Connections].To = Knot->Next->Point_Id;
- Connections[Nbr_Connections].Spline = Spline;
- Connections[Nbr_Connections].Knot = Knot;
- Connections[Nbr_Connections].Dir = 1;
- Connections[Nbr_Connections++].Count = 0;
-
- Connections[Nbr_Connections].From = Knot->Next->Point_Id;
- Connections[Nbr_Connections].To = Knot->Point_Id;
- Connections[Nbr_Connections].Spline = Spline;
- Connections[Nbr_Connections].Knot = Knot;
- Connections[Nbr_Connections].Dir = -1;
- Connections[Nbr_Connections++].Count = 0;
-
- } /* for */
-
- if (Spline->Loop & !Is_Hidden(Points[Knot->Point_Id])){
-
- if (Nbr_Connections >= Max_Nbr_Connections-2) {
- Display_Message("No more space for connections");
- return(TRUE);
- }
-
- Connections[Nbr_Connections].From = Knot->Point_Id;
- Connections[Nbr_Connections].To = Spline->First->Point_Id;
- Connections[Nbr_Connections].Spline = Spline;
- Connections[Nbr_Connections].Knot = Knot;
- Connections[Nbr_Connections].Dir = 1;
- Connections[Nbr_Connections++].Count = 0;
-
- Connections[Nbr_Connections].From = Spline->First->Point_Id;
- Connections[Nbr_Connections].To = Knot->Point_Id;
- Connections[Nbr_Connections].Spline = Spline;
- Connections[Nbr_Connections].Knot = Knot;
- Connections[Nbr_Connections].Dir = -1;
- Connections[Nbr_Connections++].Count = 0;
-
- } /* if */
-
- } /* if */
-
- } /* for */
-
- /* Sort the connection list: */
- sprintf(Error_Msg, "Sorting %d connections.", Nbr_Connections);
- Display_Status(Error_Msg);
- qsort((char *)Connections, Nbr_Connections,
- sizeof(Connection_T), CompareFunc);
-
- /* Find all two spline patches */
-
- Patch_Count = 0;
-
- for (C1 = 0; C1 < Nbr_Connections; C1++) {
-
- P1 = Connections[C1].From;
- P2 = Connections[C1].To;
-
- if (Connections[C1].Count >= 2) continue;
-
- C2 = Find_From_To_Spline_Connection(Connections[C1].Spline,
- P2, P1);
- if (C2 != -1) {
-
- /* Won't accept both points on same spline */
- if (Connections[C1].Spline ==
- Connections[C2].Spline) continue;
-
- if (!Patch_Add(Connections[C1].From,
- Connections[C2].From,
- -1,
- -1)) {
- /* Found, C1, C2 */
-
- sprintf(Error_Msg, "Tesselating patches (%d)", ++Patch_Count);
- Display_Status(Error_Msg);
- Tesselate_Patch(TI, C1, -1, C2, -1);
-
- Remove_Connection(C1);
- Remove_Connection(C2);
- }
- goto NextA; /* Stop loop */
-
- } /* if */
-
- NextA: ;
- } /* for */
-
-
- /* Find all three spline patches */
-
- for (C1 = 0; C1 < Nbr_Connections; C1++) {
-
- P1 = Connections[C1].From;
- P2 = Connections[C1].To;
-
- if (Connections[C1].Count >= 2) continue;
-
- C2 = Find_From_Connection(P2, P1);
- if (C2 == -1) goto NextB;
- do {
-
- P3 = Connections[C2].To;
- if (P3 == P1) continue;
-
- C3 = Find_From_To_Connection(P3, P1);
- if (C3 != -1) {
-
- /* We won't accept all three points on same spline */
- if (Connections[C1].Spline ==
- Connections[C2].Spline &&
- Connections[C2].Spline ==
- Connections[C3].Spline) continue;
-
- if (!Patch_Add(Connections[C1].From,
- Connections[C2].From,
- Connections[C3].From,
- -1)) {
- /* Found, C1, C2, C3 */
-
- sprintf(Error_Msg, "Tesselating patches (%d)", ++Patch_Count);
- Display_Status(Error_Msg);
- Tesselate_Patch(TI, C1, C2, C3, -1);
-
- Remove_Connection(C1);
- Remove_Connection(C2);
- Remove_Connection(C3);
- }
- goto NextB; /* Stop loop */
-
- } /* if */
-
- } while (++C2 < Nbr_Connections && Connections[C2].From == P2);
- NextB: ;
- } /* for */
-
-
- /* Find all four spline patches */
-
- for (C1 = 0; C1 < Nbr_Connections; C1++) {
-
- P1 = Connections[C1].From;
- P2 = Connections[C1].To;
-
- if (Connections[C1].Count >= 2) continue;
-
- C2 = Find_From_Connection(P2, P1);
- if (C2 == -1) continue;
-
- do {
-
- P3 = Connections[C2].To;
- if (P3 == P1) continue;
-
- C3 = Find_From_Connection(P3, P2);
- if (C3 == -1) continue;
- do {
-
- P4 = Connections[C3].To;
- if (P4 == P2) continue;
-
- C4 = Find_From_To_Connection(P4, P1);
-
- if (C4 != -1) {
-
- /* We won't accept all four points on same spline */
-
- if (Connections[C1].Spline ==
- Connections[C2].Spline &&
- Connections[C2].Spline ==
- Connections[C3].Spline &&
- Connections[C3].Spline ==
- Connections[C4].Spline) continue;
-
- if (!Patch_Add(Connections[C1].From,
- Connections[C2].From,
- Connections[C3].From,
- Connections[C4].From)) {
- /* Found, C1, C2, C3, C4 */
-
- sprintf(Error_Msg, "Tesselating patches (%d)", ++Patch_Count);
- Display_Status(Error_Msg);
- Tesselate_Patch(TI, C1, C2, C3, C4);
-
- Remove_Connection(C1);
- Remove_Connection(C2);
- Remove_Connection(C3);
- Remove_Connection(C4);
- }
- goto Next1; /* Stop loop */
-
- } /* if */
-
- } while (++C3 < Nbr_Connections && Connections[C3].From == P3);
-
- } while (++C2 < Nbr_Connections && Connections[C2].From == P2);
-
- Next1: ;
- } /* for */
-
- if (Row0 != NULL) free(Row0);
- if (Row1 != NULL) free(Row1);
- if (Row2 != NULL) free(Row2);
- Row0 = Row1 = Row2 = NULL;
-
- Display_Status("Tesselation done");
-
- return(FALSE);
-
- } /* Tesselate_Object */
-