/************************************************************************************** File : PICKING.CPP Author : Marc Villemain Last update : 13 September 1996 ***************************************************************************************/ #include "tde.h" // Precision de la souris en pixels #define C_PREC_SOURIS TDE_M_FloatToValue((float)3.0) // Distance euclidienne entre deux points 2D #define M_DistancePointPoint(A,B) TDE_M_Sqrt(TDE_M_Add(TDE_M_Sq(TDE_M_Sub(A->xX,B->xX)), \ TDE_M_Sq(TDE_M_Sub(A->xY,B->xY)))) static long lViewPortW, lViewPortH; static TDE_tdsSuperObjectMatrix stSprMatrix; void fn_vChangeRepere ( TDE_tdsVertex *p_stP, TDE_tdsVertex *p_stA, TDE_tdsVertex *p_stB, TDE_tdsVertex *p_stC, TDE_tdsVertex *p_stR ) { TDE_tdsVertex stAB, stAC, stAP; TDE_tdxValue denominateur; // calcul des vecteurs de base du triangle TDE_vSubVertexToVertex( p_stB, p_stA, &stAB) ; TDE_vSubVertexToVertex( p_stC, p_stA, &stAC) ; TDE_vSubVertexToVertex( p_stP, p_stA, &stAP) ; // coordonnee de p_stP dans le repere A,AB,AC denominateur = TDE_M_Sub(TDE_M_Mul(stAB.xX,stAC.xY),TDE_M_Mul(stAB.xY,stAC.xX)); p_stR->xX = TDE_M_Div(TDE_M_Sub(TDE_M_Mul(stAP.xX,stAC.xY),TDE_M_Mul(stAP.xY,stAC.xX)), denominateur); p_stR->xY = TDE_M_Div(TDE_M_Sub(TDE_M_Mul(stAB.xX,stAP.xY),TDE_M_Mul(stAB.xY,stAP.xX)), denominateur); } BOOL GLI_bPickTriangle( TDE_tdsVertex *p_stSouris, TDE_tdsVertex *p_stA, TDE_tdsVertex *p_stB, TDE_tdsVertex *p_stC ) { TDE_tdsVertex stRet; fn_vChangeRepere(p_stSouris, p_stA, p_stB, p_stC, &stRet); /* on teste si le point est dans le triangle A,B,C */ if ( ( stRet.xX >= TDE_M_FloatToValue( 0.0 )) && ( stRet.xY >= TDE_M_FloatToValue( 0.0 )) && ( TDE_M_Add( stRet.xX, stRet.xY ) <= TDE_M_FloatToValue( 1.0 ))) return TRUE; else return FALSE; } BOOL GLI_bPickPoly4( TDE_tdsVertex *p_stSouris, TDE_tdsVertex *p_stA, TDE_tdsVertex *p_stB, TDE_tdsVertex *p_stC, TDE_tdsVertex *p_stD ) { BOOL ret1,ret2; ret1 = GLI_bPickTriangle(p_stSouris,p_stA,p_stB,p_stC) || GLI_bPickTriangle(p_stSouris,p_stA,p_stC,p_stD); ret2 = GLI_bPickTriangle(p_stSouris,p_stD,p_stA,p_stB) || GLI_bPickTriangle(p_stSouris,p_stD,p_stB,p_stC); return ret1 && ret2; } BOOL GLI_bPickPoint( TDE_tdsVertex *p_stSouris, TDE_tdsVertex *p_stA ) { return M_DistancePointPoint(p_stSouris, p_stA) <= C_PREC_SOURIS; } BOOL GLI_bPickSegment( TDE_tdsVertex *p_stSouris, TDE_tdsVertex *p_stP1, TDE_tdsVertex *p_stP2 ) { TDE_tdsVertex stA,stB,stC,stD; // vecteurs du quadrilatere TDE_tdsVertex stDir,stNor; // vecteurs directeur et normal // calcul des vecteurs directeur et normal TDE_vSubVertexToVertex( p_stP2, p_stP1, &stDir) ; stNor.xX = TDE_M_Neg(stDir.xY); stNor.xY = stDir.xX; // on leur donne la longueur C_PREC_SOURIS TDE_vNormerVertex(&stDir, &stDir); TDE_vNormerVertex(&stNor, &stNor); TDE_vMulVertexToValue(&stDir, C_PREC_SOURIS, &stDir); TDE_vMulVertexToValue(&stNor, C_PREC_SOURIS, &stNor); stA.xX = TDE_M_Sub( TDE_M_Add( p_stP1->xX, stNor.xX ), stDir.xX ); stA.xY = TDE_M_Sub( TDE_M_Add( p_stP1->xY, stNor.xY ), stDir.xY );; stB.xX = TDE_M_Sub( TDE_M_Sub( p_stP1->xX, stNor.xX ), stDir.xX ); stB.xY = TDE_M_Sub( TDE_M_Sub( p_stP1->xY, stNor.xY ), stDir.xY );; stC.xX = TDE_M_Add( TDE_M_Sub( p_stP2->xX, stNor.xX ), stDir.xX ); stC.xY = TDE_M_Add( TDE_M_Sub( p_stP2->xY, stNor.xY ), stDir.xY );; stD.xX = TDE_M_Add( TDE_M_Add( p_stP2->xX, stNor.xX ), stDir.xX ); stD.xY = TDE_M_Add( TDE_M_Add( p_stP2->xY, stNor.xY ), stDir.xY ); return GLI_bPickPoly4(p_stSouris, &stA, &stB, &stC, &stD); } BOOL GLI_bPickSprite( TDE_tdsVertex *p_stSouris, TDE_tdsSprite *p_stSprite ) { TDE_tdsRect stRect; TDE_tdxValue xScaledSpriteW, xScaledSpriteH, xSpriteCenterY; TDE_tdxValue xSpriteCornerX, xSpriteCornerY, xSpriteCenterX; xScaledSpriteW = TDE_M_Mul(lViewPortW,p_stSprite->stDim.xX); xScaledSpriteH = TDE_M_Mul(lViewPortH,p_stSprite->stDim.xY); xSpriteCenterX = TDE_M_Mul(lViewPortW,stSprMatrix.stTranslateVertex.xX); xSpriteCenterY = TDE_M_Mul(lViewPortH,stSprMatrix.stTranslateVertex.xY); xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW,2); xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH,2); iTDE_vFillsRect(&stRect, xSpriteCornerX, xSpriteCornerY, xScaledSpriteW, xScaledSpriteH); return GLI_bPickPoly4( p_stSouris, &stRect.tdsSommet[0], &stRect.tdsSommet[1], &stRect.tdsSommet[2], &stRect.tdsSommet[3] ); } BOOL GLI_bPickSpriteAbs( TDE_tdsVertex *p_stSouris, TDE_tdsSprite *p_stSprite, TDE_tdxPixel *p_Color ) { long decal; TDE_tdsRect stRect; TDE_tdxValue xScaledSpriteW, xScaledSpriteH, xSpriteCenterY; TDE_tdxValue xSpriteCornerX, xSpriteCornerY, xSpriteCenterX; xScaledSpriteW = p_stSprite->stDim.xX; xScaledSpriteH = p_stSprite->stDim.xY; xSpriteCenterX = stSprMatrix.stTranslateVertex.xX; xSpriteCenterY = stSprMatrix.stTranslateVertex.xY; xSpriteCornerX = xSpriteCenterX - TDE_M_Div(xScaledSpriteW,2); xSpriteCornerY = xSpriteCenterY - TDE_M_Div(xScaledSpriteH,2); iTDE_vFillsRect(&stRect, xSpriteCornerX, xSpriteCornerY, xScaledSpriteW, xScaledSpriteH); decal = TDE_M_ValueToLong(p_stSprite->stDim.xX) * (TDE_M_ValueToLong(p_stSouris->xY)-TDE_M_ValueToLong(stRect.tdsSommet[0].xY)) + TDE_M_ValueToLong((p_stSouris->xX)-TDE_M_ValueToLong(stRect.tdsSommet[0].xX)); if( (decal < 0) || (decal >= p_stSprite->stDim.xX*p_stSprite->stDim.xY) ) { *p_Color = 0; return 0; } else *p_Color = p_stSprite->v_pData[decal]; return GLI_bPickPoly4( p_stSouris, &stRect.tdsSommet[0], &stRect.tdsSommet[1], &stRect.tdsSommet[2], &stRect.tdsSommet[3] ); } BOOL GLI_bPickLine( TDE_tdsVertex *p_stSouris, TDE_tdsLine *p_stLine ) { TDE_tdxAngle xAngle; TDE_tdsVertex stP1, stP2; // calcul des sommets P1 et P2 du segment TDE_vGetTranslateVertexMatrix(&stSprMatrix, &stP1); TDE_vGetAngleMatrix(&stSprMatrix, &xAngle); stP2.xX = TDE_M_Mul( p_stLine->xLength, TDE_M_Cos(xAngle) ); stP2.xY = TDE_M_Mul( p_stLine->xLength, TDE_M_Sin(xAngle) ); TDE_vAddVertexToVertex(&stP1, &stP2, &stP2); return GLI_bPickSegment( p_stSouris, &stP1, &stP2 ); } BOOL GLI_bIsObjectPick( TDE_tdsVertex *p_stSouris, TDE_tdeType eType, void *p_stObject, TDE_tdxPixel *p_Color ) { switch(eType) { case TDE_eOT_SPRITE : //return GLI_bPickSprite( p_stSouris, (TDE_tdsSprite *)p_stObject ); return GLI_bPickSpriteAbs( p_stSouris, (TDE_tdsSprite *)p_stObject, p_Color ); break; case TDE_eOT_LINE : return GLI_bPickLine( p_stSouris, (TDE_tdsLine *)p_stObject ); break; default : return FALSE; } } /*On trouve dans a_tdxSprObjPick[] les indices des fils successifs pour arriver a l'objet sous la souris le premier fils porte le numero 1 */ BOOL TDE_bGetSuperObjectPick( GLD_tdpstViewportAttributes p_stViewAttrib, TDE_tdsVertex *p_stSouris, TDE_tdstPickInfo *p_stPickInfo ) { TDE_tdsSuperObject *p_stSprObjInter, *p_stSprObjPick; BOOL ret = FALSE; TDE_tdxPixel xColor; int i; p_stPickInfo->iNbSprPick = 0; lViewPortW = p_stViewAttrib->dwWidth; lViewPortH = p_stViewAttrib->dwHeight; p_stSprObjPick = NULL; for(i=0 ; istModifiedMatrix; ret = GLI_bIsObjectPick(p_stSouris, p_stSprObjInter->eType, p_stSprObjInter->p_vPointer, &xColor); if(ret) { int j; j=p_stPickInfo->iNbSprPick-1; while(j >= 0) { if( j < (TDE_kMAXPICK-1) ) p_stPickInfo->aDEF_stInfo[j+1] = p_stPickInfo->aDEF_stInfo[j]; j--; } if ( j < (TDE_kMAXPICK-1) ) { p_stPickInfo->aDEF_stInfo[j+1].p_stSprObj = p_stSprObjInter; p_stPickInfo->aDEF_stInfo[j+1].xColor = xColor; if ( p_stPickInfo->iNbSprPick < TDE_kMAXPICK ) p_stPickInfo->iNbSprPick++; } } p_stSprObjInter = p_stSprObjInter->p_stNextZList; } } if(p_stPickInfo->iNbSprPick != 0) { ret = TRUE; } return ret; }