Code Vonc

Gélatine

v 1.0

R15+ OSX Win

TéléchargerDownload
Faire un donMake a donation
Comment installer ?How to install ?
CommentairesComments

Le déformateur Gélatine donne un effet élastique à vos objets animés.

Semblable au déformateur Secousses, il y apporte plusieurs autres fonctionnalités :
- Donne un effet beaucoup plus flasque.
- Fonctionne sur plusieurs objets en même temps.
- On définit les prises sur l'objet, comme s'il était maintenu par des points définis.
- Une utilisation simple et une atténuation facilement paramétrable.
The Gélatine deformer gives an elastic effect to your animated objects.

Like the Jiggle deformer, but with other features :
- More flabby effect.
- Work with multiple objects.
- We set the Handle points on the object.
- Easier to use, with a simple falloff curve.






v 1.0 :
- Ajout d'un effet d'étirement en fonction des normales.

v 0.5 :
- Compatible sur Windows et OSX pour C4D R15, R16, R17 64 bits.
- Traduction tchèque par Lubo Bezek.

v 1.0 :
- Add a stretching effect depending to the normals.

v 0.5 :
- Compatible on Windows and OSX for C4D R15, R16, R17 64 bits.
- Czech translation by Lubo Bezek.




Documentation







Intensité :Intensity :
Définit l'intensité du déformateur, soit le mélange entre l'objet initial et l'objet déformé. Set the deformer intensity, it mix the current state object with the deformed version.





Prises :Handles :
- Source : La position du déformateur définit le point de prise de l'objet, là où la déformation sera la plus faible.
- Sélection de points : Chaque point agit comme une source. Remplissez le champ Sélection de points avec le nom de la propriété Sélection de points que vous avez enregistré sur l'objet déformé.
- Tous : Tous les points sont déformés de manière uniforme. Utile lorsqu'une carte d'influence est utilisée sur le déformateur.
- Source : The deformer position set the handle point, where the deformation is the least.
- Points selection : Each point is like a source. Set the Point Selection field with the Point Selection Tag name you set on the deformed object.
- All : All the points are uniformly deformed. Usefull with a Vertex Map used on the deformer.






Rayon :Radius :
Définit le rayon d'influence interne. Disponible qu'avec les Prises de type Source. Set the internal radius falloff. Available only with Handles set to Source.







Rayon max :Max radius :
Définit le rayon d'influence externe. Disponible qu'avec les Prises de type Source et Sélection de points. Set the external radius falloff. Available only with Handles set to Source and Point Selection.






Sélection de points :Point selection :
Renseignez ici le nom de la propriété Sélection de points de l'objet pour définir les points de prise. Disponible qu'avec les Prises de type Sélection de points. Set here the Point Selection Tag name of the object to set the handle points. Available only with Handles set to Point Selection.






Élasticité :Elasticity :
Définit l'intensité de l'élasticité de l'objet. Set the elasticity of the object.







Amortissement :Absorption :
Une valeur d'amortissement élevée agira comme si l'objet était ralenti dans son environnement. Synonyme de friction. A high absorption value make the object movement slowed. Synonym of friction.






Angle d'amortissement :Absorption angle :
L'angle d'amortissement permet d'isoler l'effet aux points ayant les normales dans le même sens de déplacement que l'objet.. The absoprtion angle allow to restrict the effect to the points with the same normal angle that the object motion.






Fermeté :Firmness :
La valeur de fermeté donne un effet de ressort à l'objet. A high firmness value gives a spring effect to the object.






Atténuation :Mitigation :
La courbe d'atténuation représente l'évolution de la déformation à partir du centre des Prises. The curve set the deformation evolution from the Handles center.










Codes sourcesSources code

res/c4d_symbols.h

enum
{
    VONC_GELATINE_NOM	= 1000,
	
    _DUMMY_ELEMENT_
};

res/description/Ovoncgelatine.h

#ifndef _Ovoncgelatine_H_
#define _Ovoncgelatine_H_

enum
{
	VONC_GELATINE_ELASTICITE		= 1000,
	VONC_GELATINE_INTENSITE			= 1001,
	VONC_GELATINE_AMORTIS			= 1002,
	VONC_GELATINE_ATTENUATION		= 1003,
	VONC_GELATINE_FORCE				= 1004,
	VONC_GELATINE_INFO				= 1005,
	VONC_GELATINE_ATTENUATION_INIT	= 1006,
	VONC_GELATINE_RAYON				= 1009,
	VONC_GELATINE_MODE				= 1010,
	VONC_GELATINE_MODE_SRC			= 0,
	VONC_GELATINE_MODE_SEL			= 1,
	VONC_GELATINE_MODE_INF			= 2,
	VONC_GELATINE_INIT				= 1011,
	VONC_GELATINE_INVERSER			= 1012,
	VONC_GELATINE_RAYON_MAX			= 1013,
	VONC_GELATINE_SELECTION			= 1014,
	VONC_GELATINE_ETIRE_ANGLE		= 1016
};

#endif

res/description/Ovoncgelatine.res

CONTAINER Ovoncgelatine
{
	NAME Ovoncgelatine;
	INCLUDE Obase;

	GROUP ID_OBJECTPROPERTIES
	{
		REAL VONC_GELATINE_INTENSITE			{ UNIT PERCENT; MIN 0.0; MAX 100.0; CUSTOMGUI REALSLIDER; }
		LONG VONC_GELATINE_MODE {
			CYCLE {
				VONC_GELATINE_MODE_SRC;
				VONC_GELATINE_MODE_SEL;
				VONC_GELATINE_MODE_INF;
			}
		}
		REAL VONC_GELATINE_RAYON				{ UNIT METER; MIN 0.0; }
		REAL VONC_GELATINE_RAYON_MAX			{ UNIT METER; MIN 0.0; }
		STRING VONC_GELATINE_SELECTION			{ }
		BUTTON VONC_GELATINE_INIT				{ }
		
		SEPARATOR { LINE; }
		
		REAL VONC_GELATINE_ELASTICITE			{ UNIT PERCENT; MIN 0.0; MAXSLIDER 100.0; STEP 1.0; CUSTOMGUI REALSLIDER; }
		REAL VONC_GELATINE_AMORTIS				{ UNIT PERCENT; MINSLIDER 0.0; MAXSLIDER 100.0; STEP 1.0; CUSTOMGUI REALSLIDER; }
		REAL VONC_GELATINE_ETIRE_ANGLE			{ UNIT DEGREE; MIN 0.0; MAX 90; }
		REAL VONC_GELATINE_FORCE				{ UNIT PERCENT; MIN 0.0; MAXSLIDER 100.0; STEP 1.0; CUSTOMGUI REALSLIDER; }
		BOOL VONC_GELATINE_INVERSER				{ }
		
		SEPARATOR { LINE; }
		
		SPLINE VONC_GELATINE_ATTENUATION		{ }
		BUTTON VONC_GELATINE_ATTENUATION_INIT	{ }
		
		SEPARATOR { LINE; }
		
		GROUP {
			STATICTEXT VONC_GELATINE_INFO		{ }
		}
		
	}
	
}

res/strings_cz/c4d_strings.str

STRINGTABLE
{
	VONC_GELATINE_NOM "G\u00E9latine";
}

res/strings_cz/description/Ovoncgelatine.str

STRINGTABLE Ovoncgelatine
{
  Ovoncgelatine                   "G\u00E9latine";
  VONC_GELATINE_ELASTICITE        "Pru\u017Enost";
  VONC_GELATINE_INTENSITE         "Intenzita";
  VONC_GELATINE_AMORTIS           "Absorpce";
  VONC_GELATINE_ATTENUATION       "Zm\u00EDrn\u011Bn\u00ED";
  VONC_GELATINE_FORCE             "Pevnost";
  VONC_GELATINE_ATTENUATION_INIT  "V\u00FDchoz\u00ED nastaven\u00ED";
  VONC_GELATINE_INFO              "";
  VONC_GELATINE_RAYON             "Polom\u011Br";
  VONC_GELATINE_RAYON_MAX         "Max. Polom\u011Br";
  VONC_GELATINE_MODE              "Ovl\u00E1d\u00E1n\u00ED";
  VONC_GELATINE_MODE_SRC          "Zdroj";
  VONC_GELATINE_MODE_SEL          "V\u00FDb\u011Br bod\u016F";
  VONC_GELATINE_MODE_INF          "V\u0161e";
  VONC_GELATINE_INIT              "Reset";
  VONC_GELATINE_INVERSER          "Invertovat";
  VONC_GELATINE_SELECTION         "Selekce";
  VONC_GELATINE_ETIRE_ANGLE       "\u00DAhel absorpce";
}

res/strings_fr/c4d_strings.str

STRINGTABLE
{
	VONC_GELATINE_NOM "G\u00E9latine";
}

res/strings_fr/description/Ovoncgelatine.str

STRINGTABLE Ovoncgelatine
{
	Ovoncgelatine "G\u00E9latine";
	
	VONC_GELATINE_ELASTICITE		"\u00C9lasticit\u00E9";
	VONC_GELATINE_INTENSITE			"Intensit\u00E9";
	VONC_GELATINE_AMORTIS			"Amortissement";
	VONC_GELATINE_ATTENUATION		"Att\u00E9nuation";
	VONC_GELATINE_FORCE				"Fermet\u00E9";
	VONC_GELATINE_ATTENUATION_INIT	"D\u00E9faut";
	VONC_GELATINE_INFO				"";
	VONC_GELATINE_RAYON				"Rayon";
	VONC_GELATINE_RAYON_MAX			"Rayon max";
	VONC_GELATINE_MODE				"Prises";
	VONC_GELATINE_MODE_SRC			"Source";
	VONC_GELATINE_MODE_SEL			"S\u00E9lection de points";
	VONC_GELATINE_MODE_INF			"Tout";
	VONC_GELATINE_INIT				"R\u00E9initialiser";
	VONC_GELATINE_INVERSER			"Inverser";
	VONC_GELATINE_SELECTION			"S\u00E9lection de points";
	VONC_GELATINE_ETIRE_ANGLE		"Angle d'amortissement";
}

res/strings_us/c4d_strings.str

STRINGTABLE
{
	VONC_GELATINE_NOM "G\u00E9latine";
}

res/strings_us/description/Ovoncgelatine.str

STRINGTABLE Ovoncgelatine
{
	Ovoncgelatine "G\u00E9latine";
	
	VONC_GELATINE_ELASTICITE		"Elasticity";
	VONC_GELATINE_INTENSITE			"Intensity";
	VONC_GELATINE_AMORTIS			"Absorption";
	VONC_GELATINE_ATTENUATION		"Mitigation";
	VONC_GELATINE_FORCE				"Firmness";
	VONC_GELATINE_ATTENUATION_INIT	"Default";
	VONC_GELATINE_INFO				"";
	VONC_GELATINE_RAYON				"Radius";
	VONC_GELATINE_RAYON_MAX			"Max radius";
	VONC_GELATINE_MODE				"Handles";
	VONC_GELATINE_MODE_SRC			"Source";
	VONC_GELATINE_MODE_SEL			"Point selection";
	VONC_GELATINE_MODE_INF			"All";
	VONC_GELATINE_INIT				"Reset";
	VONC_GELATINE_INVERSER			"Invert";
	VONC_GELATINE_SELECTION			"Point selection";
	VONC_GELATINE_ETIRE_BOOL		"Use angle";
	VONC_GELATINE_ETIRE_ANGLE		"Absorption angle";
}

source/main.cpp

// This is the main file of the CINEMA 4D SDK
//
// When you create your own projects much less code is needed (this file is rather long as it tries to show all kinds of different uses).
//
// An empty project simply looks like this:
//
#include "c4d.h"
#include "main.h"

Bool PluginStart(void)
{
  if (!EnregistreVoncGelatine())
	return false;
  return true;
}

void PluginEnd(void)
{
}

Bool PluginMessage(Int32 id, void *data)
{
	switch (id) {
	case C4DPL_INIT_SYS:
		if (!resource.Init()) return false;
	}
	return false;
}

source/main.h

#ifndef MAIN_H__
#define MAIN_H__

Bool EnregistreVoncGelatine(void);

#endif // MAIN_H__

source/vonc_gelatine.cpp

#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include "c4d.h"
#include "c4d_symbols.h"
#include "main.h"
#include "Ovoncgelatine.h"
using namespace std;

#define MODULE_ID 1037749
#define PRISES 2

struct Cache {
	vector<Vector> precAbs;
	vector<Vector> elasticite;
	vector<Float> facteur;
	Float secPrec;
};

class VoncGelatine : public ObjectData
{
private:
	const String VERSION = "1.0";

	map<String, Cache> pointsCache;
	Int32 tpsPrec = -1;
	Float ansTps = -1;

	Int32 mode = VONC_GELATINE_MODE_SRC;
	Float rayon = 50.;
	Float rayonMax = 300.;
	Float elasticite = .5;
	Float intensite = 1.;
	Float amortis = 0.;
	Float force = 0.;
	Bool inverser = false;
	String selection = "";
	Float angle = 0.;

	Float ansRayon = -1.;
	Float ansRayonMax = -1;
	Int32 ansMode = -1;
	String ansSelection = "-1";

	SplineData* courbe;

	static void DrawCercle(BaseDraw* bd, BaseDrawHelp* bh, Float rayon, Vector couleur);
	static Vector MixVec(Vector v1, Vector v2, Float t);
	static String ObjID(BaseObject* op);

	void RecupDepart(BaseObject* op, Matrix op_mg, Matrix mod_mg, vector<Vector>* departs);
	vector<Float> CalculeFacteur(PointObject* op, Matrix op_mg, Matrix mod_mg);
	vector<Vector> CalculeNormales(PolygonObject* op, Matrix op_mg);
	void Libere(BaseObject* mod);
	void Initialise(PointObject* op, Matrix op_mg, Matrix mod_mg, String id);
	void RendUniqueOpsIter(BaseObject* obj, vector<Int32>* ips);
	void RendUniqueOps(BaseObject* mod);
	Bool DoitInit(BaseObject* op, String id);
	Bool DoitLiberer(BaseTime* time, BaseDocument* doc);
	void InitCourbe(BaseContainer* donnees);

public:
	virtual Bool Init				(GeListNode* node);
	virtual void Recup				(BaseObject* op);
	virtual void CheckDirty			(BaseObject* op, BaseDocument* doc);
	virtual Bool Message			(GeListNode* node, Int32 type, void* data);
	virtual Bool GetDEnabling		(GeListNode* node, const DescID &id, const GeData &t_data, DESCFLAGS_ENABLE flags, const BaseContainer* itemdesc);
	virtual void GetDimension		(BaseObject* op, Vector* mp, Vector* rad);
	virtual DRAWRESULT Draw			(BaseObject* op, DRAWPASS type, BaseDraw* bd, BaseDrawHelp* bh);
	virtual void GetHandle			(BaseObject* op, Int32 i, HandleInfo& info);
	virtual Int32 DetectHandle		(BaseObject* op, BaseDraw* bd, Int32 x, Int32 y, QUALIFIER qualifier);
	virtual Bool MoveHandle			(BaseObject* op, BaseObject* undo, const Vector& mouse_pos, Int32 hit_id, QUALIFIER qualifier, BaseDraw* bd);
	virtual Bool ModifyObject		(BaseObject* op, BaseDocument* doc, BaseObject* mod, const Matrix& op_mg, const Matrix& mod_mg, Float lod, Int32 flags, BaseThread* thread);

	static NodeData* Alloc(void) { return NewObjClear(VoncGelatine); }
};

Vector VoncGelatine::MixVec(Vector v1, Vector v2, Float t) {
	return v1 + (v2 - v1) * t;
}

void VoncGelatine::GetDimension(BaseObject* op, Vector* mp, Vector* rad)
{
	BaseContainer* data = op->GetDataInstance();
	*mp	 = Vector(0.0);
	*rad = Vector(data->GetFloat(VONC_GELATINE_RAYON_MAX));
}

void VoncGelatine::GetHandle(BaseObject* op, Int32 i, HandleInfo& info)
{
	BaseContainer* data = op->GetDataInstance();
	if (!data) return;

	switch (i) {
		case 0 :
			info.position.x = data->GetFloat(VONC_GELATINE_RAYON);
			info.direction.x = 1.0;
			info.type = HANDLECONSTRAINTTYPE_LINEAR;
			break;
		case 1 :
			info.position.x = data->GetFloat(VONC_GELATINE_RAYON_MAX);
			info.direction.x = 1.0;
			info.type = HANDLECONSTRAINTTYPE_LINEAR;
			break;
		default :
			break;
	}
}

Int32 VoncGelatine::DetectHandle(BaseObject* op, BaseDraw* bd, Int32 x, Int32 y, QUALIFIER qualifier)
{
	if (qualifier & QUALIFIER_CTRL) return NOTOK;

	HandleInfo   info;
	Matrix		 mg = op->GetMg();
	Int32		 i, ret = NOTOK;
	Vector		 p;

	for (i = 0; i < PRISES; i++) {
		GetHandle(op, i, info);
		if (bd->PointInRange(mg * info.position, x, y)) {
			ret = i;
			if (!(qualifier & QUALIFIER_SHIFT)) break;
		}
	}
	return ret;
}

Bool VoncGelatine::MoveHandle(BaseObject* op, BaseObject* undo, const Vector& mouse_pos, Int32 hit_id, QUALIFIER qualifier, BaseDraw* bd)
{
	BaseContainer* dst = op->GetDataInstance();

	HandleInfo info;
	Float val = mouse_pos.x;
	GetHandle(op, hit_id, info);

	if (bd) {
		Matrix mg	 = op->GetUpMg() * undo->GetMl();
		Vector pos = bd->ProjectPointOnLine(mg * info.position, mg.TransformVector(info.direction), mouse_pos.x, mouse_pos.y);
		val = Dot(~mg * pos, info.direction);
	}

	switch (hit_id) {
		case 0:
			dst->SetFloat(VONC_GELATINE_RAYON, ClampValue(val, (Float) 0.0, (Float)MAXRANGE));
			break;

		case 1:
			dst->SetFloat(VONC_GELATINE_RAYON_MAX, ClampValue(val, (Float) 0.0, (Float)MAXRANGE));
			break;

		default:
			break;
	}
	return true;
}

void VoncGelatine::DrawCercle(BaseDraw* bd, BaseDrawHelp* bh, Float rayon, Vector couleur) {
	Matrix m = bh->GetMg();
	Vector h;
	m.Scale(rayon);
	bd->SetMatrix_Matrix(nullptr, Matrix());
	bd->SetPen(couleur);
	bd->DrawCircle(m);
	h = m.v2; m.v2 = m.v3; m.v3 = h;
	bd->DrawCircle(m);
	h = m.v1; m.v1 = m.v3; m.v3 = h;
	bd->DrawCircle(m);
}

DRAWRESULT VoncGelatine::Draw(BaseObject* op, DRAWPASS drawpass, BaseDraw* bd, BaseDrawHelp* bh)
{
	if (drawpass == DRAWPASS_OBJECT) {
		BaseContainer* donnees = op->GetDataInstance();
		Int32 mode = donnees->GetInt32(VONC_GELATINE_MODE);

		if (mode == VONC_GELATINE_MODE_SRC)
			DrawCercle(bd, bh, donnees->GetFloat(VONC_GELATINE_RAYON), Vector(.1, 1., 0.5));

		if (mode != VONC_GELATINE_MODE_INF)
			DrawCercle(bd, bh, donnees->GetFloat(VONC_GELATINE_RAYON_MAX), Vector(0.663, 0.6, 1.));
	}
	else if (drawpass == DRAWPASS_HANDLES)
	{
		Int32			 i;
		Int32			 hitid = op->GetHighlightHandle(bd);
		HandleInfo info;

		bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT));
		bd->SetMatrix_Matrix(op, bh->GetMg());
		for (i = 0; i < PRISES; i++)
		{
			GetHandle(op, i, info);
			if (hitid == i)
				bd->SetPen(GetViewColor(VIEWCOLOR_SELECTION_PREVIEW));
			else
				bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT));
			bd->DrawHandle(info.position, DRAWHANDLE_BIG, 0);
		}

		GetHandle(op, 1, info);
		bd->SetPen(GetViewColor(VIEWCOLOR_ACTIVEPOINT));
		bd->DrawLine(info.position, Vector(0.0), 0);
	}
	return DRAWRESULT_OK;
}

void VoncGelatine::InitCourbe(BaseContainer* donnees) {
	AutoAlloc<SplineData> courbe;
	courbe->MakeLinearSplineBezier(2);
	CustomSplineKnot* knot0 = courbe->GetKnot(0);
	CustomSplineKnot* knot1 = courbe->GetKnot(1);
	knot0->vPos = Vector(0., 1., 0.);
	knot0->lFlagsSettings = 0;
	knot0->vTangentLeft = Vector(-.1, .4, 0.);
	knot0->vTangentRight = Vector(.1, -0.4, 0.);
	courbe->SetKnot(0, *knot0);
	knot1->vPos = Vector(1., 0., 0.);
	knot1->lFlagsSettings = 0;
	knot1->vTangentLeft = Vector(-.5, 0., 0.);
	knot1->vTangentRight = Vector(.5, 0., 0.);
	courbe->SetKnot(1, *knot1);
	donnees->SetData(VONC_GELATINE_ATTENUATION, GeData(CUSTOMDATATYPE_SPLINE, courbe));
}

Bool VoncGelatine::Init(GeListNode* node) {

	BaseObject*		 op = (BaseObject*)node;
	BaseContainer* donnees = op->GetDataInstance();

	InitCourbe(donnees);

	donnees->SetFloat(VONC_GELATINE_RAYON, rayon);
	donnees->SetFloat(VONC_GELATINE_RAYON_MAX, rayonMax);
	donnees->SetInt32(VONC_GELATINE_MODE, mode);
	donnees->SetFloat(VONC_GELATINE_INTENSITE, intensite);
	donnees->SetFloat(VONC_GELATINE_ELASTICITE, elasticite);
	donnees->SetFloat(VONC_GELATINE_AMORTIS, amortis);
	donnees->SetData(VONC_GELATINE_FORCE, force);
	donnees->SetBool(VONC_GELATINE_INVERSER, inverser);
	donnees->SetString(VONC_GELATINE_SELECTION, selection);
	donnees->SetFloat(VONC_GELATINE_ETIRE_ANGLE, angle);

	donnees->SetString(VONC_GELATINE_INFO, "v " + VERSION + " - code.vonc.fr");

	return true;
}

void VoncGelatine::Recup(BaseObject* op) {

	BaseContainer* donnees = op->GetDataInstance();

	rayon = donnees->GetFloat(VONC_GELATINE_RAYON);
	rayonMax = donnees->GetFloat(VONC_GELATINE_RAYON_MAX);
	mode = donnees->GetInt32(VONC_GELATINE_MODE);
	intensite = donnees->GetFloat(VONC_GELATINE_INTENSITE);
	elasticite = donnees->GetFloat(VONC_GELATINE_ELASTICITE);
	amortis = donnees->GetFloat(VONC_GELATINE_AMORTIS);
	force = donnees->GetFloat(VONC_GELATINE_FORCE);
	courbe = (SplineData*)(donnees->GetCustomDataType(VONC_GELATINE_ATTENUATION, CUSTOMDATATYPE_SPLINE));
	inverser = donnees->GetBool(VONC_GELATINE_INVERSER);
	selection = donnees->GetString(VONC_GELATINE_SELECTION);
	angle = donnees->GetFloat(VONC_GELATINE_ETIRE_ANGLE);

	donnees->SetString(VONC_GELATINE_INFO, "v " + VERSION + " - code.vonc.fr");

	if (rayonMax < rayon) rayonMax = rayon;
}

void VoncGelatine::CheckDirty(BaseObject* op, BaseDocument* doc) {
	
	Int32 tps = doc->GetTime().GetFrame(doc->GetFps());
	if (tps != tpsPrec) {
		tpsPrec = tps;
		op->SetDirty(DIRTYFLAGS_DATA);
	}
}

void VoncGelatine::RecupDepart(BaseObject* op, Matrix op_mg, Matrix mod_mg, vector<Vector>* departs) {

	departs->clear();

	if (mode == VONC_GELATINE_MODE_SRC) {
		departs->push_back(mod_mg.off);
	}
	else if (mode == VONC_GELATINE_MODE_SEL) {
		const Vector* points = ((PointObject*)op)->GetPointR();
		Int32 nbPoints = ((PointObject*)op)->GetPointCount();
		if (selection != "") {
			BaseTag* tag = op->GetFirstTag();
			while (tag) {
				if (tag->IsInstanceOf(Tpointselection) && tag->GetName() == selection) {
					BaseSelect* bs = ((SelectionTag*)tag)->GetBaseSelect();
					if (bs) {
						Int32 seg = 0, a, b, i;
						while (bs->GetRange(seg++, nbPoints, &a, &b)) {
							for (i = a; i <= b; ++i) {
								departs->push_back(op_mg * points[i]);
							}
						}
					}
					break;
				}
				tag = tag->GetNext();
			}
		}
	}
}

vector<Float> VoncGelatine::CalculeFacteur(PointObject* op, Matrix op_mg, Matrix mod_mg) {

	vector<Float> pointsFacteur;

	Int32 nbPoints = op->GetPointCount();
	const Vector* points = op->GetPointR();
	
	if (mode == VONC_GELATINE_MODE_INF) {
		pointsFacteur = vector<Float>(nbPoints, 1.);
		return pointsFacteur;
	}

	Float distanceMax = rayonMax - rayon;

	pointsFacteur = vector<Float>(nbPoints, distanceMax * 10.);
	vector<Vector> departs = vector<Vector>();

	RecupDepart(op, op_mg, mod_mg, &departs);

	for (vector<Vector>::iterator pointDepart = departs.begin(); pointDepart != departs.end(); ++pointDepart) {

		Vector point;
		Float distance;

		for (Int32 i = 0 ; i < nbPoints ; i++) {

			point = op_mg * points[i];
			distance = ((*pointDepart) - point).GetLength() - rayon;
			if (distance < 0.) distance = 0.;
			if (pointsFacteur[i] > distance) pointsFacteur[i] = distance;
		}
	}

	if (distanceMax > 0.) {
		Int32 i = 0;
		Float pfac;
		for (vector<Float>::iterator fac = pointsFacteur.begin(); fac != pointsFacteur.end(); ++fac) {
			pfac = (*fac) / distanceMax;
			if (pfac > 1.) pfac = 1.;
			(*fac) = pfac;
			i++;
		}
	}

	return pointsFacteur;
}

vector<Vector> VoncGelatine::CalculeNormales(PolygonObject* op, Matrix op_mg) {
	Int32 nbPolys = ((PolygonObject*)op)->GetPolygonCount();
	Int32 nbPoints = ((PolygonObject*)op)->GetPointCount();
	vector<Vector> normalesPoints = vector<Vector>(nbPoints, Vector());
	const CPolygon* polygones = op->GetPolygonR();
	const Vector* points = op->GetPointR();
	CPolygon poly;
	Vector normale;
	op_mg.off = Vector();

	for (Int32 i = 0; i < nbPolys; i++) {
		poly = polygones[i];
		normale = Cross(points[poly.a] - points[poly.c], points[poly.b] - points[poly.d]);
		normale = op_mg * normale;
		normalesPoints[poly.a] += normale;
		normalesPoints[poly.b] += normale;
		normalesPoints[poly.c] += normale;
		if (poly.c != poly.d) normalesPoints[poly.d] += normale;
	}

	return normalesPoints;
}

String VoncGelatine::ObjID(BaseObject* op) {
	String ip = String::IntToString(op->GetUniqueIP());
	String guid = String::UIntToString(op->GetGUID());
	return ip + guid + op->GetName();
}

void VoncGelatine::Libere(BaseObject* mod) {
	for (map<String, Cache>::iterator it = pointsCache.begin(); it != pointsCache.end(); ++it) {
		it->second.precAbs.clear();
		it->second.elasticite.clear();
		it->second.facteur.clear();
	}
	pointsCache.clear();
	//GePrint("Libère");
}

void VoncGelatine::Initialise(PointObject* op, Matrix op_mg, Matrix mod_mg, String id) {

	Int32 nbPoints = op->GetPointCount();
	vector<Vector> pointsElasticite = vector<Vector>(nbPoints, Vector());
	vector<Vector> pointsPrecAbs = vector<Vector>(nbPoints, Vector());
	const Vector* points = op->GetPointR();

	for (Int32 i = 0; i < nbPoints; i++) {
		pointsPrecAbs[i] = op_mg * points[i];
	}

	vector<Float> pointsFacteur = CalculeFacteur(op, op_mg, mod_mg);

	Cache cache;
	cache.precAbs = pointsPrecAbs;
	cache.elasticite = pointsElasticite;
	cache.facteur = pointsFacteur;
	cache.secPrec = -1.;

	//pointsCache.insert(pair<String, Cache>(id, cache));
	pointsCache[id] = cache;

	//GePrint("Init " + id);
}

void VoncGelatine::RendUniqueOpsIter(BaseObject* obj, vector<Int32>* ips) {
	if (!obj) return;

	Int32 ip = obj->GetUniqueIP();
	
	while (find(ips->begin(), ips->end(), ip) != ips->end()) {
		ip++;
	}

	obj->SetUniqueIP(ip);
	ips->push_back(ip);

	// Met à jour la propriété sélection de points
	if (mode == VONC_GELATINE_MODE_SEL) {
		BaseTag* tag = obj->GetFirstTag();
		while (tag) {
			if (tag->IsInstanceOf(Tpointselection) && tag->GetName() == selection) {
				tag->SetDirty(DIRTYFLAGS_DATA);
			}
			tag = tag->GetNext();
		}
	}

	RendUniqueOpsIter(obj->GetDown(), ips);
	RendUniqueOpsIter(obj->GetNext(), ips);
}

void VoncGelatine::RendUniqueOps(BaseObject* mod) {
	vector<Int32> ips;
	RendUniqueOpsIter(mod->GetUp(), &ips);
}

Bool VoncGelatine::DoitInit(BaseObject* op, String id) {
	if (pointsCache.find(id) == pointsCache.end()) return true;
	if (pointsCache[id].precAbs.size() != ((PointObject*)op)->GetPointCount()) return true;
	return false;
}

Bool VoncGelatine::DoitLiberer(BaseTime* time, BaseDocument* doc) {
	Bool libere = false;
	Float tps = time->GetFrame(doc->GetFps());

	// Si on est à l'image 0, libérer la mémoire une fois
	if (tps != ansTps && abs(tps) <= 0.000001) libere = true;

	// Si certains paramètres ont changé, libérer la mémoire
	if (ansRayon != rayon) libere = true;
	if (ansRayonMax != rayonMax) libere = true;
	if (ansMode != mode) libere = true;
	if (ansSelection != selection) libere = true;

	ansTps = tps;
	ansRayon = rayon;
	ansRayonMax = rayonMax;
	ansMode = mode;
	ansSelection = selection;

	return libere;
}

Bool VoncGelatine::ModifyObject(BaseObject* mod, BaseDocument* doc, BaseObject* op, const Matrix& op_mg, const Matrix& mod_mg, Float lod, Int32 flags, BaseThread* thread)
{

	// Si pas de points, terminer
	if (!op->IsInstanceOf(Opoint)) return true;

	Int32 nbPoints = ((PointObject*)op)->GetPointCount();
	if (nbPoints == 0) return true;

	// Récupère les paramètres
	Recup(mod);

	// ID de l'objet en cours de traitement
	String id = ObjID(op);

	// Variables de temps
	BaseTime time = doc->GetTime();
	Float sec = time.Get();

	// Libère la mémoire ?
	if (DoitLiberer(&time, doc)) {
		Libere(mod);
		RendUniqueOps(mod);
	}

	// Si la mémoire est vide ou si op a changé, initialiser ses tableaux de points
	if (DoitInit(op, id)) {
		Initialise((PointObject*)op, op_mg, mod_mg, id);
	}

	// Bool si le temps est passé ou non
	Bool tpsPasse = sec != pointsCache[id].secPrec;

	
	//------------------------------------------------------------------------------//


	// Variables de traitement
	Vector* points = ((PointObject*)op)->GetPointW();
	Float32* weight = ((PointObject*)op)->CalcVertexMap(mod);
	vector<Vector>* pointsPrecAbs = &(pointsCache[id].precAbs);
	vector<Vector>* pointsElasticite = &(pointsCache[id].elasticite);
	vector<Float>* pointsFacteur = &(pointsCache[id].facteur);
	Matrix op_mg_inv = ~op_mg;
	Vector point;
	Vector pointPrecAbs;
	Vector pointAbs;
	Vector pointElasticite;
	Vector pointNouveauAbsFac;
	Vector pointNouveau;
	Float fac;
	Float facVitesse;
	Float facAmortissement;
	vector<Vector> normalesPoints;
	Vector direction;
	Vector normale;
	Float facNormale;
	Bool utilAngleBool = angle > 0.00001 && (3.14159265359 - angle) > 0.00001;
	
	// Calcul des normales
	if (utilAngleBool) normalesPoints = CalculeNormales((PolygonObject*)op, op_mg);

	// Calcul des nouveaux points
	for (Int32 i = 0; i < nbPoints; i++) {

		point = points[i];
		pointPrecAbs = (*pointsPrecAbs)[i];
		pointAbs = op_mg * point;

		fac = (*pointsFacteur)[i];
		if (weight) fac *= 1. - weight[i];
		if (inverser) fac = 1. - fac;

		if (courbe) {
			facVitesse = courbe->GetPoint(fac * elasticite).y;
			facAmortissement = courbe->GetPoint(fac * amortis).y;
		}
		else {
			facVitesse = 1 - (fac * elasticite);
			facAmortissement = 1. - (fac * amortis);
		}

		pointElasticite = (*pointsElasticite)[i] * (1. - facVitesse);
		pointElasticite += (pointAbs - pointPrecAbs) * ClampValue(force + facVitesse, 0., 1.);

		// Angle d'amortissement
		if (utilAngleBool) {
			direction = pointElasticite.GetNormalized();
			normale = normalesPoints[i].GetNormalized();
			facNormale = GetAngle(direction, normale) / (3.14159265359 - angle);
			facNormale = Clamp01(facNormale);
			facAmortissement = 1. - (facNormale * (1. - facAmortissement));
			if (facAmortissement < 0.) facAmortissement = 0.;
		}

		pointNouveauAbsFac = pointElasticite * facAmortissement;

		pointPrecAbs = (*pointsPrecAbs)[i] + pointNouveauAbsFac;

		if (tpsPasse) {
			(*pointsElasticite)[i] = pointElasticite;
			(*pointsPrecAbs)[i] = pointPrecAbs;
		}

		pointNouveau = op_mg_inv * pointPrecAbs;

		// Intensité
		pointNouveau = MixVec(point, pointNouveau, intensite);

		// Définit le nouveau point
		points[i] = pointNouveau;
	}

	DeleteMem(weight);
	normalesPoints.clear();

	op->Message(MSG_UPDATE);

	// Variables précédentes
	pointsCache[id].secPrec = sec;

	return true;
}

Bool VoncGelatine::Message(GeListNode* node, Int32 type, void* data)
{
	if (type == MSG_MENUPREPARE) {
		((BaseObject*)node)->SetDeformMode(true);
	}
	else if (type == MSG_DESCRIPTION_COMMAND) {
		BaseContainer* donnees = ((BaseObject*)node)->GetDataInstance();
		DescriptionCommand* dc = (DescriptionCommand*)data;
		Int32 id = dc->id[0].id;

		switch (id) {

			case VONC_GELATINE_ATTENUATION_INIT :
				InitCourbe(donnees);
				break;

			case VONC_GELATINE_INIT :
				Libere((BaseObject*)node);
				RendUniqueOps((BaseObject*)node);
				((BaseObject*)node)->SetDirty(DIRTYFLAGS_DATA);
				break;

			default:
				break;
		}
	}
	return true;
}

Bool VoncGelatine::GetDEnabling(GeListNode* node, const DescID &id, const GeData &t_data, DESCFLAGS_ENABLE flags, const BaseContainer* itemdesc) {

	BaseContainer* donnees = ((BaseObject*)node)->GetDataInstance();
	
	if (donnees) {
		
		Int32 mode = donnees->GetInt32(VONC_GELATINE_MODE);

		switch (id[0].id) {

			case VONC_GELATINE_RAYON :
				if (mode != VONC_GELATINE_MODE_SRC) return false;
				break;

			case VONC_GELATINE_RAYON_MAX :
				if (mode == VONC_GELATINE_MODE_INF) return false;
				break;

			case VONC_GELATINE_SELECTION :
				if (mode != VONC_GELATINE_MODE_SEL) return false;
				break;

			default :
				break;
		}

	}
	
	return ObjectData::GetDEnabling(node, id, t_data, flags, itemdesc);
}


Bool EnregistreVoncGelatine(void)
{
	return RegisterObjectPlugin(MODULE_ID, GeLoadString(VONC_GELATINE_NOM), OBJECT_MODIFIER, VoncGelatine::Alloc, "Ovoncgelatine", AutoBitmap("Ovoncgelatine.tif"), 0);
}