HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MSS_CustomBrushState.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  * This code is for creating the state to go with this op.
27 */
28 
29 #include "MSS_CustomBrushState.h"
30 
31 #include <DM/DM_Defines.h>
32 #include <DM/DM_ViewportType.h>
33 #include <GR/GR_DisplayOption.h>
34 #include <GU/GU_PrimCircle.h>
35 #include <MSS/MSS_SingleOpState.h>
36 #include <OP/OP_OperatorTable.h>
37 #include <PRM/PRM_Parm.h>
38 #include <RE/RE_Render.h>
39 #include <SOP/SOP_Node.h>
40 #include <UT/UT_DSOVersion.h>
41 
42 #define MSS_CLICK_BUTTONS (DM_PRIMARY_BUTTON|DM_SECONDARY_BUTTON)
43 
44 using namespace HDK_Sample;
45 
46 // register the state
47 void
49 {
50  m->registerState(
51  new PI_StateTemplate("proto_custombrush", // state name
52  "Custom Brush", // English name
53  "SOP_proto_custombrush", // icon name
57  PI_NETMASK_SOP, // marks this as a SOP state
58  0));
59 }
60 
61 // our state has no parameters
64 
65 BM_State *
67  BM_SceneManager *scene)
68 {
69  return new MSS_CustomBrushState((JEDI_View &)view, templ, scene);
70 }
71 
73  JEDI_View &view,
74  PI_StateTemplate &templ,
75  BM_SceneManager *scene,
76  const char *cursor)
77  : MSS_SingleOpState(view, templ, scene, cursor),
78  myBrushHandle((DM_SceneManager &)workbench(), "MSS_CustomBrushState")
79 {
80  myIsBrushVisible = false;
81  myResizingCursor = false;
82 
83  // create brush geometry
84  GU_PrimCircleParms cparms;
85  cparms.gdp = &myBrushCursor;
86  cparms.order = 3; // quadratic
87  cparms.imperfect = 0; // rational
88  cparms.xform.identity();
89 #if defined(HOUDINI_11)
90  GU_PrimCircle::build(cparms, GEOPRIMBEZCURVE); // Bezier
91 #else
92  GU_PrimCircle::build(cparms, GEO_PRIMBEZCURVE); // Bezier
93 #endif
94 
95  myBrushCursorXform.identity();
96  myBrushRadius = 0.1;
97 
98  // only use this state in 3D viewports
100 }
101 
103 {
104  // Nothing needed.
105 }
106 
107 const char *
109 {
110  return "MSS_CustomBrushState";
111 }
112 
113 int
115 {
116  int result = MSS_SingleOpState::enter(how);
117  // ask for handleMouseEvent to be called when the mouse moves or a
118  // mouse button is clicked
119  wantsLocates(1);
121  updatePrompt();
122 
123  // turn off the highlight so we can see the color we are painting
124  OP_Node *op = getNode();
125  if(op)
126  op->setHighlight(0);
127  return result;
128 }
129 
130 void
132 {
133  // cleanup
134  wantsLocates(0);
136  myIsBrushVisible = false;
137  redrawScene();
139 }
140 
141 void
143 {
145  wantsLocates(1);
147  updatePrompt();
148 
149  // turn off the highlight so we can see the color we are painting
150  OP_Node *op = getNode();
151  if(op)
152  op->setHighlight(0);
153 }
154 
155 void
157 {
158  wantsLocates(0);
160  myIsBrushVisible = false;
161  redrawScene();
163 }
164 
165 int
167 {
168  SOP_Node *sop = (SOP_Node *)getNode();
169  if (!sop)
170  return 1; // consumed but useless
171 
172  fpreal t = getTime();
173  int x = event->state.values[X];
174  int y = event->state.values[Y];
175 
176  if (event->reason == UI_VALUE_START &&
177  (event->state.altFlags & UI_ALT_KEY ||
178  event->state.altFlags & UI_SHIFT_KEY))
179  {
180  // prepare for resizing the brush
181  myResizeCursorX = x;
182  myResizeCursorY = y;
183  myResizingCursor = true;
184  }
185  else if (myResizingCursor)
186  {
187  // scale the brush's radius
188  fpreal dist = x - myLastCursorX +
189  y - myLastCursorY;
190 
191  myBrushRadius *= powf(1.01, dist);
192 
193  if (event->reason == UI_VALUE_CHANGED)
194  myResizingCursor = false;
195 
196  updateBrush(myResizeCursorX, myResizeCursorY);
197  }
198  else if (event->reason == UI_VALUE_LOCATED)
199  {
200  // re-position the brush
201  updateBrush(x, y);
202  }
203  else
204  {
205  // Apply a stroke
206  //
207  // The set*() method calls below will automatically record the undo
208  // actions. Since we do automatic matching of the sop node type via the
209  // same name as the state, we're assuming here for simplicity that the
210  // parameters exist.
211 
212  UT_Vector3 rayorig, dir;
213  mapToWorld(x, y, dir, rayorig);
214 
215  bool begin = (event->reason == UI_VALUE_START ||
216  event->reason == UI_VALUE_PICKED);
217  if(begin)
219 
220  sop->setFloat("origin", 0, t, rayorig.x());
221  sop->setFloat("origin", 1, t, rayorig.y());
222  sop->setFloat("origin", 2, t, rayorig.z());
223 
224  sop->setFloat("direction", 0, t, dir.x());
225  sop->setFloat("direction", 1, t, dir.y());
226  sop->setFloat("direction", 2, t, dir.z());
227 
228  sop->setFloat("radius", 0, t, myBrushRadius);
229 
230  {
231  UT_String str = (event->state.values[W] == DM_SECONDARY_BUTTON)
232  ? "erase" : "paint";
233  sop->setString(str, CH_STRING_LITERAL, "operation", 0, t);
234  }
235 
236  OP_Context context(t);
237 
238  bool set_op = false;
239  if (begin)
240  {
241  // indicate the begin of a stroke
242  set_op = true;
243  sop->setString(UT_String("begin"), CH_STRING_LITERAL,"event",0,t);
244  }
245 
246  // indicate a stroke is active
247  bool active = (event->reason == UI_VALUE_ACTIVE ||
248  event->reason == UI_VALUE_PICKED);
249  if (active)
250  {
251  if(set_op)
252  {
253  // trigger a cook of the CustomBrush SOP so it can cook with
254  // the current stroke values
255  sop->getCookedGeo(context);
256  }
257 
258  set_op = true;
259  sop->setString(UT_String("active"), CH_STRING_LITERAL, "event",0,t);
260  }
261  // If the brush event is an end, we need to close the undo block.
262  if (event->reason == UI_VALUE_CHANGED ||
263  event->reason == UI_VALUE_PICKED)
264  {
265  if(set_op)
266  {
267  // trigger a cook of the CustomBrush SOP so it can cook
268  // with the current stroke values
269  sop->getCookedGeo(context);
270  }
271 
272  // now change the stroke parameter to indicate a no-op.
273  sop->setString(UT_String("end"), CH_STRING_LITERAL, "event", 0, t);
274 
275  // trigger a cook of the CustomBrush SOP so it can cook with
276  // the end stroke values
277  sop->getCookedGeo(context);
278 
279  // now change the stroke parameter to indicate a no-op.
280  sop->setString(UT_String("nop"), CH_STRING_LITERAL, "event", 0, t);
281 
283  }
284 
285  updateBrush(x, y);
286  }
287 
288  myLastCursorX = x;
289  myLastCursorY = y;
290 
291  return 1;
292 }
293 
294 void
296 {
297  if (!isPreempted() && myIsBrushVisible)
298  {
299  UT_Color clr;
300 
301  r->pushMatrix();
302  r->multiplyMatrix(myBrushCursorXform);
303 
304  if(ghost)
305  {
306  // color for obstructed parts of the brush
307  clr = UT_Color(UT_RGB, 0.625,0.4,0.375);
308  }
309  else
310  {
311  // color for unobstructed parts of the brush
312  clr = UT_Color(UT_RGB, 1, 0.1, 0);
313  }
314 
315  myBrushHandle.renderWire(*r, 0, 0, 0, clr, &myBrushCursor);
316 
317  r->popMatrix();
318  }
319 }
320 
321 void
323 {
324  showPrompt("LMB to apply stroke. MMB to erase. Shift-LMB to adjust radius.");
325 }
326 
327 void
329 {
330  // get cameraspace to worldspace transform
331  getViewportItransform(myBrushCursorXform);
332 
333  // determine the direction the camera a facing
334  UT_Vector3 forward = rowVecMult3(UT_Vector3(0, 0, -1), myBrushCursorXform);
335 
336  // position the brush under the pointer and one unit away from the camera
337  UT_Vector3 rayorig, dir;
338  mapToWorld(x, y, dir, rayorig);
339  UT_Vector3 delta(1.0 / dot(dir, forward) * dir);
340  myBrushCursorXform.translate(delta.x(), delta.y(), delta.z());
341 
342  // scale the brush
343  myBrushCursorXform.prescale(myBrushRadius, myBrushRadius, 1);
344 
345  // ensure the brush is visible
346  myIsBrushVisible = true;
347  redrawScene();
348 }
virtual int enter(BM_SimpleState::BM_EntryType how)
const GU_Detail * getCookedGeo(OP_Context &, int forced=0)
virtual void exit()
called when the user leaves the state
void popMatrix(bool all_matrices=true, RE_MatrixMode mmode=RE_MATRIX_VIEWING)
GA_API const UT_StringHolder dist
fpreal getTime() const
Obtains the current global time.
void mapToWorld(float x, float y, UT_Vector3 &dir, UT_Vector3 &rayorig)
Map viewport coordinates to worldspace location and direction.
int isPreempted() const
Definition: BM_State.h:208
UT_Vector3T< T > rowVecMult3(const UT_Vector3T< T > &v, const UT_Matrix4T< S > &m)
Definition: UT_Vector3.h:926
virtual int enter(BM_SimpleState::BM_EntryType how)
called when the user enters the state
static PRM_Template * ourTemplateList
parameters for this state
UT_Vector3T< float > UT_Vector3
#define UI_SHIFT_KEY
const unsigned PI_NETMASK_SOP
#define DM_SECONDARY_BUTTON
Definition: DM_Defines.h:181
SYS_API float powf(float x, float y)
virtual void interrupt(BM_SimpleState *=0)
GLint y
Definition: glcorearb.h:102
virtual int handleMouseEvent(UI_Event *event)
Respond to mouse or keyboard events.
SYS_FORCE_INLINE T & x(void)
Definition: UT_Vector3.h:581
void prescale(T sx, T sy, T sz, T sw=1.0f)
Definition: UT_Matrix4.h:566
void showPrompt(const char *msg)
Set the status bar text.
virtual void interrupt(BM_SimpleState *state=0)
virtual int registerState(PI_StateTemplate *type)
void newModelState(BM_ResourceManager *m)
struct _cl_event * event
Definition: glcorearb.h:2960
void pushMatrix(bool all_matrices=true, RE_MatrixMode mmode=RE_MATRIX_VIEWING)
SYS_FORCE_INLINE T & z(void)
Definition: UT_Vector3.h:585
static BM_State * ourConstructor(BM_View &view, PI_StateTemplate &templ, BM_SceneManager *scene)
used by DM to create our state
MSS_CustomBrushState(JEDI_View &view, PI_StateTemplate &templ, BM_SceneManager *scene, const char *cursor=BM_DEFAULT_CURSOR)
void wantsLocates(int yesNo)
Definition: BM_State.h:203
void removeClickInterest(int buttons)
OP_Node * getNode(void) const
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:218
void setFloat(int parmi, int vectori, fpreal t, fpreal value, int h=0)
void beginDistributedUndoBlock(const char *operation, UT_UndoBlockType blocktype)
void setViewportMask(unsigned mask)
virtual void exit()
#define MSS_CLICK_BUTTONS
virtual void updatePrompt()
sets the prompt's text
void identity()
Set the matrix to identity.
Definition: UT_Matrix4.h:924
virtual void doRender(RE_Render *r, int x, int y, int ghost)
Render the brush "cursor" geometry:
UI_DeviceEvent state
Definition: UI_Event.h:58
void updateBrush(int x, int y)
repositions the brush's guide geometry
virtual void resume(BM_SimpleState *state=0)
void redrawScene()
GEO_API const TypeMask GEOPRIMBEZCURVE
#define UI_ALT_KEY
SYS_FORCE_INLINE T & y(void)
Definition: UT_Vector3.h:583
double fpreal
Definition: SYS_Types.h:263
void addClickInterest(int buttons)
GLint GLenum GLint x
Definition: glcorearb.h:408
void setString(const UT_String &val, CH_StringMeaning meaning, int parmi, int vectori, fpreal t)
#define DM_VIEWPORT_PERSPECTIVE
UI_Reason reason
Definition: UI_Event.h:60
void renderWire(RE_Render &r, int pickflag, uint id1, uint id2, const UT_Color &color, GU_Detail *gdp=NULL, const UT_DMatrix4 *xform=NULL)
GLboolean r
Definition: glcorearb.h:1221
void getViewportItransform(UT_Matrix4 &xform)
Get cameraspace to worldspace transform.
void endDistributedUndoBlock()
void multiplyMatrix(const UT_Matrix4 &m)
static GEO_Primitive * build(const GU_PrimCircleParms &parms, GA_PrimitiveTypeId type=GEO_PRIMCIRCLE)
virtual const char * className() const
The name and type of this class:
int setHighlight(int on_off)
virtual void resume(BM_SimpleState *=0)
void translate(T dx, T dy, T dz=0.0f)
Definition: UT_Matrix4.h:608