00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "MSS_CustomBrushState.h"
00030
00031 #include <DM/DM_Defines.h>
00032 #include <DM/DM_ViewportType.h>
00033 #include <GR/GR_Detail.h>
00034 #include <GR/GR_DisplayOption.h>
00035 #include <GU/GU_PrimCircle.h>
00036 #include <MSS/MSS_SingleOpState.h>
00037 #include <OP/OP_OperatorTable.h>
00038 #include <PRM/PRM_Parm.h>
00039 #include <RE/RE_Render.h>
00040 #include <SOP/SOP_Node.h>
00041 #include <UT/UT_DSOVersion.h>
00042
00043 #define MSS_CLICK_BUTTONS (DM_PRIMARY_BUTTON|DM_SECONDARY_BUTTON)
00044
00045 using namespace HDK_Sample;
00046
00047
00048 void
00049 newModelState(BM_ResourceManager *m)
00050 {
00051 m->registerState(
00052 new PI_StateTemplate("proto_custombrush",
00053 "Custom Brush",
00054 "SOP_proto_custombrush",
00055 (void *)MSS_CustomBrushState::ourConstructor,
00056 MSS_CustomBrushState::ourTemplateList,
00057 PI_VIEWER_SCENE,
00058 PI_NETMASK_SOP,
00059 0));
00060 }
00061
00062
00063 PRM_Template *
00064 MSS_CustomBrushState::ourTemplateList = 0;
00065
00066 BM_State *
00067 MSS_CustomBrushState::ourConstructor(BM_View &view, PI_StateTemplate &templ,
00068 BM_SceneManager *scene)
00069 {
00070 return new MSS_CustomBrushState((JEDI_View &)view, templ, scene);
00071 }
00072
00073 MSS_CustomBrushState::MSS_CustomBrushState(
00074 JEDI_View &view,
00075 PI_StateTemplate &templ,
00076 BM_SceneManager *scene,
00077 char *cursor) : MSS_SingleOpState(view, templ, scene, cursor)
00078 {
00079 myIsBrushVisible = false;
00080 myResizingCursor = false;
00081
00082
00083 GU_PrimCircleParms cparms;
00084 cparms.gdp = &myBrushCursor;
00085 cparms.order = 3;
00086 cparms.imperfect = 0;
00087 cparms.xform.identity();
00088 GU_PrimCircle::build(cparms, GEOPRIMBEZCURVE);
00089
00090 myBrushCursorXform.identity();
00091 myBrushRadius = 0.1;
00092
00093
00094 setViewportMask(DM_VIEWPORT_PERSPECTIVE);
00095 }
00096
00097 MSS_CustomBrushState::~MSS_CustomBrushState()
00098 {
00099
00100 }
00101
00102 const char *
00103 MSS_CustomBrushState::className() const
00104 {
00105 return "MSS_CustomBrushState";
00106 }
00107
00108 int
00109 MSS_CustomBrushState::enter(BM_SimpleState::BM_EntryType how)
00110 {
00111 int result = MSS_SingleOpState::enter(how);
00112
00113
00114 wantsLocates(1);
00115 addClickInterest(MSS_CLICK_BUTTONS);
00116 updatePrompt();
00117
00118
00119 OP_Node *op = getNode();
00120 if(op)
00121 op->setHighlight(0);
00122 return result;
00123 }
00124
00125 void
00126 MSS_CustomBrushState::exit()
00127 {
00128
00129 wantsLocates(0);
00130 removeClickInterest(MSS_CLICK_BUTTONS);
00131 myIsBrushVisible = false;
00132 redrawScene();
00133 MSS_SingleOpState::exit();
00134 }
00135
00136 void
00137 MSS_CustomBrushState::resume(BM_SimpleState *state)
00138 {
00139 MSS_SingleOpState::resume(state);
00140 wantsLocates(1);
00141 addClickInterest(MSS_CLICK_BUTTONS);
00142 updatePrompt();
00143
00144
00145 OP_Node *op = getNode();
00146 if(op)
00147 op->setHighlight(0);
00148 }
00149
00150 void
00151 MSS_CustomBrushState::interrupt(BM_SimpleState *state)
00152 {
00153 wantsLocates(0);
00154 removeClickInterest(MSS_CLICK_BUTTONS);
00155 myIsBrushVisible = false;
00156 redrawScene();
00157 MSS_SingleOpState::interrupt(state);
00158 }
00159
00160 int
00161 MSS_CustomBrushState::handleMouseEvent(UI_Event *event)
00162 {
00163 SOP_Node *sop = (SOP_Node *)getNode();
00164 if (!sop)
00165 return 1;
00166
00167 float t = getTime();
00168 int x = event->state.values[X];
00169 int y = event->state.values[Y];
00170
00171 if (event->reason == UI_VALUE_START &&
00172 (event->state.altFlags & UI_ALT_KEY ||
00173 event->state.altFlags & UI_SHIFT_KEY))
00174 {
00175
00176 myResizeCursorX = x;
00177 myResizeCursorY = y;
00178 myResizingCursor = true;
00179 }
00180 else if (myResizingCursor)
00181 {
00182
00183 fpreal dist = x - myLastCursorX +
00184 y - myLastCursorY;
00185
00186 myBrushRadius *= powf(1.01f, dist);
00187
00188 if (event->reason == UI_VALUE_CHANGED)
00189 myResizingCursor = false;
00190
00191 updateBrush(myResizeCursorX, myResizeCursorY);
00192 }
00193 else if (event->reason == UI_VALUE_LOCATED)
00194 {
00195
00196 updateBrush(x, y);
00197 }
00198 else
00199 {
00200
00201 UT_Vector3 rayorig, dir;
00202 mapToWorld(x, y, dir, rayorig);
00203
00204 bool begin = (event->reason == UI_VALUE_START ||
00205 event->reason == UI_VALUE_PICKED);
00206 if(begin)
00207 beginDistributedUndoBlock("Stroke", ANYLEVEL);
00208
00209 PRM_ParmList *parmlist = sop->getParmList();
00210 PRM_Parm *parm;
00211
00212 parm = parmlist->getParmPtr("origin");
00213 if(parm)
00214 {
00215 parm->setValue(t, rayorig.x(), 0, 0);
00216 parm->setValue(t, rayorig.y(), 0, 1);
00217 parm->setValue(t, rayorig.z(), 0, 2);
00218 }
00219
00220 parm = parmlist->getParmPtr("direction");
00221 if(parm)
00222 {
00223 parm->setValue(t, dir.x(), 0, 0);
00224 parm->setValue(t, dir.y(), 0, 1);
00225 parm->setValue(t, dir.z(), 0, 2);
00226 }
00227
00228 parm = parmlist->getParmPtr("radius");
00229 if(parm)
00230 parm->setValue(t, myBrushRadius);
00231
00232 parm = parmlist->getParmPtr("operation");
00233 if(parm)
00234 {
00235 const char *str = (event->state.values[W] == DM_SECONDARY_BUTTON) ? "erase" : "paint";
00236 parm->setValue(t, UT_String(str), CH_STRING_LITERAL);
00237 }
00238
00239 OP_Context context(t);
00240 parm = parmlist->getParmPtr("event");
00241
00242 bool set_op = false;
00243 if(begin && parm)
00244 {
00245
00246 set_op = true;
00247 parm->setValue(t, UT_String("begin"), CH_STRING_LITERAL);
00248 }
00249
00250
00251 bool active = (event->reason == UI_VALUE_ACTIVE ||
00252 event->reason == UI_VALUE_PICKED);
00253 if (active && parm)
00254 {
00255 if(set_op)
00256 {
00257
00258
00259 sop->getCookedGeo(context);
00260 }
00261
00262 set_op = true;
00263 parm->setValue(t, UT_String("active"), CH_STRING_LITERAL);
00264 }
00265
00266 if (event->reason == UI_VALUE_CHANGED ||
00267 event->reason == UI_VALUE_PICKED)
00268 {
00269 if(parm)
00270 {
00271 if(set_op)
00272 {
00273
00274
00275 sop->getCookedGeo(context);
00276 }
00277
00278
00279 parm->setValue(t, UT_String("end"), CH_STRING_LITERAL);
00280
00281
00282
00283 sop->getCookedGeo(context);
00284
00285
00286 parm->setValue(t, UT_String("nop"), CH_STRING_LITERAL);
00287 }
00288
00289 endDistributedUndoBlock();
00290 }
00291
00292 updateBrush(x, y);
00293 }
00294
00295 myLastCursorX = x;
00296 myLastCursorY = y;
00297
00298 return 1;
00299 }
00300
00301 void
00302 MSS_CustomBrushState::doRender(RE_Render *r, short, short, int ghost)
00303 {
00304 if (!isPreempted() && myIsBrushVisible)
00305 {
00306 r->pushMatrix();
00307 r->multiplyMatrix(myBrushCursorXform);
00308
00309 GR_DisplayOption dopt;
00310 if(ghost)
00311 {
00312
00313 dopt.wireColor() = UT_Color(UT_RGB, 0.625, 0.4, 0.375);
00314 }
00315 else
00316 {
00317
00318 dopt.wireColor() = UT_Color(UT_RGB, 1, 0.1, 0);
00319 }
00320
00321 GR_Detail rgdp;
00322 rgdp.wireDraw(&myBrushCursor, *r, getViewportLOD(), 1 ,
00323 0 , &dopt, false);
00324
00325 r->popMatrix();
00326 }
00327 }
00328
00329 void
00330 MSS_CustomBrushState::updatePrompt()
00331 {
00332 showPrompt("LMB to apply stroke. MMB to erase. Shift-LMB to adjust radius.");
00333 }
00334
00335 void
00336 MSS_CustomBrushState::updateBrush(int x, int y)
00337 {
00338
00339 getViewportItransform(myBrushCursorXform);
00340
00341
00342 UT_Vector3 forward = rowVecMult(UT_Vector4(0, 0, -1, 0), myBrushCursorXform);
00343
00344
00345 UT_Vector3 rayorig, dir;
00346 mapToWorld(x, y, dir, rayorig);
00347 UT_Vector3 delta(1.0 / dot(dir, forward) * dir);
00348 myBrushCursorXform.translate(delta.x(), delta.y(), delta.z());
00349
00350
00351 myBrushCursorXform.prescale(myBrushRadius, myBrushRadius, 1);
00352
00353
00354 myIsBrushVisible = true;
00355 redrawScene();
00356 }