00001 #include "vuLightDial.h"
00002 #include "../vuUtilityWindow.h"
00003 #include <wx/mstream.h>
00004
00005 #include <iostream.h>
00006 #include <math.h>
00007
00008 #include "vuColour31a.h"
00009
00010 #include "bulb.h"
00011
00012 #ifdef WIN32
00013 #include "wx/msw/winundef.h"
00014 #endif
00015
00016 #define MIN(a,b) (a<b ? a : b)
00017 #define MAX(a,b) (a>b ? a : b)
00018
00019
00020
00021
00022
00023
00024
00025 BEGIN_EVENT_TABLE(vuLightDial, wxDialog)
00026 EVT_PAINT(vuLightDial::OnPaint)
00027 EVT_MOUSE_EVENTS(vuLightDial::OnMouseEvent)
00028 EVT_COMMAND_SCROLL(vuLightDial::idLIGHTINT, vuLightDial::OnSlideIntensity)
00029 EVT_BUTTON(vuLightDial::idHIDE, vuLightDial::OnHide)
00030 END_EVENT_TABLE();
00031
00032 #ifndef HEADERIMG
00033 #define HEADERIMG(varname) varname, varname ## _size
00034 #endif
00035
00036
00037
00038
00039
00040 vuLightDial::vuLightDial(wxWindow *parent, vuTFDesignSpec &tf)
00041 : wxDialog(parent,-1, wxString("Light Dial"),
00042 wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE),
00043 m_TFunc(tf)
00044 {
00045 m_NLights = 0;
00046 m_WeightX = -1;
00047 m_WeightY = -1;
00048 wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
00049 m_DialArea.width = 200;
00050 m_DialArea.height = 200;
00051 m_DialSpacer = new wxBoxSizer(wxHORIZONTAL);
00052 m_DialSpacer->Add(m_DialArea.width,m_DialArea.height);
00053 sizer->Add(m_DialSpacer);
00054 wxSizer *rightsizer = new wxBoxSizer(wxVERTICAL);
00055 m_LightIntensity = new wxSlider(this,idLIGHTINT,
00056 (int)(float(LDIAL_SLDRES)/LDIAL_INTENSITY),
00057 0,LDIAL_SLDRES,
00058 wxDefaultPosition,
00059 wxSize(20,m_DialArea.height-20),
00060 wxSL_VERTICAL);
00061 rightsizer->Add(new wxStaticText(this, -1, "Intensity"),
00062 0,wxALL|wxALIGN_CENTER,5);
00063 rightsizer->Add(m_LightIntensity,0,wxALL|wxALIGN_CENTER,5);
00064 rightsizer->Add(new wxButton(this,idHIDE,"Hide"),0,wxALL|wxALIGN_CENTER,5);
00065 sizer->Add(rightsizer);
00066
00067 SetSizer(sizer);
00068 SetAutoLayout(true);
00069 sizer->Layout();
00070 sizer->SetSizeHints(this);
00071 sizer->Fit(this);
00072
00073 m_DialArea.x = m_DialSpacer->GetPosition().x;
00074 m_DialArea.y = m_DialSpacer->GetPosition().y;
00075 m_IsUpdated = false;
00076
00077 #ifdef LOAD_IMAGE_FROM_FILE
00078
00079 wxString dir;
00080 vuGUI *app = &(wxGetApp());
00081 #ifndef WIN32
00082 if (app != NULL) {
00083 dir = app->argv[0];
00084 dir = dir.BeforeLast('/');
00085 }
00086 if ( wxFile::Exists(dir+"/bulb.png") )
00087 dir = dir+"/";
00088 else if ( wxFile::Exists("./bulb.png") )
00089 dir = "./";
00090 else
00091 wxLogWarning("Can't find image files in directories!");
00092
00093 #else
00094 if (app != NULL) {
00095 dir = app->argv[0];
00096 dir = dir.BeforeLast('\\');
00097 }
00098 if ( wxFile::Exists(dir+"\\bulb.png") )
00099 dir = dir+"\\";
00100 else if ( wxFile::Exists(".\\bulb.png") )
00101 dir = ".\\";
00102 else
00103 wxLogWarning("Can't find image files in directories!");
00104 #endif
00105 #endif // of LOAD_IMAGE_FROM_FILE
00106
00107 #if wxUSE_LIBPNG
00108 #ifndef LOAD_IMAGE_FROM_FILE
00109 wxMemoryInputStream mims(HEADERIMG(bulbimg));
00110 wxImage image(mims);
00111 #if wxMINOR_VERSION < 5
00112 m_BulbImg = new wxBitmap( image.ConvertToBitmap() );
00113 #else
00114 m_BulbImg = new wxBitmap( image );
00115 #endif
00116 #else
00117 if ( !image.LoadFile( dir + wxString("bulb.png")) ) {
00118 wxLogError("Can't load PNG image");
00119 m_BulbImg = NULL;
00120 } else {
00121 m_BulbImg = new wxBitmap( image.ConvertToBitmap() );
00122
00123 }
00124 #endif // of LOAD_IMAGE_FROM_FILE
00125 #endif // wxUSE_LIBPNG
00126 }
00127
00128 void vuLightDial::updateSliders() {
00129 m_LightIntensity->SetValue((int)(m_TFunc.getLightIntensity()*float(LDIAL_SLDRES)/LDIAL_INTENSITY));
00130 #ifndef WIN32
00131 DrawShape();
00132 #endif
00133 }
00134
00135 #if wxMINOR_VERSION < 5
00136 void vuLightDial::OnHide()
00137 #else
00138 void vuLightDial::OnHide(wxCommandEvent& ev)
00139 #endif
00140 {
00141 EndModal(wxID_OK);
00142 Show(false);
00143 }
00144
00145 #if wxMINOR_VERSION < 5
00146 void vuLightDial::OnPaint()
00147 #else
00148 void vuLightDial::OnPaint(wxPaintEvent& event)
00149 #endif
00150 {
00151 #if !defined(__WXMOTIF__) && !defined(WIN32)
00152 wxPaintEvent event;
00153 wxDialog::OnPaint(event);
00154 #endif
00155
00156 DrawShape();
00157 }
00158
00159 void vuLightDial::DrawShape()
00160 {
00161 wxPaintDC dc(this);
00162
00163 dc.BeginDrawing();
00164
00165
00166 dc.SetPen(*wxBLACK_PEN);
00167 wxBrush bgbrush(dc.GetBackground());
00168 dc.SetBrush(bgbrush);
00169 dc.DrawRectangle(m_DialArea.x,m_DialArea.y,
00170 m_DialArea.width,m_DialArea.height);
00171
00172 if(!m_TFunc.getNumLights()) return;
00173
00174 wxPen spen(wxColour(10,20,100),3,wxSOLID);
00175 wxBrush sbrush(wxColour(10,20,100),wxSOLID);
00176 dc.SetPen(spen);
00177 dc.SetBrush(sbrush);
00178
00179 int radius, cx, cy;
00180 if(m_NLights != (int)m_TFunc.getNumLights())
00181 {
00182 m_NLights = (int)m_TFunc.getNumLights();
00183 radius = MIN(m_DialArea.width,m_DialArea.height)/2 - 30;
00184 cx = m_DialArea.x+m_DialArea.width/2;
00185 cy = m_DialArea.y+m_DialArea.height/2;
00186 for(int i=0;i<m_NLights;i++)
00187 {
00188 float fi = i*2*M_PI/m_NLights;
00189 m_LPos[i].x = (int)rint(radius*sin(fi) + cx);
00190 m_LPos[i].y = (int)rint(-radius*cos(fi) + cy);
00191 m_LActive[i] = true;
00192 }
00193 }
00194
00195 m_CHull.clearPoints();
00196 for(int i=0;i<m_NLights;i++)
00197 if(m_LActive[i])
00198 m_CHull.addPoint(i,m_LPos[i].x, m_LPos[i].y);
00199
00200 m_NCHull = LDIAL_MAXLIGHTS;
00201 m_CHull.getCHull(m_NCHull, m_LIndices);
00202 for(int h=0;h<m_NCHull;h++) {
00203 m_HullPos[h].x = m_LPos[m_LIndices[h]].x;
00204 m_HullPos[h].y = m_LPos[m_LIndices[h]].y;
00205 }
00206
00207
00208 dc.DrawPolygon(m_NCHull,m_HullPos);
00209
00210 wxPen lpen(wxColour(0,0,0),1,wxDOT);
00211 wxPen npen(wxColour(30,30,30),2,wxSOLID);
00212 wxBrush onbrush(wxColour(100,100,200),wxSOLID);
00213 wxBrush offbrush(wxColour(100,100,100),wxSOLID);
00214 dc.SetPen(lpen);
00215
00216 for(int l=0;l<m_NLights;l++)
00217 {
00218 dc.SetBrush(m_LActive[l] ? onbrush : offbrush);
00219 int yofs = 0;
00220 if(!m_BulbImg) {
00221 dc.DrawCircle(m_LPos[l].x,m_LPos[l].y,10);
00222 } else {
00223 int xofs = m_BulbImg->GetWidth()/2;
00224 yofs = m_BulbImg->GetHeight()/2;
00225 dc.DrawBitmap( *m_BulbImg, m_LPos[l].x-xofs,m_LPos[l].y-yofs, true );
00226 if(!m_LActive[l]) {
00227 dc.SetPen(npen);
00228 dc.DrawLine(m_LPos[l].x-xofs,m_LPos[l].y-yofs,
00229 m_LPos[l].x+xofs,m_LPos[l].y+yofs);
00230 dc.DrawLine(m_LPos[l].x-xofs,m_LPos[l].y+yofs,
00231 m_LPos[l].x+xofs,m_LPos[l].y-yofs);
00232 }
00233 }
00234 char number[1024];
00235 sprintf(number,"%i", l+1);
00236 wxString snumber(number);
00237 wxCoord w,h;
00238 dc.GetTextExtent(snumber,&w,&h);
00239 dc.DrawText(snumber, m_LPos[l].x-(w/2), m_LPos[l].y-(2*yofs/3));
00240 }
00241
00242 if(m_WeightX >=0 && m_WeightY>=0){
00243
00244 wxPen lpen(wxColour(0,0,0),1,wxDOT);
00245 wxBrush lbrush(wxColour(200,200,0),wxSOLID);
00246 dc.SetPen(lpen);
00247 dc.SetBrush(lbrush);
00248
00249
00250
00251 dc.DrawCircle(m_WeightX,m_WeightY,10);
00252 dc.SetPen(wxNullPen);
00253 dc.SetBrush(wxNullBrush);
00254 }
00255
00256 dc.SetPen(wxNullPen);
00257 dc.SetBrush(wxNullBrush);
00258 dc.EndDrawing();
00259 }
00260
00261 #if wxMINOR_VERSION < 5
00262 void vuLightDial::OnSlideIntensity()
00263 #else
00264 void vuLightDial::OnSlideIntensity(wxScrollEvent& ev)
00265 #endif
00266 {
00267 float intensity = (LDIAL_SLDRES-m_LightIntensity->GetValue())
00268 /float(LDIAL_SLDRES)*LDIAL_INTENSITY;
00269 m_TFunc.setLightIntensity(intensity);
00270 m_TFunc.generateLight();
00271
00272 m_IsUpdated = true;
00273 repaintParent();
00274 }
00275
00276 #define DNORM(a,b) sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)))
00277
00278 float vuLightDial::getLj(int j, const wxPoint& x)
00279 {
00280 float lj = 1;
00281 if(!m_LActive[j]) return 0.0;
00282 for(int i=0;i<m_NLights;i++)
00283 if(i!=j && m_LActive[i]) lj *= DNORM(x,m_LPos[i])/DNORM(m_LPos[j],m_LPos[i]);
00284 return lj;
00285 }
00286
00287 #define RR 15
00288 #define LR 10
00289
00290 void vuLightDial::OnMouseEvent(wxMouseEvent& event)
00291 {
00292 int mx = (int)event.GetX();
00293 int my = (int)event.GetY();
00294
00295 static int movlight = -1;
00296
00297 if(event.ButtonDClick(3))
00298 {
00299 for(int j=0;j<m_NLights;j++) {
00300 if(abs(m_LPos[j].x-mx) < LR &&
00301 abs(m_LPos[j].y-my) < LR)
00302 {
00303 m_LActive[j] = !m_LActive[j];
00304
00305 reweightLights();
00306
00307 Refresh(false);
00308 m_IsUpdated = true;
00309 repaintParent();
00310 break;
00311 }
00312 }
00313 } else if(event.LeftIsDown())
00314 {
00315 if ((mx >= m_DialArea.x+RR &&
00316 mx <= (m_DialArea.x + m_DialArea.width-2*RR)) &&
00317 (my >= m_DialArea.y+RR &&
00318 my <= (m_DialArea.y + m_DialArea.height-2*RR)))
00319 {
00320 m_WeightX = mx;
00321 m_WeightY = my;
00322
00323 reweightLights();
00324
00325 Refresh(false);
00326 m_IsUpdated = true;
00327 repaintParent();
00328 }
00329
00330 } else if(event.Dragging() && event.RightIsDown())
00331 {
00332 if ((movlight >=0) &&
00333 (mx >= m_DialArea.x+RR &&
00334 mx <= (m_DialArea.x + m_DialArea.width-2*RR)) &&
00335 (my >= m_DialArea.y+RR &&
00336 my <= (m_DialArea.y + m_DialArea.height-2*RR)))
00337 {
00338 m_LPos[movlight].x = mx;
00339 m_LPos[movlight].y = my;
00340 m_CHull.addPoint(movlight,m_LPos[movlight].x,m_LPos[movlight].y);
00341
00342 reweightLights();
00343
00344 Refresh(false);
00345 m_IsUpdated = true;
00346 repaintParent();
00347 }
00348 } else if(!event.Dragging() && event.RightIsDown())
00349 {
00350 movlight = -1;
00351 for(int j=0;j<m_NLights;j++) {
00352 if(abs(m_LPos[j].x-mx) < LR &&
00353 abs(m_LPos[j].y-my) < LR)
00354 {
00355 movlight = j;
00356 break;
00357 }
00358 }
00359 }
00360 }
00361
00362 void vuLightDial::reweightLights()
00363 {
00364 int nl = (int)m_TFunc.getNumLights();
00365 float *wl = new float[nl];
00366 float wlsum =0;
00367
00368 #ifdef MINDISTWEIGHTING
00369 int radius = MIN(m_DialArea.width,m_DialArea.height)/2 - 30;
00370 int cx = m_DialArea.x+m_DialArea.width/2;
00371 int cy = m_DialArea.y+m_DialArea.height/2;
00372
00373 for(int i=0;i<nl;i++)
00374 {
00375 float fi = i*2*M_PI/nl;
00376 int dx = (int)rint(radius*sin(fi) + cx) - mx;
00377 int dy = (int)rint(-radius*cos(fi) + cy) - my;
00378 wl[i] = dx*dx + dy*dy;
00379 if(wl[i] < 0.00001) wl[i] = 1000000;
00380 else wl[i] = 1/wl[i];
00381 wlsum += wl[i];
00382 }
00383
00384 #else
00385 if(nl!=m_NLights) return;
00386 for(int j=0;j<nl;j++) {
00387 wl[j] = getLj(j,wxPoint(m_WeightX,m_WeightY));
00388 wlsum += wl[j];
00389 }
00390 #endif
00391 for(int i=0;i<nl;i++)
00392 wl[i] /= wlsum;
00393
00394 float intensity = (LDIAL_SLDRES-m_LightIntensity->GetValue())
00395 /float(LDIAL_SLDRES)*LDIAL_INTENSITY;
00396 m_TFunc.setLightIntensity(intensity);
00397 m_TFunc.weightLights(wl);
00398
00399 delete wl;
00400 }
00401
00402 void vuLightDial::repaintParent()
00403 {
00404 ((vuUtilityWindow*)GetParent())->notifyDataChanged();
00405 }
00406
00407
00408