1 /* This file is part of Dilay
2  * Copyright © 2015-2018 Alexander Bau
3  * Use and redistribute under the terms of the GNU General Public License
4  */
5 #include <memory>
6 #include "dynamic/faces.hpp"
7 #include "dynamic/mesh.hpp"
8 #include "primitive/plane.hpp"
9 #include "primitive/sphere.hpp"
10 #include "primitive/triangle.hpp"
11 #include "tool/sculpt/util/brush.hpp"
12 #include "util.hpp"
13 
SBFlattenParameters()14 SBFlattenParameters::SBFlattenParameters ()
15   : _lockPlane (false)
16 {
17 }
18 
hasLockedPlane() const19 bool SBFlattenParameters::hasLockedPlane () const { return bool(this->_lockedPlane); }
20 
lockedPlane() const21 const PrimPlane& SBFlattenParameters::lockedPlane () const { return *this->_lockedPlane; }
22 
lockedPlane(const PrimPlane & p)23 void SBFlattenParameters::lockedPlane (const PrimPlane& p) { this->_lockedPlane = p; }
24 
resetLockedPlane()25 void SBFlattenParameters::resetLockedPlane () { this->_lockedPlane.reset (); }
26 
mirror(const PrimPlane & m)27 void SBFlattenParameters::mirror (const PrimPlane& m)
28 {
29   if (this->hasLockedPlane ())
30   {
31     this->_lockedPlane->point (m.mirror (this->_lockedPlane->point ()));
32     this->_lockedPlane->normal (m.mirrorDirection (this->_lockedPlane->normal ()));
33   }
34 }
35 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const36 void SBDrawParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
37 {
38   if (faces.isEmpty () == false)
39   {
40     if (this->flat ())
41     {
42       const float     intensity = 0.3f * this->intensity ();
43       const glm::vec3 planeNormal = this->invert (brush.normal ());
44       const glm::vec3 planePos = brush.position () + (planeNormal * intensity * brush.radius ());
45       const PrimPlane plane (planePos, planeNormal);
46 
47       brush.mesh ().forEachVertex (faces, [&brush, &plane, intensity](unsigned int i) {
48         const glm::vec3& oldPos = brush.mesh ().vertex (i);
49         const float      factor = intensity * Util::linearStep (oldPos, brush.position (),
50                                                            0.5f * brush.radius (), brush.radius ());
51         const float      distance = glm::min (0.0f, plane.distance (oldPos));
52         const glm::vec3  newPos = oldPos - (plane.normal () * factor * distance);
53 
54         brush.mesh ().vertex (i, newPos);
55       });
56     }
57     else
58     {
59       const float     intensity = 0.1f * this->intensity () * brush.radius ();
60       const glm::vec3 avgDir = this->invert (brush.mesh ().averageNormal (faces));
61 
62       brush.mesh ().forEachVertex (faces, [&brush, &avgDir, intensity](unsigned int i) {
63         const glm::vec3& oldPos = brush.mesh ().vertex (i);
64         const float      factor =
65           intensity * Util::smoothStep (oldPos, brush.position (), 0.0f, brush.radius ());
66         const glm::vec3 newPos = oldPos + (factor * avgDir);
67 
68         brush.mesh ().vertex (i, newPos);
69       });
70     }
71   }
72 }
73 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const74 void SBGrablikeParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
75 {
76   brush.mesh ().forEachVertex (faces, [&brush](unsigned int i) {
77     const glm::vec3& oldPos = brush.mesh ().vertex (i);
78     const float factor = Util::linearStep (oldPos, brush.lastPosition (), 0.0f, brush.radius ());
79     const glm::vec3 newPos = oldPos + (factor * brush.delta ());
80 
81     brush.mesh ().vertex (i, newPos);
82   });
83 }
84 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const85 void SBSmoothParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
86 {
87   brush.mesh ().forEachVertex (faces, [this, &brush](unsigned int i) {
88     const glm::vec3  avgPos = brush.mesh ().averagePosition (i);
89     const glm::vec3& oldPos = brush.mesh ().vertex (i);
90     const glm::vec3  newPos = oldPos + (this->intensity () * (avgPos - oldPos));
91 
92     brush.mesh ().vertex (i, newPos);
93   });
94 }
95 
sculpt(const SculptBrush &,const DynamicFaces &) const96 void SBReduceParameters::sculpt (const SculptBrush&, const DynamicFaces&) const {}
97 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const98 void SBFlattenParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
99 {
100   if (faces.isEmpty () == false)
101   {
102     PrimPlane plane (glm::vec3 (0.0f), glm::vec3 (1.0f));
103 
104     if (this->hasLockedPlane ())
105     {
106       plane = this->lockedPlane ();
107     }
108     else
109     {
110       glm::vec3 avgPos, avgNormal;
111       brush.mesh ().average (faces, avgPos, avgNormal);
112       plane = PrimPlane (avgPos, avgNormal);
113     }
114 
115     brush.mesh ().forEachVertex (faces, [this, &brush, &plane](unsigned int i) {
116       const glm::vec3& oldPos = brush.mesh ().vertex (i);
117       const float      distance = plane.distance (oldPos);
118 
119       float factor =
120         this->intensity () * Util::linearStep (oldPos, brush.position (), 0.0f, brush.radius ());
121       factor *= this->hasLockedPlane () ? distance : glm::max (0.0f, distance);
122 
123       const glm::vec3 newPos = oldPos - (plane.normal () * factor);
124       brush.mesh ().vertex (i, newPos);
125     });
126   }
127 }
128 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const129 void SBCreaseParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
130 {
131   if (faces.isEmpty () == false && brush.position () != brush.lastPosition ())
132   {
133     const glm::vec3 normal = this->invert (brush.normal ());
134 
135     brush.mesh ().forEachVertex (faces, [this, &brush, &normal](unsigned int i) {
136       const glm::vec3& oldPos = brush.mesh ().vertex (i);
137       const glm::vec3  delta = brush.position () - oldPos;
138       const float      distance = glm::length (delta) / brush.radius ();
139 
140       if (distance <= 1.0f)
141       {
142         const float invDistance2 = (distance - 1.0f) * (distance - 1.0f);
143         const float hFactor = invDistance2 * this->intensity ();
144         float vFactor = invDistance2 * invDistance2 * brush.radius () * this->intensity () * 0.5f;
145         const glm::vec3 newPos = (oldPos + (hFactor * delta)) + (normal * vFactor);
146 
147         brush.mesh ().vertex (i, newPos);
148       }
149     });
150   }
151 }
152 
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const153 void SBPinchParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
154 {
155   brush.mesh ().forEachVertex (faces, [&brush](unsigned int i) {
156     const glm::vec3& oldPos = brush.mesh ().vertex (i);
157     const glm::vec3  delta = brush.position () - oldPos;
158     const float      distance = glm::length (delta) / brush.radius ();
159 
160     if (distance <= 1.0f)
161     {
162       const float     invDistance2 = (distance - 1.0f) * (distance - 1.0f);
163       const float     hFactor = invDistance2 * 0.5f;
164       const glm::vec3 newPos = oldPos + (hFactor * delta);
165 
166       brush.mesh ().vertex (i, newPos);
167     }
168   });
169 }
170 
171 struct SculptBrush::Impl
172 {
173   SculptBrush* self;
174   float        radius;
175   float        detailFactor;
176   float        stepWidthFactor;
177   bool         subdivide;
178   DynamicMesh* _mesh;
179   bool         hasPointOfAction;
180   glm::vec3    _prevPosition;
181   glm::vec3    _position;
182   glm::vec3    _normal;
183 
184   std::unique_ptr<SBParameters> _parameters;
185 
ImplSculptBrush::Impl186   Impl (SculptBrush* s)
187     : self (s)
188     , radius (0.0f)
189     , detailFactor (0.0f)
190     , stepWidthFactor (0.0f)
191     , subdivide (true)
192     , _mesh (nullptr)
193     , hasPointOfAction (false)
194   {
195   }
196 
meshSculptBrush::Impl197   DynamicMesh& mesh () const
198   {
199     assert (this->hasPointOfAction);
200     assert (this->_mesh);
201     return *this->_mesh;
202   }
203 
meshSculptBrush::Impl204   void mesh (DynamicMesh& m) { this->_mesh = &m; }
205 
subdivThresholdSculptBrush::Impl206   float subdivThreshold () const
207   {
208     assert (this->detailFactor > 0.0f);
209     assert (this->detailFactor < 1.0f);
210 
211     return (1.0f - this->detailFactor) * this->radius;
212   }
213 
lastPositionSculptBrush::Impl214   const glm::vec3& lastPosition () const
215   {
216     assert (this->hasPointOfAction);
217     return this->_prevPosition;
218   }
219 
positionSculptBrush::Impl220   const glm::vec3& position () const
221   {
222     assert (this->hasPointOfAction);
223     return this->_position;
224   }
225 
normalSculptBrush::Impl226   const glm::vec3& normal () const
227   {
228     assert (this->hasPointOfAction);
229     return this->_normal;
230   }
231 
deltaSculptBrush::Impl232   glm::vec3 delta () const
233   {
234     assert (this->hasPointOfAction);
235     return this->_position - this->_prevPosition;
236   }
237 
sphereSculptBrush::Impl238   PrimSphere sphere () const
239   {
240     assert (this->_parameters);
241 
242     const glm::vec3& pos =
243       this->_parameters->useLastPos () ? this->lastPosition () : this->position ();
244     return PrimSphere (pos, this->radius);
245   }
246 
stepWidthSculptBrush::Impl247   float stepWidth () const { return this->stepWidthFactor * glm::log (this->self->radius () + 1); }
248 
setPointOfActionSculptBrush::Impl249   void setPointOfAction (DynamicMesh& mesh, const glm::vec3& p, const glm::vec3& n)
250   {
251     this->_mesh = &mesh;
252     this->_prevPosition = this->hasPointOfAction ? this->_position : p;
253     this->_position = p;
254     this->_normal = n;
255     this->hasPointOfAction = true;
256   }
257 
resetPointOfActionSculptBrush::Impl258   void resetPointOfAction ()
259   {
260     this->hasPointOfAction = false;
261     this->_mesh = nullptr;
262   }
263 
mirrorSculptBrush::Impl264   void mirror (const PrimPlane& plane)
265   {
266     if (this->_parameters)
267     {
268       this->_parameters->mirror (plane);
269     }
270 
271     if (this->hasPointOfAction)
272     {
273       this->_prevPosition = plane.mirror (this->_prevPosition);
274       this->_position = plane.mirror (this->_position);
275       this->_normal = plane.mirrorDirection (this->_normal);
276     }
277   }
278 
getAffectedFacesSculptBrush::Impl279   DynamicFaces getAffectedFaces () const
280   {
281     assert (this->hasPointOfAction);
282     assert (this->_parameters);
283 
284     DynamicFaces faces;
285     this->_mesh->intersects (this->sphere (), faces);
286 
287     if (this->_parameters->discardBack ())
288     {
289       faces.filter ([this](unsigned int i) {
290         return glm::dot (this->normal (), this->_mesh->face (i).cross ()) > 0.0f;
291       });
292     }
293     return faces;
294   }
295 
sculptSculptBrush::Impl296   void sculpt (const DynamicFaces& faces) const
297   {
298     assert (this->_parameters);
299     this->_parameters->sculpt (*this->self, faces);
300   }
301 
parametersPointerSculptBrush::Impl302   SBParameters* parametersPointer () const { return this->_parameters.get (); }
303 
parametersPointerSculptBrush::Impl304   void parametersPointer (SBParameters* p) { this->_parameters.reset (p); }
305 };
306 
307 DELEGATE_BIG3_SELF (SculptBrush)
308 
309 GETTER_CONST (float, SculptBrush, radius)
310 GETTER_CONST (float, SculptBrush, detailFactor)
311 GETTER_CONST (float, SculptBrush, stepWidthFactor)
312 GETTER_CONST (bool, SculptBrush, subdivide)
313 DELEGATE_CONST (DynamicMesh&, SculptBrush, mesh)
314 SETTER (float, SculptBrush, radius)
315 SETTER (float, SculptBrush, detailFactor)
316 SETTER (float, SculptBrush, stepWidthFactor)
317 SETTER (bool, SculptBrush, subdivide)
318 DELEGATE_CONST (float, SculptBrush, subdivThreshold)
319 DELEGATE_CONST (const glm::vec3&, SculptBrush, lastPosition)
320 DELEGATE_CONST (const glm::vec3&, SculptBrush, position)
321 DELEGATE_CONST (const glm::vec3&, SculptBrush, normal)
322 DELEGATE_CONST (glm::vec3, SculptBrush, delta)
323 DELEGATE_CONST (PrimSphere, SculptBrush, sphere)
324 DELEGATE_CONST (float, SculptBrush, stepWidth)
325 GETTER_CONST (bool, SculptBrush, hasPointOfAction)
326 DELEGATE3 (void, SculptBrush, setPointOfAction, DynamicMesh&, const glm::vec3&, const glm::vec3&)
327 DELEGATE (void, SculptBrush, resetPointOfAction)
328 DELEGATE1 (void, SculptBrush, mirror, const PrimPlane&)
329 DELEGATE_CONST (DynamicFaces, SculptBrush, getAffectedFaces)
330 DELEGATE1_CONST (void, SculptBrush, sculpt, const DynamicFaces&)
331 DELEGATE_CONST (SBParameters*, SculptBrush, parametersPointer)
332 DELEGATE1 (void, SculptBrush, parametersPointer, SBParameters*)
333