guiFilterCtrl.cpp
Engine/source/gui/editor/guiFilterCtrl.cpp
Public Functions
ConsoleDocClass(GuiFilterCtrl , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Catmull-Rom spline through <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> number of <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">points.\n\n</a>" "Currently editor use only, no real application without <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">extension.\n\n</a> " " @internal" )
DefineEngineMethod(GuiFilterCtrl , getValue , const char * , () , "Return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tuple containing all the values in the filter." "@internal" )
DefineEngineMethod(GuiFilterCtrl , resetFiltering , void , () , "Reset the filtering." "@internal" )
DefineEngineStringlyVariadicMethod(GuiFilterCtrl , setValue , void , 3 , 20 , "(f1, f2, ...)" "Reset the filter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use the specified points, spread equidistantly across the domain." " @internal" )
Detailed Description
Public Functions
ConsoleDocClass(GuiFilterCtrl , "@brief A <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> that displays <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Catmull-Rom spline through <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> number of <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">points.\n\n</a>" "Currently editor use only, no real application without <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">extension.\n\n</a> " " @internal" )
DefineEngineMethod(GuiFilterCtrl , getValue , const char * , () , "Return <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tuple containing all the values in the filter." "@internal" )
DefineEngineMethod(GuiFilterCtrl , resetFiltering , void , () , "Reset the filtering." "@internal" )
DefineEngineStringlyVariadicMethod(GuiFilterCtrl , setValue , void , 3 , 20 , "(f1, f2, ...)" "Reset the filter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use the specified points, spread equidistantly across the domain." " @internal" )
IMPLEMENT_CONOBJECT(GuiFilterCtrl )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gui/editor/guiFilterCtrl.h" 26 27#include "console/engineAPI.h" 28#include "console/console.h" 29#include "console/consoleTypes.h" 30#include "guiFilterCtrl.h" 31#include "math/mMath.h" 32#include "gfx/gfxDrawUtil.h" 33 34 35IMPLEMENT_CONOBJECT(GuiFilterCtrl); 36 37ConsoleDocClass( GuiFilterCtrl, 38 "@brief A control that displays a Catmull-Rom spline through a number of control points.\n\n" 39 "Currently editor use only, no real application without extension.\n\n " 40 "@internal"); 41 42GuiFilterCtrl::GuiFilterCtrl() 43{ 44 mControlPointRequest = 7; 45 mFilter.setSize(7); 46 mShowIdentity = true; 47 mIdentity.set( 0.0f, 1.0f ); 48 identity(); 49 mCurKnot = -1; 50} 51 52void GuiFilterCtrl::initPersistFields() 53{ 54 addField("controlPoints", TypeS32, Offset(mControlPointRequest, GuiFilterCtrl), 55 "Total number of control points in the spline curve." ); 56 addField("filter", TypeF32Vector, Offset(mFilter, GuiFilterCtrl), 57 "Vector of control points." ); 58 addField("showIdentity", TypeBool, Offset(mShowIdentity, GuiFilterCtrl), "@internal" ); 59 addField("identity", TypePoint2F, Offset(mIdentity, GuiFilterCtrl), "@internal"); 60 61 Parent::initPersistFields(); 62} 63 64DefineEngineMethod( GuiFilterCtrl, getValue, const char*, (), , "Return a tuple containing all the values in the filter." 65 "@internal") 66{ 67 static char buffer[512]; 68 const Filter *filter = object->get(); 69 *buffer = 0; 70 71 for (U32 i=0; i < filter->size(); i++) 72 { 73 char value[32]; 74 dSprintf(value, 32, "%1.5f ", *(filter->begin()+i) ); 75 dStrcat(buffer, value, 32); 76 } 77 78 return buffer; 79} 80 81DefineEngineStringlyVariadicMethod( GuiFilterCtrl, setValue, void, 3, 20, "(f1, f2, ...)" 82 "Reset the filter to use the specified points, spread equidistantly across the domain." 83 "@internal") 84{ 85 Filter filter; 86 87 StringStackWrapper args(argc - 2, argv + 2); 88 89 filter.set(args.count(), args); 90 object->set(filter); 91} 92 93DefineEngineMethod( GuiFilterCtrl, resetFiltering, void, (), , "Reset the filtering." 94 "@internal") 95{ 96 object->identity(); 97} 98 99bool GuiFilterCtrl::onWake() 100{ 101 if (!Parent::onWake()) 102 return false; 103 104 if (U32(mControlPointRequest) != mFilter.size()) 105 { 106 mFilter.setSize(mControlPointRequest); 107 identity(); 108 } 109 110 mCurKnot = -1; 111 112 return true; 113} 114 115 116void GuiFilterCtrl::identity() 117{ 118 S32 size = mFilter.size()-1; 119 for (U32 i=0; S32(i) <= size; i++) 120 { 121 F32 step = (F32)i/(F32)size; 122 mFilter[i] = mLerp( mIdentity.x, mIdentity.y, step ); 123 } 124} 125 126 127void GuiFilterCtrl::onMouseDown(const GuiEvent &event) 128{ 129 mouseLock(); 130 setFirstResponder(); 131 132 Point2I p = globalToLocalCoord(event.mousePoint); 133 134 // determine which knot (offset same as in onRender) 135 F32 w = F32(getWidth()-4) / F32(mFilter.size()-1); 136 F32 val = (F32(p.x) + (w / 2.f)) / w; 137 mCurKnot = S32(val); 138 139 mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), getHeight())/(F32)getHeight()); 140 setUpdate(); 141} 142 143 144void GuiFilterCtrl::onMouseDragged(const GuiEvent &event) 145{ 146 if ( mCurKnot < 0 ) 147 return; 148 149 mouseLock(); 150 setFirstResponder(); 151 152 Point2I p = globalToLocalCoord(event.mousePoint); 153 mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), getHeight())/(F32)getHeight()); 154 setUpdate(); 155} 156 157void GuiFilterCtrl::onMouseUp(const GuiEvent &) 158{ 159 if ( mCurKnot < 0 ) 160 return; 161 162 mouseUnlock(); 163 execConsoleCallback(); 164} 165 166void GuiFilterCtrl::onPreRender() 167{ 168 if(U32(mControlPointRequest) != mFilter.size()) 169 { 170 mFilter.setSize(mControlPointRequest); 171 identity(); 172 setUpdate(); 173 } 174} 175 176void GuiFilterCtrl::onRender(Point2I offset, const RectI &updateRect) 177{ 178 Point2I pos = offset; 179 Point2I ext = getExtent(); 180 181 RectI bgRect(pos, ext); 182 GFX->getDrawUtil()->drawRectFill(bgRect, ColorI(255,255,255)); 183 GFX->getDrawUtil()->drawRect(bgRect, ColorI(0,0,0)); 184 185 // shrink by 2 pixels 186 pos.x += 2; 187 pos.y += 2; 188 ext.x -= 4; 189 ext.y -= 4; 190 191 // draw the identity line 192 if ( mShowIdentity ) 193 { 194 GFX->getDrawUtil()->drawLine( pos.x, pos.y + ( ext.y * ( 1.0f - mIdentity.x ) ), 195 pos.x + ext.x, pos.y + ( ext.y * ( 1.0f - mIdentity.y ) ), 196 ColorI( 230, 230, 230 ) ); 197 } 198 199 // draw the curv 200 GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, ext.x, GFXBufferTypeVolatile); 201 202 verts.lock(); 203 204 F32 scale = 1.f / F32( ext.x ); 205 for ( U32 i = 0; i < ext.x; i++) 206 { 207 F32 index = F32(i) * scale; 208 S32 y = (S32)(ext.y*(1.0f-mFilter.getValue(index))); 209 210 verts[i].point.set( (F32)(pos.x + i), (F32)(pos.y + y), 0.0f ); 211 verts[i].color = ColorI( 103, 103, 103 ); 212 } 213 214 verts.unlock(); 215 216 GFX->setVertexBuffer( verts ); 217 GFX->drawPrimitive( GFXLineStrip, 0, ext.x - 1 ); 218 219 // draw the knots 220 for (U32 k=0; k < mFilter.size(); k++) 221 { 222 RectI knotRect; 223 knotRect.point.x = (S32)(((F32)ext.x/(F32)(mFilter.size()-1)*(F32)k)); 224 knotRect.point.y = (S32)(ext.y - ((F32)ext.y * mFilter[k])); 225 knotRect.point += pos + Point2I(-2,-2); 226 knotRect.extent = Point2I(5,5); 227 228 GFX->getDrawUtil()->drawRectFill(knotRect, ColorI(255,0,0)); 229 } 230 231 renderChildControls(offset, updateRect); 232} 233 234 235 236//-------------------------------------- 237void Filter::set(S32 argc, const char *argv[]) 238{ 239 setSize(0); 240 if (argc == 1) 241 { // in the form of one string "1.0 1.0 1.0" 242 char list[1024]; 243 dStrcpy(list, *argv, 1024); // strtok modifies the string so we need to copy it 244 char *value = dStrtok(list, " "); 245 while (value) 246 { 247 push_back(dAtof(value)); 248 value = dStrtok(NULL, " "); 249 } 250 } 251 else 252 { // in the form of seperate strings "1.0" "1.0" "1.0" 253 for (; argc ; argc--, argv++) 254 push_back(dAtof(*argv)); 255 } 256} 257 258 259//-------------------------------------- 260F32 Filter::getValue(F32 x) const 261{ 262 if (size() < 2) 263 return 0.0f; 264 265 x = mClampF(x, 0.0f, 1.0f); 266 x *= F32(size()-1); 267 268 F32 p0,p1,p2,p3; 269 S32 i1 = (S32)mFloor(x); 270 S32 i2 = i1+1; 271 F32 dt = x - F32(i1); 272 273 p1 = *(begin()+i1); 274 p2 = *(begin()+i2); 275 276 if (i1 == 0) 277 p0 = p1 + (p1 - p2); 278 else 279 p0 = *(begin()+i1-1); 280 281 if (i2 == S32(size()-1)) 282 p3 = p2 + (p2 - p1); 283 else 284 p3 = *(begin()+i2+1); 285 286 return mClampF( mCatmullrom(dt, p0, p1, p2, p3), 0.0f, 1.0f ); 287} 288 289 290 291 292 293 294