1 // ---------------------------------------------------------------------------
4 // @author Philippe Decaudin - http://www.antisphere.com
5 // @license This file is part of the AntTweakBar library.
6 // For conditions of distribution and use, see License.txt
8 // ---------------------------------------------------------------------------
11 #include "TwPrecomp.h"
12 #include <AntTweakBar.h>
17 #include "TwOpenGLCore.h"
19 # include "TwDirect3D9.h"
20 # include "TwDirect3D10.h"
21 # include "TwDirect3D11.h"
22 # include "resource.h"
28 #if !defined(ANT_WINDOWS)
29 # define _snprintf snprintf
30 #endif // defined(ANT_WINDOWS)
35 CTwMgr *g_TwMgr = NULL; // current TwMgr
36 bool g_BreakOnError = false;
37 TwErrorHandler g_ErrorHandler = NULL;
39 CTwBar * const TW_GLOBAL_BAR = (CTwBar *)(-1);
40 int g_InitWndWidth = -1;
41 int g_InitWndHeight = -1;
42 TwCopyCDStringToClient g_InitCopyCDStringToClient = NULL;
43 TwCopyStdStringToClient g_InitCopyStdStringToClient = NULL;
46 const int TW_MASTER_WINDOW_ID = 0;
47 typedef map<int, CTwMgr *> CTwWndMap;
49 CTwMgr *g_TwMasterMgr = NULL;
52 extern const char *g_ErrUnknownAttrib;
53 extern const char *g_ErrNoValue;
54 extern const char *g_ErrBadValue;
55 const char *g_ErrInit = "Already initialized";
56 const char *g_ErrShut = "Already shutdown";
57 const char *g_ErrNotInit = "Not initialized";
58 const char *g_ErrUnknownAPI = "Unsupported graph API";
59 const char *g_ErrBadDevice = "Invalid graph device";
60 const char *g_ErrBadParam = "Invalid parameter";
61 const char *g_ErrExist = "Exists already";
62 const char *g_ErrNotFound = "Not found";
63 const char *g_ErrNthToDo = "Nothing to do";
64 const char *g_ErrBadSize = "Bad size";
65 const char *g_ErrIsDrawing = "Asynchronous drawing detected";
66 const char *g_ErrIsProcessing="Asynchronous processing detected";
67 const char *g_ErrOffset = "Offset larger than StructSize";
68 const char *g_ErrDelStruct = "Cannot delete a struct member";
69 const char *g_ErrNoBackQuote= "Name cannot include back-quote";
70 const char *g_ErrStdString = "Debug/Release std::string mismatch";
71 const char *g_ErrCStrParam = "Value count for TW_PARAM_CSTRING must be 1";
72 const char *g_ErrOutOfRange = "Index out of range";
73 const char *g_ErrHasNoValue = "Has no value";
74 const char *g_ErrBadType = "Incompatible type";
75 const char *g_ErrDelHelp = "Cannot delete help bar";
78 void ANT_CALL TwGlobalError(const char *_ErrorMessage);
80 #if defined(ANT_UNIX) || defined(ANT_OSX)
81 #define _stricmp strcasecmp
82 #define _strdup strdup
86 bool g_UseCurRsc = true; // use dll resources for rotoslider cursors
89 // ---------------------------------------------------------------------------
91 const float FLOAT_EPS = 1.0e-7f;
92 const float FLOAT_EPS_SQ = 1.0e-14f;
93 const float FLOAT_PI = 3.14159265358979323846f;
94 const double DOUBLE_EPS = 1.0e-14;
95 const double DOUBLE_EPS_SQ = 1.0e-28;
96 const double DOUBLE_PI = 3.14159265358979323846;
98 inline double DegToRad(double degree) { return degree * (DOUBLE_PI/180.0); }
99 inline double RadToDeg(double radian) { return radian * (180.0/DOUBLE_PI); }
101 // ---------------------------------------------------------------------------
103 // a static global object to verify that Tweakbar module has been properly terminated (in debug mode only)
105 static struct CTwVerif
110 g_TwMgr->SetLastError("Tweak bar module has not been terminated properly: call TwTerminate()\n");
115 // ---------------------------------------------------------------------------
117 // ---------------------------------------------------------------------------
119 void CColorExt::RGB2HLS()
121 float fH = 0, fL = 0, fS = 0;
122 ColorRGBToHLSf((float)R/255.0f, (float)G/255.0f, (float)B/255.0f, &fH, &fL, &fS);
128 L = (int)(255.0f*fL + 0.5f);
133 S = (int)(255.0f*fS + 0.5f);
140 void CColorExt::HLS2RGB()
142 float fR = 0, fG = 0, fB = 0;
143 ColorHLSToRGBf((float)H, (float)L/255.0f, (float)S/255.0f, &fR, &fG, &fB);
144 R = (int)(255.0f*fR + 0.5f);
149 G = (int)(255.0f*fG + 0.5f);
154 B = (int)(255.0f*fB + 0.5f);
161 void ANT_CALL CColorExt::InitColor32CB(void *_ExtValue, void *_ClientData)
163 CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
166 ext->m_IsColorF = false;
175 ext->m_HasAlpha = false;
176 ext->m_CanHaveAlpha = true;
177 if( g_TwMgr && g_TwMgr->m_GraphAPI==TW_DIRECT3D9 ) // D3D10 now use OGL rgba order!
181 ext->m_PrevConvertedColor = Color32FromARGBi(ext->A, ext->R, ext->G, ext->B);
182 ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
186 void ANT_CALL CColorExt::InitColor3FCB(void *_ExtValue, void *_ClientData)
188 InitColor32CB(_ExtValue, _ClientData);
189 CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
192 ext->m_IsColorF = true;
193 ext->m_HasAlpha = false;
194 ext->m_CanHaveAlpha = false;
198 void ANT_CALL CColorExt::InitColor4FCB(void *_ExtValue, void *_ClientData)
200 InitColor32CB(_ExtValue, _ClientData);
201 CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
204 ext->m_IsColorF = true;
205 ext->m_HasAlpha = true;
206 ext->m_CanHaveAlpha = true;
210 void ANT_CALL CColorExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
212 unsigned int *var32 = static_cast<unsigned int *>(_VarValue);
213 float *varF = static_cast<float *>(_VarValue);
214 CColorExt *ext = (CColorExt *)(_ExtValue);
215 CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
216 if( _VarValue && ext )
218 if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
219 ext->m_HasAlpha = false;
221 // Synchronize HLS and RGB
222 if( _ExtMemberIndex>=0 && _ExtMemberIndex<=2 )
224 else if( _ExtMemberIndex>=3 && _ExtMemberIndex<=5 )
226 else if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
228 assert( mProxy->m_VarParent->m_Vars.size()==8 );
229 if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
230 || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
231 || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
232 || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
233 || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
234 || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
236 mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
237 mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
238 mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
239 mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
240 mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
241 mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
242 mProxy->m_Bar->NotUpToDate();
244 if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
246 mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
247 mProxy->m_Bar->NotUpToDate();
249 if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
251 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
252 mProxy->m_Bar->NotUpToDate();
255 // Convert to color32
256 color32 col = Color32FromARGBi((ext->m_HasAlpha ? ext->A : 255), ext->R, ext->G, ext->B);
257 if( ext->m_OGL && !ext->m_IsColorF )
258 col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
259 if( ext->m_IsColorF )
260 Color32ToARGBf(col, (ext->m_HasAlpha ? varF+3 : NULL), varF+0, varF+1, varF+2);
263 if( ext->m_HasAlpha )
266 *var32 = ((*var32)&0xff000000) | (col&0x00ffffff);
268 ext->m_PrevConvertedColor = col;
272 void ANT_CALL CColorExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
274 const unsigned int *var32 = static_cast<const unsigned int *>(_VarValue);
275 const float *varF = static_cast<const float *>(_VarValue);
276 CColorExt *ext = static_cast<CColorExt *>(_ExtValue);
277 CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
278 if( _VarValue && ext )
280 if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F )
281 ext->m_HasAlpha = false;
283 if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent )
285 assert( mProxy->m_VarParent->m_Vars.size()==8 );
286 if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS
287 || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS
288 || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS
289 || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS
290 || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS
291 || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS )
293 mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS;
294 mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS;
295 mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS;
296 mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS;
297 mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS;
298 mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS;
299 mProxy->m_Bar->NotUpToDate();
301 if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha )
303 mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha;
304 mProxy->m_Bar->NotUpToDate();
306 if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly )
308 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false;
309 mProxy->m_Bar->NotUpToDate();
313 if( ext->m_IsColorF )
314 col = Color32FromARGBf((ext->m_HasAlpha ? varF[3] : 1), varF[0], varF[1], varF[2]);
317 if( ext->m_OGL && !ext->m_IsColorF )
318 col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16);
319 Color32ToARGBi(col, (ext->m_HasAlpha ? &ext->A : NULL), &ext->R, &ext->G, &ext->B);
320 if( (col & 0x00ffffff)!=(ext->m_PrevConvertedColor & 0x00ffffff) )
322 ext->m_PrevConvertedColor = col;
326 void ANT_CALL CColorExt::SummaryCB(char *_SummaryString, size_t /*_SummaryMaxLength*/, const void *_ExtValue, void * /*_ClientData*/)
329 CColorExt *ext = (CColorExt *)(_ExtValue);
330 if( ext && ext->m_StructProxy && ext->m_StructProxy->m_StructData )
332 if( ext->m_StructProxy->m_StructGetCallback )
333 ext->m_StructProxy->m_StructGetCallback(ext->m_StructProxy->m_StructData, ext->m_StructProxy->m_StructClientData);
334 //if( *(unsigned int *)(ext->m_StructProxy->m_StructData)!=ext->m_PrevConvertedColor )
335 CopyVarToExtCB(ext->m_StructProxy->m_StructData, ext, 99, NULL);
338 //unsigned int col = 0;
339 //CopyVar32FromExtCB(&col, _ExtValue, 99, _ClientData);
340 //_snprintf(_SummaryString, _SummaryMaxLength, "0x%.8X", col);
341 //(void) _SummaryMaxLength, _ExtValue, _ClientData;
342 _SummaryString[0] = ' '; // required to force background color for this value
343 _SummaryString[1] = '\0';
346 void CColorExt::CreateTypes()
350 TwStructMember ColorExtMembers[] = { { "Red", TW_TYPE_INT32, offsetof(CColorExt, R), "min=0 max=255" },
351 { "Green", TW_TYPE_INT32, offsetof(CColorExt, G), "min=0 max=255" },
352 { "Blue", TW_TYPE_INT32, offsetof(CColorExt, B), "min=0 max=255" },
353 { "Hue", TW_TYPE_INT32, offsetof(CColorExt, H), "hide min=0 max=359" },
354 { "Lightness", TW_TYPE_INT32, offsetof(CColorExt, L), "hide min=0 max=255" },
355 { "Saturation", TW_TYPE_INT32, offsetof(CColorExt, S), "hide min=0 max=255" },
356 { "Alpha", TW_TYPE_INT32, offsetof(CColorExt, A), "hide min=0 max=255" },
357 { "Mode", TW_TYPE_BOOLCPP, offsetof(CColorExt, m_HLS), "true='HLS' false='RGB' readwrite" } };
358 g_TwMgr->m_TypeColor32 = TwDefineStructExt("COLOR32", ColorExtMembers, 8, sizeof(unsigned int), sizeof(CColorExt), CColorExt::InitColor32CB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 32-bit-encoded color.");
359 g_TwMgr->m_TypeColor3F = TwDefineStructExt("COLOR3F", ColorExtMembers, 8, 3*sizeof(float), sizeof(CColorExt), CColorExt::InitColor3FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-floats-encoded RGB color.");
360 g_TwMgr->m_TypeColor4F = TwDefineStructExt("COLOR4F", ColorExtMembers, 8, 4*sizeof(float), sizeof(CColorExt), CColorExt::InitColor4FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-floats-encoded RGBA color.");
361 // Do not name them "TW_COLOR*" because the name is displayed in the help bar.
364 // ---------------------------------------------------------------------------
365 // Quaternion ext type
366 // ---------------------------------------------------------------------------
368 void ANT_CALL CQuaternionExt::InitQuat4FCB(void *_ExtValue, void *_ClientData)
370 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
373 ext->Qx = ext->Qy = ext->Qz = 0;
376 ext->Vy = ext->Vz = 0;
378 ext->Dx = ext->Dy = ext->Dz = 0;
379 ext->m_AAMode = false; // Axis & angle mode hidden
380 ext->m_ShowVal = false;
381 ext->m_IsFloat = true;
382 ext->m_IsDir = false;
383 ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
384 ext->m_DirColor = 0xffffff00;
388 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
389 ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
390 ext->ConvertToAxisAngle();
391 ext->m_Highlighted = false;
392 ext->m_Rotating = false;
393 if( ext->m_StructProxy!=NULL )
395 ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
396 ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
397 ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
398 ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
403 void ANT_CALL CQuaternionExt::InitQuat4DCB(void *_ExtValue, void *_ClientData)
405 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
408 ext->Qx = ext->Qy = ext->Qz = 0;
411 ext->Vy = ext->Vz = 0;
413 ext->Dx = ext->Dy = ext->Dz = 0;
414 ext->m_AAMode = false; // Axis & angle mode hidden
415 ext->m_ShowVal = false;
416 ext->m_IsFloat = false;
417 ext->m_IsDir = false;
418 ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
419 ext->m_DirColor = 0xffffff00;
423 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
424 ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
425 ext->ConvertToAxisAngle();
426 ext->m_Highlighted = false;
427 ext->m_Rotating = false;
428 if( ext->m_StructProxy!=NULL )
430 ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
431 ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
432 ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
433 ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
438 void ANT_CALL CQuaternionExt::InitDir3FCB(void *_ExtValue, void *_ClientData)
440 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
443 ext->Qx = ext->Qy = ext->Qz = 0;
446 ext->Vy = ext->Vz = 0;
449 ext->Dy = ext->Dz = 0;
450 ext->m_AAMode = false; // Axis & angle mode hidden
451 ext->m_ShowVal = true;
452 ext->m_IsFloat = true;
454 ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
455 ext->m_DirColor = 0xffffff00;
459 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
460 ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
461 ext->ConvertToAxisAngle();
462 ext->m_Highlighted = false;
463 ext->m_Rotating = false;
464 if( ext->m_StructProxy!=NULL )
466 ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
467 ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
468 ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
469 ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
474 void ANT_CALL CQuaternionExt::InitDir3DCB(void *_ExtValue, void *_ClientData)
476 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
479 ext->Qx = ext->Qy = ext->Qz = 0;
482 ext->Vy = ext->Vz = 0;
485 ext->Dy = ext->Dz = 0;
486 ext->m_AAMode = false; // Axis & angle mode hidden
487 ext->m_ShowVal = true;
488 ext->m_IsFloat = false;
490 ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0;
491 ext->m_DirColor = 0xffffff00;
495 ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f;
496 ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData;
497 ext->ConvertToAxisAngle();
498 ext->m_Highlighted = false;
499 ext->m_Rotating = false;
500 if( ext->m_StructProxy!=NULL )
502 ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB;
503 ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB;
504 ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB;
505 ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB;
510 void ANT_CALL CQuaternionExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
512 CQuaternionExt *ext = (CQuaternionExt *)(_ExtValue);
513 CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
514 if( _VarValue && ext )
516 // Synchronize Quat and AxisAngle
517 if( _ExtMemberIndex>=4 && _ExtMemberIndex<=7 )
519 ext->ConvertToAxisAngle();
520 // show/hide quat values
521 if( _ExtMemberIndex==4 && mProxy && mProxy->m_VarParent )
523 assert( mProxy->m_VarParent->m_Vars.size()==16 );
524 bool visible = ext->m_ShowVal;
527 if( mProxy->m_VarParent->m_Vars[13]->m_Visible != visible
528 || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible
529 || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible )
531 mProxy->m_VarParent->m_Vars[13]->m_Visible = visible;
532 mProxy->m_VarParent->m_Vars[14]->m_Visible = visible;
533 mProxy->m_VarParent->m_Vars[15]->m_Visible = visible;
534 mProxy->m_Bar->NotUpToDate();
539 if( mProxy->m_VarParent->m_Vars[4]->m_Visible != visible
540 || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible
541 || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible
542 || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible )
544 mProxy->m_VarParent->m_Vars[4]->m_Visible = visible;
545 mProxy->m_VarParent->m_Vars[5]->m_Visible = visible;
546 mProxy->m_VarParent->m_Vars[6]->m_Visible = visible;
547 mProxy->m_VarParent->m_Vars[7]->m_Visible = visible;
548 mProxy->m_Bar->NotUpToDate();
553 else if( _ExtMemberIndex>=8 && _ExtMemberIndex<=11 )
554 ext->ConvertFromAxisAngle();
555 else if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir )
557 assert( mProxy->m_VarParent->m_Vars.size()==16 );
558 bool aa = ext->m_AAMode;
559 if( mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa
560 || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa
561 || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa
562 || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa
563 || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa
564 || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa
565 || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa
566 || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa )
568 mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa;
569 mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa;
570 mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa;
571 mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa;
572 mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa;
573 mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa;
574 mProxy->m_VarParent->m_Vars[10]->m_Visible = aa;
575 mProxy->m_VarParent->m_Vars[11]->m_Visible = aa;
576 mProxy->m_Bar->NotUpToDate();
578 if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly )
580 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false;
581 mProxy->m_Bar->NotUpToDate();
587 float *var = static_cast<float *>(_VarValue);
590 var[0] = (float)ext->Dx;
591 var[1] = (float)ext->Dy;
592 var[2] = (float)ext->Dz;
596 var[0] = (float)ext->Qx;
597 var[1] = (float)ext->Qy;
598 var[2] = (float)ext->Qz;
599 var[3] = (float)ext->Qs;
604 double *var = static_cast<double *>(_VarValue);
622 void ANT_CALL CQuaternionExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData)
624 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
625 CTwMgr::CMemberProxy *mProxy = static_cast<CTwMgr::CMemberProxy *>(_ClientData);
627 if( _VarValue && ext )
629 if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir )
631 assert( mProxy->m_VarParent->m_Vars.size()==16 );
632 bool aa = ext->m_AAMode;
633 if( mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa
634 || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa
635 || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa
636 || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa
637 || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa
638 || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa
639 || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa
640 || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa )
642 mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa;
643 mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa;
644 mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa;
645 mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa;
646 mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa;
647 mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa;
648 mProxy->m_VarParent->m_Vars[10]->m_Visible = aa;
649 mProxy->m_VarParent->m_Vars[11]->m_Visible = aa;
650 mProxy->m_Bar->NotUpToDate();
652 if( static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly )
654 static_cast<CTwVarAtom *>(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false;
655 mProxy->m_Bar->NotUpToDate();
658 else if( mProxy && _ExtMemberIndex==4 && mProxy->m_VarParent )
660 assert( mProxy->m_VarParent->m_Vars.size()==16 );
661 bool visible = ext->m_ShowVal;
664 if( mProxy->m_VarParent->m_Vars[13]->m_Visible != visible
665 || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible
666 || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible )
668 mProxy->m_VarParent->m_Vars[13]->m_Visible = visible;
669 mProxy->m_VarParent->m_Vars[14]->m_Visible = visible;
670 mProxy->m_VarParent->m_Vars[15]->m_Visible = visible;
671 mProxy->m_Bar->NotUpToDate();
676 if( mProxy->m_VarParent->m_Vars[4]->m_Visible != visible
677 || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible
678 || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible
679 || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible )
681 mProxy->m_VarParent->m_Vars[4]->m_Visible = visible;
682 mProxy->m_VarParent->m_Vars[5]->m_Visible = visible;
683 mProxy->m_VarParent->m_Vars[6]->m_Visible = visible;
684 mProxy->m_VarParent->m_Vars[7]->m_Visible = visible;
685 mProxy->m_Bar->NotUpToDate();
692 const float *var = static_cast<const float *>(_VarValue);
698 QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]);
711 const double *var = static_cast<const double *>(_VarValue);
717 QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]);
727 ext->ConvertToAxisAngle();
731 void ANT_CALL CQuaternionExt::SummaryCB(char *_SummaryString, size_t _SummaryMaxLength, const void *_ExtValue, void * /*_ClientData*/)
733 const CQuaternionExt *ext = static_cast<const CQuaternionExt *>(_ExtValue);
737 _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f} A=%.0f°", ext->Vx, ext->Vy, ext->Vz, ext->Angle);
738 else if( ext->m_IsDir )
740 //float d[] = {1, 0, 0};
741 //ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)ext->Qx, (float)ext->Qy, (float)ext->Qz, (float)ext->Qs);
742 _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f}", ext->Dx, ext->Dy, ext->Dz);
745 _snprintf(_SummaryString, _SummaryMaxLength, "Q={x:%.2f,y:%.2f,z:%.2f,s:%.2f}", ext->Qx, ext->Qy, ext->Qz, ext->Qs);
749 _SummaryString[0] = ' '; // required to force background color for this value
750 _SummaryString[1] = '\0';
754 TwType CQuaternionExt::s_CustomType = TW_TYPE_UNDEF;
755 vector<float> CQuaternionExt::s_SphTri;
756 vector<color32> CQuaternionExt::s_SphCol;
757 vector<int> CQuaternionExt::s_SphTriProj;
758 vector<color32> CQuaternionExt::s_SphColLight;
759 vector<float> CQuaternionExt::s_ArrowTri[4];
760 vector<float> CQuaternionExt::s_ArrowNorm[4];
761 vector<int> CQuaternionExt::s_ArrowTriProj[4];
762 vector<color32> CQuaternionExt::s_ArrowColLight[4];
764 void CQuaternionExt::CreateTypes()
768 s_CustomType = (TwType)(TW_TYPE_CUSTOM_BASE + (int)g_TwMgr->m_Customs.size());
769 g_TwMgr->m_Customs.push_back(NULL); // increment custom type number
771 for(int pass=0; pass<2; pass++) // pass 0: create quat types; pass 1: create dir types
773 const char *quatDefPass0 = "step=0.01 hide";
774 const char *quatDefPass1 = "step=0.01 hide";
775 const char *quatSDefPass0 = "step=0.01 min=-1 max=1 hide";
776 const char *quatSDefPass1 = "step=0.01 min=-1 max=1 hide";
777 const char *dirDefPass0 = "step=0.01 hide";
778 const char *dirDefPass1 = "step=0.01";
779 const char *quatDef = (pass==0) ? quatDefPass0 : quatDefPass1;
780 const char *quatSDef = (pass==0) ? quatSDefPass0 : quatSDefPass1;
781 const char *dirDef = (pass==0) ? dirDefPass0 : dirDefPass1;
783 TwStructMember QuatExtMembers[] = { { "0", s_CustomType, 0, "" },
784 { "1", s_CustomType, 0, "" },
785 { "2", s_CustomType, 0, "" },
786 { "3", s_CustomType, 0, "" },
787 { "Quat X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qx), quatDef }, // copy of the source quaternion
788 { "Quat Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qy), quatDef },
789 { "Quat Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qz), quatDef },
790 { "Quat S", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qs), quatSDef },
791 { "Axis X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vx), "step=0.01 hide" }, // axis and angle conversion -> Mode hidden because it is not equivalent to a quat (would have required vector renormalization)
792 { "Axis Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vy), "step=0.01 hide" },
793 { "Axis Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vz), "step=0.01 hide" },
794 { "Angle (degree)", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Angle), "step=1 min=-360 max=360 hide" },
795 { "Mode", TW_TYPE_BOOLCPP, offsetof(CQuaternionExt, m_AAMode), "true='Axis Angle' false='Quaternion' readwrite hide" },
796 { "Dir X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dx), dirDef }, // copy of the source direction
797 { "Dir Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dy), dirDef },
798 { "Dir Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dz), dirDef } };
801 g_TwMgr->m_TypeQuat4F = TwDefineStructExt("QUAT4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-floats-encoded quaternion");
802 g_TwMgr->m_TypeQuat4D = TwDefineStructExt("QUAT4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-doubles-encoded quaternion");
806 g_TwMgr->m_TypeDir3F = TwDefineStructExt("DIR4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitDir3FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-floats-encoded direction");
807 g_TwMgr->m_TypeDir3D = TwDefineStructExt("DIR4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitDir3DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-doubles-encoded direction");
815 void CQuaternionExt::ConvertToAxisAngle()
817 if( fabs(Qs)>(1.0 + FLOAT_EPS) )
819 //Vx = Vy = Vz = 0; // no, keep the previous value
828 a = DOUBLE_PI; // and keep V
829 else if( fabs(Qx*Qx+Qy*Qy+Qz*Qz+Qs*Qs)<FLOAT_EPS_SQ )
834 if( a*Angle<0 ) // Preserve the sign of Angle
836 double f = 1.0f / sin(a);
844 // if( Angle>FLOAT_PI )
845 // Angle -= 2.0f*FLOAT_PI;
846 // else if( Angle<-FLOAT_PI )
847 // Angle += 2.0f*FLOAT_PI;
848 Angle = RadToDeg(Angle);
850 if( fabs(Angle)<FLOAT_EPS && fabs(Vx*Vx+Vy*Vy+Vz*Vz)<FLOAT_EPS_SQ )
851 Vx = 1.0e-7; // all components cannot be null
854 void CQuaternionExt::ConvertFromAxisAngle()
856 double n = Vx*Vx + Vy*Vy + Vz*Vz;
857 if( fabs(n)>FLOAT_EPS_SQ )
859 double f = 0.5*DegToRad(Angle);
862 //if( fabs(n - 1.0)>FLOAT_EPS_SQ )
863 // f = sin(f) * (1.0/sqrt(n)) ;
879 void CQuaternionExt::CopyToVar()
881 if( m_StructProxy!=NULL )
883 if( m_StructProxy->m_StructSetCallback!=NULL )
889 float d[] = {1, 0, 0};
890 ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
891 float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
892 d[0] *= l; d[1] *= l; d[2] *= l;
893 Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz
894 m_StructProxy->m_StructSetCallback(d, m_StructProxy->m_StructClientData);
898 float q[] = { (float)Qx, (float)Qy, (float)Qz, (float)Qs };
899 m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData);
906 float d[] = {1, 0, 0};
907 ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
908 double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
909 double dd[] = {l*d[0], l*d[1], l*d[2]};
910 Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz
911 m_StructProxy->m_StructSetCallback(dd, m_StructProxy->m_StructClientData);
915 double q[] = { Qx, Qy, Qz, Qs };
916 m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData);
920 else if( m_StructProxy->m_StructData!=NULL )
926 float *d = static_cast<float *>(m_StructProxy->m_StructData);
927 ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
928 float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
929 d[0] *= l; d[1] *= l; d[2] *= l;
930 Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz
934 float *q = static_cast<float *>(m_StructProxy->m_StructData);
935 q[0] = (float)Qx; q[1] = (float)Qy; q[2] = (float)Qz; q[3] = (float)Qs;
942 double *dd = static_cast<double *>(m_StructProxy->m_StructData);
943 float d[] = {1, 0, 0};
944 ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs);
945 double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz);
946 dd[0] = l*d[0]; dd[1] = l*d[1]; dd[2] = l*d[2];
947 Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz
951 double *q = static_cast<double *>(m_StructProxy->m_StructData);
952 q[0] = Qx; q[1] = Qy; q[2] = Qz; q[3] = Qs;
959 void CQuaternionExt::CreateSphere()
961 const int SUBDIV = 7;
965 const float A[8*3] = { 1,0,0, 0,0,-1, -1,0,0, 0,0,1, 0,0,1, 1,0,0, 0,0,-1, -1,0,0 };
966 const float B[8*3] = { 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0 };
967 const float C[8*3] = { 0,0,1, 1,0,0, 0,0,-1, -1,0,0, 1,0,0, 0,0,-1, -1,0,0, 0,0,1 };
968 //const color32 COL_A[8] = { 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff, 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000 };
969 //const color32 COL_B[8] = { 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff008000, 0xff008000, 0xff008000, 0xff008000 };
970 //const color32 COL_C[8] = { 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000, 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff };
971 const color32 COL_A[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
972 const color32 COL_B[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
973 const color32 COL_C[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
976 float xa, ya, za, xb, yb, zb, xc, yc, zc, x, y, z, norm, u[3], v[3];
980 xa = A[3*i+0]; ya = A[3*i+1]; za = A[3*i+2];
981 xb = B[3*i+0]; yb = B[3*i+1]; zb = B[3*i+2];
982 xc = C[3*i+0]; yc = C[3*i+1]; zc = C[3*i+2];
983 for( j=0; j<=SUBDIV; ++j )
984 for( k=0; k<=2*(SUBDIV-j); ++k )
988 u[0] = ((float)j)/(SUBDIV+1);
989 v[0] = ((float)(k/2))/(SUBDIV+1);
990 u[1] = ((float)(j+1))/(SUBDIV+1);
991 v[1] = ((float)(k/2))/(SUBDIV+1);
992 u[2] = ((float)j)/(SUBDIV+1);
993 v[2] = ((float)(k/2+1))/(SUBDIV+1);
997 u[0] = ((float)j)/(SUBDIV+1);
998 v[0] = ((float)(k/2+1))/(SUBDIV+1);
999 u[1] = ((float)(j+1))/(SUBDIV+1);
1000 v[1] = ((float)(k/2))/(SUBDIV+1);
1001 u[2] = ((float)(j+1))/(SUBDIV+1);
1002 v[2] = ((float)(k/2+1))/(SUBDIV+1);
1005 for( l=0; l<3; ++l )
1007 x = (1.0f-u[l]-v[l])*xa + u[l]*xb + v[l]*xc;
1008 y = (1.0f-u[l]-v[l])*ya + u[l]*yb + v[l]*yc;
1009 z = (1.0f-u[l]-v[l])*za + u[l]*zb + v[l]*zc;
1010 norm = sqrtf(x*x+y*y+z*z);
1011 x /= norm; y /= norm; z /= norm;
1012 s_SphTri.push_back(x); s_SphTri.push_back(y); s_SphTri.push_back(z);
1013 if( u[l]+v[l]>FLOAT_EPS )
1014 col = ColorBlend(COL_A[i], ColorBlend(COL_B[i], COL_C[i], v[l]/(u[l]+v[l])), u[l]+v[l]);
1017 //if( (j==0 && k==0) || (j==0 && k==2*SUBDIV) || (j==SUBDIV && k==0) )
1018 // col = 0xffff0000;
1019 s_SphCol.push_back(col);
1023 s_SphTriProj.clear();
1024 s_SphTriProj.resize(2*s_SphCol.size(), 0);
1025 s_SphColLight.clear();
1026 s_SphColLight.resize(s_SphCol.size(), 0);
1029 void CQuaternionExt::CreateArrow()
1031 const int SUBDIV = 15;
1032 const float CYL_RADIUS = 0.08f;
1033 const float CONE_RADIUS = 0.16f;
1034 const float CONE_LENGTH = 0.25f;
1035 const float ARROW_BGN = -1.1f;
1036 const float ARROW_END = 1.15f;
1040 s_ArrowTri[i].clear();
1041 s_ArrowNorm[i].clear();
1044 float x0, x1, y0, y1, z0, z1, a0, a1, nx, nn;
1045 for(i=0; i<SUBDIV; ++i)
1047 a0 = 2.0f*FLOAT_PI*(float(i))/SUBDIV;
1048 a1 = 2.0f*FLOAT_PI*(float(i+1))/SUBDIV;
1050 x1 = ARROW_END-CONE_LENGTH;
1055 s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1056 s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1057 s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1058 s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
1059 s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1060 s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
1061 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1062 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1063 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1064 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
1065 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1066 s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
1067 s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(0); s_ArrowTri[ARROW_CYL_CAP].push_back(0);
1068 s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z1);
1069 s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z0);
1070 s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1071 s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1072 s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
1073 x0 = ARROW_END-CONE_LENGTH;
1075 nx = CONE_RADIUS/(x1-x0);
1076 nn = 1.0f/sqrtf(nx*nx+1);
1077 s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1078 s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z0);
1079 s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
1080 s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1081 s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
1082 s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
1083 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1084 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1085 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1086 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
1087 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1088 s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
1089 s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(0); s_ArrowTri[ARROW_CONE_CAP].push_back(0);
1090 s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z1);
1091 s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z0);
1092 s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1093 s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1094 s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
1099 s_ArrowTriProj[i].clear();
1100 s_ArrowTriProj[i].resize(2*(s_ArrowTri[i].size()/3), 0);
1101 s_ArrowColLight[i].clear();
1102 s_ArrowColLight[i].resize(s_ArrowTri[i].size()/3, 0);
1106 static inline void QuatMult(double *out, const double *q1, const double *q2)
1108 out[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1];
1109 out[1] = q1[3]*q2[1] + q1[1]*q2[3] + q1[2]*q2[0] - q1[0]*q2[2];
1110 out[2] = q1[3]*q2[2] + q1[2]*q2[3] + q1[0]*q2[1] - q1[1]*q2[0];
1111 out[3] = q1[3]*q2[3] - (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2]);
1114 static inline void QuatFromAxisAngle(double *out, const double *axis, double angle)
1116 double n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2];
1117 if( fabs(n)>DOUBLE_EPS )
1119 double f = 0.5*angle;
1129 out[0] = out[1] = out[2] = 0.0;
1133 static inline void Vec3Cross(double *out, const double *a, const double *b)
1135 out[0] = a[1]*b[2]-a[2]*b[1];
1136 out[1] = a[2]*b[0]-a[0]*b[2];
1137 out[2] = a[0]*b[1]-a[1]*b[0];
1140 static inline double Vec3Dot(const double *a, const double *b)
1142 return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
1145 static inline void Vec3RotY(float *x, float *y, float *z)
1153 static inline void Vec3RotZ(float *x, float *y, float *z)
1161 void CQuaternionExt::ApplyQuat(float *outX, float *outY, float *outZ, float x, float y, float z, float qx, float qy, float qz, float qs)
1163 float ps = - qx * x - qy * y - qz * z;
1164 float px = qs * x + qy * z - qz * y;
1165 float py = qs * y + qz * x - qx * z;
1166 float pz = qs * z + qx * y - qy * x;
1167 *outX = - ps * qx + px * qs - py * qz + pz * qy;
1168 *outY = - ps * qy + py * qs - pz * qx + px * qz;
1169 *outZ = - ps * qz + pz * qs - px * qy + py * qx;
1172 void CQuaternionExt::QuatFromDir(double *outQx, double *outQy, double *outQz, double *outQs, double dx, double dy, double dz)
1174 // compute a quaternion that rotates (1,0,0) to (dx,dy,dz)
1176 double dn = sqrt(dx*dx + dy*dy + dz*dz);
1177 if( dn<DOUBLE_EPS_SQ )
1179 *outQx = *outQy = *outQz = 0;
1184 double rotAxis[3] = { 0, -dz, dy };
1185 if( rotAxis[0]*rotAxis[0] + rotAxis[1]*rotAxis[1] + rotAxis[2]*rotAxis[2]<DOUBLE_EPS_SQ )
1187 rotAxis[0] = rotAxis[1] = 0;
1190 double rotAngle = acos(dx/dn);
1192 QuatFromAxisAngle(rotQuat, rotAxis, rotAngle);
1193 *outQx = rotQuat[0];
1194 *outQy = rotQuat[1];
1195 *outQz = rotQuat[2];
1196 *outQs = rotQuat[3];
1200 void CQuaternionExt::Permute(float *outX, float *outY, float *outZ, float x, float y, float z)
1202 float px = x, py = y, pz = z;
1203 *outX = m_Permute[0][0]*px + m_Permute[1][0]*py + m_Permute[2][0]*pz;
1204 *outY = m_Permute[0][1]*px + m_Permute[1][1]*py + m_Permute[2][1]*pz;
1205 *outZ = m_Permute[0][2]*px + m_Permute[1][2]*py + m_Permute[2][2]*pz;
1208 void CQuaternionExt::PermuteInv(float *outX, float *outY, float *outZ, float x, float y, float z)
1210 float px = x, py = y, pz = z;
1211 *outX = m_Permute[0][0]*px + m_Permute[0][1]*py + m_Permute[0][2]*pz;
1212 *outY = m_Permute[1][0]*px + m_Permute[1][1]*py + m_Permute[1][2]*pz;
1213 *outZ = m_Permute[2][0]*px + m_Permute[2][1]*py + m_Permute[2][2]*pz;
1216 void CQuaternionExt::Permute(double *outX, double *outY, double *outZ, double x, double y, double z)
1218 double px = x, py = y, pz = z;
1219 *outX = m_Permute[0][0]*px + m_Permute[1][0]*py + m_Permute[2][0]*pz;
1220 *outY = m_Permute[0][1]*px + m_Permute[1][1]*py + m_Permute[2][1]*pz;
1221 *outZ = m_Permute[0][2]*px + m_Permute[1][2]*py + m_Permute[2][2]*pz;
1224 void CQuaternionExt::PermuteInv(double *outX, double *outY, double *outZ, double x, double y, double z)
1226 double px = x, py = y, pz = z;
1227 *outX = m_Permute[0][0]*px + m_Permute[0][1]*py + m_Permute[0][2]*pz;
1228 *outY = m_Permute[1][0]*px + m_Permute[1][1]*py + m_Permute[1][2]*pz;
1229 *outZ = m_Permute[2][0]*px + m_Permute[2][1]*py + m_Permute[2][2]*pz;
1232 static inline float QuatD(int w, int h)
1234 return (float)min(abs(w), abs(h)) - 4;
1237 static inline int QuatPX(float x, int w, int h)
1239 return (int)(x*0.5f*QuatD(w, h) + (float)w*0.5f + 0.5f);
1242 static inline int QuatPY(float y, int w, int h)
1244 return (int)(-y*0.5f*QuatD(w, h) + (float)h*0.5f - 0.5f);
1247 static inline float QuatIX(int x, int w, int h)
1249 return (2.0f*(float)x - (float)w - 1.0f)/QuatD(w, h);
1252 static inline float QuatIY(int y, int w, int h)
1254 return (-2.0f*(float)y + (float)h - 1.0f)/QuatD(w, h);
1257 void CQuaternionExt::DrawCB(int w, int h, void *_ExtValue, void *_ClientData, TwBar *_Bar, CTwVarGroup *varGrp)
1259 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
1261 assert( g_TwMgr->m_Graph->IsDrawing() );
1262 CQuaternionExt *ext = static_cast<CQuaternionExt *>(_ExtValue);
1263 assert( ext!=NULL );
1264 (void)_ClientData; (void)_Bar;
1266 // show/hide quat values
1267 assert( varGrp->m_Vars.size()==16 );
1268 bool visible = ext->m_ShowVal;
1271 if( varGrp->m_Vars[13]->m_Visible != visible
1272 || varGrp->m_Vars[14]->m_Visible != visible
1273 || varGrp->m_Vars[15]->m_Visible != visible )
1275 varGrp->m_Vars[13]->m_Visible = visible;
1276 varGrp->m_Vars[14]->m_Visible = visible;
1277 varGrp->m_Vars[15]->m_Visible = visible;
1278 _Bar->NotUpToDate();
1283 if( varGrp->m_Vars[4]->m_Visible != visible
1284 || varGrp->m_Vars[5]->m_Visible != visible
1285 || varGrp->m_Vars[6]->m_Visible != visible
1286 || varGrp->m_Vars[7]->m_Visible != visible )
1288 varGrp->m_Vars[4]->m_Visible = visible;
1289 varGrp->m_Vars[5]->m_Visible = visible;
1290 varGrp->m_Vars[6]->m_Visible = visible;
1291 varGrp->m_Vars[7]->m_Visible = visible;
1292 _Bar->NotUpToDate();
1297 static_cast<CTwVarAtom *>(varGrp->m_Vars[4])->ValueToDouble();
1299 assert( s_SphTri.size()>0 );
1300 assert( s_SphTri.size()==3*s_SphCol.size() );
1301 assert( s_SphTriProj.size()==2*s_SphCol.size() );
1302 assert( s_SphColLight.size()==s_SphCol.size() );
1304 if( QuatD(w, h)<=2 )
1306 float x, y, z, nx, ny, nz, kx, ky, kz, qx, qy, qz, qs;
1309 // normalize quaternion
1310 float qn = (float)sqrt(ext->Qs*ext->Qs+ext->Qx*ext->Qx+ext->Qy*ext->Qy+ext->Qz*ext->Qz);
1313 qx = (float)ext->Qx/qn;
1314 qy = (float)ext->Qy/qn;
1315 qz = (float)ext->Qz/qn;
1316 qs = (float)ext->Qs/qn;
1324 double normDir = sqrt(ext->m_Dir[0]*ext->m_Dir[0] + ext->m_Dir[1]*ext->m_Dir[1] + ext->m_Dir[2]*ext->m_Dir[2]);
1325 bool drawDir = ext->m_IsDir || (normDir>DOUBLE_EPS);
1326 color32 alpha = ext->m_Highlighted ? 0xffffffff : 0xb0ffffff;
1328 // check if frame is right-handed
1329 ext->Permute(&kx, &ky, &kz, 1, 0, 0);
1330 double px[3] = { (double)kx, (double)ky, (double)kz };
1331 ext->Permute(&kx, &ky, &kz, 0, 1, 0);
1332 double py[3] = { (double)kx, (double)ky, (double)kz };
1333 ext->Permute(&kx, &ky, &kz, 0, 0, 1);
1334 double pz[3] = { (double)kx, (double)ky, (double)kz };
1336 Vec3Cross(ez, px, py);
1337 bool frameRightHanded = (ez[0]*pz[0]+ez[1]*pz[1]+ez[2]*pz[2] >= 0);
1338 ITwGraph::Cull cull = frameRightHanded ? ITwGraph::CULL_CW : ITwGraph::CULL_CCW;
1342 float dir[] = {(float)ext->m_Dir[0], (float)ext->m_Dir[1], (float)ext->m_Dir[2]};
1343 if( normDir<DOUBLE_EPS )
1348 kx = dir[0]; ky = dir[1]; kz = dir[2];
1349 double rotDirAxis[3] = { 0, -kz, ky };
1350 if( rotDirAxis[0]*rotDirAxis[0] + rotDirAxis[1]*rotDirAxis[1] + rotDirAxis[2]*rotDirAxis[2]<DOUBLE_EPS_SQ )
1352 rotDirAxis[0] = rotDirAxis[1] = 0;
1355 double rotDirAngle = acos(kx/normDir);
1356 double rotDirQuat[4];
1357 QuatFromAxisAngle(rotDirQuat, rotDirAxis, rotDirAngle);
1359 kx = 1; ky = 0; kz = 0;
1360 ApplyQuat(&kx, &ky, &kz, kx, ky, kz, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1361 ApplyQuat(&kx, &ky, &kz, kx, ky, kz, qx, qy, qz, qs);
1362 for(k=0; k<4; ++k) // 4 parts of the arrow
1365 ext->Permute(&x, &y, &z, kx, ky, kz);
1366 j = (z>0) ? 3-k : k;
1368 assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() );
1369 const int ntri = (int)s_ArrowTri[j].size()/3;
1370 const float *tri = &(s_ArrowTri[j][0]);
1371 const float *norm = &(s_ArrowNorm[j][0]);
1372 int *triProj = &(s_ArrowTriProj[j][0]);
1373 color32 *colLight = &(s_ArrowColLight[j][0]);
1374 for(i=0; i<ntri; ++i)
1376 x = tri[3*i+0]; y = tri[3*i+1]; z = tri[3*i+2];
1377 nx = norm[3*i+0]; ny = norm[3*i+1]; nz = norm[3*i+2];
1384 ApplyQuat(&x, &y, &z, x, y, z, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1385 ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1386 ext->Permute(&x, &y, &z, x, y, z);
1387 ApplyQuat(&nx, &ny, &nz, nx, ny, nz, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]);
1388 ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs);
1389 ext->Permute(&nx, &ny, &nz, nx, ny, nz);
1390 triProj[2*i+0] = QuatPX(x, w, h);
1391 triProj[2*i+1] = QuatPY(y, w, h);
1392 color32 col = (ext->m_DirColor|0xff000000) & alpha;
1393 colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f)));
1395 if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats
1396 g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull);
1402 int px0 = QuatPX(0, w, h)-1, py0 = QuatPY(0, w, h), r0 = (int)(0.5f*QuatD(w, h)-0.5f);
1403 color32 col0 = 0x80000000;
1404 DrawArc(px0-1, py0, r0, 0, 360, col0);
1405 DrawArc(px0+1, py0, r0, 0, 360, col0);
1406 DrawArc(px0, py0-1, r0, 0, 360, col0);
1407 DrawArc(px0, py0+1, r0, 0, 360, col0);
1409 // draw arrows & sphere
1410 const float SPH_RADIUS = 0.75f;
1411 for(m=0; m<2; ++m) // m=0: back, m=1: front
1413 for(l=0; l<3; ++l) // draw 3 arrows
1415 kx = 1; ky = 0; kz = 0;
1417 Vec3RotZ(&kx, &ky, &kz);
1419 Vec3RotY(&kx, &ky, &kz);
1420 ApplyQuat(&kx, &ky, &kz, kx, ky, kz, qx, qy, qz, qs);
1421 for(k=0; k<4; ++k) // 4 parts of the arrow
1424 ext->Permute(&x, &y, &z, kx, ky, kz);
1425 j = (z>0) ? 3-k : k;
1428 if( (m==0 && z>0) || (m==1 && z<=0) )
1430 if( j==ARROW_CONE || j==ARROW_CONE_CAP ) // do not draw cone
1435 assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() );
1436 const int ntri = (int)s_ArrowTri[j].size()/3;
1437 const float *tri = &(s_ArrowTri[j][0]);
1438 const float *norm = &(s_ArrowNorm[j][0]);
1439 int *triProj = &(s_ArrowTriProj[j][0]);
1440 color32 *colLight = &(s_ArrowColLight[j][0]);
1441 for(i=0; i<ntri; ++i)
1443 x = tri[3*i+0]; y = tri[3*i+1]; z = tri[3*i+2];
1446 else if( !cone && x>0 )
1448 nx = norm[3*i+0]; ny = norm[3*i+1]; nz = norm[3*i+2];
1451 Vec3RotZ(&x, &y, &z);
1452 Vec3RotZ(&nx, &ny, &nz);
1456 Vec3RotY(&x, &y, &z);
1457 Vec3RotY(&nx, &ny, &nz);
1459 ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1460 ext->Permute(&x, &y, &z, x, y, z);
1461 ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs);
1462 ext->Permute(&nx, &ny, &nz, nx, ny, nz);
1463 triProj[2*i+0] = QuatPX(x, w, h);
1464 triProj[2*i+1] = QuatPY(y, w, h);
1465 float fade = ( m==0 && z<0 ) ? TClamp(2.0f*z*z, 0.0f, 1.0f) : 0;
1466 float alphaFade = 1.0f;
1467 Color32ToARGBf(alpha, &alphaFade, NULL, NULL, NULL);
1468 alphaFade *= (1.0f-fade);
1469 color32 alphaFadeCol = Color32FromARGBf(alphaFade, 1, 1, 1);
1470 color32 col = (l==0) ? 0xffff0000 : ( (l==1) ? 0xff00ff00 : 0xff0000ff );
1471 colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f))) & alphaFadeCol;
1473 if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats
1474 g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull);
1480 const float *tri = &(s_SphTri[0]);
1481 int *triProj = &(s_SphTriProj[0]);
1482 const color32 *col = &(s_SphCol[0]);
1483 color32 *colLight = &(s_SphColLight[0]);
1484 const int ntri = (int)s_SphTri.size()/3;
1485 for(i=0; i<ntri; ++i) // draw sphere
1487 x = SPH_RADIUS*tri[3*i+0]; y = SPH_RADIUS*tri[3*i+1]; z = SPH_RADIUS*tri[3*i+2];
1488 ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs);
1489 ext->Permute(&x, &y, &z, x, y, z);
1490 triProj[2*i+0] = QuatPX(x, w, h);
1491 triProj[2*i+1] = QuatPY(y, w, h);
1492 colLight[i] = ColorBlend(0xff000000, col[i], fabsf(TClamp(z/SPH_RADIUS, -1.0f, 1.0f))) & alpha;
1494 g_TwMgr->m_Graph->DrawTriangles((int)s_SphTri.size()/9, triProj, colLight, cull);
1499 g_TwMgr->m_Graph->DrawLine(w-12, h-36, w-12+5, h-36+5, 0xffc00000, true);
1500 g_TwMgr->m_Graph->DrawLine(w-12+5, h-36, w-12, h-36+5, 0xffc00000, true);
1502 g_TwMgr->m_Graph->DrawLine(w-12, h-25, w-12+3, h-25+4, 0xff00c000, true);
1503 g_TwMgr->m_Graph->DrawLine(w-12+5, h-25, w-12, h-25+7, 0xff00c000, true);
1505 g_TwMgr->m_Graph->DrawLine(w-12, h-12, w-12+5, h-12, 0xff0000c0, true);
1506 g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12+5, 0xff0000c0, true);
1507 g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12, 0xff0000c0, true);
1511 g_TwMgr->m_Graph->DrawLine(1, 0, w-1, 0, 0x40000000);
1512 g_TwMgr->m_Graph->DrawLine(w-1, 0, w-1, h-1, 0x40000000);
1513 g_TwMgr->m_Graph->DrawLine(w-1, h-1, 1, h-1, 0x40000000);
1514 g_TwMgr->m_Graph->DrawLine(1, h-1, 1, 0, 0x40000000);
1517 bool CQuaternionExt::MouseMotionCB(int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp)
1519 CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1522 (void)clientData, (void)varGrp;
1524 if( mouseX>0 && mouseX<w && mouseY>0 && mouseY<h )
1525 ext->m_Highlighted = true;
1527 if( ext->m_Rotating )
1529 double x = QuatIX(mouseX, w, h);
1530 double y = QuatIY(mouseY, w, h);
1532 double px, py, pz, ox, oy, oz;
1533 ext->PermuteInv(&px, &py, &pz, x, y, z);
1534 ext->PermuteInv(&ox, &oy, &oz, ext->m_OrigX, ext->m_OrigY, 1);
1535 double n0 = sqrt(ox*ox + oy*oy + oz*oz);
1536 double n1 = sqrt(px*px + py*py + pz*pz);
1537 if( n0>DOUBLE_EPS && n1>DOUBLE_EPS )
1539 double v0[] = { ox/n0, oy/n0, oz/n0 };
1540 double v1[] = { px/n1, py/n1, pz/n1 };
1542 Vec3Cross(axis, v0, v1);
1543 double sa = sqrt(Vec3Dot(axis, axis));
1544 double ca = Vec3Dot(v0, v1);
1545 double angle = atan2(sa, ca);
1547 angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0);
1548 double qrot[4], qres[4], qorig[4];
1549 QuatFromAxisAngle(qrot, axis, angle);
1550 double nqorig = sqrt(ext->m_OrigQuat[0]*ext->m_OrigQuat[0]+ext->m_OrigQuat[1]*ext->m_OrigQuat[1]+ext->m_OrigQuat[2]*ext->m_OrigQuat[2]+ext->m_OrigQuat[3]*ext->m_OrigQuat[3]);
1551 if( fabs(nqorig)>DOUBLE_EPS_SQ )
1553 qorig[0] = ext->m_OrigQuat[0]/nqorig;
1554 qorig[1] = ext->m_OrigQuat[1]/nqorig;
1555 qorig[2] = ext->m_OrigQuat[2]/nqorig;
1556 qorig[3] = ext->m_OrigQuat[3]/nqorig;
1557 QuatMult(qres, qrot, qorig);
1582 bool CQuaternionExt::MouseButtonCB(TwMouseButtonID button, bool pressed, int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp)
1584 CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1587 (void)clientData; (void)bar, (void)varGrp;
1589 if( button==TW_MOUSE_LEFT )
1593 ext->m_OrigQuat[0] = ext->Qx;
1594 ext->m_OrigQuat[1] = ext->Qy;
1595 ext->m_OrigQuat[2] = ext->Qz;
1596 ext->m_OrigQuat[3] = ext->Qs;
1597 ext->m_OrigX = QuatIX(mouseX, w, h);
1598 ext->m_OrigY = QuatIY(mouseY, w, h);
1599 ext->m_PrevX = ext->m_OrigX;
1600 ext->m_PrevY = ext->m_OrigY;
1601 ext->m_Rotating = true;
1604 ext->m_Rotating = false;
1607 //printf("Click %x\n", structExtValue);
1611 void CQuaternionExt::MouseLeaveCB(void *structExtValue, void *clientData, TwBar *bar)
1613 CQuaternionExt *ext = static_cast<CQuaternionExt *>(structExtValue);
1616 (void)clientData; (void)bar;
1618 //printf("Leave %x\n", structExtValue);
1619 ext->m_Highlighted = false;
1620 ext->m_Rotating = false;
1624 // ---------------------------------------------------------------------------
1625 // Convertion between VC++ Debug/Release std::string
1626 // (Needed because VC++ adds some extra info to std::string in Debug mode!)
1627 // And resolve binary std::string incompatibility between VS2008- and VS2010+
1628 // ---------------------------------------------------------------------------
1631 // VS2008 and lower store the string allocator pointer at the beginning
1632 // VS2010 and higher store the string allocator pointer at the end
1633 static void FixVS2010StdStringLibToClient(void *strPtr)
1635 char *ptr = (char *)strPtr;
1636 const size_t SizeOfUndecoratedString = 16 + 2*sizeof(size_t) + sizeof(void *); // size of a VS std::string without extra debug iterator and info.
1637 assert(SizeOfUndecoratedString <= sizeof(std::string));
1638 TwType LibStdStringBaseType = (TwType)(TW_TYPE_STDSTRING&0xffff0000);
1639 void **allocAddress2008 = (void **)(ptr + sizeof(std::string) - SizeOfUndecoratedString);
1640 void **allocAddress2010 = (void **)(ptr + sizeof(std::string) - sizeof(void *));
1641 if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2008 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2010)
1643 void *allocator = *allocAddress2008;
1644 memmove(allocAddress2008, allocAddress2008 + 1, SizeOfUndecoratedString - sizeof(void *));
1645 *allocAddress2010 = allocator;
1647 else if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2010 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2008)
1649 void *allocator = *allocAddress2010;
1650 memmove(allocAddress2008 + 1, allocAddress2008, SizeOfUndecoratedString - sizeof(void *));
1651 *allocAddress2008 = allocator;
1655 static void FixVS2010StdStringClientToLib(void *strPtr)
1657 char *ptr = (char *)strPtr;
1658 const size_t SizeOfUndecoratedString = 16 + 2*sizeof(size_t) + sizeof(void *); // size of a VS std::string without extra debug iterator and info.
1659 assert(SizeOfUndecoratedString <= sizeof(std::string));
1660 TwType LibStdStringBaseType = (TwType)(TW_TYPE_STDSTRING&0xffff0000);
1661 void **allocAddress2008 = (void **)(ptr + sizeof(std::string) - SizeOfUndecoratedString);
1662 void **allocAddress2010 = (void **)(ptr + sizeof(std::string) - sizeof(void *));
1663 if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2008 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2010)
1665 void *allocator = *allocAddress2010;
1666 memmove(allocAddress2008 + 1, allocAddress2008, SizeOfUndecoratedString - sizeof(void *));
1667 *allocAddress2008 = allocator;
1669 else if (LibStdStringBaseType == TW_TYPE_STDSTRING_VS2010 && g_TwMgr->m_ClientStdStringBaseType == TW_TYPE_STDSTRING_VS2008)
1671 void *allocator = *allocAddress2008;
1672 memmove(allocAddress2008, allocAddress2008 + 1, SizeOfUndecoratedString - sizeof(void *));
1673 *allocAddress2010 = allocator;
1678 CTwMgr::CClientStdString::CClientStdString()
1680 memset(m_Data, 0, sizeof(m_Data));
1683 void CTwMgr::CClientStdString::FromLib(const char *libStr)
1685 m_LibStr = libStr; // it is ok to have a local copy here
1686 memcpy(m_Data + sizeof(void *), &m_LibStr, sizeof(std::string));
1688 FixVS2010StdStringLibToClient(m_Data + sizeof(void *));
1692 std::string& CTwMgr::CClientStdString::ToClient()
1694 assert( g_TwMgr!=NULL );
1695 if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) )
1696 return *(std::string *)(m_Data);
1697 else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) )
1698 return *(std::string *)(m_Data + 2*sizeof(void *));
1701 assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) );
1702 return *(std::string *)(m_Data + sizeof(void *));
1707 CTwMgr::CLibStdString::CLibStdString()
1709 memset(m_Data, 0, sizeof(m_Data));
1712 void CTwMgr::CLibStdString::FromClient(const std::string& clientStr)
1714 assert( g_TwMgr!=NULL );
1715 memcpy(m_Data + sizeof(void *), &clientStr, g_TwMgr->m_ClientStdStringStructSize);
1717 FixVS2010StdStringClientToLib(m_Data + sizeof(void *));
1721 std::string& CTwMgr::CLibStdString::ToLib()
1723 assert( g_TwMgr!=NULL );
1724 if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) )
1725 return *(std::string *)(m_Data + 2*sizeof(void *));
1726 else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) )
1727 return *(std::string *)(m_Data);
1730 assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) );
1731 return *(std::string *)(m_Data + sizeof(void *));
1736 // ---------------------------------------------------------------------------
1737 // Management functions
1738 // ---------------------------------------------------------------------------
1741 static int TwCreateGraph(ETwGraphAPI _GraphAPI)
1743 assert( g_TwMgr!=NULL && g_TwMgr->m_Graph==NULL );
1748 g_TwMgr->m_Graph = new CTwGraphOpenGL;
1750 case TW_OPENGL_CORE:
1751 g_TwMgr->m_Graph = new CTwGraphOpenGLCore;
1754 #ifdef ANT_WINDOWS_DX9
1755 if( g_TwMgr->m_Device!=NULL )
1756 g_TwMgr->m_Graph = new CTwGraphDirect3D9;
1759 g_TwMgr->SetLastError(g_ErrBadDevice);
1762 #endif // ANT_WINDOWS
1765 #ifdef ANT_WINDOWS_DX10
1766 if( g_TwMgr->m_Device!=NULL )
1767 g_TwMgr->m_Graph = new CTwGraphDirect3D10;
1770 g_TwMgr->SetLastError(g_ErrBadDevice);
1773 #endif // ANT_WINDOWS
1776 #ifdef ANT_WINDOWS_DX11
1777 if( g_TwMgr->m_Device!=NULL )
1778 g_TwMgr->m_Graph = new CTwGraphDirect3D11;
1781 g_TwMgr->SetLastError(g_ErrBadDevice);
1784 #endif // ANT_WINDOWS
1788 if( g_TwMgr->m_Graph==NULL )
1790 g_TwMgr->SetLastError(g_ErrUnknownAPI);
1794 return g_TwMgr->m_Graph->Init();
1797 // ---------------------------------------------------------------------------
1799 static inline int TwFreeAsyncDrawing()
1801 if( g_TwMgr && g_TwMgr->m_Graph && g_TwMgr->m_Graph->IsDrawing() )
1803 const double SLEEP_MAX = 0.25; // wait at most 1/4 second
1805 while( g_TwMgr->m_Graph->IsDrawing() && timer.GetTime()<SLEEP_MAX )
1807 #if defined(ANT_WINDOWS)
1808 Sleep(1); // milliseconds
1809 #elif defined(ANT_UNIX) || defined(ANT_OSX)
1810 usleep(1000); // microseconds
1813 if( g_TwMgr->m_Graph->IsDrawing() )
1815 g_TwMgr->SetLastError(g_ErrIsDrawing);
1822 // ---------------------------------------------------------------------------
1825 static inline int TwFreeAsyncProcessing()
1827 if( g_TwMgr && g_TwMgr->IsProcessing() )
1829 const double SLEEP_MAX = 0.25; // wait at most 1/4 second
1831 while( g_TwMgr->IsProcessing() && timer.GetTime()<SLEEP_MAX )
1833 #if defined(ANT_WINDOWS)
1834 Sleep(1); // milliseconds
1835 #elif defined(ANT_UNIX)
1836 usleep(1000); // microseconds
1839 if( g_TwMgr->IsProcessing() )
1841 g_TwMgr->SetLastError(g_ErrIsProcessing);
1848 static inline int TwBeginProcessing()
1850 if( !TwFreeAsyncProcessing() )
1853 g_TwMgr->SetProcessing(true);
1856 static inline int TwEndProcessing()
1859 g_TwMgr->SetProcessing(false);
1863 // ---------------------------------------------------------------------------
1865 static int TwInitMgr()
1867 assert( g_TwMasterMgr!=NULL );
1868 assert( g_TwMgr!=NULL );
1870 g_TwMgr->m_CurrentFont = g_DefaultNormalFont;
1871 g_TwMgr->m_Graph = g_TwMasterMgr->m_Graph;
1873 g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj();
1874 g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj();
1876 g_TwMgr->m_HelpBar = TwNewBar("TW_HELP");
1877 if( g_TwMgr->m_HelpBar )
1879 g_TwMgr->m_HelpBar->m_Label = "~ Help & Shortcuts ~";
1880 g_TwMgr->m_HelpBar->m_PosX = 32;
1881 g_TwMgr->m_HelpBar->m_PosY = 32;
1882 g_TwMgr->m_HelpBar->m_Width = 400;
1883 g_TwMgr->m_HelpBar->m_Height = 200;
1884 g_TwMgr->m_HelpBar->m_ValuesWidth = 12*(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2);
1885 g_TwMgr->m_HelpBar->m_Color = 0xa05f5f5f; //0xd75f5f5f;
1886 g_TwMgr->m_HelpBar->m_DarkText = false;
1887 g_TwMgr->m_HelpBar->m_IsHelpBar = true;
1888 g_TwMgr->Minimize(g_TwMgr->m_HelpBar);
1893 CColorExt::CreateTypes();
1894 CQuaternionExt::CreateTypes();
1900 int ANT_CALL TwInit(ETwGraphAPI _GraphAPI, void *_Device)
1902 #if defined(_DEBUG) && defined(ANT_WINDOWS)
1903 _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF));
1906 if( g_TwMasterMgr!=NULL )
1908 g_TwMasterMgr->SetLastError(g_ErrInit);
1911 assert( g_TwMgr==0 );
1912 assert( g_Wnds.empty() );
1914 g_TwMasterMgr = new CTwMgr(_GraphAPI, _Device, TW_MASTER_WINDOW_ID);
1915 g_Wnds[TW_MASTER_WINDOW_ID] = g_TwMasterMgr;
1916 g_TwMgr = g_TwMasterMgr;
1918 TwGenerateDefaultFonts();
1919 g_TwMgr->m_CurrentFont = g_DefaultNormalFont;
1921 int Res = TwCreateGraph(_GraphAPI);
1931 // ---------------------------------------------------------------------------
1933 int ANT_CALL TwSetLastError(const char *_StaticErrorMessage)
1935 if( g_TwMasterMgr!=0 )
1937 g_TwMasterMgr->SetLastError(_StaticErrorMessage);
1944 // ---------------------------------------------------------------------------
1946 int ANT_CALL TwTerminate()
1950 //TwGlobalError(g_ErrShut); -> not an error
1951 return 0; // already shutdown
1954 // For multi-thread safety
1955 if( !TwFreeAsyncDrawing() )
1958 CTwWndMap::iterator it;
1959 for( it=g_Wnds.begin(); it!=g_Wnds.end(); it++ )
1961 g_TwMgr = it->second;
1963 g_TwMgr->m_Terminating = true;
1965 if( g_TwMgr->m_CursorsCreated )
1966 g_TwMgr->FreeCursors();
1968 if( g_TwMgr->m_Graph )
1970 if( g_TwMgr->m_KeyPressedTextObj )
1972 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj);
1973 g_TwMgr->m_KeyPressedTextObj = NULL;
1975 if( g_TwMgr->m_InfoTextObj )
1977 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj);
1978 g_TwMgr->m_InfoTextObj = NULL;
1980 if (g_TwMgr != g_TwMasterMgr)
1981 g_TwMgr->m_Graph = NULL;
1984 if (g_TwMgr != g_TwMasterMgr)
1991 // delete g_TwMasterMgr
1993 g_TwMgr = g_TwMasterMgr;
1994 if( g_TwMasterMgr->m_Graph )
1996 Res = g_TwMasterMgr->m_Graph->Shut();
1997 delete g_TwMasterMgr->m_Graph;
1998 g_TwMasterMgr->m_Graph = NULL;
2000 TwDeleteDefaultFonts();
2001 delete g_TwMasterMgr;
2002 g_TwMasterMgr = NULL;
2009 // ---------------------------------------------------------------------------
2011 int ANT_CALL TwGetCurrentWindow()
2015 TwGlobalError(g_ErrNotInit);
2016 return 0; // not initialized
2019 return g_TwMgr->m_WndID;
2022 int ANT_CALL TwSetCurrentWindow(int wndID)
2026 TwGlobalError(g_ErrNotInit);
2027 return 0; // not initialized
2030 if (wndID != g_TwMgr->m_WndID)
2032 CTwWndMap::iterator foundWnd = g_Wnds.find(wndID);
2033 if (foundWnd == g_Wnds.end())
2035 // create a new CTwMgr
2036 g_TwMgr = new CTwMgr(g_TwMasterMgr->m_GraphAPI, g_TwMasterMgr->m_Device, wndID);
2037 g_Wnds[wndID] = g_TwMgr;
2042 g_TwMgr = foundWnd->second;
2050 int ANT_CALL TwWindowExists(int wndID)
2052 CTwWndMap::iterator foundWnd = g_Wnds.find(wndID);
2053 if (foundWnd == g_Wnds.end())
2059 // ---------------------------------------------------------------------------
2061 int ANT_CALL TwDraw()
2063 PERF( PerfTimer Timer; double DT; )
2064 //CTwFPU fpu; // fpu precision only forced in update (do not modif dx draw calls)
2066 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2068 TwGlobalError(g_ErrNotInit);
2069 return 0; // not initialized
2072 assert(g_TwMgr->m_Bars.size()==g_TwMgr->m_Order.size());
2074 // For multi-thread savety
2075 if( !TwFreeAsyncDrawing() )
2079 #if defined(ANT_WINDOWS) || defined(ANT_OSX)
2080 if( !g_TwMgr->m_CursorsCreated )
2081 g_TwMgr->CreateCursors();
2082 #elif defined(ANT_UNIX)
2083 if( !g_TwMgr->m_CurrentXDisplay )
2084 g_TwMgr->m_CurrentXDisplay = glXGetCurrentDisplay();
2085 if( !g_TwMgr->m_CurrentXWindow )
2086 g_TwMgr->m_CurrentXWindow = glXGetCurrentDrawable();
2087 if( g_TwMgr->m_CurrentXDisplay && !g_TwMgr->m_CursorsCreated )
2088 g_TwMgr->CreateCursors();
2091 // Autorepeat TW_MOUSE_PRESSED
2092 double CurrTime = g_TwMgr->m_Timer.GetTime();
2093 double RepeatDT = CurrTime - g_TwMgr->m_LastMousePressedTime;
2094 double DrawDT = CurrTime - g_TwMgr->m_LastDrawTime;
2095 if( RepeatDT>2.0*g_TwMgr->m_RepeatMousePressedDelay
2096 || DrawDT>2.0*g_TwMgr->m_RepeatMousePressedDelay
2097 || abs(g_TwMgr->m_LastMousePressedPosition[0]-g_TwMgr->m_LastMouseX)>4
2098 || abs(g_TwMgr->m_LastMousePressedPosition[1]-g_TwMgr->m_LastMouseY)>4 )
2100 g_TwMgr->m_CanRepeatMousePressed = false;
2101 g_TwMgr->m_IsRepeatingMousePressed = false;
2103 if( g_TwMgr->m_CanRepeatMousePressed )
2105 if( (!g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedDelay)
2106 || (g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedPeriod) )
2108 g_TwMgr->m_IsRepeatingMousePressed = true;
2109 g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
2110 TwMouseButton(TW_MOUSE_PRESSED, g_TwMgr->m_LastMousePressedButtonID);
2113 g_TwMgr->m_LastDrawTime = CurrTime;
2115 if( g_TwMgr->m_WndWidth<0 || g_TwMgr->m_WndHeight<0 )
2117 g_TwMgr->SetLastError(g_ErrBadSize);
2120 else if( g_TwMgr->m_WndWidth==0 || g_TwMgr->m_WndHeight==0 ) // probably iconified
2121 return 1; // nothing to do
2123 // count number of bars to draw
2126 for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
2127 if( g_TwMgr->m_Bars[i]!=NULL && g_TwMgr->m_Bars[i]->m_Visible )
2132 PERF( Timer.Reset(); )
2133 g_TwMgr->m_Graph->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight);
2134 PERF( DT = Timer.GetTime(); printf("\nBegin=%.4fms ", 1000.0*DT); )
2136 PERF( Timer.Reset(); )
2137 vector<CRect> TopBarsRects, ClippedBarRects;
2138 for( i=0; i<g_TwMgr->m_Bars.size(); ++i )
2140 CTwBar *Bar = g_TwMgr->m_Bars[ g_TwMgr->m_Order[i] ];
2141 if( Bar->m_Visible )
2143 if( g_TwMgr->m_OverlapContent || Bar->IsMinimized() )
2147 // Clip overlapped transparent bars to make them more readable
2148 const int Margin = 4;
2149 CRect BarRect(Bar->m_PosX - Margin, Bar->m_PosY - Margin, Bar->m_Width + 2*Margin, Bar->m_Height + 2*Margin);
2150 TopBarsRects.clear();
2151 for( j=i+1; j<g_TwMgr->m_Bars.size(); ++j )
2153 CTwBar *TopBar = g_TwMgr->m_Bars[g_TwMgr->m_Order[j]];
2154 if( TopBar->m_Visible && !TopBar->IsMinimized() )
2155 TopBarsRects.push_back(CRect(TopBar->m_PosX, TopBar->m_PosY, TopBar->m_Width, TopBar->m_Height));
2157 ClippedBarRects.clear();
2158 BarRect.Subtract(TopBarsRects, ClippedBarRects);
2160 if( ClippedBarRects.size()==1 && ClippedBarRects[0]==BarRect )
2161 //g_TwMgr->m_Graph->DrawRect(Bar->m_PosX, Bar->m_PosY, Bar->m_PosX+Bar->m_Width-1, Bar->m_PosY+Bar->m_Height-1, 0x70ffffff); // Clipping test
2162 Bar->Draw(); // unclipped
2165 Bar->Draw(CTwBar::DRAW_BG); // draw background only
2167 // draw content for each clipped rectangle
2168 for( j=0; j<ClippedBarRects.size(); j++ )
2169 if (ClippedBarRects[j].W>1 && ClippedBarRects[j].H>1)
2171 g_TwMgr->m_Graph->SetScissor(ClippedBarRects[j].X+1, ClippedBarRects[j].Y, ClippedBarRects[j].W, ClippedBarRects[j].H-1);
2172 //g_TwMgr->m_Graph->DrawRect(0, 0, 1000, 1000, 0x70ffffff); // Clipping test
2173 Bar->Draw(CTwBar::DRAW_CONTENT);
2175 g_TwMgr->m_Graph->SetScissor(0, 0, 0, 0);
2180 PERF( DT = Timer.GetTime(); printf("Draw=%.4fms ", 1000.0*DT); )
2182 PERF( Timer.Reset(); )
2183 g_TwMgr->m_Graph->EndDraw();
2184 PERF( DT = Timer.GetTime(); printf("End=%.4fms\n", 1000.0*DT); )
2190 // ---------------------------------------------------------------------------
2192 int ANT_CALL TwWindowSize(int _Width, int _Height)
2194 g_InitWndWidth = _Width;
2195 g_InitWndHeight = _Height;
2197 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2199 //TwGlobalError(g_ErrNotInit); -> not an error here
2200 return 0; // not initialized
2203 if( _Width<0 || _Height<0 )
2205 g_TwMgr->SetLastError(g_ErrBadSize);
2209 // For multi-thread savety
2210 if( !TwFreeAsyncDrawing() )
2213 // Delete the extra text objects
2214 if( g_TwMgr->m_KeyPressedTextObj )
2216 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj);
2217 g_TwMgr->m_KeyPressedTextObj = NULL;
2219 if( g_TwMgr->m_InfoTextObj )
2221 g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj);
2222 g_TwMgr->m_InfoTextObj = NULL;
2225 g_TwMgr->m_WndWidth = _Width;
2226 g_TwMgr->m_WndHeight = _Height;
2227 g_TwMgr->m_Graph->Restore();
2229 // Recreate extra text objects
2230 if( g_TwMgr->m_WndWidth!=0 && g_TwMgr->m_WndHeight!=0 )
2232 if( g_TwMgr->m_KeyPressedTextObj==NULL )
2234 g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj();
2235 g_TwMgr->m_KeyPressedBuildText = true;
2237 if( g_TwMgr->m_InfoTextObj==NULL )
2239 g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj();
2240 g_TwMgr->m_InfoBuildText = true;
2244 for( std::vector<TwBar*>::iterator it=g_TwMgr->m_Bars.begin(); it!=g_TwMgr->m_Bars.end(); ++it )
2245 (*it)->NotUpToDate();
2250 // ---------------------------------------------------------------------------
2252 CTwMgr::CTwMgr(ETwGraphAPI _GraphAPI, void *_Device, int _WndID)
2254 m_GraphAPI = _GraphAPI;
2258 m_CurrentDbgFile = "";
2259 m_CurrentDbgLine = 0;
2260 //m_Processing = false;
2262 m_WndWidth = g_InitWndWidth;
2263 m_WndHeight = g_InitWndHeight;
2264 m_CurrentFont = NULL; // set after by TwIntialize
2265 m_NbMinimizedBars = 0;
2267 m_HelpBarNotUpToDate = true;
2268 m_HelpBarUpdateNow = false;
2269 m_LastHelpUpdateTime = 0;
2272 m_LastMouseWheelPos = 0;
2275 m_IconMarginX = m_IconMarginY = 8;
2276 m_FontResizable = true;
2277 m_KeyPressedTextObj = NULL;
2278 m_KeyPressedBuildText = false;
2279 m_KeyPressedTime = 0;
2280 m_InfoTextObj = NULL;
2281 m_InfoBuildText = true;
2282 m_BarInitColorHue = 155;
2284 m_TypeColor32 = TW_TYPE_UNDEF;
2285 m_TypeColor3F = TW_TYPE_UNDEF;
2286 m_TypeColor4F = TW_TYPE_UNDEF;
2287 m_LastMousePressedTime = 0;
2288 m_LastMousePressedButtonID = TW_MOUSE_MIDDLE;
2289 m_LastMousePressedPosition[0] = -1000;
2290 m_LastMousePressedPosition[1] = -1000;
2291 m_RepeatMousePressedDelay = 0.5;
2292 m_RepeatMousePressedPeriod = 0.1;
2293 m_CanRepeatMousePressed = false;
2294 m_IsRepeatingMousePressed = false;
2296 m_UseOldColorScheme = false;
2297 m_Contained = false;
2298 m_ButtonAlign = BUTTON_ALIGN_RIGHT;
2299 m_OverlapContent = false;
2300 m_Terminating = false;
2302 m_CursorsCreated = false;
2303 #if defined(ANT_UNIX)
2304 m_CurrentXDisplay = NULL;
2305 m_CurrentXWindow = 0;
2306 #endif // defined(ANT_UNIX)
2308 m_CopyCDStringToClient = g_InitCopyCDStringToClient;
2309 m_CopyStdStringToClient = g_InitCopyStdStringToClient;
2310 m_ClientStdStringStructSize = 0;
2311 m_ClientStdStringBaseType = (TwType)0;
2314 // ---------------------------------------------------------------------------
2320 // ---------------------------------------------------------------------------
2322 int CTwMgr::FindBar(const char *_Name) const
2324 if( _Name==NULL || strlen(_Name)<=0 )
2327 for( i=0; i<(int)m_Bars.size(); ++i )
2328 if( m_Bars[i]!=NULL && strcmp(_Name, m_Bars[i]->m_Name.c_str())==0 )
2334 // ---------------------------------------------------------------------------
2336 int CTwMgr::HasAttrib(const char *_Attrib, bool *_HasValue) const
2339 if( _stricmp(_Attrib, "help")==0 )
2341 else if( _stricmp(_Attrib, "fontsize")==0 )
2342 return MGR_FONT_SIZE;
2343 else if( _stricmp(_Attrib, "fontstyle")==0 )
2344 return MGR_FONT_STYLE;
2345 else if( _stricmp(_Attrib, "iconpos")==0 )
2346 return MGR_ICON_POS;
2347 else if( _stricmp(_Attrib, "iconalign")==0 )
2348 return MGR_ICON_ALIGN;
2349 else if( _stricmp(_Attrib, "iconmargin")==0 )
2350 return MGR_ICON_MARGIN;
2351 else if( _stricmp(_Attrib, "fontresizable")==0 )
2352 return MGR_FONT_RESIZABLE;
2353 else if( _stricmp(_Attrib, "colorscheme")==0 )
2354 return MGR_COLOR_SCHEME;
2355 else if( _stricmp(_Attrib, "contained")==0 )
2356 return MGR_CONTAINED;
2357 else if( _stricmp(_Attrib, "buttonalign")==0 )
2358 return MGR_BUTTON_ALIGN;
2359 else if( _stricmp(_Attrib, "overlap")==0 )
2363 return 0; // not found
2366 int CTwMgr::SetAttrib(int _AttribID, const char *_Value)
2371 if( _Value && strlen(_Value)>0 )
2374 m_HelpBarNotUpToDate = true;
2379 SetLastError(g_ErrNoValue);
2383 if( _Value && strlen(_Value)>0 )
2386 int n = sscanf(_Value, "%d", &s);
2387 if( n==1 && s>=1 && s<=3 )
2390 SetFont(g_DefaultSmallFont, true);
2392 SetFont(g_DefaultNormalFont, true);
2394 SetFont(g_DefaultLargeFont, true);
2399 SetLastError(g_ErrBadValue);
2405 SetLastError(g_ErrNoValue);
2408 case MGR_FONT_STYLE:
2409 if( _Value && strlen(_Value)>0 )
2411 if( _stricmp(_Value, "fixed")==0 )
2413 if( m_CurrentFont!=g_DefaultFixed1Font )
2415 SetFont(g_DefaultFixed1Font, true);
2416 m_FontResizable = false; // for now fixed font is not resizable
2420 else if( _stricmp(_Value, "default")==0 )
2422 if( m_CurrentFont!=g_DefaultSmallFont && m_CurrentFont!=g_DefaultNormalFont && m_CurrentFont!=g_DefaultLargeFont )
2424 if( m_CurrentFont == g_DefaultFixed1Font )
2425 m_FontResizable = true;
2426 SetFont(g_DefaultNormalFont, true);
2432 SetLastError(g_ErrBadValue);
2438 SetLastError(g_ErrNoValue);
2442 if( _Value && strlen(_Value)>0 )
2444 if( _stricmp(_Value, "bl")==0 || _stricmp(_Value, "lb")==0 || _stricmp(_Value, "bottomleft")==0 || _stricmp(_Value, "leftbottom")==0 )
2449 else if( _stricmp(_Value, "br")==0 || _stricmp(_Value, "rb")==0 || _stricmp(_Value, "bottomright")==0 || _stricmp(_Value, "rightbottom")==0 )
2454 else if( _stricmp(_Value, "tl")==0 || _stricmp(_Value, "lt")==0 || _stricmp(_Value, "topleft")==0 || _stricmp(_Value, "lefttop")==0 )
2459 else if( _stricmp(_Value, "tr")==0 || _stricmp(_Value, "rt")==0 || _stricmp(_Value, "topright")==0 || _stricmp(_Value, "righttop")==0 )
2466 SetLastError(g_ErrBadValue);
2472 SetLastError(g_ErrNoValue);
2475 case MGR_ICON_ALIGN:
2476 if( _Value && strlen(_Value)>0 )
2478 if( _stricmp(_Value, "vert")==0 || _stricmp(_Value, "vertical")==0 )
2483 else if( _stricmp(_Value, "horiz")==0 || _stricmp(_Value, "horizontal")==0 )
2490 SetLastError(g_ErrBadValue);
2496 SetLastError(g_ErrNoValue);
2499 case MGR_ICON_MARGIN:
2500 if( _Value && strlen(_Value)>0 )
2503 int n = sscanf(_Value, "%d%d", &x, &y);
2504 if( n==2 && x>=0 && y>=0 )
2512 SetLastError(g_ErrBadValue);
2518 SetLastError(g_ErrNoValue);
2521 case MGR_FONT_RESIZABLE:
2522 if( _Value && strlen(_Value)>0 )
2524 if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2526 m_FontResizable = true;
2529 else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2531 m_FontResizable = false;
2536 g_TwMgr->SetLastError(g_ErrBadValue);
2542 g_TwMgr->SetLastError(g_ErrNoValue);
2545 case MGR_COLOR_SCHEME:
2546 if( _Value && strlen(_Value)>0 )
2549 int n = sscanf(_Value, "%d", &s);
2550 if( n==1 && s>=0 && s<=1 )
2553 m_UseOldColorScheme = true;
2555 m_UseOldColorScheme = false;
2560 SetLastError(g_ErrBadValue);
2566 g_TwMgr->SetLastError(g_ErrNoValue);
2570 if( _Value && strlen(_Value)>0 )
2572 if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2574 else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2575 m_Contained = false;
2578 g_TwMgr->SetLastError(g_ErrBadValue);
2581 vector<TwBar*>::iterator barIt;
2582 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2583 if( (*barIt)!=NULL )
2584 (*barIt)->m_Contained = m_Contained;
2589 g_TwMgr->SetLastError(g_ErrNoValue);
2592 case MGR_BUTTON_ALIGN:
2593 if( _Value && strlen(_Value)>0 )
2595 if( _stricmp(_Value, "left")==0 )
2596 m_ButtonAlign = BUTTON_ALIGN_LEFT;
2597 else if( _stricmp(_Value, "center")==0 )
2598 m_ButtonAlign = BUTTON_ALIGN_CENTER;
2599 else if( _stricmp(_Value, "right")==0 )
2600 m_ButtonAlign = BUTTON_ALIGN_RIGHT;
2603 g_TwMgr->SetLastError(g_ErrBadValue);
2606 vector<TwBar*>::iterator barIt;
2607 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2608 if( (*barIt)!=NULL )
2609 (*barIt)->m_ButtonAlign = m_ButtonAlign;
2614 g_TwMgr->SetLastError(g_ErrNoValue);
2618 if( _Value && strlen(_Value)>0 )
2620 if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
2622 m_OverlapContent = true;
2625 else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
2627 m_OverlapContent = false;
2632 g_TwMgr->SetLastError(g_ErrBadValue);
2638 g_TwMgr->SetLastError(g_ErrNoValue);
2642 g_TwMgr->SetLastError(g_ErrUnknownAttrib);
2647 ERetType CTwMgr::GetAttrib(int _AttribID, std::vector<double>& outDoubles, std::ostringstream& outString) const
2655 outString << m_Help;
2658 if( m_CurrentFont==g_DefaultSmallFont )
2659 outDoubles.push_back(1);
2660 else if( m_CurrentFont==g_DefaultNormalFont )
2661 outDoubles.push_back(2);
2662 else if( m_CurrentFont==g_DefaultLargeFont )
2663 outDoubles.push_back(3);
2665 outDoubles.push_back(0); // should not happened
2667 case MGR_FONT_STYLE:
2668 if( m_CurrentFont==g_DefaultFixed1Font )
2669 outString << "fixed";
2671 outString << "default";
2675 outString << "bottomleft";
2676 else if( m_IconPos==1 )
2677 outString << "bottomright";
2678 else if( m_IconPos==2 )
2679 outString << "topleft";
2680 else if( m_IconPos==3 )
2681 outString << "topright";
2683 outString << "undefined"; // should not happened
2685 case MGR_ICON_ALIGN:
2686 if( m_IconAlign==0 )
2687 outString << "vertical";
2688 else if( m_IconAlign==1 )
2689 outString << "horizontal";
2691 outString << "undefined"; // should not happened
2693 case MGR_ICON_MARGIN:
2694 outDoubles.push_back(m_IconMarginX);
2695 outDoubles.push_back(m_IconMarginY);
2697 case MGR_FONT_RESIZABLE:
2698 outDoubles.push_back(m_FontResizable);
2700 case MGR_COLOR_SCHEME:
2701 outDoubles.push_back(m_UseOldColorScheme ? 0 : 1);
2705 bool contained = m_Contained;
2709 vector<TwBar*>::iterator barIt;
2710 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt )
2711 if( (*barIt)!=NULL && !(*barIt)->m_Contained )
2718 outDoubles.push_back(contained);
2721 case MGR_BUTTON_ALIGN:
2722 if( m_ButtonAlign==BUTTON_ALIGN_LEFT )
2723 outString << "left";
2724 else if( m_ButtonAlign==BUTTON_ALIGN_CENTER )
2725 outString << "center";
2727 outString << "right";
2730 outDoubles.push_back(m_OverlapContent);
2733 g_TwMgr->SetLastError(g_ErrUnknownAttrib);
2738 // ---------------------------------------------------------------------------
2740 void CTwMgr::Minimize(TwBar *_Bar)
2742 assert(m_Graph!=NULL && _Bar!=NULL);
2743 assert(m_Bars.size()==m_MinOccupied.size());
2744 if( _Bar->m_IsMinimized )
2746 if( _Bar->m_Visible )
2748 size_t i = m_NbMinimizedBars;
2749 m_NbMinimizedBars++;
2750 for( i=0; i<m_MinOccupied.size(); ++i )
2751 if( !m_MinOccupied[i] )
2753 if( i<m_MinOccupied.size() )
2754 m_MinOccupied[i] = true;
2755 _Bar->m_MinNumber = (int)i;
2758 _Bar->m_MinNumber = -1;
2759 _Bar->m_IsMinimized = true;
2760 _Bar->NotUpToDate();
2763 // ---------------------------------------------------------------------------
2765 void CTwMgr::Maximize(TwBar *_Bar)
2767 assert(m_Graph!=NULL && _Bar!=NULL);
2768 assert(m_Bars.size()==m_MinOccupied.size());
2769 if( !_Bar->m_IsMinimized )
2771 if( _Bar->m_Visible )
2773 --m_NbMinimizedBars;
2774 if( m_NbMinimizedBars<0 )
2775 m_NbMinimizedBars = 0;
2776 if( _Bar->m_MinNumber>=0 && _Bar->m_MinNumber<(int)m_MinOccupied.size() )
2777 m_MinOccupied[_Bar->m_MinNumber] = false;
2779 _Bar->m_IsMinimized = false;
2780 _Bar->NotUpToDate();
2781 if( _Bar->m_IsHelpBar )
2782 m_HelpBarNotUpToDate = true;
2785 // ---------------------------------------------------------------------------
2787 void CTwMgr::Hide(TwBar *_Bar)
2789 assert(m_Graph!=NULL && _Bar!=NULL);
2790 if( !_Bar->m_Visible )
2792 if( _Bar->IsMinimized() )
2795 _Bar->m_Visible = false;
2799 _Bar->m_Visible = false;
2800 if( !_Bar->m_IsHelpBar )
2801 m_HelpBarNotUpToDate = true;
2804 // ---------------------------------------------------------------------------
2806 void CTwMgr::Unhide(TwBar *_Bar)
2808 assert(m_Graph!=NULL && _Bar!=NULL);
2809 if( _Bar->m_Visible )
2811 if( _Bar->IsMinimized() )
2814 _Bar->m_Visible = true;
2818 _Bar->m_Visible = true;
2819 _Bar->NotUpToDate();
2820 if( !_Bar->m_IsHelpBar )
2821 m_HelpBarNotUpToDate = true;
2824 // ---------------------------------------------------------------------------
2826 void CTwMgr::SetFont(const CTexFont *_Font, bool _ResizeBars)
2828 assert(m_Graph!=NULL);
2829 assert(_Font!=NULL);
2831 m_CurrentFont = _Font;
2833 for( int i=0; i<(int)m_Bars.size(); ++i )
2834 if( m_Bars[i]!=NULL )
2836 int fh = m_Bars[i]->m_Font->m_CharHeight;
2837 m_Bars[i]->m_Font = _Font;
2840 if( m_Bars[i]->m_Movable )
2842 m_Bars[i]->m_PosX += (3*(fh-_Font->m_CharHeight))/2;
2843 m_Bars[i]->m_PosY += (fh-_Font->m_CharHeight)/2;
2845 if( m_Bars[i]->m_Resizable )
2847 m_Bars[i]->m_Width = (m_Bars[i]->m_Width*_Font->m_CharHeight)/fh;
2848 m_Bars[i]->m_Height = (m_Bars[i]->m_Height*_Font->m_CharHeight)/fh;
2849 m_Bars[i]->m_ValuesWidth = (m_Bars[i]->m_ValuesWidth*_Font->m_CharHeight)/fh;
2852 m_Bars[i]->NotUpToDate();
2855 if( g_TwMgr->m_HelpBar!=NULL )
2856 g_TwMgr->m_HelpBar->Update();
2857 g_TwMgr->m_InfoBuildText = true;
2858 g_TwMgr->m_KeyPressedBuildText = true;
2859 m_HelpBarNotUpToDate = true;
2862 // ---------------------------------------------------------------------------
2864 void ANT_CALL TwGlobalError(const char *_ErrorMessage) // to be called when g_TwMasterMgr is not created
2866 if( g_ErrorHandler==NULL )
2868 fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", _ErrorMessage);
2870 OutputDebugString("ERROR(AntTweakBar) >> ");
2871 OutputDebugString(_ErrorMessage);
2872 OutputDebugString("\n");
2873 #endif // ANT_WINDOWS
2876 g_ErrorHandler(_ErrorMessage);
2878 if( g_BreakOnError )
2882 // ---------------------------------------------------------------------------
2884 void CTwMgr::SetLastError(const char *_ErrorMessage) // _ErrorMessage must be a static string
2886 if (this != g_TwMasterMgr)
2889 g_TwMasterMgr->SetLastError(_ErrorMessage);
2893 m_LastError = _ErrorMessage;
2895 if( g_ErrorHandler==NULL )
2897 if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
2898 fprintf(stderr, "%s(%d): ", m_CurrentDbgFile, m_CurrentDbgLine);
2899 fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", m_LastError);
2901 if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 )
2903 OutputDebugString(m_CurrentDbgFile);
2905 sprintf(sl, "(%d): ", m_CurrentDbgLine);
2906 OutputDebugString(sl);
2908 OutputDebugString("ERROR(AntTweakBar) >> ");
2909 OutputDebugString(m_LastError);
2910 OutputDebugString("\n");
2911 #endif // ANT_WINDOWS
2914 g_ErrorHandler(_ErrorMessage);
2916 if( g_BreakOnError )
2920 // ---------------------------------------------------------------------------
2922 const char *CTwMgr::GetLastError()
2924 if (this != g_TwMasterMgr)
2927 return g_TwMasterMgr->GetLastError();
2930 const char *Err = m_LastError;
2935 // ---------------------------------------------------------------------------
2937 const char *CTwMgr::CheckLastError() const
2942 // ---------------------------------------------------------------------------
2944 void CTwMgr::SetCurrentDbgParams(const char *dbgFile, int dbgLine)
2946 m_CurrentDbgFile = dbgFile;
2947 m_CurrentDbgLine = dbgLine;
2950 // ---------------------------------------------------------------------------
2952 int ANT_CALL __TwDbg(const char *dbgFile, int dbgLine)
2955 g_TwMgr->SetCurrentDbgParams(dbgFile, dbgLine);
2956 return 0; // always returns zero
2959 // ---------------------------------------------------------------------------
2961 void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler, int _BreakOnError)
2963 g_ErrorHandler = _ErrorHandler;
2964 g_BreakOnError = (_BreakOnError) ? true : false;
2967 void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler)
2969 TwHandleErrors(_ErrorHandler, false);
2972 // ---------------------------------------------------------------------------
2974 const char *ANT_CALL TwGetLastError()
2976 if( g_TwMasterMgr==NULL )
2978 TwGlobalError(g_ErrNotInit);
2979 return g_ErrNotInit;
2982 return g_TwMasterMgr->GetLastError();
2985 // ---------------------------------------------------------------------------
2987 TwBar *ANT_CALL TwNewBar(const char *_Name)
2989 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
2991 TwGlobalError(g_ErrNotInit);
2992 return NULL; // not initialized
2995 TwFreeAsyncDrawing(); // For multi-thread savety
2997 if( _Name==NULL || strlen(_Name)<=0 )
2999 g_TwMgr->SetLastError(g_ErrBadParam);
3002 if( g_TwMgr->FindBar(_Name)>=0 )
3004 g_TwMgr->SetLastError(g_ErrExist);
3008 if( strstr(_Name, "`")!=NULL )
3010 g_TwMgr->SetLastError(g_ErrNoBackQuote);
3014 if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar if it exists
3016 TwDeleteBar(g_TwMgr->m_PopupBar);
3017 g_TwMgr->m_PopupBar = NULL;
3020 TwBar *Bar = new CTwBar(_Name);
3021 g_TwMgr->m_Bars.push_back(Bar);
3022 g_TwMgr->m_Order.push_back((int)g_TwMgr->m_Bars.size()-1);
3023 g_TwMgr->m_MinOccupied.push_back(false);
3024 g_TwMgr->m_HelpBarNotUpToDate = true;
3029 // ---------------------------------------------------------------------------
3031 int ANT_CALL TwDeleteBar(TwBar *_Bar)
3035 TwGlobalError(g_ErrNotInit);
3036 return 0; // not initialized
3040 g_TwMgr->SetLastError(g_ErrBadParam);
3043 if( _Bar==g_TwMgr->m_HelpBar )
3045 g_TwMgr->SetLastError(g_ErrDelHelp);
3049 TwFreeAsyncDrawing(); // For multi-thread savety
3051 vector<TwBar*>::iterator BarIt;
3053 for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3054 if( (*BarIt)==_Bar )
3056 if( BarIt==g_TwMgr->m_Bars.end() )
3058 g_TwMgr->SetLastError(g_ErrNotFound);
3062 if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists
3064 TwDeleteBar(g_TwMgr->m_PopupBar);
3065 g_TwMgr->m_PopupBar = NULL;
3068 // force bar to un-minimize
3069 g_TwMgr->Maximize(_Bar);
3070 // find an empty MinOccupied
3071 vector<bool>::iterator itm;
3073 for( itm=g_TwMgr->m_MinOccupied.begin(); itm!=g_TwMgr->m_MinOccupied.end(); ++itm, ++j)
3076 assert( itm!=g_TwMgr->m_MinOccupied.end() );
3077 // shift MinNumbers and erase the empty MinOccupied
3078 for( size_t k=0; k<g_TwMgr->m_Bars.size(); ++k )
3079 if( g_TwMgr->m_Bars[k]!=NULL && g_TwMgr->m_Bars[k]->m_MinNumber>j )
3080 g_TwMgr->m_Bars[k]->m_MinNumber -= 1;
3081 g_TwMgr->m_MinOccupied.erase(itm);
3083 vector<int>::iterator BarOrderIt = g_TwMgr->m_Order.end();
3084 for(vector<int>::iterator it=g_TwMgr->m_Order.begin(); it!=g_TwMgr->m_Order.end(); ++it )
3089 assert( BarOrderIt!=g_TwMgr->m_Order.end() );
3090 g_TwMgr->m_Order.erase(BarOrderIt);
3092 // erase & delete _Bar
3093 g_TwMgr->m_Bars.erase(BarIt);
3096 g_TwMgr->m_HelpBarNotUpToDate = true;
3100 // ---------------------------------------------------------------------------
3102 int ANT_CALL TwDeleteAllBars()
3106 TwGlobalError(g_ErrNotInit);
3107 return 0; // not initialized
3110 TwFreeAsyncDrawing(); // For multi-thread savety
3113 if( g_TwMgr->m_Terminating || g_TwMgr->m_HelpBar==NULL )
3115 for( size_t i=0; i<g_TwMgr->m_Bars.size(); ++i )
3116 if( g_TwMgr->m_Bars[i]!=NULL )
3119 delete g_TwMgr->m_Bars[i];
3120 g_TwMgr->m_Bars[i] = NULL;
3122 g_TwMgr->m_Bars.clear();
3123 g_TwMgr->m_Order.clear();
3124 g_TwMgr->m_MinOccupied.clear();
3125 g_TwMgr->m_HelpBarNotUpToDate = true;
3129 vector<CTwBar *> bars = g_TwMgr->m_Bars;
3130 for( size_t i = 0; i < bars.size(); ++i )
3131 if( bars[i]!=0 && bars[i]!=g_TwMgr->m_HelpBar)
3134 TwDeleteBar(bars[i]);
3136 g_TwMgr->m_HelpBarNotUpToDate = true;
3141 //g_TwMgr->SetLastError(g_ErrNthToDo);
3148 // ---------------------------------------------------------------------------
3150 int ANT_CALL TwSetTopBar(const TwBar *_Bar)
3154 TwGlobalError(g_ErrNotInit);
3155 return 0; // not initialized
3159 g_TwMgr->SetLastError(g_ErrBadParam);
3163 TwFreeAsyncDrawing(); // For multi-thread savety
3165 if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 )
3167 if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnBottom.c_str())==0 )
3168 return TwSetBottomBar(_Bar);
3172 for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder )
3174 i = g_TwMgr->m_Order[iOrder];
3175 assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() );
3176 if( g_TwMgr->m_Bars[i]==_Bar )
3179 if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() ) // bar not found
3181 g_TwMgr->SetLastError(g_ErrNotFound);
3185 for( int j=iOrder; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
3186 g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
3187 g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = i;
3189 if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 )
3191 int topIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnTop.c_str());
3192 TwBar *top = (topIdx>=0 && topIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[topIdx] : NULL;
3193 if( top!=NULL && top!=_Bar )
3197 if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar )
3198 TwSetTopBar(g_TwMgr->m_PopupBar);
3203 // ---------------------------------------------------------------------------
3205 TwBar * ANT_CALL TwGetTopBar()
3209 TwGlobalError(g_ErrNotInit);
3210 return NULL; // not initialized
3213 if( g_TwMgr->m_Bars.size()>0 && g_TwMgr->m_PopupBar==NULL )
3214 return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-1 ]];
3215 else if( g_TwMgr->m_Bars.size()>1 && g_TwMgr->m_PopupBar!=NULL )
3216 return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-2 ]];
3221 // ---------------------------------------------------------------------------
3223 int ANT_CALL TwSetBottomBar(const TwBar *_Bar)
3227 TwGlobalError(g_ErrNotInit);
3228 return 0; // not initialized
3232 g_TwMgr->SetLastError(g_ErrBadParam);
3236 TwFreeAsyncDrawing(); // For multi-thread savety
3238 if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 )
3240 if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnTop.c_str())==0 )
3241 return TwSetTopBar(_Bar);
3245 for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder )
3247 i = g_TwMgr->m_Order[iOrder];
3248 assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() );
3249 if( g_TwMgr->m_Bars[i]==_Bar )
3252 if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() ) // bar not found
3254 g_TwMgr->SetLastError(g_ErrNotFound);
3259 for( int j=iOrder-1; j>=0; --j )
3260 g_TwMgr->m_Order[j+1] = g_TwMgr->m_Order[j];
3261 g_TwMgr->m_Order[0] = i;
3263 if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 )
3265 int btmIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnBottom.c_str());
3266 TwBar *btm = (btmIdx>=0 && btmIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[btmIdx] : NULL;
3267 if( btm!=NULL && btm!=_Bar )
3268 TwSetBottomBar(btm);
3274 // ---------------------------------------------------------------------------
3276 TwBar* ANT_CALL TwGetBottomBar()
3280 TwGlobalError(g_ErrNotInit);
3281 return NULL; // not initialized
3284 if( g_TwMgr->m_Bars.size()>0 )
3285 return g_TwMgr->m_Bars[g_TwMgr->m_Order[0]];
3290 // ---------------------------------------------------------------------------
3292 int ANT_CALL TwSetBarState(TwBar *_Bar, TwState _State)
3296 TwGlobalError(g_ErrNotInit);
3297 return 0; // not initialized
3301 g_TwMgr->SetLastError(g_ErrBadParam);
3305 TwFreeAsyncDrawing(); // For multi-thread savety
3309 case TW_STATE_SHOWN:
3310 g_TwMgr->Unhide(_Bar);
3312 case TW_STATE_ICONIFIED:
3313 //g_TwMgr->Unhide(_Bar);
3314 g_TwMgr->Minimize(_Bar);
3316 case TW_STATE_HIDDEN:
3317 //g_TwMgr->Maximize(_Bar);
3318 g_TwMgr->Hide(_Bar);
3320 case TW_STATE_UNICONIFIED:
3321 //g_TwMgr->Unhide(_Bar);
3322 g_TwMgr->Maximize(_Bar);
3325 g_TwMgr->SetLastError(g_ErrBadParam);
3330 // ---------------------------------------------------------------------------
3333 TwState ANT_CALL TwGetBarState(const TwBar *_Bar)
3337 TwGlobalError(g_ErrNotInit);
3338 return TW_STATE_ERROR; // not initialized
3342 g_TwMgr->SetLastError(g_ErrBadParam);
3343 return TW_STATE_ERROR;
3346 if( !_Bar->m_Visible )
3347 return TW_STATE_HIDDEN;
3348 else if( _Bar->IsMinimized() )
3349 return TW_STATE_ICONIFIED;
3351 return TW_STATE_SHOWN;
3355 // ---------------------------------------------------------------------------
3357 const char * ANT_CALL TwGetBarName(TwBar *_Bar)
3361 TwGlobalError(g_ErrNotInit);
3362 return NULL; // not initialized
3366 g_TwMgr->SetLastError(g_ErrBadParam);
3369 vector<TwBar*>::iterator BarIt;
3371 for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3372 if( (*BarIt)==_Bar )
3374 if( BarIt==g_TwMgr->m_Bars.end() )
3376 g_TwMgr->SetLastError(g_ErrNotFound);
3380 return _Bar->m_Name.c_str();
3383 // ---------------------------------------------------------------------------
3385 int ANT_CALL TwGetBarCount()
3389 TwGlobalError(g_ErrNotInit);
3390 return 0; // not initialized
3393 return (int)g_TwMgr->m_Bars.size();
3397 // ---------------------------------------------------------------------------
3399 TwBar * ANT_CALL TwGetBarByIndex(int index)
3403 TwGlobalError(g_ErrNotInit);
3404 return NULL; // not initialized
3407 if( index>=0 && index<(int)g_TwMgr->m_Bars.size() )
3408 return g_TwMgr->m_Bars[index];
3411 g_TwMgr->SetLastError(g_ErrOutOfRange);
3416 // ---------------------------------------------------------------------------
3418 TwBar * ANT_CALL TwGetBarByName(const char *name)
3422 TwGlobalError(g_ErrNotInit);
3423 return NULL; // not initialized
3426 int idx = g_TwMgr->FindBar(name);
3427 if ( idx>=0 && idx<(int)g_TwMgr->m_Bars.size() )
3428 return g_TwMgr->m_Bars[idx];
3433 // ---------------------------------------------------------------------------
3435 int ANT_CALL TwRefreshBar(TwBar *bar)
3439 TwGlobalError(g_ErrNotInit);
3440 return 0; // not initialized
3444 vector<TwBar*>::iterator BarIt;
3445 for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt )
3447 (*BarIt)->NotUpToDate();
3451 vector<TwBar*>::iterator BarIt;
3453 for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i )
3456 if( BarIt==g_TwMgr->m_Bars.end() )
3458 g_TwMgr->SetLastError(g_ErrNotFound);
3467 // ---------------------------------------------------------------------------
3469 int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue);
3470 int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value);
3471 ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector<double>& outDouble, std::ostringstream& outString);
3474 int ANT_CALL TwGetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues)
3476 CTwFPU fpu; // force fpu precision
3480 TwGlobalError(g_ErrNotInit);
3481 return 0; // not initialized
3483 if( paramName==NULL || strlen(paramName)<=0 )
3485 g_TwMgr->SetLastError(g_ErrBadParam);
3488 if( outValueMaxCount<=0 || outValues==NULL )
3490 g_TwMgr->SetLastError(g_ErrBadParam);
3495 bar = TW_GLOBAL_BAR;
3498 vector<TwBar*>::iterator barIt;
3500 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i )
3503 if( barIt==g_TwMgr->m_Bars.end() )
3505 g_TwMgr->SetLastError(g_ErrNotFound);
3509 CTwVarGroup *varParent = NULL;
3512 if( varName!=NULL && strlen(varName)>0 )
3514 var = bar->Find(varName, &varParent, &varIndex);
3517 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'",
3518 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName);
3519 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3520 g_TwMgr->SetLastError(g_ErrParse);
3525 bool hasValue = false;
3526 int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue);
3529 std::ostringstream valStr;
3530 std::vector<double> valDbl;
3531 const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
3533 ERetType retType = BarVarGetAttrib(bar, var, varParent, varIndex, paramID, valDbl, valStr);
3534 unsigned int i, valDblCount = (unsigned int)valDbl.size();
3535 if( valDblCount > outValueMaxCount )
3536 valDblCount = outValueMaxCount;
3537 if( retType==RET_DOUBLE && valDblCount==0 )
3539 g_TwMgr->SetLastError(g_ErrHasNoValue);
3540 retType = RET_ERROR;
3543 if( retType==RET_DOUBLE )
3545 switch( paramValueType )
3547 case TW_PARAM_INT32:
3548 for( i=0; i<valDblCount; i++ )
3549 (static_cast<int *>(outValues))[i] = (int)valDbl[i];
3551 case TW_PARAM_FLOAT:
3552 for( i=0; i<valDblCount; i++ )
3553 (static_cast<float *>(outValues))[i] = (float)valDbl[i];
3555 case TW_PARAM_DOUBLE:
3556 for( i=0; i<valDblCount; i++ )
3557 (static_cast<double *>(outValues))[i] = valDbl[i];
3559 case TW_PARAM_CSTRING:
3561 for( i=0; i<(unsigned int)valDbl.size(); i++ ) // not valDblCount here
3562 valStr << ((i>0) ? " " : "") << valDbl[i];
3563 strncpy(static_cast<char *>(outValues), valStr.str().c_str(), outValueMaxCount);
3564 i = (unsigned int)valStr.str().size();
3565 if( i>outValueMaxCount-1 )
3566 i = outValueMaxCount-1;
3567 (static_cast<char *>(outValues))[i] = '\0';
3568 return 1; // always returns 1 for CSTRING
3570 g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type
3571 retType = RET_ERROR;
3574 else if( retType==RET_STRING )
3576 if( paramValueType == TW_PARAM_CSTRING )
3578 strncpy(static_cast<char *>(outValues), valStr.str().c_str(), outValueMaxCount);
3579 i = (unsigned int)valStr.str().size();
3580 if( i>outValueMaxCount-1 )
3581 i = outValueMaxCount-1;
3582 (static_cast<char *>(outValues))[i] = '\0';
3583 return 1; // always returns 1 for CSTRING
3587 g_TwMgr->SetLastError(g_ErrBadType); // string cannot be converted to int or double
3588 retType = RET_ERROR;
3592 if( retType==RET_ERROR )
3594 bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError());
3595 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to get param '%s%s%s %s' %s%s",
3596 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "",
3597 (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "",
3598 errMsg ? g_TwMgr->CheckLastError() : "");
3599 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3600 g_TwMgr->SetLastError(g_ErrParse);
3606 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'",
3607 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(),
3608 (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName);
3609 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3610 g_TwMgr->SetLastError(g_ErrParse);
3616 int ANT_CALL TwSetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues)
3618 CTwFPU fpu; // force fpu precision
3622 TwGlobalError(g_ErrNotInit);
3623 return 0; // not initialized
3625 if( paramName==NULL || strlen(paramName)<=0 )
3627 g_TwMgr->SetLastError(g_ErrBadParam);
3630 if( inValueCount>0 && inValues==NULL )
3632 g_TwMgr->SetLastError(g_ErrBadParam);
3636 TwFreeAsyncDrawing(); // For multi-thread savety
3639 bar = TW_GLOBAL_BAR;
3642 vector<TwBar*>::iterator barIt;
3644 for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i )
3647 if( barIt==g_TwMgr->m_Bars.end() )
3649 g_TwMgr->SetLastError(g_ErrNotFound);
3653 CTwVarGroup *varParent = NULL;
3656 if( varName!=NULL && strlen(varName)>0 )
3658 var = bar->Find(varName, &varParent, &varIndex);
3661 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'",
3662 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName);
3663 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3664 g_TwMgr->SetLastError(g_ErrParse);
3669 bool hasValue = false;
3670 int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue);
3674 const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
3677 std::ostringstream valuesStr;
3679 switch( paramValueType )
3681 case TW_PARAM_INT32:
3682 for( i=0; i<inValueCount; i++ )
3683 valuesStr << (static_cast<const int *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3685 case TW_PARAM_FLOAT:
3686 for( i=0; i<inValueCount; i++ )
3687 valuesStr << (static_cast<const float *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3689 case TW_PARAM_DOUBLE:
3690 for( i=0; i<inValueCount; i++ )
3691 valuesStr << (static_cast<const double *>(inValues))[i] << ((i<inValueCount-1) ? " " : "");
3693 case TW_PARAM_CSTRING:
3695 for( i=0; i<inValueCount; i++ )
3698 const char *str = (static_cast<char * const *>(inValues))[i];
3699 for( const char *ch = str; *ch!=0; ch++ )
3701 valuesStr << "`'`'`";
3707 if( inValueCount!=1 )
3709 g_TwMgr->SetLastError(g_ErrCStrParam); // count for CString param must be 1
3713 valuesStr << static_cast<const char *>(inValues);
3716 g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type
3719 ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, valuesStr.str().c_str());
3722 ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, NULL);
3725 bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError());
3726 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to set param '%s%s%s %s' %s%s",
3727 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "",
3728 (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "",
3729 errMsg ? g_TwMgr->CheckLastError() : "");
3730 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3731 g_TwMgr->SetLastError(g_ErrParse);
3737 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'",
3738 (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(),
3739 (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName);
3740 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
3741 g_TwMgr->SetLastError(g_ErrParse);
3746 // ---------------------------------------------------------------------------
3748 static int s_PassProxy = 0;
3749 void *CTwMgr::CStruct::s_PassProxyAsClientData = &s_PassProxy; // special tag
3751 CTwMgr::CStructProxy::CStructProxy()
3753 memset(this, 0, sizeof(*this));
3756 CTwMgr::CStructProxy::~CStructProxy()
3758 if( m_StructData!=NULL && m_DeleteStructData )
3760 //if( m_StructExtData==NULL && g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3761 // g_TwMgr->UninitVarData(m_Type, m_StructData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size);
3762 delete[] (char*)m_StructData;
3764 if( m_StructExtData!=NULL )
3766 //if( g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3767 // g_TwMgr->UninitVarData(m_Type, m_StructExtData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size);
3768 delete[] (char*)m_StructExtData;
3770 memset(this, 0, sizeof(*this));
3774 void CTwMgr::InitVarData(TwType _Type, void *_Data, size_t _Size)
3778 if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3780 CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3781 for( size_t i=0; i<s.m_Members.size(); ++i )
3783 CTwMgr::CStructMember& sm = s.m_Members[i];
3784 assert( sm.m_Offset+sm.m_Size<=_Size );
3785 InitVarData(sm.m_Type, (char *)_Data + sm.m_Offset, sm.m_Size);
3788 else if( _Type==TW_TYPE_STDSTRING )
3789 ::new(_Data) std::string;
3791 memset(_Data, 0, _Size);
3795 void CTwMgr::UninitVarData(TwType _Type, void *_Data, size_t _Size)
3799 if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3801 CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3802 for( size_t i=0; i<s.m_Members.size(); ++i )
3804 CTwMgr::CStructMember& sm = s.m_Members[i];
3805 assert( sm.m_Offset+sm.m_Size<=_Size );
3806 UninitVarData(sm.m_Type, (char *)_Data + sm.m_Offset, sm.m_Size);
3809 else if( _Type==TW_TYPE_STDSTRING )
3811 std::string *Str = (std::string *)_Data;
3813 memset(_Data, 0, _Size);
3816 memset(_Data, 0, _Size);
3821 void CTwMgr::UnrollCDStdString(std::vector<CCDStdStringRecord>& _Records, TwType _Type, void *_Data)
3825 if( _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)m_Structs.size() )
3827 CTwMgr::CStruct& s = m_Structs[_Type-TW_TYPE_STRUCT_BASE];
3829 for( size_t i=0; i<s.m_Members.size(); ++i )
3831 CTwMgr::CStructMember& sm = s.m_Members[i];
3832 UnrollCDStdString(_Records, sm.m_Type, (char *)_Data + sm.m_Offset);
3837 // Ext struct cannot have var of type TW_TYPE_CDSTDSTRING (converted from TW_TYPE_STDSTRING)
3840 else if( _Type==TW_TYPE_STDSTRING || _Type==TW_TYPE_CDSTDSTRING )
3842 _Records.push_back(CCDStdStringRecord());
3843 CCDStdStringRecord& Rec = _Records.back();
3844 Rec.m_DataPtr = _Data;
3845 memcpy(Rec.m_PrevValue, _Data, m_ClientStdStringStructSize);
3846 const char *Str = *(const char **)_Data;
3848 // Rec.m_StdString = Str;
3849 Rec.m_ClientStdString.FromLib(Str);
3850 memcpy(Rec.m_DataPtr, &(Rec.m_ClientStdString.ToClient()), sizeof(std::string));
3855 void CTwMgr::RestoreCDStdString(const std::vector<CCDStdStringRecord>& _Records)
3857 for( size_t i=0; i<_Records.size(); ++i )
3858 memcpy(_Records[i].m_DataPtr, _Records[i].m_PrevValue, m_ClientStdStringStructSize);
3861 CTwMgr::CMemberProxy::CMemberProxy()
3863 memset(this, 0, sizeof(*this));
3866 CTwMgr::CMemberProxy::~CMemberProxy()
3868 memset(this, 0, sizeof(*this));
3871 void ANT_CALL CTwMgr::CMemberProxy::SetCB(const void *_Value, void *_ClientData)
3873 if( _ClientData && _Value )
3875 const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
3876 if( g_TwMgr && mProxy )
3878 const CStructProxy *sProxy = mProxy->m_StructProxy;
3879 if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3881 CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
3882 if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
3884 CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
3885 if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
3889 memcpy((char *)sProxy->m_StructExtData + m.m_Offset, _Value, m.m_Size);
3890 if( s.m_CopyVarFromExtCallback && sProxy->m_StructExtData )
3891 s.m_CopyVarFromExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
3894 memcpy((char *)sProxy->m_StructData + m.m_Offset, _Value, m.m_Size);
3895 if( sProxy->m_StructSetCallback )
3897 g_TwMgr->m_CDStdStringRecords.resize(0);
3898 g_TwMgr->UnrollCDStdString(g_TwMgr->m_CDStdStringRecords, sProxy->m_Type, sProxy->m_StructData);
3899 sProxy->m_StructSetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
3900 g_TwMgr->RestoreCDStdString(g_TwMgr->m_CDStdStringRecords);
3909 void ANT_CALL CTwMgr::CMemberProxy::GetCB(void *_Value, void *_ClientData)
3911 if( _ClientData && _Value )
3913 const CMemberProxy *mProxy = static_cast<const CMemberProxy *>(_ClientData);
3914 if( g_TwMgr && mProxy )
3916 const CStructProxy *sProxy = mProxy->m_StructProxy;
3917 if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
3919 CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE];
3920 if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() )
3922 CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex];
3923 if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON )
3925 if( sProxy->m_StructGetCallback )
3926 sProxy->m_StructGetCallback(sProxy->m_StructData, sProxy->m_StructClientData);
3929 if( s.m_CopyVarToExtCallback && sProxy->m_StructExtData )
3930 s.m_CopyVarToExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData);
3931 memcpy(_Value, (char *)sProxy->m_StructExtData + m.m_Offset, m.m_Size);
3934 memcpy(_Value, (char *)sProxy->m_StructData + m.m_Offset, m.m_Size);
3942 // ---------------------------------------------------------------------------
3944 void ANT_CALL CTwMgr::CCDStdString::SetCB(const void *_Value, void *_ClientData)
3946 if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL )
3948 CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData;
3949 const char *SrcStr = *(const char **)_Value;
3952 static char s_EmptyString[] = "";
3953 SrcStr = s_EmptyString;
3955 if( CDStdString->m_ClientSetCallback==NULL )
3957 if( g_TwMgr->m_CopyStdStringToClient && CDStdString->m_ClientStdStringPtr!=NULL )
3959 CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string
3960 clientSrcStr.FromLib(SrcStr);
3961 g_TwMgr->m_CopyStdStringToClient(*(CDStdString->m_ClientStdStringPtr), clientSrcStr.ToClient());
3966 if( CDStdString->m_ClientSetCallback==CMemberProxy::SetCB )
3967 CDStdString->m_ClientSetCallback(&SrcStr, CDStdString->m_ClientData);
3970 CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string
3971 clientSrcStr.FromLib(SrcStr);
3972 std::string& ValStr = clientSrcStr.ToClient();
3973 CDStdString->m_ClientSetCallback(&ValStr, CDStdString->m_ClientData);
3978 void ANT_CALL CTwMgr::CCDStdString::GetCB(void *_Value, void *_ClientData)
3980 if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL )
3982 CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData;
3983 char **DstStrPtr = (char **)_Value;
3984 if( CDStdString->m_ClientGetCallback==NULL )
3986 if( CDStdString->m_ClientStdStringPtr!=NULL )
3988 //*DstStrPtr = const_cast<char *>(CDStdString->m_ClientStdStringPtr->c_str());
3989 static CTwMgr::CLibStdString s_LibStr; // static because it will be used as a returned value
3990 s_LibStr.FromClient(*CDStdString->m_ClientStdStringPtr);
3991 *DstStrPtr = const_cast<char *>(s_LibStr.ToLib().c_str());
3995 static char s_EmptyString[] = "";
3996 *DstStrPtr = s_EmptyString;
4001 // m_ClientGetCallback uses TwCopyStdStringToLibrary to copy string
4002 // and TwCopyStdStringToLibrary does the VC++ Debug/Release std::string conversion.
4003 CDStdString->m_ClientGetCallback(&(CDStdString->m_LocalString[0]), CDStdString->m_ClientData);
4004 //*DstStrPtr = const_cast<char *>(CDStdString->m_LocalString.c_str());
4005 char **StrPtr = (char **)&(CDStdString->m_LocalString[0]);
4006 *DstStrPtr = *StrPtr;
4010 // ---------------------------------------------------------------------------
4012 static int s_SeparatorTag = 0;
4014 // ---------------------------------------------------------------------------
4016 static int AddVar(TwBar *_Bar, const char *_Name, ETwType _Type, void *_VarPtr, bool _ReadOnly, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, TwButtonCallback _ButtonCallback, void *_ClientData, const char *_Def)
4018 CTwFPU fpu; // force fpu precision
4022 TwGlobalError(g_ErrNotInit);
4023 return 0; // not initialized
4026 char unnamedVarName[64];
4027 if( _Name==NULL || strlen(_Name)==0 ) // create a name automatically
4029 static unsigned int s_UnnamedVarCount = 0;
4030 _snprintf(unnamedVarName, sizeof(unnamedVarName), "TW_UNNAMED_%04X", s_UnnamedVarCount);
4031 _Name = unnamedVarName;
4032 ++s_UnnamedVarCount;
4035 if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 || (_VarPtr==NULL && _GetCallback==NULL && _Type!=TW_TYPE_BUTTON) )
4037 g_TwMgr->SetLastError(g_ErrBadParam);
4040 if( _Bar->Find(_Name)!=NULL )
4042 g_TwMgr->SetLastError(g_ErrExist);
4046 if( strstr(_Name, "`")!=NULL )
4048 g_TwMgr->SetLastError(g_ErrNoBackQuote);
4052 if( _VarPtr==NULL && _Type!=TW_TYPE_BUTTON && _GetCallback!=NULL && _SetCallback==NULL )
4053 _ReadOnly = true; // force readonly in this case
4055 // Convert color types
4056 if( _Type==TW_TYPE_COLOR32 )
4057 _Type = g_TwMgr->m_TypeColor32;
4058 else if( _Type==TW_TYPE_COLOR3F )
4059 _Type = g_TwMgr->m_TypeColor3F;
4060 else if( _Type==TW_TYPE_COLOR4F )
4061 _Type = g_TwMgr->m_TypeColor4F;
4063 // Convert rotation types
4064 if( _Type==TW_TYPE_QUAT4F )
4065 _Type = g_TwMgr->m_TypeQuat4F;
4066 else if( _Type==TW_TYPE_QUAT4D )
4067 _Type = g_TwMgr->m_TypeQuat4D;
4068 else if( _Type==TW_TYPE_DIR3F )
4069 _Type = g_TwMgr->m_TypeDir3F;
4070 else if( _Type==TW_TYPE_DIR3D )
4071 _Type = g_TwMgr->m_TypeDir3D;
4073 // VC++ uses a different definition of std::string in Debug and Release modes.
4074 // sizeof(std::string) is encoded in TW_TYPE_STDSTRING to overcome this issue.
4075 // With VS2010 the binary representation of std::string has changed too. This is
4076 // also detected here.
4077 if( (_Type&0xffff0000)==(TW_TYPE_STDSTRING&0xffff0000) || (_Type&0xffff0000)==TW_TYPE_STDSTRING_VS2010 || (_Type&0xffff0000)==TW_TYPE_STDSTRING_VS2008 )
4079 if( g_TwMgr->m_ClientStdStringBaseType==0 )
4080 g_TwMgr->m_ClientStdStringBaseType = (TwType)(_Type&0xffff0000);
4082 size_t clientStdStringStructSize = (_Type&0xffff);
4083 if( g_TwMgr->m_ClientStdStringStructSize==0 )
4084 g_TwMgr->m_ClientStdStringStructSize = clientStdStringStructSize;
4085 int diff = abs((int)g_TwMgr->m_ClientStdStringStructSize - (int)sizeof(std::string));
4086 if( g_TwMgr->m_ClientStdStringStructSize!=clientStdStringStructSize || g_TwMgr->m_ClientStdStringStructSize==0
4087 || (diff!=0 && diff!=sizeof(void*)))
4089 g_TwMgr->SetLastError(g_ErrStdString);
4093 _Type = TW_TYPE_STDSTRING; // force type to be our TW_TYPE_STDSTRING
4096 if( _Type==TW_TYPE_STDSTRING )
4098 g_TwMgr->m_CDStdStrings.push_back(CTwMgr::CCDStdString());
4099 CTwMgr::CCDStdString& CDStdString = g_TwMgr->m_CDStdStrings.back();
4100 CDStdString.m_ClientStdStringPtr = (std::string *)_VarPtr;
4101 CDStdString.m_ClientSetCallback = _SetCallback;
4102 CDStdString.m_ClientGetCallback = _GetCallback;
4103 CDStdString.m_ClientData = _ClientData;
4104 //CDStdString.m_This = g_TwMgr->m_CDStdStrings.end();
4105 //--CDStdString.m_This;
4106 TwGetVarCallback GetCB = CTwMgr::CCDStdString::GetCB;
4107 TwSetVarCallback SetCB = CTwMgr::CCDStdString::SetCB;
4108 if( _VarPtr==NULL && _SetCallback==NULL )
4110 if( _VarPtr==NULL && _GetCallback==NULL )
4112 return AddVar(_Bar, _Name, TW_TYPE_CDSTDSTRING, NULL, _ReadOnly, SetCB, GetCB, NULL, &CDStdString, _Def);
4114 else if( (_Type>TW_TYPE_UNDEF && _Type<TW_TYPE_STRUCT_BASE)
4115 || (_Type>=TW_TYPE_ENUM_BASE && _Type<TW_TYPE_ENUM_BASE+(int)g_TwMgr->m_Enums.size())
4116 || (_Type>TW_TYPE_CSSTRING_BASE && _Type<=TW_TYPE_CSSTRING_MAX)
4117 || _Type==TW_TYPE_CDSTDSTRING
4118 || IsCustomType(_Type) ) // (_Type>=TW_TYPE_CUSTOM_BASE && _Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) )
4120 CTwVarAtom *Var = new CTwVarAtom;
4121 Var->m_Name = _Name;
4122 Var->m_Ptr = _VarPtr;
4123 Var->m_Type = _Type;
4124 Var->m_ColorPtr = &(_Bar->m_ColLabelText);
4127 assert( _GetCallback==NULL && _SetCallback==NULL && _ButtonCallback==NULL );
4129 Var->m_ReadOnly = _ReadOnly;
4130 Var->m_GetCallback = NULL;
4131 Var->m_SetCallback = NULL;
4132 Var->m_ClientData = NULL;
4136 assert( _GetCallback!=NULL || _Type==TW_TYPE_BUTTON );
4138 Var->m_GetCallback = _GetCallback;
4139 Var->m_SetCallback = _SetCallback;
4140 Var->m_ClientData = _ClientData;
4141 if( _Type==TW_TYPE_BUTTON )
4143 Var->m_Val.m_Button.m_Callback = _ButtonCallback;
4144 if( _ButtonCallback==NULL && _ClientData==&s_SeparatorTag )
4146 Var->m_Val.m_Button.m_Separator = 1;
4149 else if( _ButtonCallback==NULL )
4150 Var->m_ColorPtr = &(_Bar->m_ColStaticText);
4152 if( _Type!=TW_TYPE_BUTTON )
4153 Var->m_ReadOnly = (_SetCallback==NULL || _ReadOnly);
4155 Var->m_ReadOnly = (_ButtonCallback==NULL);
4159 if( IsCustomType(_Type) ) // _Type>=TW_TYPE_CUSTOM_BASE && _Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
4161 if( Var->m_GetCallback==CTwMgr::CMemberProxy::GetCB && Var->m_SetCallback==CTwMgr::CMemberProxy::SetCB )
4162 Var->m_Val.m_Custom.m_MemberProxy = static_cast<CTwMgr::CMemberProxy *>(Var->m_ClientData);
4164 Var->m_Val.m_Custom.m_MemberProxy = NULL;
4167 _Bar->m_VarRoot.m_Vars.push_back(Var);
4168 _Bar->NotUpToDate();
4169 g_TwMgr->m_HelpBarNotUpToDate = true;
4171 if( _Def!=NULL && strlen(_Def)>0 )
4173 string d = '`' + _Bar->m_Name + "`/`" + _Name + "` " + _Def;
4174 return TwDefine(d.c_str());
4179 else if(_Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(TwType)g_TwMgr->m_Structs.size())
4181 CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE];
4182 CTwMgr::CStructProxy *sProxy = NULL;
4190 assert( _GetCallback!=NULL || _SetCallback!=NULL );
4191 assert( s.m_Size>0 );
4192 vPtr = new char[s.m_Size];
4193 memset(vPtr, 0, s.m_Size);
4194 // create a new StructProxy
4195 g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
4196 sProxy = &(g_TwMgr->m_StructProxies.back());
4197 sProxy->m_Type = _Type;
4198 sProxy->m_StructData = vPtr;
4199 sProxy->m_DeleteStructData = true;
4200 sProxy->m_StructSetCallback = _SetCallback;
4201 sProxy->m_StructGetCallback = _GetCallback;
4202 sProxy->m_StructClientData = _ClientData;
4203 sProxy->m_CustomDrawCallback = NULL;
4204 sProxy->m_CustomMouseButtonCallback = NULL;
4205 sProxy->m_CustomMouseMotionCallback = NULL;
4206 sProxy->m_CustomMouseLeaveCallback = NULL;
4207 sProxy->m_CustomCaptureFocus = false;
4208 sProxy->m_CustomIndexFirst = -1;
4209 sProxy->m_CustomIndexLast = -1;
4210 //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructData, s.m_Size);
4215 assert( s.m_Size>0 && s.m_ClientStructSize>0 );
4216 vPtr = new char[s.m_Size]; // will be m_StructExtData
4217 memset(vPtr, 0, s.m_Size);
4218 // create a new StructProxy
4219 g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy());
4220 sProxy = &(g_TwMgr->m_StructProxies.back());
4221 sProxy->m_Type = _Type;
4222 sProxy->m_StructExtData = vPtr;
4223 sProxy->m_StructSetCallback = _SetCallback;
4224 sProxy->m_StructGetCallback = _GetCallback;
4225 sProxy->m_StructClientData = _ClientData;
4226 sProxy->m_CustomDrawCallback = NULL;
4227 sProxy->m_CustomMouseButtonCallback = NULL;
4228 sProxy->m_CustomMouseMotionCallback = NULL;
4229 sProxy->m_CustomMouseLeaveCallback = NULL;
4230 sProxy->m_CustomCaptureFocus = false;
4231 sProxy->m_CustomIndexFirst = -1;
4232 sProxy->m_CustomIndexLast = -1;
4233 //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructExtData, s.m_Size);
4236 sProxy->m_StructData = _VarPtr;
4237 sProxy->m_DeleteStructData = false;
4241 sProxy->m_StructData = new char[s.m_ClientStructSize];
4242 memset(sProxy->m_StructData, 0, s.m_ClientStructSize);
4243 sProxy->m_DeleteStructData = true;
4244 //g_TwMgr->InitVarData(ClientStructType, sProxy->m_StructData, s.m_ClientStructSize); //ClientStructType is unknown
4246 _VarPtr = NULL; // force use of TwAddVarCB for members
4248 // init m_StructExtdata
4249 if( s.m_ExtClientData==CTwMgr::CStruct::s_PassProxyAsClientData )
4250 s.m_StructExtInitCallback(sProxy->m_StructExtData, sProxy);
4252 s.m_StructExtInitCallback(sProxy->m_StructExtData, s.m_ExtClientData);
4255 for( int i=0; i<(int)s.m_Members.size(); ++i )
4257 CTwMgr::CStructMember& m = s.m_Members[i];
4258 string name = string(_Name) + '.' + m.m_Name;
4259 const char *access = "";
4261 access = "readonly ";
4262 string def = "label=`" + m.m_Name + "` group=`" + _Name + "` " + access; // + m.m_DefString; // member def must be done after group def
4265 if( TwAddVarRW(_Bar, name.c_str(), m.m_Type, (char*)vPtr+m.m_Offset, def.c_str())==0 )
4270 assert( sProxy!=NULL );
4271 // create a new MemberProxy
4272 g_TwMgr->m_MemberProxies.push_back(CTwMgr::CMemberProxy());
4273 CTwMgr::CMemberProxy& mProxy = g_TwMgr->m_MemberProxies.back();
4274 mProxy.m_StructProxy = sProxy;
4275 mProxy.m_MemberIndex = i;
4276 assert( !(s.m_IsExt && (m.m_Type==TW_TYPE_STDSTRING || m.m_Type==TW_TYPE_CDSTDSTRING)) ); // forbidden because this case is not handled by UnrollCDStdString
4277 if( TwAddVarCB(_Bar, name.c_str(), m.m_Type, CTwMgr::CMemberProxy::SetCB, CTwMgr::CMemberProxy::GetCB, &mProxy, def.c_str())==0 )
4279 mProxy.m_Var = _Bar->Find(name.c_str(), &mProxy.m_VarParent, NULL);
4280 mProxy.m_Bar = _Bar;
4283 if( sProxy!=NULL && IsCustomType(m.m_Type) ) // m.m_Type>=TW_TYPE_CUSTOM_BASE && m.m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
4285 if( sProxy->m_CustomIndexFirst<0 )
4286 sProxy->m_CustomIndexFirst = sProxy->m_CustomIndexLast = i;
4288 sProxy->m_CustomIndexLast = i;
4291 char structInfo[64];
4292 sprintf(structInfo, "typeid=%d valptr=%p close ", _Type, vPtr);
4293 string grpDef = '`' + _Bar->m_Name + "`/`" + _Name + "` " + structInfo;
4294 if( _Def!=NULL && strlen(_Def)>0 )
4296 int ret = TwDefine(grpDef.c_str());
4297 for( int i=0; i<(int)s.m_Members.size(); ++i ) // members must be defined even if grpDef has error
4299 CTwMgr::CStructMember& m = s.m_Members[i];
4300 if( m.m_DefString.length()>0 )
4302 string memberDef = '`' + _Bar->m_Name + "`/`" + _Name + '.' + m.m_Name + "` " + m.m_DefString;
4303 if( !TwDefine(memberDef.c_str()) ) // all members must be defined even if memberDef has error
4311 if( _Type==TW_TYPE_CSSTRING_BASE )
4312 g_TwMgr->SetLastError(g_ErrBadSize); // static string of size null
4314 g_TwMgr->SetLastError(g_ErrNotFound);
4319 // ---------------------------------------------------------------------------
4321 int ANT_CALL TwAddVarRW(TwBar *_Bar, const char *_Name, ETwType _Type, void *_Var, const char *_Def)
4323 return AddVar(_Bar, _Name, _Type, _Var, false, NULL, NULL, NULL, NULL, _Def);
4326 // ---------------------------------------------------------------------------
4328 int ANT_CALL TwAddVarRO(TwBar *_Bar, const char *_Name, ETwType _Type, const void *_Var, const char *_Def)
4330 return AddVar(_Bar, _Name, _Type, const_cast<void *>(_Var), true, NULL, NULL, NULL, NULL, _Def);
4333 // ---------------------------------------------------------------------------
4335 int ANT_CALL TwAddVarCB(TwBar *_Bar, const char *_Name, ETwType _Type, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, void *_ClientData, const char *_Def)
4337 return AddVar(_Bar, _Name, _Type, NULL, false, _SetCallback, _GetCallback, NULL, _ClientData, _Def);
4340 // ---------------------------------------------------------------------------
4342 int ANT_CALL TwAddButton(TwBar *_Bar, const char *_Name, TwButtonCallback _Callback, void *_ClientData, const char *_Def)
4344 return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, false, NULL, NULL, _Callback, _ClientData, _Def);
4347 // ---------------------------------------------------------------------------
4349 int ANT_CALL TwAddSeparator(TwBar *_Bar, const char *_Name, const char *_Def)
4351 return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, true, NULL, NULL, NULL, &s_SeparatorTag, _Def);
4354 // ---------------------------------------------------------------------------
4356 int ANT_CALL TwRemoveVar(TwBar *_Bar, const char *_Name)
4360 TwGlobalError(g_ErrNotInit);
4361 return 0; // not initialized
4363 if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 )
4365 g_TwMgr->SetLastError(g_ErrBadParam);
4369 if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists
4371 TwDeleteBar(g_TwMgr->m_PopupBar);
4372 g_TwMgr->m_PopupBar = NULL;
4375 _Bar->StopEditInPlace(); // desactivate EditInPlace
4377 CTwVarGroup *Parent = NULL;
4379 CTwVar *Var = _Bar->Find(_Name, &Parent, &Index);
4380 if( Var!=NULL && Parent!=NULL && Index>=0 )
4382 if( Parent->m_StructValuePtr!=NULL )
4384 g_TwMgr->SetLastError(g_ErrDelStruct);
4389 Parent->m_Vars.erase(Parent->m_Vars.begin()+Index);
4390 if( Parent!=&(_Bar->m_VarRoot) && Parent->m_Vars.size()<=0 )
4391 TwRemoveVar(_Bar, Parent->m_Name.c_str());
4392 _Bar->NotUpToDate();
4393 if( _Bar!=g_TwMgr->m_HelpBar )
4394 g_TwMgr->m_HelpBarNotUpToDate = true;
4398 g_TwMgr->SetLastError(g_ErrNotFound);
4402 // ---------------------------------------------------------------------------
4404 int ANT_CALL TwRemoveAllVars(TwBar *_Bar)
4408 TwGlobalError(g_ErrNotInit);
4409 return 0; // not initialized
4413 g_TwMgr->SetLastError(g_ErrBadParam);
4417 if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && _Bar!=g_TwMgr->m_HelpBar ) // delete popup bar first if it exists
4419 TwDeleteBar(g_TwMgr->m_PopupBar);
4420 g_TwMgr->m_PopupBar = NULL;
4423 _Bar->StopEditInPlace(); // desactivate EditInPlace
4425 for( vector<CTwVar*>::iterator it=_Bar->m_VarRoot.m_Vars.begin(); it!=_Bar->m_VarRoot.m_Vars.end(); ++it )
4431 _Bar->m_VarRoot.m_Vars.resize(0);
4432 _Bar->NotUpToDate();
4433 g_TwMgr->m_HelpBarNotUpToDate = true;
4437 // ---------------------------------------------------------------------------
4439 int ParseToken(string& _Token, const char *_Def, int& Line, int& Column, bool _KeepQuotes, bool _EndCR, char _Sep1='\0', char _Sep2='\0')
4441 const char *Cur = _Def;
4444 while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' || *Cur=='\n' )
4446 if( *Cur=='\n' && _EndCR )
4447 return (int)(Cur-_Def); // a CR has been found
4454 else if( *Cur=='\t' )
4455 Column += g_TabLength;
4456 else if( *Cur!='\r' )
4460 int QuoteLine=0, QuoteColumn=0;
4461 const char *QuoteCur;
4464 bool LineJustIncremented = false;
4465 while( (Quote==0 && (*Cur!='\0' && *Cur!=' ' && *Cur!='\t' && *Cur!='\r' && *Cur!='\n' && *Cur!=_Sep1 && *Cur!=_Sep2))
4466 || (Quote!=0 && (*Cur!='\0' /* && *Cur!='\r' && *Cur!='\n' */)) ) // allow multi-line strings
4468 LineJustIncremented = false;
4470 if( Quote==0 && (*Cur=='\'' || *Cur=='\"' || *Cur=='`') )
4474 QuoteColumn = Column;
4476 AddChar = _KeepQuotes;
4478 else if ( Quote!=0 && *Cur==Quote )
4481 AddChar = _KeepQuotes;
4488 Column += g_TabLength;
4489 else if( *Cur=='\n' )
4492 LineJustIncremented = true;
4502 Column = QuoteColumn;
4503 return -(int)(Cur-_Def); // unclosed quote
4509 if( !LineJustIncremented )
4513 else if( *Cur=='\t' )
4514 Column += g_TabLength;
4515 else if( *Cur!='\r' && *Cur!='\0' )
4517 return (int)(Cur-_Def);
4521 // ---------------------------------------------------------------------------
4523 int GetBarVarFromString(CTwBar **_Bar, CTwVar **_Var, CTwVarGroup **_VarParent, int *_VarIndex, const char *_Str)
4529 vector<string> Names;
4531 const char *Cur =_Str;
4533 while( *Cur!='\0' && p>0 && Names.size()<=3 )
4535 p = ParseToken(Token, Cur, l, c, false, true, '/', '\\');
4536 if( p>0 && Token.size()>0 )
4538 Names.push_back(Token);
4539 Cur += p + ((Cur[p]!='\0')?1:0);
4542 if( p<=0 || (Names.size()!=1 && Names.size()!=2) )
4543 return 0; // parse error
4544 int BarIdx = g_TwMgr->FindBar(Names[0].c_str());
4547 if( Names.size()==1 && strcmp(Names[0].c_str(), "GLOBAL")==0 )
4549 *_Bar = TW_GLOBAL_BAR;
4550 return +3; // 'GLOBAL' found
4553 return -1; // bar not found
4555 *_Bar = g_TwMgr->m_Bars[BarIdx];
4556 if( Names.size()==1 )
4557 return 1; // bar found, no var name parsed
4558 *_Var = (*_Bar)->Find(Names[1].c_str(), _VarParent, _VarIndex);
4560 return -2; // var not found
4561 return 2; // bar and var found
4565 int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue)
4567 assert(_Bar!=NULL && _HasValue!=NULL && _Attrib!=NULL && strlen(_Attrib)>0);
4569 if( _Bar==TW_GLOBAL_BAR )
4571 assert( _Var==NULL );
4572 return g_TwMgr->HasAttrib(_Attrib, _HasValue);
4574 else if( _Var==NULL )
4575 return _Bar->HasAttrib(_Attrib, _HasValue);
4577 return _Var->HasAttrib(_Attrib, _HasValue);
4581 int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value)
4583 assert(_Bar!=NULL && _AttribID>0);
4585 /* don't delete popupbar here: if any attrib is changed every frame by the app, popup will not work anymore.
4586 if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar->m_BarLinkedToPopupList==_Bar ) // delete popup bar first if it exists
4588 TwDeleteBar(g_TwMgr->m_PopupBar);
4589 g_TwMgr->m_PopupBar = NULL;
4593 if( _Bar==TW_GLOBAL_BAR )
4595 assert( _Var==NULL );
4596 return g_TwMgr->SetAttrib(_AttribID, _Value);
4598 else if( _Var==NULL )
4599 return _Bar->SetAttrib(_AttribID, _Value);
4601 return _Var->SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex);
4602 // don't make _Bar not-up-to-date here, should be done in SetAttrib if needed to avoid too frequent refreshs
4606 ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector<double>& outDoubles, std::ostringstream& outString)
4608 assert(_Bar!=NULL && _AttribID>0);
4610 if( _Bar==TW_GLOBAL_BAR )
4612 assert( _Var==NULL );
4613 return g_TwMgr->GetAttrib(_AttribID, outDoubles, outString);
4615 else if( _Var==NULL )
4616 return _Bar->GetAttrib(_AttribID, outDoubles, outString);
4618 return _Var->GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString);
4621 // ---------------------------------------------------------------------------
4623 static inline std::string ErrorPosition(bool _MultiLine, int _Line, int _Column)
4630 //_snprintf(pos, sizeof(pos)-1, " line %d column %d", _Line, _Column);
4631 _snprintf(pos, sizeof(pos)-1, " line %d", _Line); (void)_Column;
4632 pos[sizeof(pos)-1] = '\0';
4637 // ---------------------------------------------------------------------------
4639 int ANT_CALL TwDefine(const char *_Def)
4641 CTwFPU fpu; // force fpu precision
4645 TwGlobalError(g_ErrNotInit);
4646 return 0; // not initialized
4650 g_TwMgr->SetLastError(g_ErrBadParam);
4654 bool MultiLine = false;
4655 const char *Cur = _Def;
4668 enum EState { PARSE_NAME, PARSE_ATTRIB };
4669 EState State = PARSE_NAME;
4674 CTwVarGroup *VarParent = NULL;
4681 const char *PrevCur = Cur;
4682 p = ParseToken(Token, Cur, Line, Column, (State==PARSE_NAME), (State==PARSE_ATTRIB), (State==PARSE_ATTRIB)?'=':'\0');
4683 if( p<=0 || Token.size()<=0 )
4685 if( p>0 && Cur[p]=='\0' )
4690 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), (p<0)?(Cur-p):PrevCur);
4691 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4692 g_TwMgr->SetLastError(g_ErrParse);
4695 char CurSep = Cur[p];
4696 Cur += p + ((CurSep!='\0')?1:0);
4698 if( State==PARSE_NAME )
4700 int Err = GetBarVarFromString(&Bar, &Var, &VarParent, &VarIndex, Token.c_str());
4704 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Bar not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4706 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Variable not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4708 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4709 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4710 g_TwMgr->SetLastError(g_ErrParse);
4713 State = PARSE_ATTRIB;
4715 else // State==PARSE_ATTRIB
4717 assert(State==PARSE_ATTRIB);
4720 bool HasValue = false;
4722 int AttribID = BarVarHasAttrib(Bar, Var, Token.c_str(), &HasValue);
4725 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Unknown attribute%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4726 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4727 g_TwMgr->SetLastError(g_ErrParse);
4731 // special case for backward compatibility
4732 if( HasValue && ( _stricmp(Token.c_str(), "readonly")==0 || _stricmp(Token.c_str(), "hexa")==0 ) )
4734 if( CurSep==' ' || CurSep=='\t' )
4736 const char *ch = Cur;
4737 while( *ch==' ' || *ch=='\t' ) // find next non-space character
4739 if( *ch!='=' ) // if this is not '=' the param has no value
4749 p = ParseToken(EqualStr, Cur, Line, Column, true, true, '=');
4751 if( p<0 || EqualStr.size()>0 || CurSep!='=' )
4753 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: '=' not found while reading attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4754 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4755 g_TwMgr->SetLastError(g_ErrParse);
4760 p = ParseToken(Value, Cur, Line, Column, false, true);
4763 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: can't read attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4764 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4765 g_TwMgr->SetLastError(g_ErrParse);
4769 Cur += p + ((CurSep!='\0')?1:0);
4771 const char *PrevLastErrorPtr = g_TwMgr->CheckLastError();
4772 if( BarVarSetAttrib(Bar, Var, VarParent, VarIndex, AttribID, HasValue?Value.c_str():NULL)==0 )
4774 if( g_TwMgr->CheckLastError()==NULL || strlen(g_TwMgr->CheckLastError())<=0 || g_TwMgr->CheckLastError()==PrevLastErrorPtr )
4775 _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: wrong attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4777 _snprintf(g_ErrParse, sizeof(g_ErrParse), "%s%s [%-16s...]", g_TwMgr->CheckLastError(), ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str());
4778 g_ErrParse[sizeof(g_ErrParse)-1] = '\0';
4779 g_TwMgr->SetLastError(g_ErrParse);
4782 // sweep spaces to detect next attrib
4783 while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' )
4787 Column += g_TabLength;
4788 else if( *Cur!='\r' )
4791 if( *Cur=='\n' ) // new line detected
4800 g_TwMgr->m_HelpBarNotUpToDate = true;
4804 // ---------------------------------------------------------------------------
4806 TwType ANT_CALL TwDefineEnum(const char *_Name, const TwEnumVal *_EnumValues, unsigned int _NbValues)
4808 CTwFPU fpu; // force fpu precision
4812 TwGlobalError(g_ErrNotInit);
4813 return TW_TYPE_UNDEF; // not initialized
4815 if( _EnumValues==NULL && _NbValues!=0 )
4817 g_TwMgr->SetLastError(g_ErrBadParam);
4818 return TW_TYPE_UNDEF;
4821 if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar first if it exists
4823 TwDeleteBar(g_TwMgr->m_PopupBar);
4824 g_TwMgr->m_PopupBar = NULL;
4827 size_t enumIndex = g_TwMgr->m_Enums.size();
4828 if( _Name!=NULL && strlen(_Name)>0 )
4829 for( size_t j=0; j<g_TwMgr->m_Enums.size(); ++j )
4830 if( strcmp(_Name, g_TwMgr->m_Enums[j].m_Name.c_str())==0 )
4835 if( enumIndex==g_TwMgr->m_Enums.size() )
4836 g_TwMgr->m_Enums.push_back(CTwMgr::CEnum());
4837 assert( enumIndex>=0 && enumIndex<g_TwMgr->m_Enums.size() );
4838 CTwMgr::CEnum& e = g_TwMgr->m_Enums[enumIndex];
4839 if( _Name!=NULL && strlen(_Name)>0 )
4843 e.m_Entries.clear();
4844 for(unsigned int i=0; i<_NbValues; ++i)
4846 CTwMgr::CEnum::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:"");
4847 pair<CTwMgr::CEnum::CEntries::iterator, bool> Result = e.m_Entries.insert(Entry);
4848 if( !Result.second )
4849 (Result.first)->second = Entry.second;
4852 return TwType( TW_TYPE_ENUM_BASE + enumIndex );
4855 // ---------------------------------------------------------------------------
4857 TwType TW_CALL TwDefineEnumFromString(const char *_Name, const char *_EnumString)
4859 if (_EnumString == NULL)
4860 return TwDefineEnum(_Name, NULL, 0);
4863 stringstream EnumStream(_EnumString);
4865 vector<string> Labels;
4866 while( getline(EnumStream, Label, ',') ) {
4868 size_t Start = Label.find_first_not_of(" \n\r\t");
4869 size_t End = Label.find_last_not_of(" \n\r\t");
4870 if( Start==string::npos || End==string::npos )
4873 Label = Label.substr(Start, (End-Start)+1);
4875 Labels.push_back(Label);
4877 // create TwEnumVal array
4878 vector<TwEnumVal> Vals(Labels.size());
4879 for( int i=0; i<(int)Labels.size(); i++ )
4882 Vals[i].Label = Labels[i].c_str();
4885 return TwDefineEnum(_Name, Vals.empty() ? NULL : &(Vals[0]), (unsigned int)Vals.size());
4888 // ---------------------------------------------------------------------------
4890 void ANT_CALL CTwMgr::CStruct::DefaultSummary(char *_SummaryString, size_t _SummaryMaxLength, const void *_Value, void *_ClientData)
4892 const CTwVarGroup *varGroup = static_cast<const CTwVarGroup *>(_Value); // special case
4893 if( _SummaryString && _SummaryMaxLength>0 )
4894 _SummaryString[0] = '\0';
4895 size_t structIndex = (size_t)(_ClientData);
4896 if( g_TwMgr && _SummaryString && _SummaryMaxLength>2
4897 && varGroup && static_cast<const CTwVar *>(varGroup)->IsGroup()
4898 && structIndex>=0 && structIndex<=g_TwMgr->m_Structs.size() )
4900 // return g_TwMgr->m_Structs[structIndex].m_Name.c_str();
4901 CTwMgr::CStruct& s = g_TwMgr->m_Structs[structIndex];
4902 _SummaryString[0] = '{';
4903 _SummaryString[1] = '\0';
4904 bool separator = false;
4905 for( size_t i=0; i<s.m_Members.size(); ++i )
4907 string varName = varGroup->m_Name + '.' + s.m_Members[i].m_Name;
4908 const CTwVar *var = varGroup->Find(varName.c_str(), NULL, NULL);
4911 if( var->IsGroup() )
4913 const CTwVarGroup *grp = static_cast<const CTwVarGroup *>(var);
4914 if( grp->m_SummaryCallback!=NULL )
4916 size_t l = strlen(_SummaryString);
4919 _SummaryString[l++] = ',';
4920 _SummaryString[l++] = '\0';
4922 if( grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary )
4923 grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp, grp->m_SummaryClientData);
4925 grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp->m_StructValuePtr, grp->m_SummaryClientData);
4931 size_t l = strlen(_SummaryString);
4934 _SummaryString[l++] = ',';
4935 _SummaryString[l++] = '\0';
4938 const CTwVarAtom *atom = static_cast<const CTwVarAtom *>(var);
4939 atom->ValueToString(&valString);
4940 if( atom->m_Type==TW_TYPE_BOOLCPP || atom->m_Type==TW_TYPE_BOOL8 || atom->m_Type==TW_TYPE_BOOL16 || atom->m_Type==TW_TYPE_BOOL32 )
4942 if (valString == "0")
4944 else if (valString == "1")
4945 valString = "\x7f"; // check sign
4947 strncat(_SummaryString, valString.c_str(), _SummaryMaxLength-l);
4950 if( strlen(_SummaryString)>_SummaryMaxLength-2 )
4954 size_t l = strlen(_SummaryString);
4955 if( l>_SummaryMaxLength-2 )
4957 _SummaryString[_SummaryMaxLength-2] = '.';
4958 _SummaryString[_SummaryMaxLength-1] = '.';
4959 _SummaryString[_SummaryMaxLength+0] = '\0';
4963 _SummaryString[l+0] = '}';
4964 _SummaryString[l+1] = '\0';
4969 // ---------------------------------------------------------------------------
4971 TwType ANT_CALL TwDefineStruct(const char *_StructName, const TwStructMember *_StructMembers, unsigned int _NbMembers, size_t _StructSize, TwSummaryCallback _SummaryCallback, void *_SummaryClientData)
4973 CTwFPU fpu; // force fpu precision
4977 TwGlobalError(g_ErrNotInit);
4978 return TW_TYPE_UNDEF; // not initialized
4980 if( _StructMembers==NULL || _NbMembers==0 || _StructSize==0 )
4982 g_TwMgr->SetLastError(g_ErrBadParam);
4983 return TW_TYPE_UNDEF;
4986 if( _StructName!=NULL && strlen(_StructName)>0 )
4987 for( size_t j=0; j<g_TwMgr->m_Structs.size(); ++j )
4988 if( strcmp(_StructName, g_TwMgr->m_Structs[j].m_Name.c_str())==0 )
4990 g_TwMgr->SetLastError(g_ErrExist);
4991 return TW_TYPE_UNDEF;
4994 size_t structIndex = g_TwMgr->m_Structs.size();
4996 s.m_Size = _StructSize;
4997 if( _StructName!=NULL && strlen(_StructName)>0 )
4998 s.m_Name = _StructName;
5001 s.m_Members.resize(_NbMembers);
5002 if( _SummaryCallback!=NULL )
5004 s.m_SummaryCallback = _SummaryCallback;
5005 s.m_SummaryClientData = _SummaryClientData;
5009 s.m_SummaryCallback = CTwMgr::CStruct::DefaultSummary;
5010 s.m_SummaryClientData = (void *)(structIndex);
5012 for( unsigned int i=0; i<_NbMembers; ++i )
5014 CTwMgr::CStructMember& m = s.m_Members[i];
5015 if( _StructMembers[i].Name!=NULL )
5016 m.m_Name = _StructMembers[i].Name;
5020 sprintf(name, "%u", i);
5023 m.m_Type = _StructMembers[i].Type;
5024 m.m_Size = 0; // to avoid endless recursivity in GetDataSize
5025 m.m_Size = CTwVar::GetDataSize(m.m_Type);
5026 if( _StructMembers[i].Offset<_StructSize )
5027 m.m_Offset = _StructMembers[i].Offset;
5030 g_TwMgr->SetLastError(g_ErrOffset);
5031 return TW_TYPE_UNDEF;
5033 if( _StructMembers[i].DefString!=NULL && strlen(_StructMembers[i].DefString)>0 )
5034 m.m_DefString = _StructMembers[i].DefString;
5039 g_TwMgr->m_Structs.push_back(s);
5040 assert( g_TwMgr->m_Structs.size()==structIndex+1 );
5041 return TwType( TW_TYPE_STRUCT_BASE + structIndex );
5044 // ---------------------------------------------------------------------------
5046 TwType ANT_CALL TwDefineStructExt(const char *_StructName, const TwStructMember *_StructExtMembers, unsigned int _NbExtMembers, size_t _StructSize, size_t _StructExtSize, TwStructExtInitCallback _StructExtInitCallback, TwCopyVarFromExtCallback _CopyVarFromExtCallback, TwCopyVarToExtCallback _CopyVarToExtCallback, TwSummaryCallback _SummaryCallback, void *_ClientData, const char *_Help)
5048 CTwFPU fpu; // force fpu precision
5052 TwGlobalError(g_ErrNotInit);
5053 return TW_TYPE_UNDEF; // not initialized
5055 if( _StructSize==0 || _StructExtInitCallback==NULL || _CopyVarFromExtCallback==NULL || _CopyVarToExtCallback==NULL )
5057 g_TwMgr->SetLastError(g_ErrBadParam);
5058 return TW_TYPE_UNDEF;
5060 TwType type = TwDefineStruct(_StructName, _StructExtMembers, _NbExtMembers, _StructExtSize, _SummaryCallback, _ClientData);
5061 if( type>=TW_TYPE_STRUCT_BASE && type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
5063 CTwMgr::CStruct& s = g_TwMgr->m_Structs[type-TW_TYPE_STRUCT_BASE];
5065 s.m_ClientStructSize = _StructSize;
5066 s.m_StructExtInitCallback = _StructExtInitCallback;
5067 s.m_CopyVarFromExtCallback = _CopyVarFromExtCallback;
5068 s.m_CopyVarToExtCallback = _CopyVarToExtCallback;
5069 s.m_ExtClientData = _ClientData;
5077 // ---------------------------------------------------------------------------
5079 bool TwGetKeyCode(int *_Code, int *_Modif, const char *_String)
5081 assert(_Code!=NULL && _Modif!=NULL);
5083 *_Modif = TW_KMOD_NONE;
5085 size_t Start = strlen(_String)-1;
5088 while( Start>0 && _String[Start-1]!='+' )
5090 while( _String[Start]==' ' || _String[Start]=='\t' )
5092 char *CodeStr = _strdup(_String+Start);
5093 for( size_t i=strlen(CodeStr)-1; i>=0; ++i )
5094 if( CodeStr[i]==' ' || CodeStr[i]=='\t' )
5100 if( strstr(_String, "SHIFT")!=NULL || strstr(_String, "shift")!=NULL )
5101 *_Modif |= TW_KMOD_SHIFT;
5102 if( strstr(_String, "CTRL")!=NULL || strstr(_String, "ctrl")!=NULL )
5103 *_Modif |= TW_KMOD_CTRL;
5104 if( strstr(_String, "META")!=NULL || strstr(_String, "meta")!=NULL )
5105 *_Modif |= TW_KMOD_META;
5107 if( strstr(_String, "ALTGR")!=NULL || strstr(_String, "altgr")!=NULL )
5108 ((void)(0)); // *_Modif |= TW_KMOD_ALTGR;
5109 else // ALT and ALTGR are exclusive
5110 if( strstr(_String, "ALT")!=NULL || strstr(_String, "alt")!=NULL )
5111 *_Modif |= TW_KMOD_ALT;
5113 char *up = _strdup(_String);
5115 for( char *upch=up; *upch!='\0'; ++upch )
5116 *upch = (char)toupper(*upch);
5117 if( strstr(up, "SHIFT")!=NULL )
5118 *_Modif |= TW_KMOD_SHIFT;
5119 if( strstr(up, "CTRL")!=NULL )
5120 *_Modif |= TW_KMOD_CTRL;
5121 if( strstr(up, "META")!=NULL )
5122 *_Modif |= TW_KMOD_META;
5124 if( strstr(up, "ALTGR")!=NULL )
5125 ((void)(0)); // *_Modif |= TW_KMOD_ALTGR;
5126 else // ALT and ALTGR are exclusive
5127 if( strstr(up, "ALT")!=NULL )
5128 *_Modif |= TW_KMOD_ALT;
5131 if( strlen(CodeStr)==1 )
5132 *_Code = (unsigned char)(CodeStr[0]);
5133 else if( _stricmp(CodeStr, "backspace")==0 || _stricmp(CodeStr, "bs")==0 )
5134 *_Code = TW_KEY_BACKSPACE;
5135 else if( _stricmp(CodeStr, "tab")==0 )
5136 *_Code = TW_KEY_TAB;
5137 else if( _stricmp(CodeStr, "clear")==0 || _stricmp(CodeStr, "clr")==0 )
5138 *_Code = TW_KEY_CLEAR;
5139 else if( _stricmp(CodeStr, "return")==0 || _stricmp(CodeStr, "ret")==0 )
5140 *_Code = TW_KEY_RETURN;
5141 else if( _stricmp(CodeStr, "pause")==0 )
5142 *_Code = TW_KEY_PAUSE;
5143 else if( _stricmp(CodeStr, "escape")==0 || _stricmp(CodeStr, "esc")==0 )
5144 *_Code = TW_KEY_ESCAPE;
5145 else if( _stricmp(CodeStr, "space")==0 )
5146 *_Code = TW_KEY_SPACE;
5147 else if( _stricmp(CodeStr, "delete")==0 || _stricmp(CodeStr, "del")==0 )
5148 *_Code = TW_KEY_DELETE;
5150 else if( strlen(CodeStr)==4 && CodeStr[3]>='0' && CodeStr[3]<='9' && (strstr(CodeStr, "pad")==CodeStr || strstr(CodeStr, "PAD")==CodeStr) )
5151 *_Code = TW_KEY_PAD_0 + CodeStr[3]-'0';
5152 else if( _stricmp(CodeStr, "pad.")==0 )
5153 *_Code = TW_KEY_PAD_PERIOD;
5154 else if( _stricmp(CodeStr, "pad/")==0 )
5155 *_Code = TW_KEY_PAD_DIVIDE;
5156 else if( _stricmp(CodeStr, "pad*")==0 )
5157 *_Code = TW_KEY_PAD_MULTIPLY;
5158 else if( _stricmp(CodeStr, "pad+")==0 )
5159 *_Code = TW_KEY_PAD_PLUS;
5160 else if( _stricmp(CodeStr, "pad-")==0 )
5161 *_Code = TW_KEY_PAD_MINUS;
5162 else if( _stricmp(CodeStr, "padenter")==0 )
5163 *_Code = TW_KEY_PAD_ENTER;
5164 else if( _stricmp(CodeStr, "pad=")==0 )
5165 *_Code = TW_KEY_PAD_EQUALS;
5167 else if( _stricmp(CodeStr, "up")==0 )
5169 else if( _stricmp(CodeStr, "down")==0 )
5170 *_Code = TW_KEY_DOWN;
5171 else if( _stricmp(CodeStr, "right")==0 )
5172 *_Code = TW_KEY_RIGHT;
5173 else if( _stricmp(CodeStr, "left")==0 )
5174 *_Code = TW_KEY_LEFT;
5175 else if( _stricmp(CodeStr, "insert")==0 || _stricmp(CodeStr, "ins")==0 )
5176 *_Code = TW_KEY_INSERT;
5177 else if( _stricmp(CodeStr, "home")==0 )
5178 *_Code = TW_KEY_HOME;
5179 else if( _stricmp(CodeStr, "end")==0 )
5180 *_Code = TW_KEY_END;
5181 else if( _stricmp(CodeStr, "pgup")==0 )
5182 *_Code = TW_KEY_PAGE_UP;
5183 else if( _stricmp(CodeStr, "pgdown")==0 )
5184 *_Code = TW_KEY_PAGE_DOWN;
5185 else if( (strlen(CodeStr)==2 || strlen(CodeStr)==3) && (CodeStr[0]=='f' || CodeStr[0]=='F') )
5188 if( sscanf(CodeStr+1, "%d", &n)==1 && n>0 && n<16 )
5189 *_Code = TW_KEY_F1 + n-1;
5198 bool TwGetKeyString(std::string *_String, int _Code, int _Modif)
5200 assert(_String!=NULL);
5202 if( _Modif & TW_KMOD_SHIFT )
5203 *_String += "SHIFT+";
5204 if( _Modif & TW_KMOD_CTRL )
5205 *_String += "CTRL+";
5206 if ( _Modif & TW_KMOD_ALT )
5208 if ( _Modif & TW_KMOD_META )
5209 *_String += "META+";
5210 // if ( _Modif & TW_KMOD_ALTGR )
5211 // *_String += "ALTGR+";
5214 case TW_KEY_BACKSPACE:
5215 *_String += "BackSpace";
5221 *_String += "Clear";
5224 *_String += "Return";
5227 *_String += "Pause";
5233 *_String += "Space";
5236 *_String += "Delete";
5269 case TW_KEY_PAD_PERIOD:
5272 case TW_KEY_PAD_DIVIDE:
5275 case TW_KEY_PAD_MULTIPLY:
5278 case TW_KEY_PAD_MINUS:
5281 case TW_KEY_PAD_PLUS:
5284 case TW_KEY_PAD_ENTER:
5285 *_String += "PADEnter";
5287 case TW_KEY_PAD_EQUALS:
5298 *_String += "Right";
5304 *_String += "Insert";
5312 case TW_KEY_PAGE_UP:
5315 case TW_KEY_PAGE_DOWN:
5316 *_String += "PgDown";
5364 if( _Code>0 && _Code<256 )
5365 *_String += char(_Code);
5368 *_String += "Unknown";
5375 // ---------------------------------------------------------------------------
5377 const int TW_MOUSE_NOMOTION = -1;
5378 ETwMouseAction TW_MOUSE_MOTION = (ETwMouseAction)(-2);
5379 ETwMouseAction TW_MOUSE_WHEEL = (ETwMouseAction)(-3);
5380 ETwMouseButtonID TW_MOUSE_NA = (ETwMouseButtonID)(-1);
5382 static int TwMouseEvent(ETwMouseAction _EventType, TwMouseButtonID _Button, int _MouseX, int _MouseY, int _WheelPos)
5384 CTwFPU fpu; // force fpu precision
5386 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
5388 // TwGlobalError(g_ErrNotInit); -> not an error here
5389 return 0; // not initialized
5391 if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
5393 //g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready.
5397 // For multi-thread safety
5398 if( !TwFreeAsyncDrawing() )
5401 if( _MouseX==TW_MOUSE_NOMOTION )
5402 _MouseX = g_TwMgr->m_LastMouseX;
5404 g_TwMgr->m_LastMouseX = _MouseX;
5405 if( _MouseY==TW_MOUSE_NOMOTION )
5406 _MouseY = g_TwMgr->m_LastMouseY;
5408 g_TwMgr->m_LastMouseY = _MouseY;
5411 if( (!g_TwMgr->m_IsRepeatingMousePressed || !g_TwMgr->m_CanRepeatMousePressed) && _EventType==TW_MOUSE_PRESSED )
5413 g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime();
5414 g_TwMgr->m_LastMousePressedButtonID = _Button;
5415 g_TwMgr->m_LastMousePressedPosition[0] = _MouseX;
5416 g_TwMgr->m_LastMousePressedPosition[1] = _MouseY;
5417 g_TwMgr->m_CanRepeatMousePressed = true;
5418 g_TwMgr->m_IsRepeatingMousePressed = false;
5420 else if( _EventType==TW_MOUSE_RELEASED || _EventType==TW_MOUSE_WHEEL )
5422 g_TwMgr->m_CanRepeatMousePressed = false;
5423 g_TwMgr->m_IsRepeatingMousePressed = false;
5426 bool Handled = false;
5427 bool wasPopup = (g_TwMgr->m_PopupBar!=NULL);
5431 // search for a bar with mousedrag enabled
5432 CTwBar *BarDragging = NULL;
5433 for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0; --i )
5435 Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5436 if( Bar!=NULL && Bar->m_Visible && Bar->IsDragging() )
5443 for( i=(int)g_TwMgr->m_Bars.size(); i>=0; --i )
5445 if( i==(int)g_TwMgr->m_Bars.size() ) // first try the bar with mousedrag enabled (this bar has the focus)
5449 Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5450 if( Bar==BarDragging )
5453 if( Bar!=NULL && Bar->m_Visible )
5455 if( _EventType==TW_MOUSE_MOTION )
5456 Handled = Bar->MouseMotion(_MouseX, _MouseY);
5457 else if( _EventType==TW_MOUSE_PRESSED || _EventType==TW_MOUSE_RELEASED )
5458 Handled = Bar->MouseButton(_Button, (_EventType==TW_MOUSE_PRESSED), _MouseX, _MouseY);
5459 else if( _EventType==TW_MOUSE_WHEEL )
5461 if( abs(_WheelPos-g_TwMgr->m_LastMouseWheelPos)<4 ) // avoid crazy wheel positions
5462 Handled = Bar->MouseWheel(_WheelPos, g_TwMgr->m_LastMouseWheelPos, _MouseX, _MouseY);
5469 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
5473 if( i>=0 && Bar!=NULL && Handled && (_EventType==TW_MOUSE_PRESSED || Bar->IsMinimized()) && i!=((int)g_TwMgr->m_Bars.size())-1 )
5475 int iOrder = g_TwMgr->m_Order[i];
5476 for( int j=i; j<(int)g_TwMgr->m_Bars.size()-1; ++j )
5477 g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1];
5478 g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = iOrder;
5481 if( _EventType==TW_MOUSE_PRESSED || (Bar!=NULL && Bar->IsMinimized() && Handled) )
5483 if( wasPopup && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL ) // delete popup
5485 TwDeleteBar(g_TwMgr->m_PopupBar);
5486 g_TwMgr->m_PopupBar = NULL;
5489 if( i>=0 && Bar!=NULL && Handled && !wasPopup )
5493 if( _EventType==TW_MOUSE_WHEEL )
5494 g_TwMgr->m_LastMouseWheelPos = _WheelPos;
5496 return Handled ? 1 : 0;
5499 int ANT_CALL TwMouseButton(ETwMouseAction _EventType, TwMouseButtonID _Button)
5501 return TwMouseEvent(_EventType, _Button, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, 0);
5504 int ANT_CALL TwMouseMotion(int _MouseX, int _MouseY)
5506 return TwMouseEvent(TW_MOUSE_MOTION, TW_MOUSE_NA, _MouseX, _MouseY, 0);
5509 int ANT_CALL TwMouseWheel(int _Pos)
5511 return TwMouseEvent(TW_MOUSE_WHEEL, TW_MOUSE_NA, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, _Pos);
5514 // ---------------------------------------------------------------------------
5516 static int TranslateKey(int _Key, int _Modifiers)
5518 // CTRL special cases
5519 //if( (_Modifiers&TW_KMOD_CTRL) && !(_Modifiers&TW_KMOD_ALT || _Modifiers&TW_KMOD_META) && _Key>0 && _Key<32 )
5521 if( (_Modifiers&TW_KMOD_CTRL) )
5523 if( _Key>='a' && _Key<='z' && ( ((_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
5525 else if ( _Key>='A' && _Key<='Z' && ( ((_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS
5529 // PAD translation (for SDL keysym)
5530 if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS
5532 //bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
5533 //_Modifiers &= ~TW_KMOD_SHIFT; // remove shift modifier
5534 bool Num = (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
5535 if( _Key==266 ) // SDLK_KP_PERIOD
5536 _Key = Num ? '.' : TW_KEY_DELETE;
5537 else if( _Key==267 ) // SDLK_KP_DIVIDE
5539 else if( _Key==268 ) // SDLK_KP_MULTIPLY
5541 else if( _Key==269 ) // SDLK_KP_MINUS
5543 else if( _Key==270 ) // SDLK_KP_PLUS
5545 else if( _Key==271 ) // SDLK_KP_ENTER
5546 _Key = TW_KEY_RETURN;
5547 else if( _Key==272 ) // SDLK_KP_EQUALS
5549 else if( Num ) // num SDLK_KP0..9
5551 else if( _Key==256 ) // non-num SDLK_KP01
5552 _Key = TW_KEY_INSERT;
5553 else if( _Key==257 ) // non-num SDLK_KP1
5555 else if( _Key==258 ) // non-num SDLK_KP2
5557 else if( _Key==259 ) // non-num SDLK_KP3
5558 _Key = TW_KEY_PAGE_DOWN;
5559 else if( _Key==260 ) // non-num SDLK_KP4
5561 else if( _Key==262 ) // non-num SDLK_KP6
5562 _Key = TW_KEY_RIGHT;
5563 else if( _Key==263 ) // non-num SDLK_KP7
5565 else if( _Key==264 ) // non-num SDLK_KP8
5567 else if( _Key==265 ) // non-num SDLK_KP9
5568 _Key = TW_KEY_PAGE_UP;
5573 // ---------------------------------------------------------------------------
5575 static int KeyPressed(int _Key, int _Modifiers, bool _TestOnly)
5577 CTwFPU fpu; // force fpu precision
5579 if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL )
5581 // TwGlobalError(g_ErrNotInit); -> not an error here
5582 return 0; // not initialized
5584 if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 )
5586 //g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready.
5590 // For multi-thread savety
5591 if( !TwFreeAsyncDrawing() )
5595 // Test for TwDeleteBar
5596 if( _Key>='0' && _Key<='9' )
5599 if( (int)g_TwMgr->m_Bars.size()>n && g_TwMgr->m_Bars[n]!=NULL )
5601 printf("Delete %s\n", g_TwMgr->m_Bars[n]->m_Name.c_str());
5602 TwDeleteBar(g_TwMgr->m_Bars[n]);
5605 printf("can't delete %d\n", n);
5611 //sprintf(s, "twkeypressed k=%d m=%x\n", _Key, _Modifiers);
5612 //OutputDebugString(s);
5614 _Key = TranslateKey(_Key, _Modifiers);
5615 if( _Key>' ' && _Key<256 ) // don't test SHIFT if _Key is a common key
5616 _Modifiers &= ~TW_KMOD_SHIFT;
5617 // complete partial modifiers comming from SDL
5618 if( _Modifiers & TW_KMOD_SHIFT )
5619 _Modifiers |= TW_KMOD_SHIFT;
5620 if( _Modifiers & TW_KMOD_CTRL )
5621 _Modifiers |= TW_KMOD_CTRL;
5622 if( _Modifiers & TW_KMOD_ALT )
5623 _Modifiers |= TW_KMOD_ALT;
5624 if( _Modifiers & TW_KMOD_META )
5625 _Modifiers |= TW_KMOD_META;
5627 bool Handled = false;
5629 CTwBar *PopupBar = g_TwMgr->m_PopupBar;
5632 if( _Key>0 && _Key<TW_KEY_LAST )
5634 // First send it to bar which includes the mouse pointer
5635 int MouseX = g_TwMgr->m_LastMouseX;
5636 int MouseY = g_TwMgr->m_LastMouseY;
5637 for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5639 Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5640 if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized()
5641 && ( (MouseX>=Bar->m_PosX && MouseX<Bar->m_PosX+Bar->m_Width && MouseY>=Bar->m_PosY && MouseY<Bar->m_PosY+Bar->m_Height)
5645 Handled = Bar->KeyTest(_Key, _Modifiers);
5647 Handled = Bar->KeyPressed(_Key, _Modifiers);
5651 // If not handled, send it to non-iconified bars in the right order
5652 for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5654 Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5656 for( size_t j=0; j<g_TwMgr->m_Bars.size(); ++j )
5657 if( g_TwMgr->m_Order[j]==i )
5659 Bar = g_TwMgr->m_Bars[j];
5665 if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() )
5668 Handled = Bar->KeyTest(_Key, _Modifiers);
5670 Handled = Bar->KeyPressed(_Key, _Modifiers);
5671 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
5676 // If not handled, send it to iconified bars in the right order
5677 for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i )
5679 Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]];
5680 if( Bar!=NULL && Bar->m_Visible && Bar->IsMinimized() )
5683 Handled = Bar->KeyTest(_Key, _Modifiers);
5685 Handled = Bar->KeyPressed(_Key, _Modifiers);
5689 if( g_TwMgr->m_HelpBar!=NULL && g_TwMgr->m_Graph && !_TestOnly )
5692 TwGetKeyString(&Str, _Key, _Modifiers);
5694 sprintf(Msg, "Key pressed: %s", Str.c_str());
5695 g_TwMgr->m_KeyPressedStr = Msg;
5696 g_TwMgr->m_KeyPressedBuildText = true;
5697 // OutputDebugString(Msg);
5701 if( Handled && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL && g_TwMgr->m_PopupBar==PopupBar ) // delete popup
5703 TwDeleteBar(g_TwMgr->m_PopupBar);
5704 g_TwMgr->m_PopupBar = NULL;
5707 if( Handled && Bar!=NULL && Bar!=g_TwMgr->m_PopupBar && Bar!=PopupBar ) // popup bar may have been destroyed
5710 return Handled ? 1 : 0;
5713 int ANT_CALL TwKeyPressed(int _Key, int _Modifiers)
5715 return KeyPressed(_Key, _Modifiers, false);
5718 int ANT_CALL TwKeyTest(int _Key, int _Modifiers)
5720 return KeyPressed(_Key, _Modifiers, true);
5723 // ---------------------------------------------------------------------------
5725 struct StructCompare : public binary_function<TwType, TwType, bool>
5727 bool operator()(const TwType& _Left, const TwType& _Right) const
5729 assert( g_TwMgr!=NULL );
5730 int i0 = _Left-TW_TYPE_STRUCT_BASE;
5731 int i1 = _Right-TW_TYPE_STRUCT_BASE;
5732 if( i0>=0 && i0<(int)g_TwMgr->m_Structs.size() && i1>=0 && i1<(int)g_TwMgr->m_Structs.size() )
5733 return g_TwMgr->m_Structs[i0].m_Name < g_TwMgr->m_Structs[i1].m_Name;
5739 typedef set<TwType, StructCompare> StructSet;
5741 static void InsertUsedStructs(StructSet& _Set, const CTwVarGroup *_Grp)
5743 assert( g_TwMgr!=NULL && _Grp!=NULL );
5745 for( size_t i=0; i<_Grp->m_Vars.size(); ++i )
5746 if( _Grp->m_Vars[i]!=NULL && _Grp->m_Vars[i]->m_Visible && _Grp->m_Vars[i]->IsGroup() )// && _Grp->m_Vars[i]->m_Help.length()>0 )
5748 const CTwVarGroup *SubGrp = static_cast<const CTwVarGroup *>(_Grp->m_Vars[i]);
5749 if( SubGrp->m_StructValuePtr!=NULL && SubGrp->m_StructType>=TW_TYPE_STRUCT_BASE && SubGrp->m_StructType<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[SubGrp->m_StructType-TW_TYPE_STRUCT_BASE].m_Name.length()>0 )
5751 if( SubGrp->m_Help.length()>0 )
5752 _Set.insert(SubGrp->m_StructType);
5755 int idx = SubGrp->m_StructType - TW_TYPE_STRUCT_BASE;
5756 if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 )
5758 for( size_t j=0; j<g_TwMgr->m_Structs[idx].m_Members.size(); ++j )
5759 if( g_TwMgr->m_Structs[idx].m_Members[j].m_Help.length()>0 )
5761 _Set.insert(SubGrp->m_StructType);
5767 InsertUsedStructs(_Set, SubGrp);
5771 static void SplitString(vector<string>& _OutSplits, const char *_String, int _Width, const CTexFont *_Font)
5773 assert( _Font!=NULL && _String!=NULL );
5774 _OutSplits.resize(0);
5775 int l = (int)strlen(_String);
5782 if( _String!=NULL && l>0 && _Width>0 )
5788 bool PrevNotBlank = true;
5790 bool Tab = false, CR = false;
5792 const string TabString(g_TabLength, ' ');
5799 w += g_TabLength * _Font->m_CharWidth[(int)' '];
5804 w += _Width+1; // force split
5809 w += _Font->m_CharWidth[(int)c];
5810 if( w>_Width || i==l-1 )
5812 if( Last<=First || i==l-1 )
5817 for(int k=0; k<Last-First+(CR?0:1); ++k)
5818 if( _String[First+k]=='\t' )
5821 Split += _String[First+k];
5825 Split.assign(_String+First, Last-First+(CR?0:1));
5826 _OutSplits.push_back(Split);
5829 while( First<l && (_String[First]==' ' || _String[First]=='\t') ) // skip blanks
5833 PrevNotBlank = true;
5837 else if( c==' ' || c=='\t' )
5841 PrevNotBlank = false;
5846 PrevNotBlank = true;
5853 static int AppendHelpString(CTwVarGroup *_Grp, const char *_String, int _Level, int _Width, ETwType _Type)
5855 assert( _Grp!=NULL && g_TwMgr!=NULL && g_TwMgr->m_HelpBar!=NULL);
5856 assert( _String!=NULL );
5858 const CTexFont *Font = g_TwMgr->m_HelpBar->m_Font;
5861 for( int s=0; s<_Level; ++s )
5863 int DecalWidth = (_Level+2)*Font->m_CharWidth[(int)' '];
5865 if( _Width>DecalWidth )
5867 vector<string> Split;
5868 SplitString(Split, _String, _Width-DecalWidth, Font);
5869 for( int i=0; i<(int)Split.size(); ++i )
5871 CTwVarAtom *Var = new CTwVarAtom;
5872 Var->m_Name = Decal + Split[i];
5874 if( _Type==TW_TYPE_HELP_HEADER )
5875 Var->m_ReadOnly = false;
5877 Var->m_ReadOnly = true;
5878 Var->m_NoSlider = true;
5879 Var->m_DontClip = true;
5880 Var->m_Type = _Type;
5881 Var->m_LeftMargin = (signed short)((_Level+1)*Font->m_CharWidth[(int)' ']);
5882 Var->m_TopMargin = (signed short)(-g_TwMgr->m_HelpBar->m_Sep);
5883 //Var->m_TopMargin = 1;
5884 Var->m_ColorPtr = &(g_TwMgr->m_HelpBar->m_ColHelpText);
5886 _Grp->m_Vars.push_back(Var);
5893 static int AppendHelp(CTwVarGroup *_Grp, const CTwVarGroup *_ToAppend, int _Level, int _Width)
5895 assert( _Grp!=NULL );
5896 assert( _ToAppend!=NULL );
5899 for( int s=0; s<_Level; ++s )
5902 if( _ToAppend->m_Help.size()>0 )
5903 n += AppendHelpString(_Grp, _ToAppend->m_Help.c_str(), _Level, _Width, TW_TYPE_HELP_GRP);
5905 for( size_t i=0; i<_ToAppend->m_Vars.size(); ++i )
5906 if( _ToAppend->m_Vars[i]!=NULL && _ToAppend->m_Vars[i]->m_Visible )
5909 if( !_ToAppend->m_Vars[i]->IsGroup() )
5911 const CTwVarAtom *a = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i]);
5912 if( a->m_Type==TW_TYPE_BUTTON && a->m_Val.m_Button.m_Callback==NULL )
5914 else if( a->m_KeyIncr[0]==0 && a->m_KeyIncr[1]==0 && a->m_KeyDecr[0]==0 && a->m_KeyDecr[1]==0 && a->m_Help.length()<=0 )
5917 else if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL // that's a struct var
5918 && _ToAppend->m_Vars[i]->m_Help.length()<=0 )
5923 CTwVarAtom *Var = new CTwVarAtom;
5924 Var->m_Name = Decal;
5925 if( _ToAppend->m_Vars[i]->m_Label.size()>0 )
5926 Var->m_Name += _ToAppend->m_Vars[i]->m_Label;
5928 Var->m_Name += _ToAppend->m_Vars[i]->m_Name;
5930 if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL )
5931 { // That's a struct var
5932 Var->m_Type = TW_TYPE_HELP_STRUCT;
5933 Var->m_Val.m_HelpStruct.m_StructType = static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructType;
5934 Var->m_ReadOnly = true;
5935 Var->m_NoSlider = true;
5937 else if( !_ToAppend->m_Vars[i]->IsGroup() )
5939 Var->m_Type = TW_TYPE_SHORTCUT;
5940 Var->m_Val.m_Shortcut.m_Incr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[0];
5941 Var->m_Val.m_Shortcut.m_Incr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyIncr[1];
5942 Var->m_Val.m_Shortcut.m_Decr[0] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[0];
5943 Var->m_Val.m_Shortcut.m_Decr[1] = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_KeyDecr[1];
5944 Var->m_ReadOnly = static_cast<const CTwVarAtom *>(_ToAppend->m_Vars[i])->m_ReadOnly;
5945 Var->m_NoSlider = true;
5949 Var->m_Type = TW_TYPE_HELP_GRP;
5950 Var->m_DontClip = true;
5951 Var->m_LeftMargin = (signed short)((_Level+2)*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
5952 //Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2-2+2*(_Level-1));
5953 Var->m_TopMargin = 2;
5954 if( Var->m_TopMargin>g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3 )
5955 Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3);
5956 Var->m_ReadOnly = true;
5959 _Grp->m_Vars.push_back(Var);
5960 size_t VarIndex = _Grp->m_Vars.size()-1;
5962 if( _ToAppend->m_Vars[i]->IsGroup() && static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i])->m_StructValuePtr==NULL )
5964 int nAppended = AppendHelp(_Grp, static_cast<const CTwVarGroup *>(_ToAppend->m_Vars[i]), _Level+1, _Width);
5965 if( _Grp->m_Vars.size()==VarIndex+1 )
5967 delete _Grp->m_Vars[VarIndex];
5968 _Grp->m_Vars.resize(VarIndex);
5973 else if( _ToAppend->m_Vars[i]->m_Help.length()>0 )
5974 n += AppendHelpString(_Grp, _ToAppend->m_Vars[i]->m_Help.c_str(), _Level+1, _Width, TW_TYPE_HELP_ATOM);
5981 static void CopyHierarchy(CTwVarGroup *dst, const CTwVarGroup *src)
5983 if( dst==NULL || src==NULL )
5986 dst->m_Name = src->m_Name;
5987 dst->m_Open = src->m_Open;
5988 dst->m_Visible = src->m_Visible;
5989 dst->m_ColorPtr = src->m_ColorPtr;
5990 dst->m_DontClip = src->m_DontClip;
5991 dst->m_IsRoot = src->m_IsRoot;
5992 dst->m_LeftMargin = src->m_LeftMargin;
5993 dst->m_TopMargin = src->m_TopMargin;
5995 dst->m_Vars.resize(src->m_Vars.size());
5996 for(size_t i=0; i<src->m_Vars.size(); ++i)
5997 if( src->m_Vars[i]!=NULL && src->m_Vars[i]->IsGroup() )
5999 CTwVarGroup *grp = new CTwVarGroup;
6000 CopyHierarchy(grp, static_cast<const CTwVarGroup *>(src->m_Vars[i]));
6001 dst->m_Vars[i] = grp;
6004 dst->m_Vars[i] = NULL;
6007 // copy the 'open' flag from original hierarchy to current hierarchy
6008 static void SynchroHierarchy(CTwVarGroup *cur, const CTwVarGroup *orig)
6010 if( cur==NULL || orig==NULL )
6013 if( strcmp(cur->m_Name.c_str(), orig->m_Name.c_str())==0 )
6014 cur->m_Open = orig->m_Open;
6017 while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
6020 for(size_t i=0; i<cur->m_Vars.size(); ++i)
6021 if( cur->m_Vars[i]!=NULL && cur->m_Vars[i]->IsGroup() && j<orig->m_Vars.size() && orig->m_Vars[j]!=NULL && orig->m_Vars[j]->IsGroup() )
6023 CTwVarGroup *curGrp = static_cast<CTwVarGroup *>(cur->m_Vars[i]);
6024 const CTwVarGroup *origGrp = static_cast<const CTwVarGroup *>(orig->m_Vars[j]);
6025 if( strcmp(curGrp->m_Name.c_str(), origGrp->m_Name.c_str())==0 )
6027 curGrp->m_Open = origGrp->m_Open;
6029 SynchroHierarchy(curGrp, origGrp);
6032 while( j<orig->m_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) )
6039 void CTwMgr::UpdateHelpBar()
6041 if( m_HelpBar==NULL || m_HelpBar->IsMinimized() )
6043 if( !m_HelpBarUpdateNow && (float)m_Timer.GetTime()<m_LastHelpUpdateTime+2 ) // update at most every 2 seconds
6045 m_HelpBarUpdateNow = false;
6046 m_LastHelpUpdateTime = (float)m_Timer.GetTime();
6048 //printf("UPDATE HELPBAR\n");
6051 CTwVarGroup prevHierarchy;
6052 CopyHierarchy(&prevHierarchy, &m_HelpBar->m_VarRoot);
6054 TwRemoveAllVars(m_HelpBar);
6056 if( m_HelpBar->m_UpToDate )
6057 m_HelpBar->Update();
6059 if( m_Help.size()>0 )
6060 AppendHelpString(&(m_HelpBar->m_VarRoot), m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6061 if( m_HelpBar->m_Help.size()>0 )
6062 AppendHelpString(&(m_HelpBar->m_VarRoot), m_HelpBar->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6063 AppendHelpString(&(m_HelpBar->m_VarRoot), "", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_HEADER);
6065 for( size_t ib=0; ib<m_Bars.size(); ++ib )
6066 if( m_Bars[ib]!=NULL && !(m_Bars[ib]->m_IsHelpBar) && m_Bars[ib]!=m_PopupBar && m_Bars[ib]->m_Visible )
6069 CTwVarGroup *Grp = new CTwVarGroup;
6070 Grp->m_SummaryCallback = NULL;
6071 Grp->m_SummaryClientData = NULL;
6072 Grp->m_StructValuePtr = NULL;
6073 if( m_Bars[ib]->m_Label.size()<=0 )
6074 Grp->m_Name = m_Bars[ib]->m_Name;
6076 Grp->m_Name = m_Bars[ib]->m_Label;
6078 Grp->m_ColorPtr = &(m_HelpBar->m_ColGrpText);
6079 m_HelpBar->m_VarRoot.m_Vars.push_back(Grp);
6080 if( m_Bars[ib]->m_Help.size()>0 )
6081 AppendHelpString(Grp, m_Bars[ib]->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_GRP);
6083 // Append variables (recursive)
6084 AppendHelp(Grp, &(m_Bars[ib]->m_VarRoot), 1, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0);
6086 // Append structures
6087 StructSet UsedStructs;
6088 InsertUsedStructs(UsedStructs, &(m_Bars[ib]->m_VarRoot));
6089 CTwVarGroup *StructGrp = NULL;
6090 int MemberCount = 0;
6091 for( StructSet::iterator it=UsedStructs.begin(); it!=UsedStructs.end(); ++it )
6093 int idx = (*it) - TW_TYPE_STRUCT_BASE;
6094 if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 )
6096 if( StructGrp==NULL )
6098 StructGrp = new CTwVarGroup;
6099 StructGrp->m_StructType = TW_TYPE_HELP_STRUCT; // a special line background color will be used
6100 StructGrp->m_Name = "Structures";
6101 StructGrp->m_Open = false;
6102 StructGrp->m_ColorPtr = &(m_HelpBar->m_ColStructText);
6103 //Grp->m_Vars.push_back(StructGrp);
6106 CTwVarAtom *Var = new CTwVarAtom;
6108 Var->m_Type = TW_TYPE_HELP_GRP;
6109 Var->m_DontClip = true;
6110 Var->m_LeftMargin = (signed short)(3*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']);
6111 Var->m_TopMargin = 2;
6112 Var->m_ReadOnly = true;
6113 Var->m_NoSlider = true;
6114 Var->m_Name = '{'+g_TwMgr->m_Structs[idx].m_Name+'}';
6115 StructGrp->m_Vars.push_back(Var);
6116 size_t structIndex = StructGrp->m_Vars.size()-1;
6117 if( g_TwMgr->m_Structs[idx].m_Help.size()>0 )
6118 AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Help.c_str(), 2, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-2*Var->m_LeftMargin, TW_TYPE_HELP_ATOM);
6120 // Append struct members
6121 for( size_t im=0; im<g_TwMgr->m_Structs[idx].m_Members.size(); ++im )
6123 if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 )
6125 CTwVarAtom *Var = new CTwVarAtom;
6127 Var->m_Type = TW_TYPE_SHORTCUT;
6128 Var->m_Val.m_Shortcut.m_Incr[0] = 0;
6129 Var->m_Val.m_Shortcut.m_Incr[1] = 0;
6130 Var->m_Val.m_Shortcut.m_Decr[0] = 0;
6131 Var->m_Val.m_Shortcut.m_Decr[1] = 0;
6132 Var->m_ReadOnly = false;
6133 Var->m_NoSlider = true;
6134 if( g_TwMgr->m_Structs[idx].m_Members[im].m_Label.length()>0 )
6135 Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Label;
6137 Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Name;
6138 StructGrp->m_Vars.push_back(Var);
6139 //if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 )
6140 AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Members[im].m_Help.c_str(), 3, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-4*Var->m_LeftMargin, TW_TYPE_HELP_ATOM);
6144 if( StructGrp->m_Vars.size()==structIndex+1 ) // remove struct from help
6146 delete StructGrp->m_Vars[structIndex];
6147 StructGrp->m_Vars.resize(structIndex);
6153 if( StructGrp!=NULL )
6155 if( MemberCount==1 )
6156 StructGrp->m_Name = "Structure";
6157 if( StructGrp->m_Vars.size()>0 )
6158 Grp->m_Vars.push_back(StructGrp);
6167 // Append RotoSlider
6168 CTwVarGroup *RotoGrp = new CTwVarGroup;
6169 RotoGrp->m_SummaryCallback = NULL;
6170 RotoGrp->m_SummaryClientData = NULL;
6171 RotoGrp->m_StructValuePtr = NULL;
6172 RotoGrp->m_Name = "RotoSlider";
6173 RotoGrp->m_Open = false;
6174 RotoGrp->m_ColorPtr = &(m_HelpBar->m_ColGrpText);
6175 m_HelpBar->m_VarRoot.m_Vars.push_back(RotoGrp);
6176 AppendHelpString(RotoGrp, "The RotoSlider allows rapid editing of numerical values.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6177 AppendHelpString(RotoGrp, "To modify a numerical value, click on its label or on its roto [.] button, then move the mouse outside of the grey circle while keeping the mouse button pressed, and turn around the circle to increase or decrease the numerical value.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6178 AppendHelpString(RotoGrp, "The two grey lines depict the min and max bounds.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6179 AppendHelpString(RotoGrp, "Moving the mouse far form the circle allows precise increase or decrease, while moving near the circle allows fast increase or decrease.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM);
6181 SynchroHierarchy(&m_HelpBar->m_VarRoot, &prevHierarchy);
6183 m_HelpBarNotUpToDate = false;
6186 // ---------------------------------------------------------------------------
6188 #if defined(ANT_WINDOWS)
6190 #include "res/TwXCursors.h"
6192 void CTwMgr::CreateCursors()
6194 if( m_CursorsCreated )
6196 m_CursorArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_ARROW));
6197 m_CursorMove = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEALL));
6198 m_CursorWE = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEWE));
6199 m_CursorNS = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENS));
6200 m_CursorTopRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
6201 m_CursorTopLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
6202 m_CursorBottomLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW));
6203 m_CursorBottomRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE));
6204 m_CursorHelp = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HELP));
6205 m_CursorCross = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6206 m_CursorUpArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
6207 m_CursorNo = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_NO));
6208 m_CursorIBeam = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_IBEAM));
6210 m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HAND));
6212 m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW));
6215 HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL);
6217 g_UseCurRsc = false; // force the use of built-in cursors (not using resources)
6219 m_CursorCenter = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+0));
6221 m_CursorCenter = PixmapCursor(0);
6222 if( m_CursorCenter==NULL )
6223 m_CursorCenter = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6225 m_CursorPoint = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+1));
6227 m_CursorPoint = PixmapCursor(1);
6228 if( m_CursorPoint==NULL )
6229 m_CursorPoint = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6231 for( cur=0; cur<NB_ROTO_CURSORS; ++cur )
6234 m_RotoCursors[cur] = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+2+cur));
6236 m_RotoCursors[cur] = PixmapCursor(cur+2);
6237 if( m_RotoCursors[cur]==NULL )
6238 m_RotoCursors[cur] = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS));
6241 m_CursorsCreated = true;
6245 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6248 unsigned char mask[32*4];
6249 unsigned char pict[32*4];
6250 for( y=0; y<32; ++y )
6252 mask[y*4+0] = pict[y*4+0] = 0;
6253 mask[y*4+1] = pict[y*4+1] = 0;
6254 mask[y*4+2] = pict[y*4+2] = 0;
6255 mask[y*4+3] = pict[y*4+3] = 0;
6256 for( x=0; x<32; ++x )
6258 mask[y*4+x/8] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<<(7-(x%8)));
6259 pict[y*4+x/8] |= (((unsigned int)(g_CurPict[_CurIdx][x+y*32]))<<(7-(x%8)));
6263 unsigned char ands[32*4];
6264 unsigned char xors[32*4];
6265 for( y=0; y<32*4; ++y )
6271 HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL);
6272 CCursor cursor = ::CreateCursor(hdll, g_CurHot[_CurIdx][0], g_CurHot[_CurIdx][1], 32, 32, ands, xors);
6277 void CTwMgr::FreeCursors()
6281 if( m_CursorCenter!=NULL )
6283 ::DestroyCursor(m_CursorCenter);
6284 m_CursorCenter = NULL;
6286 if( m_CursorPoint!=NULL )
6288 ::DestroyCursor(m_CursorPoint);
6289 m_CursorPoint = NULL;
6291 for( int cur=0; cur<NB_ROTO_CURSORS; ++cur )
6292 if( m_RotoCursors[cur]!=NULL )
6294 ::DestroyCursor(m_RotoCursors[cur]);
6295 m_RotoCursors[cur] = NULL;
6298 m_CursorsCreated = false;
6301 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6303 if( m_CursorsCreated )
6306 memset(&ci, 0, sizeof(ci));
6307 ci.cbSize = sizeof(ci);
6308 BOOL ok = ::GetCursorInfo(&ci);
6309 if( ok && (ci.flags & CURSOR_SHOWING) )
6310 ::SetCursor(_Cursor);
6315 #elif defined(ANT_OSX)
6317 #include "res/TwXCursors.h"
6319 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6321 unsigned char *data;
6324 NSBitmapImageRep *imgr = [[NSBitmapImageRep alloc]
6325 initWithBitmapDataPlanes: NULL
6332 colorSpaceName: NSCalibratedWhiteColorSpace
6333 bitmapFormat: NSAlphaNonpremultipliedBitmapFormat
6337 data = [imgr bitmapData];
6338 memset(data,0x0,32*8);
6339 for (y=0;y<32;y++) {
6340 for (x=0;x<32;x++) {
6341 //printf("%d",g_CurMask[_CurIdx][x+y*32]);
6342 data[(x>>2) + y*8] |= (unsigned char)(g_CurPict[_CurIdx][x+y*32] << 2*(3-(x&3))+1); //turn whiteon
6343 data[(x>>2) + y*8] |= (unsigned char)(g_CurMask[_CurIdx][x+y*32] << 2*(3-(x&3))); //turn the alpha all the way up
6347 NSImage *img = [[NSImage alloc] initWithSize: [imgr size]];
6348 [img addRepresentation: imgr];
6349 NSCursor *cur = [[NSCursor alloc] initWithImage: img hotSpot: NSMakePoint(g_CurHot[_CurIdx][0],g_CurHot[_CurIdx][1])];
6356 return [NSCursor arrowCursor];
6359 void CTwMgr::CreateCursors()
6361 if (m_CursorsCreated)
6364 m_CursorArrow = [[NSCursor arrowCursor] retain];
6365 m_CursorMove = [[NSCursor crosshairCursor] retain];
6366 m_CursorWE = [[NSCursor resizeLeftRightCursor] retain];
6367 m_CursorNS = [[NSCursor resizeUpDownCursor] retain];
6368 m_CursorTopRight = [[NSCursor arrowCursor] retain]; //osx not have one
6369 m_CursorTopLeft = [[NSCursor arrowCursor] retain]; //osx not have one
6370 m_CursorBottomRight = [[NSCursor arrowCursor] retain]; //osx not have one
6371 m_CursorBottomLeft = [[NSCursor arrowCursor] retain]; //osx not have one
6372 m_CursorHelp = [[NSCursor arrowCursor] retain]; //osx not have one
6373 m_CursorHand = [[NSCursor pointingHandCursor] retain];
6374 m_CursorCross = [[NSCursor arrowCursor] retain];
6375 m_CursorUpArrow = [[NSCursor arrowCursor] retain];
6376 m_CursorNo = [[NSCursor arrowCursor] retain];
6377 m_CursorIBeam = [[NSCursor IBeamCursor] retain];
6378 for (int i=0;i<NB_ROTO_CURSORS; i++)
6380 m_RotoCursors[i] = [PixmapCursor(i+2) retain];
6382 m_CursorCenter = [PixmapCursor(0) retain];
6383 m_CursorPoint = [PixmapCursor(1) retain];
6384 m_CursorsCreated = true;
6387 void CTwMgr::FreeCursors()
6389 [m_CursorArrow release];
6390 [m_CursorMove release];
6391 [m_CursorWE release];
6392 [m_CursorNS release];
6393 [m_CursorTopRight release];
6394 [m_CursorTopLeft release];
6395 [m_CursorBottomRight release];
6396 [m_CursorBottomLeft release];
6397 [m_CursorHelp release];
6398 [m_CursorHand release];
6399 [m_CursorCross release];
6400 [m_CursorUpArrow release];
6401 [m_CursorNo release];
6402 [m_CursorIBeam release];
6403 for( int i=0; i<NB_ROTO_CURSORS; ++i )
6404 [m_RotoCursors[i] release];
6405 [m_CursorCenter release];
6406 [m_CursorPoint release];
6407 m_CursorsCreated = false;
6410 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6412 if (m_CursorsCreated && _Cursor) {
6418 #elif defined(ANT_UNIX)
6420 #include "res/TwXCursors.h"
6422 static XErrorHandler s_PrevErrorHandler = NULL;
6424 static int InactiveErrorHandler(Display *display, XErrorEvent *err)
6426 fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n", err->error_code, err->request_code);
6431 static void IgnoreXErrors()
6433 if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
6435 XFlush(g_TwMgr->m_CurrentXDisplay);
6436 XSync(g_TwMgr->m_CurrentXDisplay, False);
6438 s_PrevErrorHandler = XSetErrorHandler(InactiveErrorHandler);
6441 static void RestoreXErrors()
6443 if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() )
6445 XFlush(g_TwMgr->m_CurrentXDisplay);
6446 XSync(g_TwMgr->m_CurrentXDisplay, False);
6448 XSetErrorHandler(s_PrevErrorHandler);
6451 CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx)
6453 if( !m_CurrentXDisplay || !m_CurrentXWindow )
6458 XColor black, white, exact;
6459 Colormap colmap = DefaultColormap(m_CurrentXDisplay, DefaultScreen(m_CurrentXDisplay));
6460 Status s1 = XAllocNamedColor(m_CurrentXDisplay, colmap, "black", &black, &exact);
6461 Status s2 = XAllocNamedColor(m_CurrentXDisplay, colmap, "white", &white, &exact);
6462 if( s1==0 || s2==0 )
6463 return XC_left_ptr; // cannot allocate colors!
6465 unsigned int mask[32];
6466 unsigned int pict[32];
6467 for( y=0; y<32; ++y )
6469 mask[y] = pict[y] = 0;
6470 for( x=0; x<32; ++x )
6472 mask[y] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<<x);
6473 pict[y] |= (((unsigned int)(g_CurPict[_CurIdx][x+y*32]))<<x);
6476 Pixmap maskPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)mask, 32, 32);
6477 Pixmap pictPix = XCreateBitmapFromData(m_CurrentXDisplay, m_CurrentXWindow, (char*)pict, 32, 32);
6478 Cursor cursor = XCreatePixmapCursor(m_CurrentXDisplay, pictPix, maskPix, &white, &black, g_CurHot[_CurIdx][0], g_CurHot[_CurIdx][1]);
6479 XFreePixmap(m_CurrentXDisplay, maskPix);
6480 XFreePixmap(m_CurrentXDisplay, pictPix);
6490 void CTwMgr::CreateCursors()
6492 if( m_CursorsCreated || !m_CurrentXDisplay || !m_CurrentXWindow )
6496 m_CursorArrow = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
6497 m_CursorMove = XCreateFontCursor(m_CurrentXDisplay, XC_plus);
6498 m_CursorWE = XCreateFontCursor(m_CurrentXDisplay, XC_left_side);
6499 m_CursorNS = XCreateFontCursor(m_CurrentXDisplay, XC_top_side);
6500 m_CursorTopRight= XCreateFontCursor(m_CurrentXDisplay, XC_top_right_corner);
6501 m_CursorTopLeft = XCreateFontCursor(m_CurrentXDisplay, XC_top_left_corner);
6502 m_CursorBottomRight = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_right_corner);
6503 m_CursorBottomLeft = XCreateFontCursor(m_CurrentXDisplay, XC_bottom_left_corner);
6504 m_CursorHelp = XCreateFontCursor(m_CurrentXDisplay, XC_question_arrow);
6505 m_CursorHand = XCreateFontCursor(m_CurrentXDisplay, XC_hand1);
6506 m_CursorCross = XCreateFontCursor(m_CurrentXDisplay, XC_X_cursor);
6507 m_CursorUpArrow = XCreateFontCursor(m_CurrentXDisplay, XC_center_ptr);
6508 m_CursorNo = XCreateFontCursor(m_CurrentXDisplay, XC_left_ptr);
6509 m_CursorIBeam = XCreateFontCursor(m_CurrentXDisplay, XC_xterm);
6510 for( int i=0; i<NB_ROTO_CURSORS; ++i )
6512 m_RotoCursors[i] = PixmapCursor(i+2);
6514 m_CursorCenter = PixmapCursor(0);
6515 m_CursorPoint = PixmapCursor(1);
6516 m_CursorsCreated = true;
6521 void CTwMgr::FreeCursors()
6525 XFreeCursor(m_CurrentXDisplay, m_CursorArrow);
6526 XFreeCursor(m_CurrentXDisplay, m_CursorMove);
6527 XFreeCursor(m_CurrentXDisplay, m_CursorWE);
6528 XFreeCursor(m_CurrentXDisplay, m_CursorNS);
6529 XFreeCursor(m_CurrentXDisplay, m_CursorTopRight);
6530 XFreeCursor(m_CurrentXDisplay, m_CursorTopLeft);
6531 XFreeCursor(m_CurrentXDisplay, m_CursorBottomRight);
6532 XFreeCursor(m_CurrentXDisplay, m_CursorBottomLeft);
6533 XFreeCursor(m_CurrentXDisplay, m_CursorHelp);
6534 XFreeCursor(m_CurrentXDisplay, m_CursorHand);
6535 XFreeCursor(m_CurrentXDisplay, m_CursorCross);
6536 XFreeCursor(m_CurrentXDisplay, m_CursorUpArrow);
6537 XFreeCursor(m_CurrentXDisplay, m_CursorNo);
6538 for( int i=0; i<NB_ROTO_CURSORS; ++i )
6539 XFreeCursor(m_CurrentXDisplay, m_RotoCursors[i]);
6540 XFreeCursor(m_CurrentXDisplay, m_CursorCenter);
6541 XFreeCursor(m_CurrentXDisplay, m_CursorPoint);
6543 m_CursorsCreated = false;
6548 void CTwMgr::SetCursor(CTwMgr::CCursor _Cursor)
6550 if( m_CursorsCreated && m_CurrentXDisplay && m_CurrentXWindow )
6552 Display *dpy = glXGetCurrentDisplay();
6553 if( dpy==g_TwMgr->m_CurrentXDisplay )
6555 Window wnd = glXGetCurrentDrawable();
6556 if( wnd!=g_TwMgr->m_CurrentXWindow )
6559 g_TwMgr->m_CurrentXWindow = wnd;
6561 // now _Cursor is not a valid cursor ID.
6566 XDefineCursor(m_CurrentXDisplay, m_CurrentXWindow, _Cursor);
6573 #endif //defined(ANT_UNIX)
6575 // ---------------------------------------------------------------------------
6577 void ANT_CALL TwCopyCDStringToClientFunc(TwCopyCDStringToClient copyCDStringToClientFunc)
6579 g_InitCopyCDStringToClient = copyCDStringToClientFunc;
6581 g_TwMgr->m_CopyCDStringToClient = copyCDStringToClientFunc;
6584 void ANT_CALL TwCopyCDStringToLibrary(char **destinationLibraryStringPtr, const char *sourceClientString)
6588 if( destinationLibraryStringPtr!=NULL )
6589 *destinationLibraryStringPtr = const_cast<char *>(sourceClientString);
6593 // static buffer to store sourceClientString copy associated to sourceClientString pointer
6594 std::vector<char>& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)sourceClientString];
6596 size_t len = (sourceClientString!=NULL) ? strlen(sourceClientString) : 0;
6597 if( Buf.size()<len+1 )
6598 Buf.resize(len+128); // len + some margin
6599 char *SrcStrCopy = &(Buf[0]);
6600 SrcStrCopy[0] = '\0';
6601 if( sourceClientString!=NULL )
6602 memcpy(SrcStrCopy, sourceClientString, len+1);
6603 SrcStrCopy[len] = '\0';
6604 if( destinationLibraryStringPtr!=NULL )
6605 *destinationLibraryStringPtr = SrcStrCopy;
6608 void ANT_CALL TwCopyStdStringToClientFunc(TwCopyStdStringToClient copyStdStringToClientFunc)
6610 g_InitCopyStdStringToClient = copyStdStringToClientFunc;
6612 g_TwMgr->m_CopyStdStringToClient = copyStdStringToClientFunc;
6615 void ANT_CALL TwCopyStdStringToLibrary(std::string& destLibraryString, const std::string& srcClientString)
6618 // check if destLibraryString should be initialized
6619 char *Mem = (char *)&destLibraryString;
6621 for( int i=0; i<sizeof(std::string) && Init; ++i )
6623 Init = false; // has already been initialized
6625 // ::new(&destLibraryString) std::string;
6628 destLibraryString = srcClientString;
6634 CTwMgr::CLibStdString srcLibString; // Convert VC++ Debug/Release std::string
6635 srcLibString.FromClient(srcClientString);
6636 const char *SrcStr = srcLibString.ToLib().c_str();
6637 const char **DstStrPtr = (const char **)&destLibraryString;
6639 // SrcStr can be defined locally by the caller, so we need to copy it
6640 // ( *DstStrPtr = copy of SrcStr )
6642 // static buffer to store srcClientString copy associated to srcClientString pointer
6643 std::vector<char>& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)&srcClientString];
6645 size_t len = strlen(SrcStr);
6646 if( Buf.size()<len+1 )
6647 Buf.resize(len+128); // len + some margin
6648 char *SrcStrCopy = &(Buf[0]);
6650 memcpy(SrcStrCopy, SrcStr, len+1);
6651 SrcStrCopy[len] = '\0';
6652 *DstStrPtr = SrcStrCopy;
6653 //*(const char **)&destLibraryString = srcClientString.c_str();
6656 // ---------------------------------------------------------------------------
6658 bool CRect::Subtract(const CRect& _Rect, vector<CRect>& _OutRects) const
6662 if( _Rect.Empty() || _Rect.Y>=Y+H || _Rect.Y+_Rect.H<=Y || _Rect.X>=X+W || _Rect.X+_Rect.W<=X )
6664 _OutRects.push_back(*this);
6674 _OutRects.push_back(CRect(X, Y, W, Y0-Y+1));
6677 if( _Rect.Y+_Rect.H<Y+H )
6679 Y1 = _Rect.Y+_Rect.H;
6680 _OutRects.push_back(CRect(X, Y1, W, Y+H-Y1));
6688 _OutRects.push_back(CRect(X, Y0, X0-X+1, Y1-Y0+1));
6691 if( _Rect.X+_Rect.W<X+W )
6693 X1 = _Rect.X+_Rect.W; //-1;
6694 _OutRects.push_back(CRect(X1, Y0, X+W-X1, Y1-Y0+1));
6700 bool CRect::Subtract(const vector<CRect>& _Rects, vector<CRect>& _OutRects) const
6703 size_t i, j, NbRects = _Rects.size();
6706 _OutRects.push_back(*this);
6711 vector<CRect> TmpRects;
6712 Subtract(_Rects[0], _OutRects);
6714 for( i=1; i<NbRects; i++)
6716 for( j=0; j<_OutRects.size(); j++ )
6717 _OutRects[j].Subtract(_Rects[i], TmpRects);
6718 _OutRects.swap(TmpRects);
6721 return _OutRects.empty();
6725 // ---------------------------------------------------------------------------