/***************************************************************************** * Initializes the Triangle structure based on the original irit polygon. * ****************************************************************************** * (C) Gershon Elber, Technion, Israel Institute of Technology * ****************************************************************************** * Written by: David Shafrir & Alex Reicher Ver 0.3, Sep. 2003 * *****************************************************************************/ #include "triangle.h" static void PolyAveragePoint(IPPolygonStruct *Poly, PointType p); static int IsPolyBackfaced(IPPolygonStruct *Poly, PointType Viewer, int Parallel); int VertexGetUVAttrAux(IPVertexStruct *Vertex, RealType *u, RealType *v); static void CalcInterpol(EdgeStruct *Edge, IPVertexStruct *v, IPVertexStruct *vMid, RealType *TVertex, ObjectStruct *o, SceneStruct *Scene); /***************************************************************************** * DESCRIPTION: M * Calulate the transformed vertex coordinate. M * * * PARAMETERS: M * Vertex: IN, pointer to the Vertex. M * Matrices: IN, pointer to matrices context. M * o: IN, pointer to Object which contains the Triangle that M * contains the vertex. M * Result: OUT, the result transformed homogenous coordinate. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * VertexTransform M *****************************************************************************/ void VertexTransform(IPVertexStruct *Vertex, MatrixContextStruct *Matrices, ObjectStruct *o, RealType *Result) { RealType w; PT_COPY(Result, Vertex -> Coord); Result[3] = 1.0; if (o -> Animated == TRUE) { MatMultWVecby4by4(Result, Result, o -> AnimationMatrix); } MatMultWVecby4by4(Result, Result, Matrices -> TransMat); w = 1 / Result[3]; PT_SCALE(Result, w); MatMultPtby4by4(Result, Result, Matrices -> ScreenMat); } /***************************************************************************** * DESCRIPTION: * * Computes average of the vertices points of the tiangle polygon. * * * * PARAMETERS: * * Poly: IN, pointer to the Irit polygon object. * * p: OUT, result average point. * * * * RETURN VALUE: * * void * *****************************************************************************/ static void PolyAveragePoint(IPPolygonStruct *Poly, PointType p) { IPVertexStruct *v; PT_RESET(p); for (v = Poly -> PVertex; v; v = v -> Pnext) PT_ADD(p, p, v -> Coord); PT_SCALE(p, 1.0 / 3.0); } /***************************************************************************** * DESCRIPTION: * * Determines if viewer sees the backface side of the polygon, uses plane * * equation to obtain normal value. * * Assumes that normal is directed into the object normaly and both viewer * * and Plane equation are in object space. * * * * PARAMETERS: * * Poly: Pointer to Irit polygon object. * * * * RETURN VALUE: * * int: Boolean value, zero if viewer sees front side of the polygon. * *****************************************************************************/ static int IsPolyBackfaced(IPPolygonStruct *Poly, PointType Viewer, int Parallel) { /* Assume that normal to the sphere is directed into sphere. */ return !Parallel ? PLANE_EQ_EVAL(Poly -> Plane, Viewer) > -IRIT_EPS : DOT_PROD(Poly -> Plane, Viewer) > -IRIT_EPS; } /***************************************************************************** * DESCRIPTION: M * Creates a new Triangle object and allocates memory for it's fileds. M * Should be called before the first time the object is used. M * * * PARAMETERS: M * Tri: IN, pointer to the Triangle object. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * TriangleInit M *****************************************************************************/ void TriangleInit(TriangleStruct *Tri) { int i; /* Allocate space to store interpolation data for every edge + one */ /* temporary val because light's number can change over time, we */ /* allocate the maximal number. */ Tri -> Vals = MALLOC(IntensivityStruct*, 4); Tri -> dVals = MALLOC(IntensivityStruct*, 4); for (i = 0; i < 4; i++) { Tri -> Vals[i] = MALLOC(IntensivityStruct, MAX_LIGHTS_NUM); Tri -> dVals[i] = MALLOC(IntensivityStruct, MAX_LIGHTS_NUM); } } /***************************************************************************** * DESCRIPTION: M * Free the memory of a the Triangle. M * * * PARAMETERS: M * Tri: IN, pointer to the Triangle object. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * TriangleRelease M *****************************************************************************/ void TriangleRelease(TriangleStruct *Tri) { int i; for (i = 0; i < 4; i++) { FREE(Tri -> Vals[i]); FREE(Tri -> dVals[i]); } FREE(Tri -> Vals); FREE(Tri -> dVals); } /***************************************************************************** * DESCRIPTION: * * Caculates iterpolation values for an edge. * * * * PARAMETERS: * * Edge: Pointer to the edge. * * v: Pointer to the first vertex of the edge. * * vMid: Pointer to the first middle vertex of the triangle. * * TVertex: The transformed coordinates of the vertex. * * o: The object the triangle belongs to. * * Scene: The scene context. * * * * RETURN VALUE: * * void * *****************************************************************************/ static void CalcInterpol(EdgeStruct *Edge, IPVertexStruct *v, IPVertexStruct *vMid, RealType *TVertex, ObjectStruct *o, SceneStruct *Scene) { int j, VRed, VGreen, VBlue, ShadeModal = Scene -> ShadeModel; PointType Coord; InterpolStruct *Value = &Edge -> Value; Value -> IntensSize = Scene -> Lights.n; Edge -> dValue.IntensSize = Scene -> Lights.n; Edge -> x = REAL_TO_INT(TVertex[X_AXIS]); Edge -> YMin = REAL_TO_INT(TVertex[Y_AXIS]); Edge -> Value.z = TVertex[Z_AXIS]; Edge -> Value.w = 1 / TVertex[3]; if (o -> Txtr.Type == TEXTURE_TYPE_RSTR || o -> Txtr.Type == TEXTURE_TYPE_PROC || o -> Txtr.Type == TEXTURE_TYPE_SRF) { if (VertexGetUVAttrAux(v, &Value -> u, &Value -> v)) { Value -> u = (Value -> u - o -> Txtr.PrmUMin) / (o -> Txtr.PrmUMax - o -> Txtr.PrmUMin); Value -> v = (Value -> v - o -> Txtr.PrmVMin) / (o -> Txtr.PrmVMax - o -> Txtr.PrmVMin); } else { /* No UV Values. Use the XY positions instead. */ Value -> u = v -> Coord[0]; Value -> v = v -> Coord[1]; } Value -> u *= Value -> w; Value -> v *= Value -> w; } else { Value -> u = Value -> v = 0.0; } /* Handle normal. */ PT_COPY(Value -> n, v -> Normal); PT_SCALE(Value -> n, Value -> w); if (Value -> HasColor = AttrGetRGBColor(v -> Attr, &VRed, &VGreen, &VBlue)) { Value -> c[0] = VRed / 255.0; Value -> c[1] = VGreen / 255.0; Value -> c[2] = VBlue / 255.0; } else PT_RESET(Value -> c); Edge -> dValue.HasColor = Value -> HasColor; /* Handle interpol values. */ switch (ShadeModal) { case SHADING_GOURAUD: if (o -> Transformed ) MatMultPtby4by4(Coord, v -> Coord, Scene -> Matrices.ViewInvMat); else PT_COPY(Coord, v -> Coord); for (j = 0; j < Scene -> Lights.n; ++j) { LightIntensivity(&Scene -> Lights.Src[j], Coord, v -> Normal, o, Scene, &Value -> i[j]); Value -> i[j].Diff *= Value -> w; Value -> i[j].Spec *= Value -> w; } break; case SHADING_FLAT: Edge -> dValue.i = NULL; if (o -> Transformed ) MatMultPtby4by4(Coord, vMid -> Coord, Scene -> Matrices.ViewInvMat); else PT_COPY(Coord, vMid -> Coord); for (j = 0; j < Scene -> Lights.n ; ++j) LightIntensivity(&Scene -> Lights.Src[j], Coord, vMid -> Normal, o, Scene, &Value -> i[j]); break; default: /* For Phong don't use interpolation values. */ Value -> i = NULL; Edge -> dValue.i = NULL; } } /***************************************************************************** * DESCRIPTION: M * Wraps an Irit polygon and initialize the Triangle structure M * from polygon and object data. M * That includes scan line and interpolation algorithm data initialization. M * * * PARAMETERS: M * Tri: OUT, pointer to the Triangle object. M * Poly: IN, pointer to Irit polygon object. M * o: IN, pointer to Object which contains a Triangle and stores M * various charactarisitics common to every polygon in the object. M * Scene: IN, pointer to the scene context. M * * * RETURN VALUE: M * int: 1 in successful, 0 if polygon is not OK. M * * * KEYWORDS: M * TriangleSet M *****************************************************************************/ int TriangleSet(TriangleStruct *Tri, IPPolygonStruct *Poly, ObjectStruct *o, SceneStruct *Scene) { int e, i, XMax = 0, XMin = 0, YMin, YMinXMin; EdgeStruct *PEdge, First; IPVertexStruct *v, VertexMid, *Vertex[3]; RealType TVertex[3][4]; PointType Viewer; if (!Poly || AttrGetRealAttrib(Poly -> Attr, "_INVIS") == 1) return 0; PT_COPY(&Viewer, Scene -> Matrices.Viewer); for (i = 0; i < 3; i++) { Tri -> Edge[i].Value.i = Tri -> Vals[i]; Tri -> Edge[i].dValue.i = Tri -> dVals[i]; } /* Simplify access to vertices. */ for (v = Poly -> PVertex, i = 0; v != NULL; v = v -> Pnext, i++) { Vertex[i] = v; } /* In flat model we evalute everything with respect to the average point.*/ if (Scene -> ShadeModel == SHADING_FLAT) { PolyAveragePoint(Poly, VertexMid.Coord); PT_COPY(VertexMid.Normal, Poly -> Plane); PT_NORMALIZE(VertexMid.Normal); } /* Transform vertices. */ if (o -> Transformed != TRUE) { for (i = 0; i < 3; i++) { VertexTransform(Vertex[i], &Scene -> Matrices, o, TVertex[i]); } } else { for (i = 0; i < 3; i++) { PT_COPY(TVertex[i], Vertex[i] -> Coord); TVertex[i][3] = AttrGetRealAttrib(Vertex[i] -> Attr, "_1/W"); } } for (i = 0; i < 3; i++) { if ( TVertex[i][W_AXIS] < 0 ) { static int PrintIt = FALSE; if (!PrintIt) { _IRndrReportWarning(IRIT_EXP_STR("Negative w coorinate")); PrintIt = TRUE; } return 0; } } if (APX_EQ(Poly -> Plane[X_AXIS], 0) && /* Do not create Triangle for the*/ APX_EQ(Poly -> Plane[Y_AXIS], 0) && /* poly with zero length normal. */ APX_EQ(Poly -> Plane[Z_AXIS], 0)) return 0; if (Scene -> BackFace && IsPolyBackfaced(Poly, Viewer, Scene -> Matrices.ParallelProjection)) return 0; /* Skip back side polygons if user asks. */ Tri -> Object = o; /* Connect to container object */ Tri -> Poly = Poly; /* and to the source polygon. */ /* Count edges and min-max dimensions for the polygon. */ YMinXMin = XMin = Tri -> YMin = IRIT_MAX_INT; XMax = Tri -> YMax = -IRIT_MAX_INT; for (i = 0; i < 3; i++) { YMin = REAL_TO_INT(TVertex[i][Y_AXIS]); if (YMin < Tri -> YMin) { Tri -> YMin= YMin; YMinXMin = REAL_TO_INT(TVertex[i][X_AXIS]); } else if (YMin == Tri -> YMin) { MINM(YMinXMin, REAL_TO_INT(TVertex[i][X_AXIS])); } MAXM(Tri -> YMax, YMin); MINM(XMin, REAL_TO_INT(TVertex[i][X_AXIS])); MAXM(XMax, REAL_TO_INT(TVertex[i][X_AXIS])); } /* We have no deal with Triangles out of image rectangle. */ if ((Tri -> YMax <= 0) || (Tri -> YMin >= Scene -> SizeY) || (XMax <= 0) || (XMin >= Scene -> SizeX)) { return 0; } YMin = Tri -> YMin; /* Obtain and initialize Triangle's vertices current (inital) */ /* characteristics which are scan line algorithm values, and */ /* interpolants such as normal, intensivity, homogeneous coordinate... */ for (i = 0; i < 3; i++) { CalcInterpol(&Tri -> Edge[i], Vertex[i], &VertexMid, TVertex[i], o, Scene); } /* Create and initalize interpolation values data structure. */ First = Tri -> Edge[0]; if (Scene -> ShadeModel == SHADING_PHONG) First.Value.i = NULL; else First.Value.i = Tri -> Vals[3]; /* The temporary val. */ InterpolCopy(&First.Value, &Tri -> Edge -> Value); for (e = 0; e < 3; ++e) { RealType dy; EdgeStruct *Next; PEdge = &Tri -> Edge[e]; Next = (e + 1 == 3) ? &First : PEdge + 1; dy = PEdge -> dy = Next -> YMin - PEdge -> YMin; InterpolDelta(&PEdge -> dValue, &Next -> Value, &PEdge -> Value, dy); if (PEdge -> dy < 0) { PEdge -> dx = PEdge -> x - Next -> x; PEdge -> x = Next -> x; PEdge -> YMin = Next -> YMin; InterpolCopy(&PEdge -> Value, &Next -> Value); } else PEdge -> dx = Next -> x - PEdge -> x; PEdge -> Inc = PEdge -> dy = ABS(PEdge -> dy); } /* Sort edges, keep sorted in SortedEdge array. */ /* SortedEdge[0] is the left one, SortedEdge[1] the right one and */ /* SortedEdge[2] the last. We ignore horizonal edges. */ Tri -> SortedEdge[0] = Tri -> SortedEdge[1] = Tri -> SortedEdge[2] = NULL; for (i = 0; i < 3; ++i) { if ( (Tri -> Edge[i].dy != 0) && (Tri -> Edge[i].YMin == YMin)) { if ((Tri -> Edge[i].x == YMinXMin) && (!Tri -> SortedEdge[0] || ((RealType) Tri -> Edge[i].dx / Tri -> Edge[i].dy) < ((RealType) Tri -> SortedEdge[0] -> dx / Tri -> SortedEdge[0] -> dy))) { /* Found the left edge. */ if (!Tri -> SortedEdge[1]) Tri -> SortedEdge[1] = Tri -> SortedEdge[0]; Tri -> SortedEdge[0] = &Tri -> Edge[i]; } /* Found the right edge. */ else Tri -> SortedEdge[1] = &Tri -> Edge[i]; } else if (Tri -> Edge[i].dy != 0) { Tri -> SortedEdge[2] = &Tri -> Edge[i]; } } if (!Tri -> SortedEdge[0]) { for (i = 0; i < 3; i++) { if (Tri -> Edge[i].x == XMin ) Tri -> SortedEdge[0] = &Tri -> Edge[i]; if (Tri -> Edge[i].x == XMax) Tri -> SortedEdge[1] = &Tri -> Edge[i]; } } return 1; }