00001
00002
00003 #ifndef OglGui_Carousel3D_h
00004 #define OglGui_Carousel3D_h
00005
00006 #include <vector>
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef OglGui_Carousel3DListener_h
00016 #include "OglGui/Carousel3DListener.h"
00017 #endif
00018
00019 #ifndef OglGui_ChangingToView_h
00020 #include "OglGui/ChangingToView.h"
00021 #endif
00022
00023 namespace OglGui {
00024
00025 class Carousel3D : public Window,
00026 public ChangingToViewListener
00027 {
00028 public:
00029 Carousel3D(int x, int y, int w, int h) :
00030 Window(x, y, w, h, false)
00031 {
00032 Init(w,h);
00033 }
00034
00035 Carousel3D(Window* parent, int x, int y, int w, int h) :
00036 Window(parent, x, y, w, h, false)
00037 {
00038 Init(w,h);
00039 }
00040
00041 void SetCarousel3DListener(Carousel3DListener* l, void *userData)
00042 {
00043 mListener = l;
00044 mListenerData = userData;
00045 }
00046
00047 virtual void OnChangingToViewDestiny(ChangingToView* v, void *userData)
00048 {
00049 int idx = (int)(long long) userData;
00050 if (mListener)
00051 mListener->OnChangingToViewDestination(this, idx, mListenerData);
00052 }
00053
00054 float CenterX() { return mCenterX; }
00055 float CenterY() { return mCenterY; }
00056 float CenterZ() { return mCenterZ; }
00057 float Radius() { return mRadius; }
00058
00059 void Friction(double f) { mFriction = f; }
00060 double Friction() { return mFriction; }
00061
00062 OGLVIEW3D* AddView(strconst str)
00063 {
00064 OGLVIEW3D* v = view3DSys.View3D(mOglWnd, 0, 0, 0, 0, 1, 1, 1);
00065 if (v)
00066 {
00067
00068 mOglViews.push_back(v);
00069 mTitles.push_back(str);
00070 }
00071 return v;
00072 }
00073
00074 void
00075 AddCaptureView(strconst str, int x, int y, int w, int h, bool capture=true)
00076 {
00077 OGLVIEW3D* v = AddView(str);
00078 view3DSys.SetRotation(v, 180, 0, 0);
00079 view3DSys.SetTexFilter(v, 0, GL_LINEAR);
00080 view3DSys.SetTexFilter(v, 1, GL_LINEAR);
00081 OGLIMAGE* oglIm = MyOglImage(4, 10, 10);
00082 oglIm->noTexScaling = 1;
00083 v->im = oglIm;
00084
00085 ChangingToView* chToView = new ChangingToView(v);
00086 int idx = mTitles.size()-1;
00087 chToView->SetChangingToViewListener(this, (void *) idx);
00088 mChangingToViews.push_back(chToView);
00089
00090 if (capture)
00091 OglImCapture(v->im, x, y, w, h);
00092 }
00093
00094 ChangingToView* ChToView(int idx)
00095 {
00096 if (idx < 0 || idx >= mChangingToViews.size())
00097 return 0;
00098 return mChangingToViews[idx];
00099 }
00100
00101 int IndexOf(strconst str)
00102 {
00103 for (int i=0; i<mTitles.size(); i++)
00104 {
00105 if (str == mTitles[i])
00106 return i;
00107 }
00108 return -1;
00109 }
00110
00111 int IndexOf(OGLVIEW3D* v)
00112 {
00113 for (int i=0; i<mOglViews.size(); i++)
00114 {
00115 if (v == mOglViews[i])
00116 return i;
00117 }
00118 return -1;
00119 }
00120
00121 void TitledCapture(strconst str, int x, int y, int w, int h)
00122 {
00123 int idx = IndexOf(str);
00124 if (idx == -1)
00125 AddCaptureView(str, x, y, w, h);
00126 else
00127 {
00128 OglImCapture(mOglViews[idx]->im, x, y, w, h);
00129 CheckOglImageChanged(mOglViews[idx]->im);
00130 for (int i=0; i<mOglViews.size(); i++)
00131 {
00132 OGLVIEW3D* oglV3D = mOglViews[i];
00133 OGLIMAGE* im = oglV3D->im;
00134 oglV3D->w = (w/(float)h);
00135 oglV3D->h = 1;
00136 float tW = im->noTexScaling ? im->texW : im->w;
00137 float tH = im->noTexScaling ? im->texH : im->h;
00138 float zX = (oglV3D->w)*(tW/im->w);
00139 float zY = (oglV3D->h)*(tH/im->h);
00140 view3DSys.SetZoom(oglV3D,zX,zY);
00141 }
00142 }
00143 }
00144
00145 void Clamp360(float& f)
00146 {
00147 while (f < 0)
00148 f += 360;
00149 while (f - 360 > 0)
00150 f -= 360;
00151 }
00152
00153 void RotateTo(float deg, int ms=500)
00154 {
00155 Clamp360(mCenterRotY);
00156 Clamp360(deg);
00157
00158 float diff = deg - mCenterRotY;
00159 float absDiff = fabs(diff);
00160
00161 if ((mCenterRotY == deg) || absDiff <= 0.2 || absDiff >= 359.8)
00162 {
00163 mCenterRotY = deg;
00164 mIsRotatingTo = false;
00165 return;
00166 }
00167 if (absDiff > 180)
00168 deg += (diff > 0 ? -360 : 360);
00169
00170 mRotateTo = deg;
00171 mRotateToStart = mCenterRotY;
00172
00173 mRotateToDuration = ms/1000.0;
00174
00175 mRotateToStartTime = OglClock();
00176 mIsRotatingTo = true;
00177 }
00178
00179 void RotateToSpike(int idx, int ms=500)
00180 {
00181 float spikes = 360.f / mOglViews.size();
00182 RotateTo(-idx * spikes, ms);
00183 UpdateScene();
00184 }
00185
00186 void RotateToNearest(int ms=500)
00187 {
00188 Clamp360(mCenterRotY);
00189 int nrOfViews = mOglViews.size();
00190 float spikes = 360.f / nrOfViews;
00191 float n = floor(0.5f + mCenterRotY / spikes);
00192 int s = abs(n-nrOfViews);
00193 RotateToSpike(s);
00194 }
00195
00196 void HandleRotateTo()
00197 {
00198 if (!mIsRotatingTo)
00199 return;
00200
00201
00202 double timePassed = OglClock() - mRotateToStartTime;
00203 if (timePassed > mRotateToDuration)
00204 {
00205 mCenterRotY = mRotateTo;
00206 mIsRotatingTo = false;
00207 return;
00208 }
00209 double factor = timePassed/mRotateToDuration;
00210 mCenterRotY = mRotateToStart + factor * (mRotateTo-mRotateToStart);
00211 UpdateScene();
00212 }
00213
00214 virtual void DisplayFunc()
00215 {
00216 if (!mShowCarousel)
00217 return;
00218
00219 OGC myOGC;
00220 OGCSave(&myOGC);
00221
00222 view3DSys.View3DCameraTransform(mOglWnd);
00223
00224 int nrOfViews = mOglViews.size();
00225
00226 mRadius = (nrOfViews*mOglViews[0]->w) / OGL_PI_2;
00227 mCenterZ = -mRadius - 1.5;
00228 glTranslatef(mCenterX, mCenterY, mCenterZ);
00229 glRotatef(mCenterRotY, 0.0f, 1.0f, 0.0f);
00230
00231 for (int i=0; i<nrOfViews; i++)
00232 {
00233 glPushMatrix();
00234 glRotatef( i * 360.f/nrOfViews, 0.0f, 1.0f, 0.0f );
00235 glTranslatef(0, 0, mRadius);
00236 view3DSys.DrawView(mOglViews[i]);
00237 glColor3f( 1.0f, 1.0f, 0.0f );
00238 oglSys.Printf3D(mTxtFontBase, -0.5, 0.5, 0.1, 0.08, 0.08, 0.01,
00239 "%s", mTitles[i].c_str());
00240 glPopMatrix();
00241 }
00242 OGCRestore( &myOGC );
00243 glLoadName(0);
00244
00245 HandleRotateTo();
00246
00247
00248 if (!mFlowing)
00249 return;
00250
00251
00252 float t = (OglClock() - mFlowDragStartTime);
00253 float endT = fabs(mFlowSpeed / mFriction);
00254 if (t >= endT)
00255 {
00256 t = endT;
00257 mFlowing = false;
00258
00259 UpdateScene();
00260 RotateToNearest();
00261 }
00262 float d = mFlowSpeed*t + (0.5 * (mFlowSpeed>0?1:-1)*mFriction * (t*t));
00263 mCenterRotY = mFlowStartRotY + d;
00264 }
00265
00266 virtual void MouseFunc(int msg, int btn, int state, int x, int y)
00267 {
00268 Window::MouseFunc(msg, btn, state, x, y);
00269
00270 if (msg == oglMouseDown && btn == oglLeftButton)
00271 {
00272 if (mDragged = ((mFlowing||mIsRotatingTo) ? true : false))
00273 SetAlwaysDraw(mFlowing = mIsRotatingTo = false);
00274
00275 mFlowDragStartTime = OglClock();
00276 mDragStarted = true;
00277 mFlowDragDiff = 0;
00278 mFlowDragStartX = x;
00279 mFlowDragLastX = x;
00280 mFlowStartRotY = mCenterRotY;
00281 }
00282 if (msg == oglMouseMove && mDragStarted)
00283 {
00284 mFlowDragDiff = mFlowDragLastX - x;
00285 mCenterRotY -= mFlowDragDiff / 10.f;
00286 mFlowDragLastX = x;
00287 if (fabs(mFlowStartRotY - mCenterRotY) > mDragPixThreshold)
00288 mDragged = true;
00289 }
00290 if (msg == oglMouseUp && btn == oglLeftButton)
00291 {
00292 OGLVIEW3D* v;
00293 if (!mDragged && mListener && (v = view3DSys.FindView(mOglWnd,x,y)))
00294 mListener->OnCarousel3D(this, IndexOf(v), mListenerData);
00295 if (mDragged)
00296 {
00297
00298 double t = (OglClock() - mFlowDragStartTime);
00299 if (t<0.1) t = 0.1;
00300 mFlowSpeed = ((x-mFlowDragStartX)/10.f) / t;
00301 if (abs(mFlowDragDiff) < 5)
00302 mFlowSpeed = 0;
00303 SetAlwaysDraw(mFlowing = (fabs(mFlowSpeed) > 30));
00304 mFlowStartRotY = mCenterRotY;
00305
00306 mFlowDragStartTime = OglClock();
00307 }
00308 mDragStarted = mDragged = false;
00309 }
00310 }
00311
00312 virtual void InitFunc()
00313 {
00314 OGLWND* oglWnd = oglSys.GetTopOGLWND( mOglWnd );
00315 void* font;
00316
00317 #ifdef OGL_USING_GLUT
00318 mTxtFontBase = oglSys.Create3DFont( mOglWnd, font, 1, 0.6f, NULL );
00319 #else
00320 font = (void*) CreateFont(
00321 -12, 0, 0, 0, FW_NORMAL, 0, 0, 0,
00322 ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
00323 ANTIALIASED_QUALITY, VARIABLE_PITCH | FF_DONTCARE, "Verdana" );
00324
00325 mTxtFontBase = oglSys.Create3DFont( mOglWnd, font, 1, 0.6f, NULL );
00326
00327 DeleteObject( (HFONT) font );
00328 #endif
00329 Window::InitFunc();
00330 }
00331
00332 protected:
00333
00334 void ReadPixels(OGLIMAGE* oglIm, int x, int y, int w, int h)
00335 {
00336 if (oglIm->imData)
00337 free(oglIm->imData);
00338
00339
00340 if( !(oglIm->imData = (void *) malloc(w * h * 4))){
00341 oglSys.ErrorBox("Error", "Could not allocate image memory");
00342 exit( 0 );;
00343 }
00344 oglIm->w = w;
00345 oglIm->h = h;
00346
00347
00348 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00349 glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
00350 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
00351 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
00352
00353 glReadPixels( x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, oglIm->imData );
00354
00355 glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
00356 glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
00357 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
00358 oglIm->changed = 1;
00359 }
00360
00361 void OglImCapture(OGLIMAGE* oglIm, int x, int y, int w, int h)
00362 {
00363 if (!oglIm)
00364 return;
00365 ReadPixels(oglIm, x, y, w, h);
00366 }
00367
00368 OGLIMAGE* MyOglImage(int type, int w, int h)
00369 {
00370 OGLIMAGE* oglIm = NewOglImage(type, w, h);
00371 oglIm->imData = calloc(w*h,4);
00372 memset(oglIm->imData, 0x80, w*h*4);
00373 oglIm->imDataFunc = MyOglImDataFunc;
00374 oglIm->onDestroy = MyOglImDestroy;
00375 return oglIm;
00376 }
00377
00378 private:
00379 static void *MyOglImDataFunc(OGLIMAGE *oglIm)
00380 {
00381 return (void *) oglIm ? oglIm->imData : 0;
00382 }
00383
00384 static void MyOglImDestroy(OGLIMAGE *oglIm)
00385 {
00386 if (!oglIm)
00387 return;
00388 if(oglIm->imData)
00389 free(oglIm->imData);
00390 oglIm->imData = 0;
00391 }
00392
00393 void Init(int w, int h)
00394 {
00395
00396 SetBorderFillShaded(-2);
00397 oglSys.SetAllowCameraMove(mOglWnd, CamMove_Mouse);
00398 oglSys.AllowPicking(mOglWnd, false, false);
00399 Friction(-150);
00400
00401 mTargetOGLWND = oglSys.GetTopOGLWND(mOglWnd);
00402 mShowCarousel = true;
00403 mDragStarted = false;
00404 mDragged = false;
00405 mFlowing = false;
00406 mIsRotatingTo = false;
00407 mRotateToDuration = 0;
00408 mDragPixThreshold = 3;
00409 mCenterX = 0;
00410 mCenterY = 0;
00411 mCenterZ = -4.5;
00412 mCenterRotY = 0;
00413 }
00414
00415 Carousel3DListener* mListener;
00416 void* mListenerData;
00417
00418 std::vector<OGLVIEW3D*> mOglViews;
00419 std::vector<ChangingToView*> mChangingToViews;
00420 std::vector<std::string> mTitles;
00421
00422 OGLWND* mTargetOGLWND;
00423 bool mShowCarousel;
00424 int mDragLastX;
00425 int mDragPixThreshold;
00426 int mTxtFontBase;
00427
00428
00429 double mRotateToStartTime;
00430 bool mIsRotatingTo;
00431
00432 double mRotateToDuration;
00433 float mRotateToStart;
00434 float mRotateTo;
00435 float mCenterRotY;
00436 float mCenterX;
00437 float mCenterY;
00438 float mCenterZ;
00439 float mRadius;
00440
00441
00442 double mFlowDragStartTime;
00443 double mFlowSpeed;
00444 double mFriction;
00445 int mFlowDragDiff;
00446 int mFlowDragStartX;
00447 int mFlowDragLastX;
00448 int mFlowStartRotY;
00449 bool mDragStarted;
00450 bool mDragged;
00451 bool mFlowing;
00452 };
00453
00454 }
00455 #endif