/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//
// CurveLayout3D
//
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#include "CKAll.h"
CKObjectDeclaration *FillBehaviorCurveLayout3DDecl();
CKERROR CreateCurveLayout3DProto(CKBehaviorPrototype** pproto);
int CurveLayout3D(const CKBehaviorContext& behcontext);
//-------------------------------------------------
// Creates a declaration of this behavior
//
//-------------------------------------------------
CKObjectDeclaration *FillBehaviorCurveLayout3DDecl()
{
CKObjectDeclaration *od = CreateCKObjectDeclaration("3D Curve Layout");
od->SetDescription("Organize a set of 3D belong a 3D curve in space");
/* rem:
In: triggers the process.
Out: is activated when the process is completed.
Curve: curve to position the 3D entities to organize.
A: starting position in percent on the curve to consider.
B: ending position in percent on the curve to consider.
Follow: if TRUE, the 3D Entity's orientation will point in the direction of the curve's tangent.
Roll: angle to roll around the follow axis.
Direction: specifies which base vector is to be the following direction (if the 'Follow' parameter is set to TRUE).
Hierarchy: if TRUE, then this behavior will also apply to the 3D Entity's children.
The entities in the group are placed along the curve.
*/
// Category in Virtools interface
od->SetCategory("Interface/Layouts");
od->SetType( CKDLL_BEHAVIORPROTOTYPE);
// Unique identifier of this prototype
od->SetGuid(CKGUID(0x2557342c,0x15246746));
od->SetAuthorGuid(VIRTOOLS_GUID);
od->SetAuthorName("Virtools");
od->SetVersion(0x00010000);
// Function that will create the behavior prototype
od->SetCreationFunction(CreateCurveLayout3DProto);
// Class ID of the objects to which the behavior can applied
od->SetCompatibleClassId(CKCID_GROUP);
return od;
}
//-------------------------------------------------
// CurveLayout3D behavior prototype creation function
//
//-------------------------------------------------
CKERROR CreateCurveLayout3DProto(CKBehaviorPrototype **pproto)
{
CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("3D Curve Layout");
if(!proto) return CKERR_OUTOFMEMORY;
// Input/Outputs declaration
proto->DeclareInput("In");
proto->DeclareOutput("Out");
proto->DeclareInParameter("Curve", CKPGUID_CURVE);
proto->DeclareInParameter("A", CKPGUID_PERCENTAGE,"0" );
proto->DeclareInParameter("B", CKPGUID_PERCENTAGE,"100" );
proto->DeclareInParameter("Follow", CKPGUID_BOOL,"FALSE" );
proto->DeclareInParameter("Roll", CKPGUID_ANGLE,"0" );
proto->DeclareInParameter("Direction",CKPGUID_DIRECTION,"Z");
proto->DeclareInParameter("Hierarchy", CKPGUID_BOOL,"TRUE" );
proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL);
proto->SetBehaviorFlags(CKBEHAVIOR_TARGETABLE);
// Function that will be called upon behavior execution
proto->SetFunction(CurveLayout3D);
*pproto = proto;
return CK_OK;
}
void
BB_Orientate(CK3dEntity *ent, VxVector& dir, int dirMode=5, float roll=0.0f, const VxVector& _up=VxVector::axisY(), float speedValue=1.0f, CKBOOL k=FALSE, CKBOOL unitaryScale=FALSE)
{
VxVector scale;
if( !unitaryScale ) ent->GetScale( &scale );
if( (dirMode & 1) == 0 ) dir = -dir;
VxVector old_dir, right;
//--- tend to be Y world axis
VxVector up = _up;
up.x *= 0.5f; up.z *= 0.5f;
//--- direction mode dependant
switch( dirMode ){
case 5: // Z
case 6: // -Z
{
if(up.x>1.5f) ent->GetOrientation(NULL, &up); // memorize first up vector
ent->GetOrientation( &old_dir, NULL);
dir = old_dir + speedValue * ( dir - old_dir );
right = CrossProduct(up, dir);
up = CrossProduct(dir, right);
dir.Normalize();
right.Normalize();
up.Normalize();
ent->SetOrientation( &dir , &up, &right, NULL, k );
if( roll != 0.0f ) ent->Rotate( 0, 0, 1, roll, ent, k);
} break;
case 1: // X
case 2: // -X
{
if(up.x>1.5f) ent->GetOrientation(NULL, &up); // memorize first up vector
ent->GetOrientation( NULL, NULL, &old_dir );
dir = old_dir + speedValue * ( dir - old_dir );
right = CrossProduct(dir, up);
up = CrossProduct(right, dir);
dir.Normalize();
right.Normalize();
up.Normalize();
ent->SetOrientation( &right , &up, &dir, NULL, k );
if( roll != 0.0f ) ent->Rotate( 1, 0, 0, roll, ent, k);
} break;
case 3: // Y
case 4: // -Y
{
if(up.x>1.5f) ent->GetOrientation(&up, NULL); // memorize first up vector
ent->GetOrientation( NULL, &old_dir );
dir = old_dir + speedValue * ( dir - old_dir );
right = CrossProduct(up, dir);
up = CrossProduct(dir, right);
dir.Normalize();
right.Normalize();
up.Normalize();
ent->SetOrientation( &right , &dir, &up, NULL, k );
if( roll != 0.0f ) ent->Rotate( 0, 1, 0, roll, ent, k);
} break;
}
if( !unitaryScale ) ent->SetScale( &scale );
}
//-------------------------------------------------
// CurveLayout3D behavior execution function
//
//-------------------------------------------------
int CurveLayout3D(const CKBehaviorContext& behcontext)
{
CKBehavior* beh = behcontext.Behavior;
// IO activation
beh->ActivateInput(0, FALSE);
beh->ActivateOutput(0);
// Get the reference curve
CKCurve* curve = (CKCurve*)beh->GetInputParameterObject(0);
if (!curve) return CKBR_PARAMETERERROR;
// Get the group in the curve layout
CKGroup* group = (CKGroup*)beh->GetTarget();
if(!group) return CKBR_OK;
int objectCount = group->GetObjectCount();
if (!objectCount) return CKBR_OK;
// Check if the group is only formed of 3D entities
if (!CKIsChildClassOf(group->GetCommonClassID(),CKCID_3DENTITY)) return CKBR_OK;
float start = 0.0f;
beh->GetInputParameterValue(1,&start);
float end = 1.0f;
beh->GetInputParameterValue(2,&end);
CKBOOL follow = TRUE;
beh->GetInputParameterValue(3,&follow);
float roll = 0.0f;
beh->GetInputParameterValue(4,&roll);
int naxis = 5; // Z by default
beh->GetInputParameterValue(5, &naxis );
CKBOOL hierarchy = TRUE;
beh->GetInputParameterValue(6, &hierarchy);
// Position of each entity in the group relative to the reference frame
VxVector currentPosition, dir;
float current = start;
int steps = objectCount-1;
if (!steps) steps = 1;
float step = (end-start)/steps;
for (int i = 0 ; i < objectCount ; i++, current += step) {
CK3dEntity* obj = (CK3dEntity*)group->GetObject(i);
curve->GetPos(current, ¤tPosition,&dir);
obj->SetPosition(¤tPosition, NULL, !hierarchy);
if (follow) {
BB_Orientate(obj, dir, naxis, roll, VxVector::axisY(), 1.0f, !hierarchy);
}
}
return CKBR_OK;
}