/* ##TYPEDEF#---------------------------------------------------------------------------- Types definition ---------------------------------------------------------------------------------------*/ /*This is a structure used by my clipping function of triangles to create shadow faces*/ typedef struct SHW_tdstResultIntersectionCT_ { ACP_tdst2DUVValues uvPoint; short xStart1; short xStart2; ACP_tdxBool xCT1; ACP_tdxBool xCT2; } SHW_tdstResultIntersectionCT; #define C_ShadowOnActors 256 #define C_ShadowOnMe 512 /* ##-############################################ */ /* ##SECTION FROM SPO: Used for bounding volumes /* ############################################### */ MTH_tdxReal VoidReal; ACP_tdxHandleOfObject GeoHandle; /* ##M=================================================================================== NAME : SHW_M_hGetFirstLodOfVisualSetFromPo DESCRIPTION : return first level of detail of visual set of a physical object INPUT : Physical object OUTPUT : first level of detail of visual set of a physical object ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ #define SHW_M_hGetFirstLodOfVisualSetFromPo(Po) \ (GLI_vGetVisualSetLOD(PO_fn_hGetVisualSet(Po), 0, &VoidReal, &GeoHandle), GeoHandle) /* ##M=================================================================================== NAME : SHW_M_hGetRepositionZoneFromPo DESCRIPTION : return reposition zone of a physical object INPUT : Physical object OUTPUT : reposition zone of a physical object ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ #define SHW_M_hGetRepositionZoneFromPo(Po) \ (GLI_vGetVisualSetLOD(PO_fn_hGetVisualSet(Po), 0, &VoidReal, &GeoHandle), GeoHandle) /* ##-############################################ */ /* ##END SECTION FROM SPO /* ############################################### */ /* ##GLOBVAR#---------------------------------------------------------------------------- Globale variable declaration ---------------------------------------------------------------------------------------*/ GLI_tdstTexture *g_p_stTextureOfTextureShadow; /*Index of the shadow of character*/ /*Global variable for the quality of shadow*/ short g_xGeneralLevelOfQualityOfShadows=2; short g_xLevelOfQualityOfShadows=2; /*Global array of information about the intersected faces*/ SHW_tdstShadowInfo g_a_stShadowInfo[SHW_C_xMaxGeomObjectPicked]; /*Array of Handles of characters that have shadow already calculated: Exemple into mirrors*/ HIE_tdxHandleToSuperObject g_hHandleOfFather= NULL; /*ACP_tdxBool g_bOnPlatForm = FALSE;*/ ACP_tdxBool g_bIsOnGround = FALSE; ACP_tdxBool g_bRayIsVertical; MTH3D_tdstVector g_stStartPicking; MTH3D_tdstVector g_stDirOfShadow; /* YLG*/ /*MTH3D_tdstVector g_stVertexA,*/ MTH3D_tdstVector g_stVertexB; MTH3D_tdstVector g_stVertexAB; MTH_tdxReal g_xNearDistance; MTH3D_tdstVector g_stPickedPoint; HIE_tdxHandleToSuperObject g_hPickedSprObj; ACP_tdxHandleOfObject g_hPickedObject; ACP_tdxIndex g_xPickedElement; ACP_tdxIndex g_xPickedFace; short g_shNbObjPicked; POS_tdstCompletePosition g_stInvertCurrentMatrix; /*MTH3D_tdstVector g_stVertexALocal;*/ /*MTH3D_tdstVector g_stVertexBLocal;*/ /*MTH3D_tdstVector g_stVertexABLocal;*/ ACP_tdxBool g_bFirstFace; /* ##FUNCDEF#---------------------------------------------------------------------------- Functions definition ---------------------------------------------------------------------------------------*/ /* ##F=================================================================================== NAME : SHW_fn_bIsCharacterBoundingVolumeIntersectwithSphere DESCRIPTION : return TRUE if bounding volumes intersect with sphere ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bIsCharacterBoundingVolumeIntersectWithSphere ( HIE_tdxHandleToSuperObject _hSprObj ) { GEO_tdxHandleToParallelBox hParallelBox = NULL; GEO_tdxHandleToBoundingSphere hBoundingSphere = NULL; ACP_tdxBool bBoundingBox; MTH3D_tdstVector stGlobalSphereCenter, stLocalSphereCenter; /* FQ: I had to init those 2 variables, or else it hung on some special cases...*/ /* Like Swamp2's moveable bridge int the N64 Version !*/ MTH_tdxReal xSphereRadius=0.0f, xScaledRadius=0.0f; MTH3D_tdstVector stMinPoint; MTH3D_tdstVector stMaxPoint; if (HIE_fn_SO_bCheckChildren(_hSprObj)) return TRUE; bBoundingBox = HIE_fn_SO_bHasABoxBoundingVolume(_hSprObj); if(bBoundingBox) hParallelBox = (GEO_tdxHandleToParallelBox)HIE_fn_hGetSuperObjectBoundingVolume(_hSprObj); else hBoundingSphere = (GEO_tdxHandleToBoundingSphere)HIE_fn_hGetSuperObjectBoundingVolume(_hSprObj); if ((hBoundingSphere) && (!bBoundingBox)) { /*PRF_fn_vIncreaseVariable(PRF_C_ulVarGLI1, NULL, 1);*/ MTH3D_M_vCopyVector(&stLocalSphereCenter, GEO_fn_pGetCenterPointOfBoundingSphere(hBoundingSphere)); xSphereRadius = GEO_fn_xGetRadiusOfBoundingSphere(hBoundingSphere); POS_fn_vMulMatrixVertex(&stGlobalSphereCenter, HIE_fn_hGetSuperObjectGlobalMatrix(_hSprObj), &stLocalSphereCenter); xScaledRadius = xSphereRadius * POS_fn_xGetMaxScale(HIE_fn_hGetSuperObjectGlobalMatrix(_hSprObj)); } else if ((bBoundingBox) && (hParallelBox)) { MTH3D_tdstVector *p_stMinPoint; MTH3D_tdstVector *p_stMaxPoint; MTH3D_tdstVector stTranslation; /*PRF_fn_vIncreaseVariable(PRF_C_ulVarGLI1, NULL, 1);*/ p_stMinPoint = GEO_fn_pGetMinPointOfParallelBox(hParallelBox); p_stMaxPoint = GEO_fn_pGetMaxPointOfParallelBox(hParallelBox); stTranslation = (HIE_fn_hGetSuperObjectGlobalMatrix(_hSprObj))->stTranslationVector; MTH3D_M_vAddVector(&stMinPoint, p_stMinPoint , &stTranslation); MTH3D_M_vAddVector(&stMaxPoint, p_stMaxPoint , &stTranslation); } /*Fast intersection test with the bounding volumes */ if(((!hBoundingSphere) && (!hParallelBox))|| (!bBoundingBox && INT_fn_bIntersectSphereWithSphere(&g_stPickedPoint,g_xNearDistance,&stGlobalSphereCenter,xScaledRadius)) || (bBoundingBox && INT_fn_bIntersectSphereWithBox(&g_stPickedPoint, g_xNearDistance, &stMinPoint,&stMaxPoint))) return TRUE; return FALSE; } /* ##F=================================================================================== NAME : SHW_fn_bFirstIntersectShadowSuperObject DESCRIPTION : Find the face intersected by a semi-axe Recursive function to find the highest face on several SpObj ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bFirstIntersectShadowSuperObject ( HIE_tdxHandleToSuperObject _hSprObj, ACP_tdxIndex *p_xIntersTest, HIE_tdxHandleToSuperObject hHandleOfCharacter ) { GEO_tdxHandleToBoundingSphere hBoundingSphere = NULL; GEO_tdxHandleToParallelBox hParallelBox = NULL; ACP_tdxHandleOfObject hSentObject=NULL; ACP_tdxIndex i; long lTempSuperObjectType; HIE_tdxHandleToSuperObject _hChild; MTH3D_tdstVector stHitPoint; ACP_tdxIndex xElement; ACP_tdxIndex xDataElement; ACP_tdxBool bBoundingBox; MTH3D_tdstVector stMinPoint; MTH3D_tdstVector stMaxPoint; MTH3D_tdstVector stVertexALocal; MTH3D_tdstVector stVertexBLocal; MTH3D_tdstVector stVertexABLocal; if ( HIE_fn_SO_bIsNotPickable( _hSprObj )) return ((*p_xIntersTest)!=0); lTempSuperObjectType=HIE_fn_ulGetSuperObjectType(_hSprObj); if (*p_xIntersTeststTranslationVector; MTH3D_M_vAddVector(&stMinPoint, p_stMinPoint , &stTranslation); MTH3D_M_vAddVector(&stMaxPoint, p_stMaxPoint , &stTranslation); } /*Quick Test of intersection with the bounding volume*/ if(((!hBoundingSphere) && (!hParallelBox))|| (HIE_fn_SO_bCheckChildren(_hSprObj)) || ((!bBoundingBox) && fn_bDetectIntersectSegmentWithBoundingSphere(HIE_fn_hGetSuperObjectGlobalMatrix(_hSprObj), &g_stStartPicking,&g_stVertexAB, hBoundingSphere) ) || ((bBoundingBox) && INT_fn_bDetectIntersectSegmentWithBox(&g_stStartPicking,&g_stVertexAB, &stMinPoint ,&stMaxPoint,NULL))) { ACP_tdxBool bContinue; bContinue= TRUE; /*Several functions to get the geometric linked object*/ if(lTempSuperObjectType == HIE_C_ulPO) hSentObject=SHW_M_hGetRepositionZoneFromPo((PO_tdxHandleToPhysicalObject)HIE_fn_hGetSuperObjectObject(_hSprObj)); else if (lTempSuperObjectType == HIE_C_ulEDT_Geometric) hSentObject=(ACP_tdxHandleOfObject)HIE_fn_hGetSuperObjectObject(_hSprObj); #ifndef D_THROW_IPO else if(lTempSuperObjectType & (HIE_C_ulIPO | HIE_C_ulIPO_Mirror)) hSentObject=SHW_M_hGetRepositionZoneFromPo(IPO_fn_hGetPhysicalObject((IPO_tdxHandleToInstanciatedPhysicalObject)HIE_fn_hGetSuperObjectObject(_hSprObj))); #endif /* D_THROW_IPO */ else bContinue = FALSE; if (bContinue) { POS_fn_vInvertMatrix(&g_stInvertCurrentMatrix, g_p_stCurrentMatrix); POS_fn_vMulMatrixVertex(&stVertexALocal, &g_stInvertCurrentMatrix, &g_stStartPicking); POS_fn_vMulMatrixVertex(&stVertexBLocal, &g_stInvertCurrentMatrix, &g_stVertexB); MTH3D_M_vSubVector(&stVertexABLocal, &stVertexBLocal, &stVertexALocal); /* Slow Intersection Test with the geometric object*/ if (INT_fn_bIntersectSegmentWithShadowFaceOfGeometricObject ( &stVertexALocal, &stVertexBLocal, &stVertexABLocal, hSentObject, &stHitPoint, &xElement, &xDataElement ) ) { MTH3D_tdstVector stMulMatrixTempVector; POS_fn_vMulMatrixVertex(&stMulMatrixTempVector,g_p_stCurrentMatrix,&stHitPoint); /*If I've found an upper face*/ if (MTH_M_bGreater(stMulMatrixTempVector.xZ , g_stPickedPoint.xZ)) { (*p_xIntersTest)++; MTH3D_M_vCopyVector(&g_stPickedPoint,&stMulMatrixTempVector); g_xPickedElement=xElement; g_xPickedFace=xDataElement; g_hPickedSprObj=_hSprObj; g_hPickedObject=hSentObject; } } if (*p_xIntersTeststTranslationVector; MTH3D_M_vAddVector(&stMinPoint, p_stMinPoint , &stTranslation); MTH3D_M_vAddVector(&stMaxPoint, p_stMaxPoint , &stTranslation); } /*Fast intersection test with the bounding volumes */ if(((!hBoundingSphere) && (!hParallelBox))|| (HIE_fn_SO_bCheckChildren(_hSprObj))|| (!bBoundingBox && INT_fn_bIntersectSphereWithSphere(&g_stPickedPoint,g_xNearDistance,&stGlobalSphereCenter,xScaledRadius)) || (bBoundingBox && INT_fn_bIntersectSphereWithBox(&g_stPickedPoint, g_xNearDistance, &stMinPoint,&stMaxPoint))) { MTH3D_tdstVector p_stLocalCenter; if(lTempSuperObjectType == HIE_C_ulPO) hSentObject=SHW_M_hGetRepositionZoneFromPo((PO_tdxHandleToPhysicalObject)HIE_fn_hGetSuperObjectObject(_hSprObj)); /*I get the linked geometric object */ else if(lTempSuperObjectType == HIE_C_ulEDT_Geometric) hSentObject=(ACP_tdxHandleOfObject)HIE_fn_hGetSuperObjectObject(_hSprObj); /*XB980821*/ #ifndef D_THROW_IPO else if(lTempSuperObjectType & (HIE_C_ulIPO | HIE_C_ulIPO_Mirror)) hSentObject = SHW_M_hGetRepositionZoneFromPo(IPO_fn_hGetPhysicalObject((IPO_tdxHandleToInstanciatedPhysicalObject)HIE_fn_hGetSuperObjectObject(_hSprObj))); #endif /* D_THROW_IPO */ /*End XB */ /* conversion to local coordinate system */ POS_fn_vInvertMatrix(&g_stInvertCurrentMatrix, g_p_stCurrentMatrix); POS_fn_vMulMatrixVertex(&p_stLocalCenter, &g_stInvertCurrentMatrix, &g_stPickedPoint); /*Slow intersection test with the geometric object that gives to me an array of faces intersected*/ if (INT_fn_bIntersectSphereWithShadowFaceOfGeometricObject( &p_stLocalCenter, g_xNearDistance, hSentObject, SHW_C_xMaxTriangles, &(g_a_stShadowInfo[g_shNbObjPicked].xNbElement), g_a_stShadowInfo[g_shNbObjPicked].a_stShadowObject, &bBadMaterial) ) { /*If I am working on the first geometric object intersected by the semi-axe*/ if (g_bFirstFace) { long xNbel; short xObjPicked; ACP_tdxBool xAddFace; xNbel=0; xObjPicked=g_shNbObjPicked; xAddFace=0; /*I must add the first picked face to the array of face but without making it bouble*/ if (hSentObject==g_hPickedObject) { short xNbElement; ACP_tdxBool bFlag = FALSE; p_stShadowInfo = &g_a_stShadowInfo[xObjPicked]; p_stShadowObject = p_stShadowInfo->a_stShadowObject; xNbElement = p_stShadowInfo->xNbElement; if (xNbElement > SHW_C_xMaxTriangles) { xNbElement= SHW_C_xMaxTriangles; bFlag = TRUE; } xNbel = 0; while ((!xAddFace)&&(xNbelxElementIndex)==g_xPickedElement)&& ((p_stShadowObject->xDataElementIndex)==g_xPickedFace) ); p_stShadowObject ++; xNbel++; } if (!xAddFace) { if (/*p_stShadowInfo->xNbElementa_stShadowObject[xNbElement]); p_stShadowObject->xElementIndex=g_xPickedElement; p_stShadowObject->xDataElementIndex=g_xPickedFace; p_stShadowInfo->xNbElement++; } else { p_stShadowObject = &(p_stShadowInfo->a_stShadowObject[xNbElement-1]); p_stShadowObject->xElementIndex=g_xPickedElement; p_stShadowObject->xDataElementIndex=g_xPickedFace; } } } g_bFirstFace =FALSE; } p_stShadowInfo = &g_a_stShadowInfo[g_shNbObjPicked]; p_stShadowInfo->hPickedSpObj=_hSprObj; p_stShadowInfo->hPickedObject=hSentObject; g_shNbObjPicked++; } else { if ((g_bFirstFace)&&(hSentObject==g_hPickedObject)) { if (!bBadMaterial) { p_stShadowInfo = &g_a_stShadowInfo[g_shNbObjPicked]; p_stShadowInfo->hPickedSpObj=_hSprObj; p_stShadowInfo->hPickedObject=hSentObject; p_stShadowObject = p_stShadowInfo->a_stShadowObject; p_stShadowInfo->xNbElement=1; p_stShadowObject->xElementIndex=g_xPickedElement; p_stShadowObject->xDataElementIndex=g_xPickedFace; g_shNbObjPicked++; g_bFirstFace = FALSE; } } } if (g_shNbObjPicked=2) g_xGeneralLevelOfQualityOfShadows=2; else if (xQualityOfShadow==1) g_xGeneralLevelOfQualityOfShadows=1; else (g_xGeneralLevelOfQualityOfShadows=0); } /* ##F=================================================================================== NAME : SHW_fn_bInTriangleCalcul DESCRIPTION : Used by SHW_fn_bInTriangle ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bInTriangleCalcul ( MTH_tdxReal *x2, MTH_tdxReal *y2, MTH_tdxReal *x1, MTH_tdxReal *y1, MTH_tdxReal *x, MTH_tdxReal *y ) { return MTH_M_bGreaterEqual ( MTH_M_xMul(MTH_M_xSub(*x2,*x1),MTH_M_xSub(*y,*y1)), MTH_M_xMul(MTH_M_xSub(*y2,*y1),MTH_M_xSub(*x,*x1)) ); } /* ##F=================================================================================== NAME : SHW_fn_bInTriangle DESCRIPTION : Test if a 2D point is into a 2D triangle ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bInTriangle ( MTH_tdxReal *x1, MTH_tdxReal *y1, MTH_tdxReal *x2, MTH_tdxReal *y2, MTH_tdxReal *x3, MTH_tdxReal *y3, MTH_tdxReal *x, MTH_tdxReal *y) { ACP_tdxBool bTemp; /* bTemp=SHW_fn_bInTriangleCalcul(x2,y2,x1,y1,x,y);*/ /* return ((bTemp==SHW_fn_bInTriangleCalcul(x3,y3,x2,y2,x,y))&&(bTemp==SHW_fn_bInTriangleCalcul(x1,y1,x3,y3,x,y)));*/ bTemp=((SHW_fn_bInTriangleCalcul(x2,y2,x1,y1,x,y)&&SHW_fn_bInTriangleCalcul(x3,y3,x2,y2,x,y))&& SHW_fn_bInTriangleCalcul(x1,y1,x3,y3,x,y)); return bTemp; } /* ##F=================================================================================== NAME : SHW_fn_bCreateIntersectionSegmentSegment DESCRIPTION : Return intersection of two 2D segments ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bCreateIntersectionSegmentSegment ( MTH_tdxReal *xA, MTH_tdxReal *yA, MTH_tdxReal *xB, MTH_tdxReal *yB, MTH_tdxReal *xD, MTH_tdxReal *yD, MTH_tdxReal *xE, MTH_tdxReal *yE, MTH_tdxReal *xIntersectionOnSegmentAB, MTH_tdxReal *xIntersectionOnSegmentDE ) { if (MTH_M_bEqual(*xE,*xD)) { if MTH_M_bEqual(*xA,*xB) return 0; if MTH_M_bEqual(*yE,*yD) return 0; *xIntersectionOnSegmentAB=MTH_M_xDiv(MTH_M_xSub(*xD,*xA),MTH_M_xSub(*xB,*xA)); if ((MTH_M_bLess(*xIntersectionOnSegmentAB,MTH_C_ZERO))|| (MTH_M_bGreater(*xIntersectionOnSegmentAB,MTH_C_ONE))) return 0; *xIntersectionOnSegmentDE=MTH_M_xDiv(MTH_M_xAdd(MTH_M_xMul(*xIntersectionOnSegmentAB, MTH_M_xSub(*yB,*yA)),MTH_M_xSub(*yA,*yD)),MTH_M_xSub(*yE,*yD)); if ((MTH_M_bLess(*xIntersectionOnSegmentDE,MTH_C_ZERO))|| (MTH_M_bGreater(*xIntersectionOnSegmentDE,MTH_C_ONE))) return 0; return 1; } else { MTH_tdxReal Div_yEmyD_xEmxD,xEmxD; xEmxD=MTH_M_xSub(*xE,*xD); Div_yEmyD_xEmxD=MTH_M_xDiv(MTH_M_xSub(*yE,*yD),xEmxD); if (MTH_M_bEqualZero(Div_yEmyD_xEmxD)) return 0; *xIntersectionOnSegmentAB= MTH_M_xDiv(MTH_M_xAdd(MTH_M_xSub(*yD,*yA),MTH_M_xMul(Div_yEmyD_xEmxD,MTH_M_xSub(*xA,*xD))), MTH_M_xAdd(MTH_M_xSub(*yB,*yA),MTH_M_xMul(Div_yEmyD_xEmxD,MTH_M_xSub(*xA,*xB)))); if ((MTH_M_bLess(*xIntersectionOnSegmentAB,MTH_C_ZERO))|| (MTH_M_bGreater(*xIntersectionOnSegmentAB,MTH_C_ONE))) return 0; *xIntersectionOnSegmentDE=MTH_M_xDiv(MTH_M_xSub(MTH_M_xAdd(MTH_M_xMul(*xIntersectionOnSegmentAB, *xB),MTH_M_xMul(MTH_M_xSub(MTH_C_ONE,*xIntersectionOnSegmentAB),*xA)),*xD),xEmxD); if ((MTH_M_bLess(*xIntersectionOnSegmentDE,MTH_C_ZERO))|| (MTH_M_bGreater(*xIntersectionOnSegmentDE,MTH_C_ONE))) return 0; return 1; } }/*SHW_fn_bCreateIntersectionSegmentSegment*/ /* ##F=================================================================================== NAME : SHW_fn_vOrderTabResultInt DESCRIPTION : Return an order in an array of points: Specific to Fake Shadow SEE THE DESCRIPTION OF THIS FUNCTION IN DOCUBI IF YOU MISS SOMETHING ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vOrderTabResultInt ( SHW_tdstResultIntersectionCT *_p_a10_stTabResultInt, short *_p_a10_xOrderInTabResult, short _xImax ) { long i; short j,jprec,xCT1,xStart1,xCT2,xStart2; ACP_tdxBool test,testOK; SHW_tdstResultIntersectionCT *p_stTabResultInt; short *p_xOrderInTabResult; *_p_a10_xOrderInTabResult=0; xCT1=_p_a10_stTabResultInt->xCT1; xStart1=_p_a10_stTabResultInt->xStart1; xCT2=_p_a10_stTabResultInt->xCT2; xStart2=_p_a10_stTabResultInt->xStart2; jprec=0; p_xOrderInTabResult = _p_a10_xOrderInTabResult; for (i=1;i<_xImax;i++) { j=0; testOK=1; p_stTabResultInt = _p_a10_stTabResultInt; while (testOK) { test=(((xCT1==p_stTabResultInt->xCT1)&&(xStart1==p_stTabResultInt->xStart1))|| ((xCT2==p_stTabResultInt->xCT2)&&(xStart2==p_stTabResultInt->xStart2))|| ((xCT1==p_stTabResultInt->xCT2)&&(xStart1==p_stTabResultInt->xStart2))|| ((xCT2==p_stTabResultInt->xCT1)&&(xStart2==p_stTabResultInt->xStart1))); testOK=(((j==jprec)||(j==*p_xOrderInTabResult)||(test==0))&&(j<_xImax)); if (testOK) { j++; p_stTabResultInt++; } } jprec=*p_xOrderInTabResult; p_xOrderInTabResult++; *p_xOrderInTabResult=j; xCT1=p_stTabResultInt->xCT1; xStart1=p_stTabResultInt->xStart1; xCT2=p_stTabResultInt->xCT2; xStart2=p_stTabResultInt->xStart2; } }/*SHW_fn_vOrderTabResultInt*/ /* ##F=================================================================================== NAME : SHW_fn_vCalculateCoordinatesForCorners DESCRIPTION : Calculate the coordinates of a corner of UV texture:Specific to Fake Shadow ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vCalculateCoordinatesForCorners ( MTH3D_tdstVector *_p_stTempTriangle, SHW_tdstResultIntersectionCT *_p_stTabResultInt, MTH3D_tdstVector *_p_stDirectionOfShadow, MTH3D_tdstVector *_p_stTempGlobalNormal, MTH_tdxReal *_p_xZc1 , MTH_tdxReal *_p_xZc2 , MTH_tdxReal *_p_xInvGlobalNormalxZ, MTH3D_tdstVector *_p_stGlobalPoints ) { MTH_tdxReal UTemp1=MTH_M_xMul(*_p_xZc1 ,MTH_M_xSub(_p_stTabResultInt->uvPoint.xU,MTH_M_xFloatToReal(0.5f))); MTH_tdxReal UTemp2=MTH_M_xMul(*_p_xZc2 ,MTH_M_xSub(_p_stTabResultInt->uvPoint.xV,MTH_M_xFloatToReal(0.5f))); _p_stGlobalPoints->xX=MTH_M_xSub(g_stStartPicking.xX,MTH_M_xAdd(MTH_M_xMul(UTemp1,_p_stDirectionOfShadow->xY),MTH_M_xMul(UTemp2,_p_stDirectionOfShadow->xX))); _p_stGlobalPoints->xY=MTH_M_xAdd(g_stStartPicking.xY,MTH_M_xSub(MTH_M_xMul(UTemp1,_p_stDirectionOfShadow->xX),MTH_M_xMul(UTemp2,_p_stDirectionOfShadow->xY))); _p_stGlobalPoints->xZ=MTH_M_xSub ( _p_stTempTriangle->xZ, MTH_M_xMul ( *_p_xInvGlobalNormalxZ, MTH_M_xAdd ( MTH_M_xMul(_p_stTempGlobalNormal->xX,MTH_M_xSub(_p_stGlobalPoints->xX,_p_stTempTriangle->xX)), MTH_M_xMul(_p_stTempGlobalNormal->xY,MTH_M_xSub(_p_stGlobalPoints->xY,_p_stTempTriangle->xY)) ) ) ); }/*SHW_fn_vCalculateCoordinatesForCorners*/ /* ##F=================================================================================== NAME : SHW_fn_vClipShadow DESCRIPTION : Clip a face only with UV in [0;1] Specific to Fake Shadow ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vClipShadow ( ACP_tdst2DUVValues *_p_a3_stCalculatedUV, ACP_tdxIndex *_p_xTempPoints, ACP_tdxIndex *_p_xTempFace, MTH3D_tdstVector *_p_a3_stTempTriangle, MTH3D_tdstVector *_p_stDirectionOfShadow, MTH3D_tdstVector *_p_stTempGlobalNormal, MTH_tdxReal *_p_xZc1, MTH_tdxReal *_p_xZc2, MTH_tdxReal *_p_xInvGlobalNormalxZ ) { ACP_tdxIndex xIndexOfFirstPoint; ACP_tdst2DUVValues stUVC,stUVC2; SHW_tdstResultIntersectionCT a10_stTabResultInt[10]; short a10_wOrderInTabResult[10]; short xNbIntTC=0,i,j; MTH3D_tdstVector a10_stGlobalPoints[10]; ACP_tdxBool bInT1,bInT2,bInT3,bInT4,bInC1,bInC2,bInC3; ACP_tdxHandleOfObject hHandleOfGeometricShadowObject; SHW_tdstResultIntersectionCT *p_stTabResultInt; MTH3D_tdstVector *p_stTmpGlobalPoints; short *p_wOrderInTabResult; GLI_tdxUVValue *p_xValueU0, *p_xValueU1, *p_xValueU2; GLI_tdxUVValue *p_xValueV0, *p_xValueV1, *p_xValueV2; MTH3D_tdstVector *p_stTempTriangle; ACP_tdst2DUVValues *p_stCalculatedUV; MTH3D_tdstVector *p_stNextTempTriangle; ACP_tdst2DUVValues *p_stNextCalculatedUV; p_stCalculatedUV = _p_a3_stCalculatedUV; p_xValueU0 = &p_stCalculatedUV->xU; p_xValueV0 = &p_stCalculatedUV->xV; p_stCalculatedUV ++; p_xValueU1 = &p_stCalculatedUV->xU; p_xValueV1 = &p_stCalculatedUV->xV; p_stCalculatedUV ++; p_xValueU2 = &p_stCalculatedUV->xU; p_xValueV2 = &p_stCalculatedUV->xV; bInC1 = (MTH_M_bInUnitEqual(*p_xValueU0) && MTH_M_bInUnitEqual(*p_xValueV0)); bInC2 = (MTH_M_bInUnitEqual(*p_xValueU1) && MTH_M_bInUnitEqual(*p_xValueV1)); bInC3 = (MTH_M_bInUnitEqual(*p_xValueU2) && MTH_M_bInUnitEqual(*p_xValueV2)); hHandleOfGeometricShadowObject = p_hHandleOfGeometricShadowObject[g_xIndexOfShadow]; /*If the three points of the triangle are in the UV square*/ if ((bInC1)&&(bInC2)&&(bInC3)) { p_stTempTriangle = _p_a3_stTempTriangle; p_stCalculatedUV = _p_a3_stCalculatedUV; for (i=0;i<3;i++, p_stTempTriangle++, p_stCalculatedUV++) { GEO_vSetPointOfObject(hHandleOfGeometricShadowObject,p_stTempTriangle,(short)((*_p_xTempPoints)+i)); GEO_vSetUVOfIndexedTriangles(hHandleOfGeometricShadowObject,0,(short)((*_p_xTempPoints)+i),p_stCalculatedUV); } GEO_vSetFaceOfIndexedTriangles(hHandleOfGeometricShadowObject,0,*_p_xTempFace,*_p_xTempPoints,(short)((*_p_xTempPoints)+1),(short)((*_p_xTempPoints)+2)); /*M_PrintfN64(("Adding Face %d,%d,%d\n",xIndexOfFirstPoint,*_p_xTempPoints,(short)((*_p_xTempPoints)+1),(short)((*_p_xTempPoints)+2)));*/ GEO_vSetIndexedUVOfFaceOfIndexedTriangles(hHandleOfGeometricShadowObject,0,*_p_xTempFace,*_p_xTempPoints,(short)((*_p_xTempPoints)+1),(short)((*_p_xTempPoints)+2)); (*_p_xTempFace)++; (*_p_xTempPoints)+=3; } else { xNbIntTC=0; p_stTabResultInt = a10_stTabResultInt; stUVC.xU=MTH_C_ZERO; stUVC.xV=MTH_C_ZERO; bInT1=SHW_fn_bInTriangle(p_xValueU0,p_xValueV0,p_xValueU1,p_xValueV1,p_xValueU2,p_xValueV2,&stUVC.xU,&stUVC.xV); if (bInT1) { p_stTabResultInt->xCT1=0; p_stTabResultInt->xCT2=0; p_stTabResultInt->xStart1=3; p_stTabResultInt->xStart2=0; p_stTabResultInt->uvPoint.xU=MTH_C_ZERO; p_stTabResultInt->uvPoint.xV=MTH_C_ZERO; SHW_fn_vCalculateCoordinatesForCorners(_p_a3_stTempTriangle,p_stTabResultInt,_p_stDirectionOfShadow,_p_stTempGlobalNormal,_p_xZc1,_p_xZc2 ,_p_xInvGlobalNormalxZ,&a10_stGlobalPoints[xNbIntTC]); xNbIntTC++; p_stTabResultInt++; } stUVC.xU=MTH_C_ONE; /* stUVC.xV=MTH_C_ZERO;*/ bInT2=SHW_fn_bInTriangle(p_xValueU0,p_xValueV0,p_xValueU1,p_xValueV1,p_xValueU2,p_xValueV2,&stUVC.xU,&stUVC.xV); if (bInT2) { p_stTabResultInt->xCT1=0; p_stTabResultInt->xCT2=0; p_stTabResultInt->xStart1=0; p_stTabResultInt->xStart2=1; p_stTabResultInt->uvPoint.xU=MTH_C_ONE; p_stTabResultInt->uvPoint.xV=MTH_C_ZERO; SHW_fn_vCalculateCoordinatesForCorners(_p_a3_stTempTriangle,p_stTabResultInt,_p_stDirectionOfShadow,_p_stTempGlobalNormal,_p_xZc1,_p_xZc2,_p_xInvGlobalNormalxZ,&a10_stGlobalPoints[xNbIntTC]); xNbIntTC++; p_stTabResultInt++; } /* stUVC.xU=MTH_C_ONE;*/ stUVC.xV=MTH_C_ONE; bInT3=SHW_fn_bInTriangle(p_xValueU0,p_xValueV0,p_xValueU1,p_xValueV1,p_xValueU2,p_xValueV2,&stUVC.xU,&stUVC.xV); if (bInT3) { p_stTabResultInt->xCT1=0; p_stTabResultInt->xCT2=0; p_stTabResultInt->xStart1=1; p_stTabResultInt->xStart2=2; p_stTabResultInt->uvPoint.xU=MTH_C_ONE; p_stTabResultInt->uvPoint.xV=MTH_C_ONE; SHW_fn_vCalculateCoordinatesForCorners(_p_a3_stTempTriangle,p_stTabResultInt,_p_stDirectionOfShadow,_p_stTempGlobalNormal,_p_xZc1,_p_xZc2,_p_xInvGlobalNormalxZ,&a10_stGlobalPoints[xNbIntTC]); p_stTabResultInt++; xNbIntTC++; } stUVC.xU=MTH_C_ZERO; /* stUVC.xV=MTH_C_ONE;*/ bInT4=SHW_fn_bInTriangle(p_xValueU0,p_xValueV0,p_xValueU1,p_xValueV1,p_xValueU2,p_xValueV2,&stUVC.xU,&stUVC.xV); if (bInT4) { p_stTabResultInt->xCT1=0; p_stTabResultInt->xCT2=0; p_stTabResultInt->xStart1=2; p_stTabResultInt->xStart2=3; p_stTabResultInt->uvPoint.xU=MTH_C_ZERO; p_stTabResultInt->uvPoint.xV=MTH_C_ONE; SHW_fn_vCalculateCoordinatesForCorners(_p_a3_stTempTriangle,p_stTabResultInt,_p_stDirectionOfShadow,_p_stTempGlobalNormal,_p_xZc1,_p_xZc2,_p_xInvGlobalNormalxZ,&a10_stGlobalPoints[xNbIntTC]); p_stTabResultInt++; xNbIntTC++; } /*If all the UV square is in the triangle*/ if ((bInT1)&&(bInT2)&&(bInT3)&&(bInT4)) { ACP_tdxIndex xIndexOfFirstPoint=(*_p_xTempPoints); p_stTabResultInt = a10_stTabResultInt; p_stTmpGlobalPoints = a10_stGlobalPoints; for (i=0;iuvPoint)); p_stTmpGlobalPoints++; p_stTabResultInt++; (*_p_xTempPoints)++; } for (i=1;ixCT1=1; p_stTabResultInt->xCT2=1; p_stTabResultInt->xStart1=2; p_stTabResultInt->xStart2=0; p_stTabResultInt->uvPoint.xU=*p_xValueU0; p_stTabResultInt->uvPoint.xV=*p_xValueV0; p_stTmpGlobalPoints->xX=p_stTempTriangle->xX; p_stTmpGlobalPoints->xY=p_stTempTriangle->xY; p_stTmpGlobalPoints->xZ=p_stTempTriangle->xZ; p_stTabResultInt++; p_stTmpGlobalPoints++; xNbIntTC++; } p_stTempTriangle++; if (bInC2) { p_stTabResultInt->xCT1=1; p_stTabResultInt->xCT2=1; p_stTabResultInt->xStart1=0; p_stTabResultInt->xStart2=1; p_stTabResultInt->uvPoint.xU=*p_xValueU1; p_stTabResultInt->uvPoint.xV=*p_xValueV1; p_stTmpGlobalPoints->xX=p_stTempTriangle->xX; p_stTmpGlobalPoints->xY=p_stTempTriangle->xY; p_stTmpGlobalPoints->xZ=p_stTempTriangle->xZ; p_stTabResultInt++; p_stTmpGlobalPoints++; xNbIntTC++; } p_stTempTriangle++; if (bInC3) { p_stTabResultInt->xCT1=1; p_stTabResultInt->xCT2=1; p_stTabResultInt->xStart1=1; p_stTabResultInt->xStart2=2; p_stTabResultInt->uvPoint.xU=*p_xValueU2; p_stTabResultInt->uvPoint.xV=*p_xValueV2; p_stTmpGlobalPoints->xX=p_stTempTriangle->xX; p_stTmpGlobalPoints->xY=p_stTempTriangle->xY; p_stTmpGlobalPoints->xZ=p_stTempTriangle->xZ; p_stTabResultInt++; p_stTmpGlobalPoints++; xNbIntTC++; } /*Here are the intersection computations*/ for (i=0;i<4;i++) { switch(i) { case 0: { stUVC.xU=MTH_C_ZERO; stUVC.xV=MTH_C_ZERO; stUVC2.xU=MTH_C_ONE; stUVC2.xV=MTH_C_ZERO; break; } case 1: { stUVC.xU=MTH_C_ONE; /* stUVC.xV=MTH_C_ZERO;*/ /* stUVC2.xU=MTH_C_ONE;*/ stUVC2.xV=MTH_C_ONE; break; } case 2: { /* stUVC.xU=MTH_C_ONE;*/ stUVC.xV=MTH_C_ONE; stUVC2.xU=MTH_C_ZERO; /* stUVC2.xV=MTH_C_ONE;*/ break; } case 3: { stUVC.xU=MTH_C_ZERO; /* stUVC.xV=MTH_C_ONE;*/ /* stUVC2.xU=MTH_C_ZERO;*/ stUVC2.xV=MTH_C_ZERO; break; } } p_stTabResultInt = &a10_stTabResultInt[xNbIntTC]; p_stTmpGlobalPoints = &a10_stGlobalPoints[xNbIntTC]; p_stTempTriangle = _p_a3_stTempTriangle; p_stCalculatedUV = _p_a3_stCalculatedUV; p_stNextTempTriangle = p_stTempTriangle; p_stNextCalculatedUV = p_stCalculatedUV; for (j=0;j<3;j++, p_stTempTriangle++, p_stCalculatedUV++) { MTH_tdxReal xAlpha1,xAlpha2; if (j==2) { p_stNextTempTriangle = _p_a3_stTempTriangle; p_stNextCalculatedUV = _p_a3_stCalculatedUV; } else { p_stNextTempTriangle++; p_stNextCalculatedUV++; } if (SHW_fn_bCreateIntersectionSegmentSegment(&stUVC.xU,&stUVC.xV,&stUVC2.xU,&stUVC2.xV, &p_stCalculatedUV->xU,&p_stCalculatedUV->xV, &p_stNextCalculatedUV->xU,&p_stNextCalculatedUV->xV, &xAlpha1,&xAlpha2)) { MTH_tdxReal xS1; p_stTabResultInt->xCT1=0; p_stTabResultInt->xCT2=1; p_stTabResultInt->xStart1=i; p_stTabResultInt->xStart2=j; xS1=MTH_M_xSub(MTH_C_ONE,xAlpha1); p_stTabResultInt->uvPoint.xU=MTH_M_xAdd(MTH_M_xMul(xS1,stUVC.xU),MTH_M_xMul(xAlpha1,stUVC2.xU)); p_stTabResultInt->uvPoint.xV=MTH_M_xAdd(MTH_M_xMul(xS1,stUVC.xV),MTH_M_xMul(xAlpha1,stUVC2.xV)); xS1=MTH_M_xSub(MTH_C_ONE,xAlpha2); p_stTmpGlobalPoints->xX=MTH_M_xAdd(MTH_M_xMul(xS1,p_stTempTriangle->xX),MTH_M_xMul(xAlpha2,p_stNextTempTriangle->xX)); p_stTmpGlobalPoints->xY=MTH_M_xAdd(MTH_M_xMul(xS1,p_stTempTriangle->xY),MTH_M_xMul(xAlpha2,p_stNextTempTriangle->xY)); p_stTmpGlobalPoints->xZ=MTH_M_xAdd(MTH_M_xMul(xS1,p_stTempTriangle->xZ),MTH_M_xMul(xAlpha2,p_stNextTempTriangle->xZ)); p_stTabResultInt++; p_stTmpGlobalPoints++; xNbIntTC++; } } } /*To put the array of points in order */ SHW_fn_vOrderTabResultInt(a10_stTabResultInt,a10_wOrderInTabResult,xNbIntTC); xIndexOfFirstPoint=*_p_xTempPoints; /*Add the points found*/ p_wOrderInTabResult = a10_wOrderInTabResult; for (i=0;ixX,*_p_xYPoint), MTH_M_xMul(_p_stDirectionOfShadow->xY,*_p_xXPoint))))); } /* ##F=================================================================================== NAME : SHW_fn_xFormulaV DESCRIPTION : Calculate V from x and y ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ MTH_tdxReal SHW_fn_xFormulaV ( MTH_tdxReal *_p_xScaleY, MTH_tdxReal *_p_xCoefAltitude, MTH3D_tdstVector *_p_stDirectionOfShadow, MTH_tdxReal *_p_xXPoint, MTH_tdxReal *_p_xYPoint ) { return MTH_M_xSub(MTH_C_Inv2,MTH_M_xMul(*_p_xScaleY,MTH_M_xMul(*_p_xCoefAltitude, MTH_M_xAdd(MTH_M_xMul(_p_stDirectionOfShadow->xX,*_p_xXPoint), MTH_M_xMul(_p_stDirectionOfShadow->xY,*_p_xYPoint))))); } /* ##F=================================================================================== NAME : SHW_fn_bFaceIsGoodInZForShadow DESCRIPTION : Test if a point of the face is over the Character ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ ACP_tdxBool SHW_fn_bFaceIsGoodInZForShadow ( MTH3D_tdstVector *_p_a3_stTempTriangle, MTH3D_tdstVector *_p_stPickedPoint, short _xObjPicked, short _xFacePicked ) { long i; ACP_tdxBool bTest=1; ACP_tdxBool bAnnulTestHigher=1; ACP_tdxBool bAnnulTestLower=1; MTH3D_tdstVector *p_stTempTriangle; SHW_tdstShadowInfo *p_stShadowInfo; p_stTempTriangle = _p_a3_stTempTriangle; /* Second test for nearly vertical faces if they are connected to horizontal faces*/ p_stShadowInfo = &g_a_stShadowInfo[_xObjPicked]; if (p_stShadowInfo->bDrawFace[_xFacePicked]==1) { ACP_tdxBool bPoint1IsOk=0; ACP_tdxBool bPoint2IsOk=0; ACP_tdxBool bPoint3IsOk=0; ACP_tdxIndex xPointIndex0,xPointIndex1,xPointIndex2; short j; COL_tdstShadowElement *p_stShadowElement; short *p_bDrawFace; ACP_tdxIndex xNbElement; /* First test if all the points are above or below the picked point*/ for (i=0;i<3;i++,p_stTempTriangle++) { if (MTH_M_bLess(p_stTempTriangle->xZ,MTH_M_xAdd(_p_stPickedPoint->xZ,MTH_M_xFloatToReal(0.80f)))) { bAnnulTestHigher=0; } if (MTH_M_bGreater(p_stTempTriangle->xZ,MTH_M_xSub(_p_stPickedPoint->xZ,MTH_M_xFloatToReal(0.80f)))) { bAnnulTestLower=0; } } if ((bAnnulTestHigher)&&(bAnnulTestLower)) return 0; p_stShadowElement = &p_stShadowInfo->a_stShadowObject[_xFacePicked]; GEO_vGetFaceOfIndexedTriangles(p_stShadowInfo->hPickedObject, p_stShadowElement->xElementIndex, p_stShadowElement->xDataElementIndex, &xPointIndex0,&xPointIndex1,&xPointIndex2); p_stShadowElement = p_stShadowInfo->a_stShadowObject; p_bDrawFace = &p_stShadowInfo->bDrawFace[0]; xNbElement = p_stShadowInfo->xNbElement; for (j=0;jhPickedObject, p_stShadowElement->xElementIndex, p_stShadowElement->xDataElementIndex, &xPoint2Index0,&xPoint2Index1,&xPoint2Index2); if (((xPointIndex0==xPoint2Index0)||(xPointIndex0==xPoint2Index1)||(xPointIndex0==xPoint2Index2))) bPoint1IsOk=1; if ((!bPoint2IsOk)&&((xPointIndex1==xPoint2Index0)||(xPointIndex1==xPoint2Index1)||(xPointIndex1==xPoint2Index2))) bPoint2IsOk=1; if ((!bPoint3IsOk)&&((xPointIndex2==xPoint2Index0)||(xPointIndex2==xPoint2Index1)||(xPointIndex2==xPoint2Index2))) bPoint3IsOk=1; } } bTest=((bPoint1IsOk)&&(bPoint2IsOk)&&(bPoint3IsOk)); } return bTest; }/*SHW_fn_bFaceIsGoodInZForShadow*/ /* ##F=================================================================================== NAME : SHW_fn_vCreateIntersectionShadowFace DESCRIPTION : Create the shadow of one SpObj on one face ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vCreateIntersectionShadowFace ( MTH3D_tdstVector *_p_stGlobalNormal, MTH_tdxReal *_p_xInvGlobalNormalxZ, ACP_tdxHandleOfObject _hPickedObject, short _xObjPicked, short _xFacePicked, ACP_tdxIndex _xPickedElement, ACP_tdxIndex _xPickedFace, MTH3D_tdstVector *_p_stPickedPoint, MTH3D_tdstVector *_p_stDirectionOfShadow, ACP_tdxIndex *_p_xTempPoints, ACP_tdxIndex *_p_xTempFace, MTH_tdxReal *_p_xScaleX, MTH_tdxReal *_p_xScaleY, MTH_tdxReal *_p_xCoefAltitude, MTH_tdxReal *_p_xZc1, MTH_tdxReal *_p_xZc2 ) { MTH3D_tdstVector a3_stTempTriangle[3]; MTH3D_tdstVector *p_stTempTriangle; MTH_tdxReal xXPoint,xYPoint; ACP_tdst2DUVValues a3_stCalculatedUV[3]; ACP_tdst2DUVValues *p_stCalculatedUV; short i; GEO_tdxHandleToMatrix hGlobalMatrixOfCharacter; SHW_fn_vGetPointsOfFaceOfIndexedTriangle(_hPickedObject,_xPickedElement,_xPickedFace,a3_stTempTriangle); p_stTempTriangle = a3_stTempTriangle; hGlobalMatrixOfCharacter = HIE_fn_hGetSuperObjectGlobalMatrix(g_a_stShadowInfo[_xObjPicked].hPickedSpObj); for (i=0;i<3;i++, p_stTempTriangle++) { p_stTempTriangle->xZ += 0.05f; /* I get the triangle in the global reference*/ POS_fn_vMulMatrixVertex (p_stTempTriangle,hGlobalMatrixOfCharacter,p_stTempTriangle); } /*I create the shadow faces if the trangle is correct and if there is still enough space in my array*/ if ( /* (SHW_fn_bFaceIsGoodInZForShadow(a3_stTempTriangle,_p_stPickedPoint,_xObjPicked,_xFacePicked))&&*/ (*_p_xTempPoints<=SHW_C_xNbMaxOfPointsPerShadow-6)&& (*_p_xTempFace<=SHW_C_xNbMaxOfFacesPerShadow-4)) { p_stTempTriangle = a3_stTempTriangle; p_stCalculatedUV = a3_stCalculatedUV; for (i=0;i<3;i++, p_stTempTriangle++, p_stCalculatedUV++) { xXPoint=(MTH_M_xSub(p_stTempTriangle->xX,g_stStartPicking.xX)); xYPoint=(MTH_M_xSub(p_stTempTriangle->xY,g_stStartPicking.xY)); /*I compute the corresponding UV*/ p_stCalculatedUV->xU=SHW_fn_xFormulaU(_p_xScaleX,_p_xCoefAltitude,_p_stDirectionOfShadow,&xXPoint,&xYPoint); p_stCalculatedUV->xV=SHW_fn_xFormulaV(_p_xScaleY,_p_xCoefAltitude,_p_stDirectionOfShadow,&xXPoint,&xYPoint); } /*PRF_fn_vStartChrono(PRF_C_ulGLI5, NULL);*/ SHW_fn_vClipShadow(a3_stCalculatedUV,_p_xTempPoints,_p_xTempFace,a3_stTempTriangle,_p_stDirectionOfShadow, _p_stGlobalNormal,_p_xZc1,_p_xZc2,_p_xInvGlobalNormalxZ); /*PRF_fn_vStopChrono(PRF_C_ulGLI5, NULL);*/ } }/*SHW_fn_vCreateIntersectionShadowFace*/ /* ##F=================================================================================== NAME : SHW_fn_vCreateShadowOfCharacterOnFace DESCRIPTION : Create the shadow of a character on one face ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vCreateShadowOfCharacterOnFace ( MTH3D_tdstVector *_p_stGlobalNormal, MTH_tdxReal _xInvNormalZ, HIE_tdxHandleToSuperObject _hFather, ACP_tdxHandleOfObject _hPickedObject, short _xObjPicked, short _xFacePicked, ACP_tdxIndex _xPickedElement, ACP_tdxIndex _xPickedFace, MTH3D_tdstVector *_p_stPickedPoint, ACP_tdxIndex *_p_xTempPoints, ACP_tdxIndex *_p_xTempFace, MTH_tdxReal *_p_xCoefAltitude, MTH_tdxReal *_p_xScaleX, MTH_tdxReal *_p_xScaleY ) { GEO_tdxHandleToMatrix hGlobalMatrixOfCharacter; MTH3D_tdstVector stCharacterRotationX; MTH3D_tdstVector stCharacterRotationY; MTH3D_tdstVector stCharacterRotationZ; MTH_tdxReal xZc1; MTH_tdxReal xZc2; hGlobalMatrixOfCharacter=HIE_fn_hGetSuperObjectGlobalMatrix(_hFather); if (MTH3D_M_bIsNullVector(&g_stDirOfShadow)) { /* I get the rotation matrix of the character*/ POS_fn_vGetRotationMatrix(hGlobalMatrixOfCharacter ,&stCharacterRotationX,&stCharacterRotationY,&stCharacterRotationZ) ; } else { MTH3D_M_vCopyVector(&stCharacterRotationX, &g_stDirOfShadow); } /*Important: Rotation doesn't have to take in account the Z coef*/ stCharacterRotationX.xZ=MTH_C_ZERO; /*If the orientation vector is in Z only*/ if ((MTH_M_bLess(MTH_M_xAbs(stCharacterRotationX.xX),MTH_M_xFloatToReal(0.1f)))&& (MTH_M_bLess(MTH_M_xAbs(stCharacterRotationX.xY),MTH_M_xFloatToReal(0.1f)))) { /*I don't have any orientation so the shadow will be round*/ /*The round scale must be defined here*/ stCharacterRotationX.xX=MTH_M_xDiv(0.48f,fn_x3dDataGetShadowScaleXFromSO(_hFather)); stCharacterRotationX.xY=stCharacterRotationX.xX; } MTH3D_M_vNormalizeVector(&stCharacterRotationX,&stCharacterRotationX); xZc1=MTH_M_xDiv(MTH_C_ONE,MTH_M_xMul(*_p_xScaleX,*_p_xCoefAltitude)); xZc2=MTH_M_xDiv(MTH_C_ONE,MTH_M_xMul(*_p_xScaleY,*_p_xCoefAltitude)); /*PRF_fn_vStartChrono(PRF_C_ulGLI6, NULL);*/ SHW_fn_vCreateIntersectionShadowFace (_p_stGlobalNormal,&_xInvNormalZ,_hPickedObject,_xObjPicked,_xFacePicked,_xPickedElement,_xPickedFace,_p_stPickedPoint, &stCharacterRotationX,_p_xTempPoints,_p_xTempFace,_p_xScaleX,_p_xScaleY,_p_xCoefAltitude,&xZc1,&xZc2); /*PRF_fn_vStopChrono(PRF_C_ulGLI6, NULL);*/ }/*SHW_fn_vCreateShadowOfCharacterOnFace*/ /* ##F=================================================================================== //NAME : SHW_fn_vNormalZSort NAME : SHW_fn_wNormalZSort DESCRIPTION : Test the normal coefficient in Z to determine if the face is drawn or not ========================================================================================= CREATION : Philippe Thiébaut MODIFICAION : YLG =======================================================================================*/ short SHW_fn_wNormalZSort ( HIE_tdxHandleToSuperObject _hPickedSprObject, ACP_tdxHandleOfObject _hPickedObject, COL_tdstShadowElement *_p_stShadowObject, MTH3D_tdstVector *_p_stGlobalNormal ) { MTH3D_tdstVector vTempLocalNormal; /*I get the global normal of the face by multiplying the local normal by the rotation matrix*/ GEO_vGetNormalOfGeometricObjectElement( _hPickedObject, _p_stShadowObject->xElementIndex, _p_stShadowObject->xDataElementIndex, &vTempLocalNormal); POS_fn_vRotateVector(_p_stGlobalNormal,HIE_fn_hGetSuperObjectGlobalMatrix(_hPickedSprObject),&vTempLocalNormal); MTH3D_M_vNormalizeVector(_p_stGlobalNormal,_p_stGlobalNormal); /*Here the faces are considered as horizontal*/ if (MTH_M_bGreater(_p_stGlobalNormal->xZ,MTH_M_xFloatToReal(0.3f))) return 2; /*Here the faces are considered as nearly vertical*/ else if (MTH_M_bGreater(_p_stGlobalNormal->xZ,MTH_M_xFloatToReal(0.1f))) return 1; /*Here the faces don't cast any shadow*/ else return 0; }/*SHW_fn_vNormalZSort*/ /* ##F=================================================================================== NAME : SHW_fnvIsThereTooManyFaces DESCRIPTION : Return if there is too many faces ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fnvIsThereTooManyFaces(short *xNbObjPicked) { short xObjPicked=0; ACP_tdxBool bDrawShadowOnlyOnOneObject=FALSE; /*PRF_fn_vStartChrono(PRF_C_ulGLI7, NULL);*/ if (g_a_stShadowInfo[0].xNbElement==SHW_C_xMaxTriangles) { g_a_stShadowInfo[0].xNbElement=1; (*xNbObjPicked)=1; } else { for (xObjPicked=1;xObjPicked<(*xNbObjPicked);xObjPicked++) { if (g_a_stShadowInfo[xObjPicked].xNbElement==SHW_C_xMaxTriangles) bDrawShadowOnlyOnOneObject=TRUE; } if (bDrawShadowOnlyOnOneObject) (*xNbObjPicked)=1; } /*PRF_fn_vStopChrono(PRF_C_ulGLI7, NULL);*/ } /* ##F=================================================================================== NAME : SHW_fn_vTakeCareOfProjectionVector DESCRIPTION : ========================================================================================= CREATION : Yann Le Guyader =======================================================================================*/ void SHW_fn_vTakeCareOfProjectionVector ( HIE_tdxHandleToSuperObject _hHandleOfCharacter, MTH3D_tdstVector *_p_stProjectionVector, MTH_tdxReal *_p_xScaleX, MTH_tdxReal *_p_xScaleY ) { MTH3D_tdstVector stLightDir; MTH3D_tdstVector stVectB; MTH_tdxReal xCosX, xCosY; MTH_tdxReal xNormUV; MTH3D_M_vCopyVector(&stLightDir, fn_p_st3dDataGetSHWDeformationVectorFromSO(_hHandleOfCharacter)); if (MTH3D_M_bIsNullVector(&stLightDir)) { MTH3D_M_vNullVector(&g_stDirOfShadow); MTH3D_M_vSetVectorElements(_p_stProjectionVector,MTH_C_ZERO,MTH_C_ZERO,/*MTH_C_MinusONE*/ MTH_M_xFloatToReal(-15.0f)); *_p_xScaleX = MTH_M_xInv(*_p_xScaleX); *_p_xScaleY = MTH_M_xInv(*_p_xScaleY); g_bRayIsVertical = TRUE; } else { MTH3D_M_vSetVectorElements(_p_stProjectionVector,MTH_C_ZERO,MTH_C_ZERO,MTH_C_MinusONE); if (MTH3D_M_bEqualVector(&stLightDir, _p_stProjectionVector)) g_bRayIsVertical = TRUE; else g_bRayIsVertical = FALSE; MTH3D_M_vCopyVector(&g_stDirOfShadow, &stLightDir); MTH3D_M_vCopyVector(&stVectB, &g_stDirOfShadow); stVectB.xX = MTH_C_ZERO; xNormUV = MTH_M_xMul(MTH3D_M_xDotProductVector(_p_stProjectionVector,_p_stProjectionVector), MTH3D_M_xDotProductVector(&stVectB, &stVectB)); /* if U OR V null, set product to 1*/ if (MTH_M_bIsNull(xNormUV)) xNormUV= MTH_C_ONE; else /* |U|*|V|*/ xNormUV = MTH_M_xSqrt(xNormUV); xCosX = MTH_M_xDiv(MTH3D_M_xDotProductVector(_p_stProjectionVector,&stVectB),xNormUV); if (!MTH_M_bIsNull(xCosX)) { *_p_xScaleX = MTH_M_xMul(*_p_xScaleX, xCosX); } *_p_xScaleX = MTH_M_xInv(*_p_xScaleX); MTH3D_M_vCopyVector(&stVectB, &g_stDirOfShadow); stVectB.xY = MTH_C_ZERO; xNormUV = MTH_M_xMul(MTH3D_M_xDotProductVector(_p_stProjectionVector,_p_stProjectionVector), MTH3D_M_xDotProductVector(&stVectB, &stVectB)); /* if U OR V null, set product to 1*/ if (MTH_M_bIsNull(xNormUV)) xNormUV= MTH_C_ONE; else /* |U|*|V|*/ xNormUV = MTH_M_xSqrt(xNormUV); xCosY = MTH_M_xDiv(MTH3D_M_xDotProductVector(_p_stProjectionVector,&stVectB),xNormUV); if (!MTH_M_bIsNull(xCosY)) { *_p_xScaleY = MTH_M_xMul(*_p_xScaleY, xCosY); } *_p_xScaleY = MTH_M_xInv(*_p_xScaleY); g_stDirOfShadow.xZ = MTH_C_ZERO; MTH3D_M_vCopyVector(_p_stProjectionVector, &stLightDir); } } /* ##F=================================================================================== NAME : SHW_fn_vDrawShadow DESCRIPTION : Draw a Fake Shadow for a Character ========================================================================================= CREATION : Philippe Thiébaut =======================================================================================*/ void SHW_fn_vDrawComplexShadow ( struct GLD_tdstViewportAttributes_ *_p_stVpt, HIE_tdxHandleToSuperObject _hHandleOfCharacter, HIE_tdxHandleToSuperObject _hSprObjSector, long _lSectorDrawmask ) { ACP_tdxIndex xResultIntersection = 0; ACP_tdxIndex xTempPoints=0,xTempFace=0; short xFacePicked=0,xObjPicked=0; MTH3D_tdstVector stGlobalNormalOfPickedFace; GEO_tdxHandleToMatrix hGlobalMatrixOfCharacter=NULL; MTH_tdxReal xCoefAltitude; short xIndexOfCalculatedShadow; GEO_tdstElementIndexedTriangles *p_stIndexedTriangle; MTH_tdxReal xScaleX; MTH_tdxReal xScaleY; SHW_tdstShadowInfo *p_stShadowInfo=NULL; MTH3D_tdstVector *p_stGlobalNormal=NULL; COL_tdstShadowElement *p_stShadowElement=NULL; ACP_tdxHandleOfObject hHandleOfGeometricShadowObject = NULL; ACP_tdxIndex xNbElement; short *p_bDrawFace; MTH_tdxReal xHeight; HIE_tdxHandleToSuperObject hTest,hSprObjSector; g_hHandleOfFather = NULL; g_bIsOnGround = FALSE; g_bFirstFace = TRUE; hGlobalMatrixOfCharacter=HIE_fn_hGetSuperObjectGlobalMatrix(_hHandleOfCharacter); POS_fn_vGetTranslationVector(hGlobalMatrixOfCharacter, &g_stStartPicking ) ; hHandleOfGeometricShadowObject = p_hHandleOfGeometricShadowObject[g_xIndexOfShadow]; xScaleX = MTH_M_xAbs(fn_x3dDataGetShadowScaleXFromSO(_hHandleOfCharacter)); xScaleY = MTH_M_xAbs(fn_x3dDataGetShadowScaleYFromSO(_hHandleOfCharacter)); POS_fn_vSetIdentityMatrix(&g_stInvertCurrentMatrix); g_shNbObjPicked=0; g_hPickedSprObj = NULL; g_xPickedElement=0; g_xPickedFace=0; /* * complete calculation */ g_xNearDistance= MTH_M_xMax(xScaleX,xScaleY); SHW_fn_vTakeCareOfProjectionVector(_hHandleOfCharacter,&g_stVertexAB,&xScaleX,&xScaleY); xHeight = *fn_p_x3dDataGetSHWHeightFromSO(_hHandleOfCharacter); g_stStartPicking.xZ=MTH_M_xAdd(g_stStartPicking.xZ, xHeight); MTH3D_M_vAddVector(&g_stVertexB,&g_stStartPicking,&g_stVertexAB); if ( SHW_fn_bIntersectShadowWithUnknownObjectBelow ( _hSprObjSector, _hHandleOfCharacter, _p_stVpt ) ) { /*Formula for scale*/ xCoefAltitude=MTH_M_xAdd(MTH_C_Inv2,MTH_M_xMul(MTH_M_xFloatToReal(0.03f),MTH_M_xSub(g_stStartPicking.xZ,g_stPickedPoint.xZ))); MTH3D_M_vCopyVector(&g_stStartPicking, &g_stPickedPoint); /*Test if there are too many faces around the picked point*/ SHW_fnvIsThereTooManyFaces(&g_shNbObjPicked); p_stShadowInfo = g_a_stShadowInfo; for ( xObjPicked=0;xObjPickedxNbElement; p_bDrawFace = &p_stShadowInfo->bDrawFace[0]; p_stShadowElement = p_stShadowInfo->a_stShadowObject; p_stGlobalNormal = p_stShadowInfo->pstGlobalNormal; if (xNbElement >= SHW_C_xNbMaxOfFacesPerShadow) xNbElement = SHW_C_xNbMaxOfFacesPerShadow; for ( xFacePicked=0;xFacePickedhPickedSpObj, p_stShadowInfo->hPickedObject, p_stShadowElement, p_stGlobalNormal))!=0) { MTH_tdxReal xInvNormalZ; xInvNormalZ=MTH_M_xDiv(MTH_C_ONE,p_stGlobalNormal->xZ); SHW_fn_vCreateShadowOfCharacterOnFace ( p_stGlobalNormal, xInvNormalZ, _hHandleOfCharacter, p_stShadowInfo->hPickedObject, xObjPicked, xFacePicked, p_stShadowElement->xElementIndex, p_stShadowElement->xDataElementIndex, &g_stPickedPoint,&xTempPoints,&xTempFace,&xCoefAltitude, &xScaleX,&xScaleY ); }/*if (g_a_stShadowInfo[xObjPicked].bDrawFace[xFacePicked]!=0)*/ }/*for*/ }/*for*/ hHandleOfGeometricShadowObject->xNbPoints=xTempPoints; p_stIndexedTriangle = (GEO_tdstElementIndexedTriangles *)hHandleOfGeometricShadowObject->d_stListOfElements[0]; p_stIndexedTriangle->xNbFaces=xTempFace; if (xTempPoints!=0) { SHW_fn_vSentToViewPort(_p_stVpt,_hHandleOfCharacter,_hSprObjSector,_lSectorDrawmask,hHandleOfGeometricShadowObject); }/*(xTempPoints!=0)*/ g_xIndexOfShadow++; } }