Gélatine
v 1.0
R15, R16, R17, R18, R19, R20, R21, R22, R23
res
└ description
└ strings_cs-CZ
└ description
└ strings_en-US
└ description
└ strings_fr-FR
└ description
source
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_cs-CZ/c4d_strings.str
STRINGTABLE { VONC_GELATINE_NOM "G\u00E9latine"; }
res/strings_cs-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_en-US/c4d_strings.str
STRINGTABLE { VONC_GELATINE_NOM "G\u00E9latine"; }
res/strings_en-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"; }
res/strings_fr-FR/c4d_strings.str
STRINGTABLE { VONC_GELATINE_NOM "G\u00E9latine"; }
res/strings_fr-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"; }
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() { if (!EnregistreVoncGelatine()) return false; return true; } void PluginEnd() { } Bool PluginMessage(Int32 id, void *data) { switch (id) { case C4DPL_INIT_SYS: if (!g_resource.Init()) return false; return true; } return false; }
source/main.h
#ifndef MAIN_H__ #define MAIN_H__ Bool EnregistreVoncGelatine(); #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() { 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.sqmat * 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.sqmat *= rayon; bd->SetMatrix_Matrix(nullptr, Matrix()); bd->SetPen(couleur); bd->DrawCircle(m); h = m.sqmat.v2; m.sqmat.v2 = m.sqmat.v3; m.sqmat.v3 = h; bd->DrawCircle(m); h = m.sqmat.v1; m.sqmat.v1 = m.sqmat.v3; m.sqmat.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; const Int32 id = dc->_descId[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() { return RegisterObjectPlugin(MODULE_ID, GeLoadString(VONC_GELATINE_NOM), OBJECT_MODIFIER, VoncGelatine::Alloc, "Ovoncgelatine"_s, AutoBitmap("Ovoncgelatine.tif"_s), 0); }
vonc_gelatine.pyp
# César Vonc - code.vonc.fr - v 1.0 - juillet 2016 # coding=utf-8 import os import sys import math import hashlib import c4d from c4d import plugins, utils, bitmaps, gui, Vector, Matrix from c4d.utils import HPBToMatrix, MatrixScale, MixVec, CompareFloatTolerant, Clamp MODULE_ID = 1037749 VONC_GELATINE_NOM = 1000 VONC_GELATINE_ELASTICITE = 1000 VONC_GELATINE_INTENSITE = 1001 VONC_GELATINE_AMORTIS = 1002 VONC_GELATINE_ATTENUATION = 1003 VONC_GELATINE_FORCE = 1004 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 class Gelatine(plugins.ObjectData) : PRISES = 2 def __init__(soi) : soi.pointsCache = {} soi.tpsPrec = -1 soi.ansTps = -1 soi.mode = VONC_GELATINE_MODE_SRC soi.rayon = 50. soi.rayonMax = 300. soi.elasticite = .5 soi.intensite = 1. soi.amortis = 0. soi.force = 0. soi.inverser = False soi.selection = "" soi.ansRayon = None soi.ansRayonMax = None soi.ansMode = None soi.ansSelection = None soi.courbe = c4d.SplineData() soi.courbe.MakeLinearSplineBezier(2) soi.courbe.SetKnot(index = 0, vPos = Vector(0., 1., 0.), lFlagsSettings = 0, vTangentLeft = Vector(-.1, 0.4, 0.), vTangentRight = Vector(.1, -0.4, 0.)) soi.courbe.SetKnot(index = 1, vPos = Vector(1., 0., 0.), lFlagsSettings = 0, vTangentLeft = Vector(-0.5, 0., 0.), vTangentRight = Vector(0.5, 0., 0.)) def GetHandleCount(op) : return Gelatine.PRISES def GetHandle(self, op, i, info) : donnees = op.GetDataInstance() if donnees is None : return if i == 0 : info.position = Vector(donnees.GetFloat(VONC_GELATINE_RAYON), 0.0, 0.0) info.direction = Vector(1.0, 0.0, 0.0) info.type = c4d.HANDLECONSTRAINTTYPE_LINEAR elif i == 1 : info.position = Vector(donnees.GetFloat(VONC_GELATINE_RAYON_MAX), 0.0, 0.0) info.direction = Vector(1.0, 0.0, 0.0) info.type = c4d.HANDLECONSTRAINTTYPE_LINEAR def DetectHandle(self, op, bd, x, y, qualifier) : if qualifier & c4d.QUALIFIER_CTRL : return c4d.NOTOK mg = op.GetMg() ret = c4d.NOTOK for i in range(self.GetHandleCount()) : info = c4d.HandleInfo() self.GetHandle(op, i, info) if bd.PointInRange(info.position * mg, x, y) : ret = i if not qualifier & c4d.QUALIFIER_SHIFT : break return ret def MoveHandle(self, op, undo, mouse_pos, hit_id, qualifier, bd) : dst = op.GetDataInstance() info = c4d.HandleInfo() val = mouse_pos.x self.GetHandle(op, hit_id, info) if bd is not None : mg = op.GetUpMg() * undo.GetMl() pos = bd.ProjectPointOnLine(info.position * mg, info.direction ^ mg, mouse_pos.x, mouse_pos.y) val = (pos[0] * ~mg) * info.direction if hit_id == 0 : dst.SetFloat(VONC_GELATINE_RAYON, utils.FCut(val, 0.0, float('inf'))) elif hit_id == 1 : dst.SetFloat(VONC_GELATINE_RAYON_MAX, utils.FCut(val, 0.0, float('inf'))) return True @staticmethod def DrawCercle(bd, bh, rayon, couleur) : m = bh.GetMg() m.Scale(rayon) bd.SetMatrix_Matrix(None, c4d.Matrix()) # bd.SetPen(bd.GetObjectColor(bh, op)) 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) def Draw(soi, op, drawpass, bd, bh) : donnees = op.GetDataInstance() if donnees is None : return c4d.DRAWRESULT_SKIP mode = donnees.GetLong(VONC_GELATINE_MODE) if drawpass == c4d.DRAWPASS_OBJECT : if mode == VONC_GELATINE_MODE_SRC : soi.DrawCercle(bd, bh, donnees.GetFloat(VONC_GELATINE_RAYON), Vector(.1, 1., 0.5)) if mode != VONC_GELATINE_MODE_INF : soi.DrawCercle(bd, bh, donnees.GetFloat(VONC_GELATINE_RAYON_MAX), Vector(0.663, 0.6, 1.)) return c4d.DRAWRESULT_OK elif drawpass == c4d.DRAWPASS_HANDLES : i = 0 bd.SetMatrix_Matrix(None, bh.GetMg()) surbrille = op.GetHighlightHandle(bd) for i in range(soi.PRISES) : if mode != VONC_GELATINE_MODE_SRC and i == 0 : continue if mode == VONC_GELATINE_MODE_INF : continue info = c4d.HandleInfo() soi.GetHandle(op, i, info) if i == surbrille : bd.SetPen(c4d.GetViewColor(c4d.VIEWCOLOR_SELECTION_PREVIEW)) else : bd.SetPen(c4d.GetViewColor(c4d.VIEWCOLOR_ACTIVEPOINT)) bd.DrawHandle(info.position, c4d.DRAWHANDLE_BIG, 0) info = c4d.HandleInfo() soi.GetHandle(op, 1, info) bd.SetPen(c4d.GetViewColor(c4d.VIEWCOLOR_ACTIVEPOINT)) bd.DrawLine(info.position, Vector(0), 0) return c4d.DRAWRESULT_OK return c4d.DRAWRESULT_SKIP def Init(soi, op) : donnees = op.GetDataInstance() donnees.SetFloat(VONC_GELATINE_RAYON, soi.rayon) donnees.SetFloat(VONC_GELATINE_RAYON_MAX, soi.rayonMax) donnees.SetInt32(VONC_GELATINE_MODE, soi.mode) donnees.SetFloat(VONC_GELATINE_INTENSITE, soi.intensite) donnees.SetFloat(VONC_GELATINE_ELASTICITE, soi.elasticite) donnees.SetFloat(VONC_GELATINE_AMORTIS, soi.amortis) donnees.SetData(VONC_GELATINE_ATTENUATION, soi.courbe) donnees.SetData(VONC_GELATINE_FORCE, soi.force) donnees.SetBool(VONC_GELATINE_INVERSER, soi.inverser) donnees.SetString(VONC_GELATINE_SELECTION, soi.selection) return True def Recup(soi, op) : donnees = op.GetDataInstance() soi.rayon = donnees.GetFloat(VONC_GELATINE_RAYON) soi.rayonMax = donnees.GetFloat(VONC_GELATINE_RAYON_MAX) soi.mode = donnees.GetInt32(VONC_GELATINE_MODE) soi.intensite = donnees.GetFloat(VONC_GELATINE_INTENSITE) soi.elasticite = donnees.GetFloat(VONC_GELATINE_ELASTICITE) soi.amortis = donnees.GetFloat(VONC_GELATINE_AMORTIS) soi.force = donnees.GetFloat(VONC_GELATINE_FORCE) soi.courbe = donnees.GetData(VONC_GELATINE_ATTENUATION) soi.inverser = donnees.GetBool(VONC_GELATINE_INVERSER) soi.selection = donnees.GetString(VONC_GELATINE_SELECTION) if soi.rayonMax < soi.rayon : soi.rayonMax = soi.rayon def CheckDirty(soi, op, doc) : tps = doc.GetTime().GetFrame(doc.GetFps()) if tps != soi.tpsPrec : soi.tpsPrec = tps op.SetDirty(c4d.DIRTY_DATA) def RecupVoisinsPoints(soi, op) : nbPoints = op.GetPointCount() voisins = [None] * nbPoints polys = op.GetAllPolygons() for i in range(nbPoints) : voisins[i] = [] for poly in polys : if poly.c != poly.d : voisins[poly.a].append(poly.b) voisins[poly.a].append(poly.c) voisins[poly.a].append(poly.d) voisins[poly.b].append(poly.a) voisins[poly.b].append(poly.c) voisins[poly.b].append(poly.d) voisins[poly.c].append(poly.a) voisins[poly.c].append(poly.b) voisins[poly.c].append(poly.d) voisins[poly.d].append(poly.a) voisins[poly.d].append(poly.b) voisins[poly.d].append(poly.c) else : voisins[poly.a].append(poly.b) voisins[poly.a].append(poly.c) voisins[poly.b].append(poly.a) voisins[poly.b].append(poly.c) voisins[poly.c].append(poly.a) voisins[poly.c].append(poly.b) for i in range(nbPoints) : voisins[i] = list(set(voisins[i])) return voisins def RecupDepart(soi, op, op_mg, mod_mg) : departs = [] if soi.mode == VONC_GELATINE_MODE_SRC : departs = [mod_mg.off] elif soi.mode == VONC_GELATINE_MODE_SEL : departs = [] points = op.GetAllPoints() if soi.selection : for tag in op.GetTags() : if tag.CheckType(c4d.Tpointselection) and tag.GetName() == soi.selection : bs = tag.GetBaseSelect() for i, sel in enumerate(bs.GetAll(op.GetPointCount())) : if not sel : continue pt = points[i] pt = (op_mg).Mul(pt) departs.append(pt) return departs def CalculeFacteur(soi, op, op_mg, mod_mg) : nbPoints = op.GetPointCount() points = op.GetAllPoints() if soi.mode == VONC_GELATINE_MODE_INF : pointsFacteur = [1.] * nbPoints return pointsFacteur # distanceMax = (op.GetRad() * 2.).GetLength() distanceMax = soi.rayonMax - soi.rayon pointsFacteur = [distanceMax * 10.] * nbPoints departs = soi.RecupDepart(op, op_mg, mod_mg) for pointDepart in departs : for i, point in enumerate(points) : # point = (op_mg).Mul(point) # distance = (pointDepart - point).GetLength() # if pointsFacteur[i] > distance : # pointsFacteur[i] = distance distance -= soi.rayon if distance < 0. : distance = 0. if pointsFacteur[i] > distance : pointsFacteur[i] = distance if distanceMax > 0 : for i, fac in enumerate(pointsFacteur) : pfac = fac / distanceMax if pfac > 1. : pfac = 1. pointsFacteur[i] = pfac return pointsFacteur @staticmethod def ObjID(op) : return str(op.GetUniqueIP()) + str(op.GetGUID()) + op.GetName() # return str(op.GetUniqueIP()) + str(op.GetGUID()) def Libere(soi, mod) : soi.pointsCache = {} def Initialise(soi, op, op_mg, mod_mg, id) : pointsElasticite = [Vector()] * op.GetPointCount() pointsPrecAbs = op.GetAllPoints() mg = op.GetMg() for i, point in enumerate(pointsPrecAbs) : pointsPrecAbs[i] = mg.Mul(point) pointsFacteur = soi.CalculeFacteur(op, op_mg, mod_mg) soi.pointsCache[id] = { "precAbs" : pointsPrecAbs, "elasticite" : pointsElasticite, "facteur" : pointsFacteur, "secPrec" : -1. } def RendUniqueOps(soi, mod) : objs = [] ips = {} if mod.GetUp() is not None : objs = mod.GetUp().GetChildren() objs.append(mod.GetUp()) for obj in objs : ip = obj.GetUniqueIP() while (ip in ips) : ip += 1 obj.SetUniqueIP(ip) ips[ip] = True # Met à jour la propriété sel de points if soi.mode == VONC_GELATINE_MODE_SEL : for tag in obj.GetTags() : if tag.CheckType(c4d.Tpointselection) and tag.GetName() == soi.selection : tag.SetDirty(c4d.DIRTY_DATA) objs.extend(obj.GetChildren()) def DoitInit(soi, op, id) : if not id in soi.pointsCache : return True if len(soi.pointsCache[id]["precAbs"]) != op.GetPointCount() : return True return False def DoitLiberer(soi, time, doc) : libere = False tps = time.GetFrame(doc.GetFps()) # Si on est à l'image 0, libérer la mémoire une fois if tps != soi.ansTps and tps == 0 : libere = True # Si certains paramètres ont changé, libérer la mémoire if soi.ansRayon != soi.rayon : libere = True if soi.ansRayonMax != soi.rayonMax : libere = True if soi.ansMode != soi.mode : libere = True if soi.ansSelection != soi.selection : libere = True soi.ansTps = tps soi.ansRayon = soi.rayon soi.ansRayonMax = soi.rayonMax soi.ansMode = soi.mode soi.ansSelection = soi.selection return libere def ModifyObject(soi, mod, doc, op, op_mg, mod_mg, lod, flags, thread) : # Si pas de points, terminer if not op.CheckType(c4d.Opoint) or not op.GetPointCount() : return True # Récupère les paramètres soi.Recup(mod) # ID de l'objet en cours de traitement id = soi.ObjID(op) # Variables de temps time = doc.GetTime() sec = time.Get() # Libère la mémoire ? if soi.DoitLiberer(time, doc) : soi.Libere(mod) soi.RendUniqueOps(mod) # Si la mémoire est vide ou si op a changé, initialiser ses tableaux de points if soi.DoitInit(op, id) : soi.Initialise(op, op_mg, mod_mg, id) # Bool si le temps est passé ou non tpsPasse = sec != soi.pointsCache[id]["secPrec"] #--------------------------------------------------------------------------------# # Points et compagnie points = op.GetAllPoints() weight = op.CalcVertexmap(mod) pointsPrecAbs = soi.pointsCache[id]["precAbs"] pointsElasticite = soi.pointsCache[id]["elasticite"] pointsFacteur = soi.pointsCache[id]["facteur"] op_mg_inv = (~op_mg) courbeGetPoint = soi.courbe.GetPoint force = soi.force amortis = soi.amortis inverser = soi.inverser intensite = soi.intensite elasticite = soi.elasticite # Boucle principale for i, point in enumerate(points) : pointPrecAbs = pointsPrecAbs[i] pointAbs = op_mg.Mul(point) fac = pointsFacteur[i] if weight is not None : fac *= 1. - weight[i] if inverser : fac = 1. - fac facVitesse = courbeGetPoint(fac * elasticite).y facAmortissement = courbeGetPoint(fac * amortis).y pointElasticite = pointsElasticite[i] * (1. - facVitesse) pointElasticite += (pointAbs - pointPrecAbs) * Clamp(0., 1., force + facVitesse) pointNouveauAbsFac = pointElasticite * facAmortissement # # if pointNouveauAbsFac.GetLengthSquared() > 10000. : # pointNouveauAbsFac = pointNouveauAbsFac.GetNormalized() * (10000.**.5) # pointPrecAbs = pointsPrecAbs[i] + pointNouveauAbsFac if tpsPasse : pointsElasticite[i] = pointElasticite pointsPrecAbs[i] = pointPrecAbs # Limite max # if (soi.pointsCache[id]["precAbs"][i] - pointAbs).GetLengthSquared() > 500000. : # soi.pointsCache[id]["precAbs"][i] = (soi.pointsCache[id]["precAbs"][i] - pointAbs).GetNormalized() * (500000.**.5) + pointAbs # # pointNouveau = op_mg_inv.Mul(soi.pointsCache[id]["precAbs"][i]) pointNouveau = op_mg_inv.Mul(pointPrecAbs) # Intensité pointNouveau = MixVec(point, pointNouveau, intensite) # Définit le nouveau point op.SetPoint(i, pointNouveau) op.Message(c4d.MSG_UPDATE) # Variables précédentes soi.pointsCache[id]["secPrec"] = sec return True def Message(soi, op, type, data) : if type == c4d.MSG_MENUPREPARE : op.SetDeformMode(True) elif type == c4d.MSG_DESCRIPTION_COMMAND : donnees = op.GetDataInstance() id = data["id"][0].id if id == VONC_GELATINE_ATTENUATION_INIT : soi.courbe = c4d.SplineData() soi.courbe.MakeLinearSplineBezier(2) soi.courbe.SetKnot(index = 0, vPos = Vector(0., 1., 0.), lFlagsSettings = 0, vTangentLeft = Vector(-.1, 0.4, 0.), vTangentRight = Vector(.1, -0.4, 0.)) soi.courbe.SetKnot(index = 1, vPos = Vector(1., 0., 0.), lFlagsSettings = 0, vTangentLeft = Vector(-0.5, 0., 0.), vTangentRight = Vector(0.5, 0., 0.)) donnees.SetData(VONC_GELATINE_ATTENUATION, soi.courbe) elif id == VONC_GELATINE_INIT : soi.Libere(op) soi.RendUniqueOps(op) op.SetDirty(c4d.DIRTY_DATA) return True def GetDEnabling(self, node, id, t_data, flags, itemdesc): donnees = node.GetDataInstance() if donnees is None : return True _id = id[0].id if _id == VONC_GELATINE_RAYON : mode = donnees.GetLong(VONC_GELATINE_MODE) if mode != VONC_GELATINE_MODE_SRC : return False elif _id == VONC_GELATINE_RAYON_MAX : mode = donnees.GetLong(VONC_GELATINE_MODE) if mode == VONC_GELATINE_MODE_INF : return False elif _id == VONC_GELATINE_SELECTION : mode = donnees.GetLong(VONC_GELATINE_MODE) if mode != VONC_GELATINE_MODE_SEL : return False return True if __name__ == "__main__": path, fn = os.path.split(__file__) bmp = bitmaps.BaseBitmap() bmp.InitWith(os.path.join(path, "res", "Ovoncgelatine.tif")) plugins.RegisterObjectPlugin(id=MODULE_ID, str=c4d.plugins.GeLoadString(VONC_GELATINE_NOM), g=Gelatine, description="Ovoncgelatine", icon=bmp, info=c4d.OBJECT_MODIFIER)