nux-1.14.0
|
00001 /* 00002 * Copyright 2010 Inalogic® Inc. 00003 * 00004 * This program is free software: you can redistribute it and/or modify it 00005 * under the terms of the GNU Lesser General Public License, as 00006 * published by the Free Software Foundation; either version 2.1 or 3.0 00007 * of the License. 00008 * 00009 * This program is distributed in the hope that it will be useful, but 00010 * WITHOUT ANY WARRANTY; without even the implied warranties of 00011 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 00012 * PURPOSE. See the applicable version of the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of both the GNU Lesser General Public 00016 * License along with this program. If not, see <http://www.gnu.org/licenses/> 00017 * 00018 * Authored by: Jay Taoko <jaytaoko@inalogic.com> 00019 * 00020 */ 00021 00022 00023 #include "Nux.h" 00024 #include "NuxCore/Math/Constants.h" 00025 #include "NuxCore/Math/Spline.h" 00026 #include "NuxCore/Math/Bezier.h" 00027 #include "BezierCurveControl.h" 00028 00029 namespace nux 00030 { 00031 00032 const int KNOT_SIZE = 2; 00033 const int KNOT_HIT_TEST = 4; 00034 00035 BezierCurveControl::BezierCurveControl (NUX_FILE_LINE_DECL) 00036 : View (NUX_FILE_LINE_PARAM) 00037 , m_minX (0.0f), 00038 m_minY (0.0f), 00039 m_maxX (1.0f), 00040 m_maxY (1.0f), 00041 m_FunctionCallback (0) 00042 { 00043 SetMinimumSize (400, 300); 00044 SetBaseSize (400, 300); 00045 00046 m_control_knot.push_back (Knot (0.0f, 0.0f) ); 00047 m_control_knot.push_back (Knot (0.1f, 0.0f) ); 00048 m_control_knot.push_back (Knot (0.7f, 0.9f) ); 00049 m_control_knot.push_back (Knot (1.0f, 1.0f) ); 00050 00051 mouse_down.connect (sigc::mem_fun (this, &BezierCurveControl::RecvMouseDown) ); 00052 mouse_up.connect (sigc::mem_fun (this, &BezierCurveControl::RecvMouseUp) ); 00053 mouse_drag.connect (sigc::mem_fun (this, &BezierCurveControl::RecvMouseDrag) ); 00054 00055 } 00056 00057 BezierCurveControl::~BezierCurveControl() 00058 { 00059 00060 00061 } 00062 00063 00064 long BezierCurveControl::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00065 { 00066 long ret = TraverseInfo; 00067 00068 if (ievent.e_event == NUX_MOUSE_PRESSED) 00069 { 00070 if (!GetGeometry().IsPointInside (ievent.e_x, ievent.e_y) ) 00071 { 00072 //ProcEvInfo = eDoNotProcess; 00073 //return TraverseInfo; 00074 } 00075 } 00076 00077 ret = PostProcessEvent2 (ievent, ret, 0); 00078 return ret; 00079 } 00080 00081 00082 void BezierCurveControl::Draw (GraphicsEngine &GfxContext, bool force_draw) 00083 { 00084 Geometry base = GetGeometry(); 00085 00086 GetPainter().PaintBackground (GfxContext, base); 00087 GetPainter().Paint2DQuadWireframe (GfxContext, base, Color (COLOR_BACKGROUND_SECONDARY) ); 00088 00089 #define N 3 00090 t_u32 i; 00091 t_u32 nsample = 30; 00092 double t; 00093 t_u32 nbKnot = (t_u32) m_control_knot.size(); 00094 00095 if (nbKnot > 0) 00096 { 00097 double *xcon = new double[nbKnot]; 00098 double xval; 00099 double *ycon = new double[nbKnot]; 00100 double yval; 00101 00102 00103 for (i = 0; i < nbKnot; i++) 00104 { 00105 xcon[i] = m_control_knot[i].m_X; 00106 ycon[i] = m_control_knot[i].m_Y; 00107 } 00108 00109 int W = GetBaseWidth() - 2; 00110 int H = GetBaseHeight() - 2; 00111 int X = GetBaseX() + 1; 00112 int Y = GetBaseY() + 1; 00113 00114 double xprev, yprev; 00115 Bezier_XY (N, 0.0, xcon, ycon, &xprev, &yprev); 00116 00117 //GetPainter().Draw2DLine(X, Y, X+W, Y+H, Color(0xFFFF0000)); 00118 00119 base.OffsetPosition (1, 1); 00120 base.OffsetSize (-2, -2); 00121 00122 GfxContext.PushClippingRectangle (base); 00123 00124 GfxContext.GetRenderStates().EnableLineSmooth (TRUE, 1, GL_FASTEST); 00125 GfxContext.GetRenderStates().SetBlend (TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 00126 00127 for (i = 1; i < nsample; i++) 00128 { 00129 t = ( double ) ( i ) / ( double ) ( nsample - 1 ); 00130 Bezier_XY ( N, t, xcon, ycon, &xval, &yval ); 00131 00132 int X0, Y0, X1, Y1; 00133 X0 = X + W * (xprev - m_minX) / (m_maxX - m_minX); 00134 Y0 = Y + H * ( 1 - (yprev - m_minY) / (m_maxY - m_minY) ); 00135 X1 = X + W * (xval - m_minX) / (m_maxX - m_minX); 00136 Y1 = Y + H * ( 1 - (yval - m_minY) / (m_maxY - m_minY) ); 00137 00138 GetPainter().Draw2DLine (GfxContext, X0, Y0, X1, Y1, Color (0xFFFF0000) ); 00139 00140 xprev = xval; 00141 yprev = yval; 00142 } 00143 00144 GfxContext.GetRenderStates().EnableLineSmooth (FALSE); 00145 GfxContext.GetRenderStates().SetBlend (GL_FALSE); 00146 00147 for (i = 0; i < nbKnot - 1; i++) 00148 { 00149 int X0, Y0, X1, Y1; 00150 X0 = X + W * (m_control_knot[i].m_X - m_minX) / (m_maxX - m_minX); 00151 Y0 = Y + H * ( 1 - (m_control_knot[i].m_Y - m_minY) / (m_maxY - m_minY) ); 00152 X1 = X + W * (m_control_knot[i+1].m_X - m_minX) / (m_maxX - m_minX); 00153 Y1 = Y + H * ( 1 - (m_control_knot[i+1].m_Y - m_minY) / (m_maxY - m_minY) ); 00154 00155 GetPainter().Draw2DLine (GfxContext, X0, Y0, X1, Y1, Color (0xFF0000FF) ); 00156 00157 } 00158 00159 for (i = 0; i < nbKnot; i++) 00160 { 00161 int X0, Y0; 00162 X0 = X + W * (m_control_knot[i].m_X - m_minX) / (m_maxX - m_minX); 00163 Y0 = Y + H * ( 1 - (m_control_knot[i].m_Y - m_minY) / (m_maxY - m_minY) ); 00164 00165 if (m_control_knot[i].m_IsSelected) 00166 GetPainter().Paint2DQuadColor (GfxContext, X0 - KNOT_SIZE, Y0 - KNOT_SIZE, 2 * KNOT_SIZE, 2 * KNOT_SIZE, Color (0xFF00FF00) ); 00167 else 00168 GetPainter().Paint2DQuadColor (GfxContext, X0 - KNOT_SIZE, Y0 - KNOT_SIZE, 2 * KNOT_SIZE, 2 * KNOT_SIZE, Color (0xFF777777) ); 00169 } 00170 00171 delete[] xcon; 00172 delete[] ycon; 00173 } 00174 00175 // for(int i = 1; i < GetWidth(); i++) 00176 // { 00177 // float x1, y1; 00178 // 00179 // x1 = x0 + dX; 00180 // y1 = EvalFunction(x1); 00181 // 00182 // int X0, Y0, X1, Y1; 00183 // X0 = X + W * (x0 - m_minX) / (m_maxX - m_minX); 00184 // Y0 = Y - H * (y0 + m_minY) / (m_maxY - m_minY); 00185 // X1 = X + W * (x1 - m_minX) / (m_maxX - m_minX); 00186 // Y1 = Y - H * (y1 + m_minY) / (m_maxY - m_minY); 00187 // GetPainter().Draw2DLine(X0, Y0, X1, Y1, Color(0xFFFF0000)); 00188 // 00189 // x0 = x1; 00190 // y0 = y1; 00191 // 00192 // } 00193 GfxContext.PopClippingRectangle(); 00194 } 00195 00196 00197 void BezierCurveControl::DrawContent (GraphicsEngine &GfxContext, bool force_draw) 00198 { 00199 00200 } 00201 00202 void BezierCurveControl::PostDraw (GraphicsEngine &GfxContext, bool force_draw) 00203 { 00204 00205 } 00206 00207 00208 void BezierCurveControl::SetXAxisBounds (float minX, float maxX) 00209 { 00210 m_minX = minX; 00211 m_maxX = maxX; 00212 QueueDraw(); 00213 } 00214 00215 void BezierCurveControl::SetYAxisBounds (float minY, float maxY) 00216 { 00217 m_minY = minY; 00218 m_maxY = maxY; 00219 QueueDraw(); 00220 } 00221 00222 void BezierCurveControl::SetFunctionCallback (FunctionCallback f) 00223 { 00224 m_FunctionCallback = f; 00225 QueueDraw(); 00226 } 00227 00228 float BezierCurveControl::EvalFunction (float x) 00229 { 00230 if (m_FunctionCallback != 0) 00231 return (*m_FunctionCallback) (x); 00232 00233 return 0; 00234 } 00235 00236 void BezierCurveControl::UpdateGraph() 00237 { 00238 QueueDraw(); 00239 } 00240 00241 00242 // check if a value lies within a closed interval 00243 #ifndef INSIDE_BOUNDS 00244 #define INSIDE_BOUNDS( x, lo, hi ) ( (x) >= (lo) && (x) <= (hi) ) 00245 #endif 00246 00247 //check if a 2D point lies within a 2D box 00248 #ifndef PT_INSIDE_BOX 00249 #define PT_INSIDE_BOX( x, y, lo_x, hi_x, lo_y, hi_y ) ( INSIDE_BOUNDS(x,lo_x,hi_x) && INSIDE_BOUNDS(y,lo_y,hi_y) ) 00250 #endif 00251 00252 void BezierCurveControl::RecvMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags) 00253 { 00254 QueueDraw(); 00255 } 00256 00257 void BezierCurveControl::RecvMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags) 00258 { 00259 t_u32 nbKnot = (t_u32) m_control_knot.size(); 00260 00261 for (t_u32 i = 0; i < nbKnot; i++) 00262 { 00263 m_control_knot[i].m_IsSelected = false; 00264 } 00265 00266 int W = GetBaseWidth() - 2; 00267 int H = GetBaseHeight() - 2; 00268 int X = GetBaseX() + 1; 00269 int Y = GetBaseY() + 1; 00270 00271 bool b = PT_INSIDE_BOX (X + x, Y + y, X, X + W, Y, Y + H); 00272 00273 if (b == false) 00274 return; 00275 00276 X = GetBaseX(); 00277 Y = GetBaseY(); 00278 00279 for (t_u32 i = 0; i < nbKnot; i++) 00280 { 00281 int Xp, Yp; 00282 Xp = X + W * (m_control_knot[i].m_X - m_minX) / (m_maxX - m_minX); 00283 Yp = Y + H * ( 1 - (m_control_knot[i].m_Y - m_minY) / (m_maxY - m_minY) ); 00284 00285 if (PT_INSIDE_BOX (X + x, Y + y, Xp - KNOT_HIT_TEST, Xp + KNOT_HIT_TEST, Yp - KNOT_HIT_TEST, Yp + KNOT_HIT_TEST) ) 00286 { 00287 m_control_knot[i].m_IsSelected = true; 00288 break; 00289 } 00290 } 00291 00292 QueueDraw(); 00293 } 00294 00295 void BezierCurveControl::RecvMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) 00296 { 00297 float xp, yp; 00298 00299 int W = GetBaseWidth(); 00300 int H = GetBaseHeight(); 00301 t_u32 nbKnot = (t_u32) m_control_knot.size(); 00302 00303 xp = m_minX + (m_maxX - m_minX) * dx / W; 00304 yp = m_minY + (m_maxY - m_minY) * dy / H; 00305 00306 00307 00308 for (t_u32 i = 0; i < nbKnot; i++) 00309 { 00310 if (m_control_knot[i].m_IsSelected) 00311 { 00312 m_control_knot[i].m_X += xp; 00313 m_control_knot[i].m_Y -= yp; 00314 00315 if (m_control_knot[i].m_X < m_minX) 00316 { 00317 m_control_knot[i].m_X = m_minX; 00318 } 00319 00320 if (m_control_knot[i].m_X > m_maxX) 00321 { 00322 m_control_knot[i].m_X = m_maxX; 00323 } 00324 00325 if (m_control_knot[i].m_Y < m_minY) 00326 { 00327 m_control_knot[i].m_Y = m_minY; 00328 } 00329 00330 if (m_control_knot[i].m_Y > m_maxY) 00331 { 00332 m_control_knot[i].m_Y = m_maxY; 00333 } 00334 00335 break; 00336 } 00337 } 00338 00339 QueueDraw(); 00340 } 00341 00342 00343 }