Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / object_viewer / object_viewer.cpp
blobe431430b634c847f161f72f797a5a87196620f68
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std_afx.h"
22 #undef OBJECT_VIEWER_EXPORT
23 #define OBJECT_VIEWER_EXPORT __declspec( dllexport )
25 #include <vector>
28 #include "object_viewer.h"
30 #include "nel/3d/nelu.h"
31 #include "nel/3d/mesh.h"
32 #include "nel/3d/mesh_mrm.h"
33 #include "nel/3d/mesh_mrm_skinned.h"
34 #include "nel/3d/transform_shape.h"
35 #include "nel/3d/mesh_instance.h"
36 #include "nel/3d/text_context.h"
37 #include "nel/3d/skeleton_model.h"
38 #include "nel/3d/init_3d.h"
39 #include "nel/3d/scene_group.h"
40 #include "nel/3d/animation_playlist.h"
41 #include "nel/3d/track_keyframer.h"
42 #include "nel/3d/register_3d.h"
43 #include "nel/3d/seg_remanence.h"
45 #include "nel/misc/common.h"
46 #include "nel/misc/file.h"
47 #include "nel/misc/path.h"
48 #include "nel/misc/time_nl.h"
49 #include "nel/misc/config_file.h"
51 #include "nel/sound/u_audio_mixer.h"
52 #include "nel/3d/water_pool_manager.h"
53 #include "nel/3d/landscape_model.h"
54 #include "nel/3d/visual_collision_manager.h"
55 #include "nel/3d/visual_collision_entity.h"
56 #include "nel/3d/ps_util.h"
59 #include "nel/pacs/global_retriever.h"
63 #include "select_movie_size.h"
64 #include "editable_range.h"
65 #include "range_manager.h"
66 #include "located_properties.h"
67 #include "color_button.h"
68 #include "particle_dlg.h"
69 #include "resource.h"
70 #include "main_frame.h"
71 #include "sound_system.h"
72 #include "scheme_manager.h"
73 #include "day_night_dlg.h"
74 #include "water_pool_editor.h"
75 #include "vegetable_dlg.h"
76 #include "dialog_progress.h"
77 #include "select_string.h"
78 #include "global_wind_dlg.h"
79 #include "sound_anim_dlg.h"
80 #include "light_group_factor.h"
81 #include "choose_bg_color_dlg.h"
82 #include "choose_sun_color_dlg.h"
83 #include "choose_frame_delay.h"
84 #include "skeleton_scale_dlg.h"
85 #include "graph.h"
86 #include "tune_mrm_dlg.h"
89 using namespace std;
90 using namespace NL3D;
91 using namespace NLMISC;
92 using namespace NLSOUND;
93 using namespace NLPACS;
99 static std::string SPath;
101 uint SkeletonUsedForSound = 0xFFFFFFFF;
102 CSoundContext SoundContext;
106 // Note!
108 // If this DLL is dynamically linked against the MFC
109 // DLLs, any functions exported from this DLL which
110 // call into MFC must have the AFX_MANAGE_STATE macro
111 // added at the very beginning of the function.
113 // For example:
115 // extern "C" BOOL PASCAL EXPORT ExportedFunction()
116 // {
117 // AFX_MANAGE_STATE(AfxGetStaticModuleState());
118 // // normal function body here
119 // }
121 // It is very important that this macro appear in each
122 // function, prior to any calls into MFC. This means that
123 // it must appear as the first statement within the
124 // function, even before any object variable declarations
125 // as their constructors may generate calls into the MFC
126 // DLL.
128 // Please see MFC Technical Notes 33 and 58 for additional
129 // details.
132 /////////////////////////////////////////////////////////////////////////////
133 // CObject_viewerApp
135 BEGIN_MESSAGE_MAP(CObject_viewerApp, CWinApp)
136 //{{AFX_MSG_MAP(CObject_viewerApp)
137 //}}AFX_MSG_MAP
138 END_MESSAGE_MAP()
140 /////////////////////////////////////////////////////////////////////////////
141 // CObject_viewerApp construction
143 CObject_viewerApp::CObject_viewerApp()
145 // TODO: add construction code here,
146 // Place all significant initialization in InitInstance
149 /////////////////////////////////////////////////////////////////////////////
150 // The one and only CObject_viewerApp object
152 CObject_viewerApp theApp;
155 bool CObjectViewer::_InstanceRunning = false;
157 // ***************************************************************************
159 class CObjView : public CView
161 public:
162 CObjView()
164 MainFrame=NULL;
166 virtual ~CObjView() {}
167 virtual void OnDraw (CDC *) {}
168 afx_msg BOOL OnEraseBkgnd(CDC* pDC)
170 return FALSE;
172 virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
174 if ((CNELU::Driver) && MainFrame)
175 MainFrame->DriverWindowProc (CNELU::Driver, m_hWnd, message, wParam, lParam);
177 return CView::WindowProc(message, wParam, lParam);
179 DECLARE_DYNCREATE(CObjView)
180 CMainFrame *MainFrame;
183 // ***************************************************************************
185 IMPLEMENT_DYNCREATE(CObjView, CView)
188 // ***************************************************************************
190 void animateCNELUScene (CCloudScape *cs, uint64 deltaTime = 0)
192 if (!cs) return;
193 static sint64 firstTime = NLMISC::CTime::getLocalTime();
194 static sint64 lastTime = NLMISC::CTime::getLocalTime();
195 if (deltaTime == 0)
197 deltaTime = NLMISC::CTime::getLocalTime() - lastTime;
199 lastTime += deltaTime;
200 float fdelta = 0.001f * (float) (lastTime - firstTime);
201 CNELU::Scene->animate ( fdelta);
202 cs->anim (fdelta, CNELU::Scene->getCam());
205 // ***************************************************************************
207 CObjectViewer::CObjectViewer ()
209 AFX_MANAGE_STATE(AfxGetStaticModuleState());
211 _SceneRoot= NULL;
213 init3d ();
215 // vl: is it really useful? i moved it from ov.exe init
216 CScene::registerBasics ();
218 registerSerial3d();
220 _MainFrame = NULL;
221 _SlotDlg=NULL;
222 _AnimationSetDlg=NULL;
223 _AnimationDlg=NULL;
224 _ParticleDlg = NULL;
225 _FontGenerator = NULL;
226 _VegetableLandscape= NULL;
227 _VegetableCollisionManager= NULL;
228 _VegetableCollisionEntity= NULL;
229 _CameraFocal = 75.f; // default value for the focal
230 _SelectedObject = 0xffffffff;
231 _LightGroupDlg = NULL;
232 _ChooseFrameDelayDlg = NULL;
233 _ChooseBGColorDlg = NULL;
234 _DayNightDlg = NULL;
235 _WaterPoolDlg = NULL;
236 _SoundAnimDlg = NULL;
237 _VegetableDlg = NULL;
238 _GlobalWindDlg = NULL;
239 _SkeletonScaleDlg = NULL;
240 _TuneMRMDlg= NULL;
243 // no frame delay is the default
244 _FrameDelay = 0;
246 // Hotspot color
247 _HotSpotColor.R=255;
248 _HotSpotColor.G=255;
249 _HotSpotColor.B=0;
250 _HotSpotColor.A=255;
252 _BackGroundColor = CRGBA::Black;
254 // Hotspot size
255 _HotSpotSize=10.f;
257 _Wpm = &NL3D::GetWaterPoolManager();
259 _GlobalRetriever= NULL;
260 _ObjectLightTest= NULL;
262 _CharacterScalePos= 1;
263 _CurrentCamera = -1;
264 _Direct3d = false;
265 _Fog = false;
266 _FogStart = 0;
267 _FogEnd = 1;
268 _FogColor = NLMISC::CRGBA::Black;
270 _FXUserMatrix.identity();
272 _FXMatrixVisible = false;
273 _FXUserMatrixVisible = false;
274 _SceneMatrixVisible = false;
275 _OcclusionTestMeshsVisible = false;
276 _CS = NULL;
279 // ***************************************************************************
280 std::string CObjectViewer::getModulePath() const
282 // Get the configuration file path (located in same directory as module)
283 HMODULE hModule = AfxGetInstanceHandle();
284 nlassert(hModule); // shouldn't be null now anymore in any case
285 nlassert(hModule != GetModuleHandle(NULL)); // if this is dll, the module handle can't be same as exe
286 TCHAR sModulePath[256];
287 int res = GetModuleFileName(hModule, sModulePath, 256); nlassert(res);
288 nldebug("Object viewer module path is '%s'", sModulePath);
290 SPath = NLMISC::CFile::getPath(tStrToUtf8(sModulePath));
292 return SPath + "object_viewer.cfg";
296 // ***************************************************************************
297 void CObjectViewer::loadDriverName()
299 // Load the config file
300 CConfigFile cf;
301 cf.load (getModulePath());
302 CConfigFile::CVar *var = cf.getVarPtr("driver");
303 _Direct3d = var && (var->asString() == "direct3d");
306 // ***************************************************************************
307 void CObjectViewer::loadConfigFile()
309 // Load object_viewer.ini
312 // Load the config file
313 CConfigFile cf;
314 cf.load (getModulePath());
318 // Add search pathes
319 CConfigFile::CVar &search_pathes = cf.getVar ("search_pathes");
320 for (uint i=0; i<(uint)search_pathes.size(); i++)
321 CPath::addSearchPath (search_pathes.asString(i));
323 catch(const EUnknownVar &)
328 // Add recusrive search pathes
329 CConfigFile::CVar &recursive_search_pathes = cf.getVar ("recursive_search_pathes");
330 for (uint i=0; i<(uint)recursive_search_pathes.size(); i++)
331 CPath::addSearchPath (recursive_search_pathes.asString(i), true, false);
333 catch(const EUnknownVar &)
336 // Add extension remapping
339 CConfigFile::CVar &extensions_remapping = cf.getVar ("extensions_remapping");
340 if (extensions_remapping.size()%2 != 0)
342 nlwarning ("extensions_remapping must have a multiple of 2 entries (ex: extensions_remapping={\"dds\",\"tga\"};)");
344 else
346 for (uint i=0; i<(uint)extensions_remapping.size(); i+=2)
347 CPath::remapExtension(extensions_remapping.asString(i), extensions_remapping.asString(i+1), true);
350 catch (const EUnknownVar &)
354 // debug, display path
355 //CPath::display();
357 // set the sound banks and sample banks
360 /* CConfigFile::CVar &var = cf.getVar("sound_path");
361 string soundPath = var.asString();
363 var = cf.getVar("soundbanks");
364 for (uint i=0; i<(uint)var.size(); i++)
366 string dir = soundPath;
367 dir.append("/").append(var.asString(i).c_str());
368 CSoundSystem::addSoundBank(dir);
372 CConfigFile::CVar &var = cf.getVar("sample_path");
373 string samplePath(var.asString());
374 CSoundSystem::setSamplePath(samplePath);
378 CConfigFile::CVar &var = cf.getVar("packed_sheet_path");
379 string packedSheetPath(var.asString());
380 CSoundSystem::setPackedSheetPath(packedSheetPath);
383 /*CConfigFile::CVar var = cf.getVar("samplebanks");
384 for (uint i=0; i<(uint)var.size(); i++)
385 CSoundSystem::addSampleBank(var.asString(i).c_str());*/
387 catch (const EUnknownVar &)
389 //::MessageBox(NULL, "warning : 'sample_path' or 'packed_sheet_path' variable not defined.\nSound will not work properly.", "Objectviewer.cfg", MB_OK|MB_ICONEXCLAMATION);
392 // load the camera focal
395 CConfigFile::CVar &camera_focal = cf.getVar("camera_focal");
396 _CameraFocal = camera_focal.asFloat();
398 catch (const EUnknownVar &)
403 // load Scene light setup.
406 CConfigFile::CVar &var = cf.getVar("scene_light_enabled");
407 _SceneLightEnabled = var.asInt() !=0 ;
409 catch (const EUnknownVar &)
411 _SceneLightEnabled= false;
415 CConfigFile::CVar &var = cf.getVar("scene_light_sun_ambiant");
416 _SceneLightSunAmbiant.R = var.asInt(0);
417 _SceneLightSunAmbiant.G = var.asInt(1);
418 _SceneLightSunAmbiant.B = var.asInt(2);
420 catch (const EUnknownVar &)
422 _SceneLightSunAmbiant= NLMISC::CRGBA::Black;
426 CConfigFile::CVar &var = cf.getVar("scene_light_sun_diffuse");
427 _SceneLightSunDiffuse.R = var.asInt(0);
428 _SceneLightSunDiffuse.G = var.asInt(1);
429 _SceneLightSunDiffuse.B = var.asInt(2);
431 catch (const EUnknownVar &)
433 _SceneLightSunDiffuse= NLMISC::CRGBA::White;
437 CConfigFile::CVar &var = cf.getVar("scene_light_sun_specular");
438 _SceneLightSunSpecular.R = var.asInt(0);
439 _SceneLightSunSpecular.G = var.asInt(1);
440 _SceneLightSunSpecular.B = var.asInt(2);
442 catch (const EUnknownVar &)
444 _SceneLightSunSpecular= NLMISC::CRGBA::White;
448 CConfigFile::CVar &var = cf.getVar("scene_light_sun_dir");
449 _SceneLightSunDir.x = var.asFloat(0);
450 _SceneLightSunDir.y = var.asFloat(1);
451 _SceneLightSunDir.z = var.asFloat(2);
452 _SceneLightSunDir.normalize();
454 catch (const EUnknownVar &)
456 _SceneLightSunDir.set(0, 1, -1);
457 _SceneLightSunDir.normalize();
461 CConfigFile::CVar &var = cf.getVar("object_light_test");
462 _ObjectLightTestShape= var.asString();
464 catch (const EUnknownVar &)
468 // Load vegetable Landscape cfg.
469 loadVegetableLandscapeCfg(cf);
471 // load automatfic animations
474 CConfigFile::CVar &var = cf.getVar("automatic_animation_path");
475 CUniquePtr<CAnimationSet> as(new CAnimationSet);
477 bool loadingOk = as->loadFromFiles(var.asString(),true ,"anim",true);
479 if (!loadingOk)
481 //::MessageBox(NULL, "Warning : Unable to load all automatic animation", "Error", MB_OK | MB_ICONEXCLAMATION);
482 nlwarning("Unable to load all automatic animation");
484 CNELU::Scene->setAutomaticAnimationSet(as.release());
486 catch (const EUnknownVar &)
488 //::MessageBox(NULL, "No automatic animation path specified, please set 'automatic_animation_path'", "warning", MB_OK);
489 nlwarning("No automatic animation path specified");
492 // load CharacterScalePos
495 CConfigFile::CVar &var = cf.getVar("character_scale_pos");
496 _CharacterScalePos= var.asFloat();
498 catch (const EUnknownVar &)
502 // Fog
503 CConfigFile::CVar *var = cf.getVarPtr("fog");
504 if (var)
505 _Fog = var->asInt() != 0;
506 var = cf.getVarPtr("fog_start");
507 if (var)
508 _FogStart = var->asFloat();
509 var = cf.getVarPtr("fog_end");
510 if (var)
511 _FogEnd = var->asFloat();
512 var = cf.getVarPtr("fog_color");
513 if (var)
514 _FogColor = CRGBA ((uint8)(var->asInt(0)), (uint8)(var->asInt(1)), (uint8)(var->asInt(2)));
516 // Clouds
517 _CSS.NbCloud = 0;
518 if (var = cf.getVarPtr("cloud_count"))
519 _CSS.NbCloud = var->asInt();
520 if (var = cf.getVarPtr("cloud_diffuse"))
522 _CSS.Diffuse.R = var->asInt(0);
523 _CSS.Diffuse.G = var->asInt(1);
524 _CSS.Diffuse.B = var->asInt(2);
526 if (var = cf.getVarPtr("cloud_ambient"))
528 _CSS.Ambient.R = var->asInt(0);
529 _CSS.Ambient.G = var->asInt(1);
530 _CSS.Ambient.B = var->asInt(2);
532 if (var = cf.getVarPtr("cloud_speed"))
533 _CSS.CloudSpeed = var->asFloat();
534 if (var = cf.getVarPtr("cloud_update_period"))
535 _CSS.TimeToChange = var->asFloat();
536 if (var = cf.getVarPtr("cloud_wind_speed"))
537 _CSS.WindSpeed = var->asFloat();
539 catch (const Exception& e)
541 ::MessageBox(NULL, nlUtf8ToTStr(e.what()), _T("Objectviewer.cfg"), MB_OK | MB_ICONEXCLAMATION);
546 // ***************************************************************************
547 // properly remove a single window
548 static void removeWindow(CWnd *wnd)
550 if (!wnd) return;
551 wnd->DestroyWindow();
552 delete wnd;
555 // ***************************************************************************
556 CObjectViewer::~CObjectViewer ()
558 AFX_MANAGE_STATE(AfxGetStaticModuleState());
559 removeWindow(_MainFrame);
560 removeWindow(_SlotDlg);
561 removeWindow(_AnimationSetDlg);
562 removeWindow(_AnimationDlg);
563 removeWindow(_DayNightDlg);
564 removeWindow(_WaterPoolDlg);
565 removeWindow(_SoundAnimDlg);
566 removeWindow(_LightGroupDlg);
567 removeWindow(_ChooseBGColorDlg);
568 removeWindow(_VegetableDlg);
569 removeWindow(_GlobalWindDlg);
570 removeWindow(_SkeletonScaleDlg);
571 removeWindow(_TuneMRMDlg);
572 delete _FontGenerator;
575 // ***************************************************************************
577 void CObjectViewer::initCamera ()
579 // Camera
580 CFrustum frustrum;
581 uint32 width, height;
582 CNELU::Driver->getWindowSize (width, height);
583 frustrum.initPerspective( _CameraFocal *(float)Pi/180.f, height != 0 ? (float)width/(float)height : 0.f, 0.1f, 1000.f);
584 CNELU::Camera->setFrustum (frustrum);
586 // Others camera
587 uint i;
588 for (i=0; i<_Cameras.size (); i++)
590 frustrum.initPerspective( _ListInstance[_Cameras[i]]->Camera->getFov(), height != 0 ? (float)width/(float)height : 0.f, 0.1f, 1000.f);
591 _ListInstance[_Cameras[i]]->Camera->setFrustum (frustrum);
595 // ***************************************************************************
597 namespace NL3D {
598 CFontGenerator *newCFontGenerator(const std::string &fontFileName);
601 // ***************************************************************************
603 bool CObjectViewer::initUI (HWND parent)
605 AFX_MANAGE_STATE(AfxGetStaticModuleState());
607 // initialize NeL context if needed
608 if (!NLMISC::INelContext::isContextInitialised())
610 new NLMISC::CApplicationContext();
611 nldebug("NeL Object Viewer: initUI");
614 // The fonts manager
615 _FontManager.setMaxMemory(2000000);
617 // The windows path
618 uint dSize = ::GetWindowsDirectory(NULL, 0);
619 nlverify(dSize);
621 TCHAR *wd = new TCHAR[dSize];
622 nlverify(::GetWindowsDirectory(wd, dSize));
623 _FontPath = tStrToUtf8(wd) + "\\fonts\\arial.ttf";
624 delete[] wd;
626 // The font generator
627 _FontGenerator = NL3D::newCFontGenerator ( _FontPath );
629 // The viewport
630 CViewport viewport;
632 // Create the icon
633 HICON hIcon = (HICON)LoadImage(theApp.m_hInstance, MAKEINTRESOURCE(IDI_APP_ICON), IMAGE_ICON,
634 16, 16, 0);
636 // load name of the driver from the config file
637 loadDriverName();
639 // Create a doomy driver
640 IDriver *driver= _Direct3d?CDRU::createD3DDriver():CDRU::createGlDriver();
642 // Get parent window
643 CWnd parentWnd;
644 CWnd *parentWndPtr=NULL;
645 if (parent)
647 parentWnd.Attach (parent);
648 parentWndPtr=&parentWnd;
651 // Create the main frame
652 _MainFrame = new CMainFrame (this, (winProc) driver->getWindowProc());
654 // Read register
655 _MainFrame->registerValue (true);
657 // Create the window
658 _MainFrame->CFrameWnd::Create (AfxRegisterWndClass(0, 0, NULL, hIcon),
659 _T("NeL object viewer"), 0x00cfc000, /*WS_OVERLAPPEDWINDOW,*/ CFrameWnd::rectDefault, parentWndPtr,
660 MAKEINTRESOURCE(IDR_OBJECT_VIEWER_MENU), 0x00000300 /*WS_EX_ACCEPTFILES*/ /*|WS_EX_CLIENTEDGE*/);
662 // Detach the hwnd
663 parentWnd.Detach ();
665 // Delete doomy driver
666 delete driver;
668 // Create a cwnd
669 getRegisterWindowState (_MainFrame, REGKEY_OBJ_VIEW_OPENGL_WND, true);
670 _MainFrame->ActivateFrame ();
671 _MainFrame->ShowWindow (SW_SHOW);
672 _MainFrame->UpdateWindow();
674 // Context to open a view
675 CCreateContext context;
676 context.m_pCurrentDoc=NULL;
677 context.m_pCurrentFrame=_MainFrame;
678 context.m_pLastView=NULL;
679 context.m_pNewDocTemplate=NULL;
680 context.m_pNewViewClass=RUNTIME_CLASS(CObjView);
682 // Create a view
683 CObjView *view = (CObjView*)_MainFrame->CreateView (&context);
684 view->ShowWindow (SW_SHOW);
685 _MainFrame->SetActiveView(view);
686 view = (CObjView*)_MainFrame->GetActiveView();
687 view->MainFrame = _MainFrame;
689 _MainFrame->ShowWindow (SW_SHOW);
691 RECT viewportRect;
692 GetClientRect(view->m_hWnd, &viewportRect);
694 // Init NELU
695 if (!CNELU::init (viewportRect.right, viewportRect.bottom, viewport, 32, true, view->m_hWnd, false, _Direct3d))
697 return false;
699 //CNELU::init (640, 480, viewport, 32, true, _MainFrame->m_hWnd);
700 CNELU::Scene->setPolygonBalancingMode(CScene::PolygonBalancingClamp);
702 // load the config file
703 loadConfigFile();
705 // Set the fog
706 CNELU::Driver->enableFog (_Fog);
707 CNELU::Driver->setupFog (_FogStart, _FogEnd, _FogColor);
709 // init sound
710 CSoundSystem::initSoundSystem ();
712 // Create a root.
713 _SceneRoot= (CTransform*)CNELU::Scene->createModel(NL3D::TransformId);
715 // Init default lighting seutp.
716 setupSceneLightingSystem(_SceneLightEnabled, _SceneLightSunDir, _SceneLightSunAmbiant, _SceneLightSunDiffuse, _SceneLightSunSpecular);
718 // Camera
719 initCamera ();
721 _MainFrame->OnResetCamera();
723 // Create animation set dialog
724 _AnimationSetDlg=new CAnimationSetDlg (this, _MainFrame);
725 _AnimationSetDlg->Create (IDD_ANIMATION_SET);
726 getRegisterWindowState (_AnimationSetDlg, REGKEY_OBJ_VIEW_ANIMATION_SET_DLG, false);
728 // Create animation set dialog
729 _AnimationDlg=new CAnimationDlg (this, _MainFrame);
730 _AnimationDlg->Create (IDD_ANIMATION);
731 getRegisterWindowState (_AnimationDlg, REGKEY_OBJ_VIEW_ANIMATION_DLG, false);
733 // Create the main dialog
734 _SlotDlg=new CMainDlg (this, _MainFrame);
735 _SlotDlg->Create (IDD_MAIN_DLG);
736 getRegisterWindowState (_SlotDlg, REGKEY_OBJ_VIEW_SLOT_DLG, false);
738 // Create particle dialog
739 _ParticleDlg=new CParticleDlg (this, _MainFrame, _MainFrame, _AnimationDlg);
740 _ParticleDlg->Create (IDD_PARTICLE);
741 getRegisterWindowState (_ParticleDlg, REGKEY_OBJ_PARTICLE_DLG, false);
743 // Create water pool editor dialog
744 _WaterPoolDlg = new CWaterPoolEditor(_Wpm, _MainFrame);
745 _WaterPoolDlg->Create (IDD_WATER_POOL);
746 getRegisterWindowState (_WaterPoolDlg, REGKEY_OBJ_WATERPOOL_DLG, false);
748 // Create day night dialog
749 _DayNightDlg = new CDayNightDlg (this, _MainFrame);
750 _DayNightDlg->Create (IDD_DAYNIGHT);
751 getRegisterWindowState (_DayNightDlg, REGKEY_OBJ_DAYNIGHT_DLG, false);
753 // Create vegetable dialog
754 _VegetableDlg=new CVegetableDlg (this, _MainFrame);
755 _VegetableDlg->Create (IDD_VEGETABLE_DLG);
756 getRegisterWindowState (_VegetableDlg, REGKEY_OBJ_VIEW_VEGETABLE_DLG, false);
758 // Create global wind dialog
759 _GlobalWindDlg= new CGlobalWindDlg (this, _MainFrame);
760 _GlobalWindDlg->Create(IDD_GLOBAL_WIND);
761 getRegisterWindowState (_GlobalWindDlg, REGKEY_OBJ_GLOBAL_WIND_DLG, false);
763 // Create sound animation editor dialog
764 _SoundAnimDlg = new CSoundAnimDlg(this, _AnimationDlg, _MainFrame);
765 _SoundAnimDlg->Create (IDD_SOUND_ANIM_DLG, _MainFrame);
766 getRegisterWindowState (_SoundAnimDlg, REGKEY_OBJ_SOUND_ANIM_DLG, false);
768 // Create light group editor dialog
769 _LightGroupDlg = new CLightGroupFactor(_MainFrame);
770 _LightGroupDlg->Create (IDD_LIGHT_GROUP_FACTOR, _MainFrame);
771 getRegisterWindowState (_LightGroupDlg, REGKEY_OBJ_LIGHT_GROUP_DLG, false);
773 // Create frame delay window
774 _ChooseFrameDelayDlg = new CChooseFrameDelay(this, _MainFrame);
775 _ChooseFrameDelayDlg->Create(IDD_CHOOSE_FRAME_DELAY, _MainFrame);
776 getRegisterWindowState (_ChooseFrameDelayDlg, REGKEY_CHOOSE_FRAME_DELAY_DLG, false);
778 // Set backgroupnd color
779 setBackGroundColor(_MainFrame->BgColor);
781 // Create bg color window (must create after the background color has been set)
782 _ChooseBGColorDlg = new CChooseBGColorDlg(this, _MainFrame);
783 _ChooseBGColorDlg->Create(IDD_CHOOSE_BG_COLOR, _MainFrame);
784 getRegisterWindowState (_ChooseBGColorDlg, REGKEY_CHOOSE_BG_COLOR_DLG, false);
786 // Create bg color window (must create after the background color has been set)
787 _ChooseSunColorDlg = new CChooseSunColorDlg(CNELU::Scene, _MainFrame);
788 _ChooseSunColorDlg->Create(IDD_CHOOSE_SUN_COLOR, _MainFrame);
789 getRegisterWindowState (_ChooseSunColorDlg, REGKEY_CHOOSE_SUN_COLOR_DLG, false);
791 // Create skeleton scale dlg
792 _SkeletonScaleDlg = new CSkeletonScaleDlg(this, _MainFrame);
793 _SkeletonScaleDlg->Create(IDD_SKELETON_SCALE_DLG, _MainFrame);
794 getRegisterWindowState (_SkeletonScaleDlg, REGKEY_SKELETON_SCALE_DLG, false);
796 // Create tune mrm dlg
797 _TuneMRMDlg = new CTuneMrmDlg(this, CNELU::Scene, _MainFrame);
798 _TuneMRMDlg->Create(IDD_TUNE_MRM_DLG, _MainFrame);
799 getRegisterWindowState (_TuneMRMDlg, REGKEY_TUNE_MRM_DLG, false);
802 _MainFrame->update ();
805 // Set current frame
806 setAnimTime (0.f, 100.f);
808 // Add mouse listener to event server
809 _MouseListener.addToServer(CNELU::EventServer);
811 CNELU::Driver->activate ();
813 // Enable sum of vram
814 CNELU::Driver->enableUsedTextureMemorySum ();
816 // load the scheme bank if one is present
817 CIFile iF;
818 std::string path = SPath + "default.scb";
819 if (iF.open(path))
823 iF.serial(SchemeManager);
825 catch (const NLMISC::EStream &e)
827 std::string msg = toString("Unable to load the default scheme bank file : %s", e.what());
828 ::MessageBox(NULL, nlUtf8ToTStr(msg), _T("Object Viewer"), MB_ICONEXCLAMATION);
831 iF.close();
833 // try to load a default config file for the viewer (for anitmation and particle edition setup)
834 path = SPath + "default.ovcgf";
836 if (iF.open (path))
840 serial (iF);
842 catch (const Exception& e)
844 std::string msg = toString("Error while loading default.ovcgf : %s", e.what());
845 ::MessageBox(NULL, nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
849 // Create the cloud scape
850 _CS = new CCloudScape(CNELU::Driver);
851 _CS->init (&_CSS);
853 return true;
856 // ***************************************************************************
858 void CObjectViewer::addTransformation (CMatrix &current, CAnimation *anim, float begin, float end, ITrack *posTrack, ITrack *rotquatTrack,
859 ITrack *nextPosTrack, ITrack *nextRotquatTrack, bool removeLast)
861 // In place ?
862 if (_AnimationDlg->Inplace)
864 // Just identity
865 current.identity();
867 else
869 // Remove the start of the animation
870 CQuat rotEnd (0,0,0,1);
871 CVector posEnd (0,0,0);
872 if (rotquatTrack)
874 // Interpolate the rotation
875 rotquatTrack->interpolate (end, rotEnd);
877 if (posTrack)
879 // Interpolate the position
880 posTrack->interpolate (end, posEnd);
883 // Add the final rotation and position
884 CMatrix tmp;
885 tmp.identity ();
886 tmp.setRot (rotEnd);
887 tmp.setPos (posEnd);
889 // Incremental ?
890 if (_AnimationDlg->IncPos)
891 current *= tmp;
892 else
893 current = tmp;
895 if (removeLast)
897 CQuat rotStart (0,0,0,1);
898 CVector posStart (0,0,0);
899 if (nextRotquatTrack)
901 // Interpolate the rotation
902 nextRotquatTrack->interpolate (begin, rotStart);
904 if (nextPosTrack)
906 // Interpolate the position
907 nextPosTrack->interpolate (begin, posStart);
909 // Remove the init rotation and position of the next animation
910 tmp.identity ();
911 tmp.setRot (rotStart);
912 tmp.setPos (posStart);
913 tmp.invert ();
914 current *= tmp;
916 // Normalize the mt
917 CVector I = current.getI ();
918 CVector J = current.getJ ();
919 I.z = 0;
920 J.z = 0;
921 J.normalize ();
922 CVector K = I^J;
923 K.normalize ();
924 I = J^K;
925 I.normalize ();
926 tmp.setRot (I, J, K);
927 tmp.setPos (current.getPos ());
928 current = tmp;
933 // ***************************************************************************
935 void CObjectViewer::setupPlaylist (float time)
937 // Update animation dlg
939 // Gor each object
940 uint i;
941 for (i=0; i<_ListInstance.size(); i++)
943 // Empty with playlist
944 uint j;
945 for (j=0; j<CChannelMixer::NumAnimationSlot; j++)
947 // Empty slot
948 _ListInstance[i]->Playlist.setAnimation (j, CAnimationPlaylist::empty);
951 // With channel mixer ?
952 if (_AnimationSetDlg->UseMixer)
954 // Setup from slots
955 _ListInstance[i]->setAnimationPlaylist (getFrameRate ());
957 // A playlist
958 _ListInstance[i]->Playlist.setupMixer (_ListInstance[i]->ChannelMixer, _AnimationDlg->getTime());
960 else
962 // Some animation in the list ?
963 if (_ListInstance[i]->Saved.PlayList.size()>0)
965 // Index choosed
966 uint choosedIndex = 0xffffffff;
968 // Track here
969 bool there = false;
971 // Current matrix
972 CMatrix current;
973 current.identity ();
975 // Current animation
976 CAnimation *anim = NULL;
977 ITrack *posTrack = NULL;
978 ITrack *rotquatTrack = NULL;
980 // Try channel animationset
981 anim = _ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[0]));
982 if (anim)
984 posTrack = (ITrack *)anim->getTrackByName ("pos");
985 rotquatTrack = (ITrack *)anim->getTrackByName ("rotquat");
987 there = posTrack || rotquatTrack;
989 // Accumul time
990 float startTime=0;
991 float endTime=anim->getEndTime()-anim->getBeginTime();
993 // Animation index
994 uint index = 0;
996 // Get animation used in the list
997 while (time>=endTime)
999 // Next animation
1000 index++;
1001 if (index<_ListInstance[i]->Saved.PlayList.size())
1003 // Pointer on the animation
1004 CAnimation *newAnim=_ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName(_ListInstance[i]->Saved.PlayList[index]));
1005 ITrack *newPosTrack = (ITrack *)newAnim->getTrackByName ("pos");
1006 ITrack *newRotquatTrack = (ITrack *)newAnim->getTrackByName ("rotquat");
1008 // Add the transformation
1009 addTransformation (current, anim, newAnim->getBeginTime(), anim->getEndTime(), posTrack, rotquatTrack, newPosTrack, newRotquatTrack, true);
1011 // Pointer on the animation
1012 anim = newAnim;
1013 posTrack = newPosTrack;
1014 rotquatTrack = newRotquatTrack;
1016 // Add start time
1017 startTime = endTime;
1018 endTime = startTime + anim->getEndTime()-anim->getBeginTime();
1021 else
1023 // Add the transformation
1024 addTransformation (current, anim, 0, anim->getEndTime(), posTrack, rotquatTrack, NULL, NULL, false);
1026 break;
1030 // Time cropped ?
1031 if (index>=_ListInstance[i]->Saved.PlayList.size())
1033 // Yes
1034 index--;
1036 // Good index
1037 choosedIndex = _ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[index]);
1038 anim=_ListInstance[i]->AnimationSet.getAnimation (choosedIndex);
1040 // End time for last anim
1041 startTime = anim->getEndTime () - time;
1043 else
1045 // No
1047 // Add the transformation
1048 addTransformation (current, anim, 0, anim->getBeginTime() + time - startTime, posTrack, rotquatTrack, NULL, NULL, false);
1050 // Good index
1051 choosedIndex = _ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[index]);
1053 // Get the animation
1054 anim=_ListInstance[i]->AnimationSet.getAnimation (choosedIndex);
1056 // Final time
1057 startTime -= anim->getBeginTime ();
1060 // Set the slot
1061 _ListInstance[i]->Playlist.setTimeOrigin (0, startTime);
1062 _ListInstance[i]->Playlist.setWrapMode (0, CAnimationPlaylist::Clamp);
1063 _ListInstance[i]->Playlist.setStartWeight (0, 1, 0);
1064 _ListInstance[i]->Playlist.setEndWeight (0, 1, 1);
1065 _ListInstance[i]->Playlist.setAnimation (0, choosedIndex);
1067 // Setup the channel
1068 _ListInstance[i]->Playlist.setupMixer (_ListInstance[i]->ChannelMixer, _AnimationDlg->getTime());
1070 // Setup the pos and rot for this shape
1071 if (there)
1073 CVector pos= current.getPos();
1074 // Get a skeleton model
1075 CSkeletonModel *skelModel=dynamic_cast<CSkeletonModel*>(_ListInstance[i]->TransformShape);
1076 // If a skeleton model
1077 if(skelModel)
1079 // scale animated pos value with the CFG scale
1080 pos*= _CharacterScalePos;
1083 if (_ListInstance[i]->TransformShape)
1085 _ListInstance[i]->TransformShape->setPos (pos);
1086 _ListInstance[i]->TransformShape->setRotQuat (current.getRot());
1088 if (_ListInstance[i]->Camera)
1090 _ListInstance[i]->Camera->setPos (pos);
1091 _ListInstance[i]->Camera->setRotQuat (current.getRot());
1095 else
1097 if (_ListInstance[i]->TransformShape)
1099 CMeshBase *meshBase = dynamic_cast<CMeshBase *> ((IShape*)_ListInstance[i]->TransformShape->Shape);
1100 if (meshBase)
1102 _ListInstance[i]->TransformShape->setPos (meshBase->getDefaultPos ()->getDefaultValue ());
1103 _ListInstance[i]->TransformShape->setRotQuat (meshBase->getDefaultRotQuat ()->getDefaultValue ());
1104 _ListInstance[i]->TransformShape->setScale (meshBase->getDefaultScale ()->getDefaultValue ());
1106 else
1108 /*_ListInstance[i]->TransformShape->setPos (CVector::Null);
1109 _ListInstance[i]->TransformShape->setRotQuat (CQuat::Identity);
1110 _ListInstance[i]->TransformShape->setScale (1, 1, 1);*/
1113 if (_ListInstance[i]->Camera)
1115 _ListInstance[i]->Camera->setPos (_ListInstance[i]->Camera->getDefaultPos ()->getDefaultValue ());
1116 _ListInstance[i]->Camera->setTargetPos (_ListInstance[i]->Camera->getDefaultTargetPos ()->getDefaultValue ());
1124 // tool funct : this if a window has another window as a parent (recursive)
1125 // if parent == true, this return true
1126 static bool isParentWnd(HWND parent, HWND son)
1128 if (parent == son) return true;
1129 HWND directParent = GetParent (son);
1130 if (!directParent) return false;
1131 if (directParent == parent) return true;
1132 return isParentWnd(parent, directParent);
1136 // ***************************************************************************
1137 void CObjectViewer::go ()
1139 nlassert(!_InstanceRunning); // this shouldn't be called if an instance of the viewer is running.
1140 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1142 _InstanceRunning = true;
1143 CGraph graph("ms", 10, 10, 200, 100, CRGBA(64, 64, 64), 20, 200);
1147 _CrtCheckMemory();
1148 if (isParentWnd(_MainFrame->m_hWnd, GetForegroundWindow()))
1150 CNELU::Driver->activate ();
1152 // Handle animation
1153 _AnimationDlg->handle ();
1155 // Handle sound animation
1156 _SoundAnimDlg->handle ();
1158 // Handle sound animation
1159 _LightGroupDlg->handle ();
1161 // Setup the channel mixer
1162 _AnimationSetDlg->UpdateData ();
1164 // Setup the play list
1165 setupPlaylist (_AnimationDlg->getTime());
1167 // Eval sound tracks
1168 evalSoundTrack (_AnimationDlg->getLastTime(), _AnimationDlg->getTime());
1170 // Animate the automatic animation in the scene
1171 //CNELU::Scene->animate( (float) + NLMISC::CTime::ticksToSecond( NLMISC::CTime::getPerformanceTime() ) );
1174 // Eval channel mixer for transform
1175 for (uint i=0; i<_ListInstance.size(); i++)
1177 _ListInstance[i]->ChannelMixer.eval (false);
1179 animateCNELUScene (_CS);
1181 // Clear the buffers
1182 CNELU::clearBuffers(_BackGroundColor);
1185 //if (_CS) _CS->setDebugQuad(true);
1187 // call of callback list
1189 std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
1190 for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
1192 (*it)->goPreRender();
1195 // Render the CS
1196 if (_CS) _CS->render ();
1198 // Draw the scene
1199 CNELU::Scene->render();
1201 // call of callback list
1203 std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
1204 for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
1206 (*it)->goPostRender();
1210 if (_OcclusionTestMeshsVisible)
1212 CNELU::Scene->renderOcclusionTestMeshs();
1215 // Profile polygon count
1216 CPrimitiveProfile in, out;
1217 CNELU::Driver->profileRenderedPrimitives (in, out);
1219 // Draw the hotSpot
1220 if (_MainFrame->MoveMode == CMainFrame::ObjectMode)
1222 float radius=_HotSpotSize/2.f;
1223 CNELU::Driver->setupModelMatrix (CMatrix::Identity);
1224 CDRU::drawLine (_MouseListener.getHotSpot()+CVector (radius, 0, 0), _MouseListener.getHotSpot()+CVector (-radius, 0, 0), _HotSpotColor, *CNELU::Driver);
1225 CDRU::drawLine (_MouseListener.getHotSpot()+CVector (0, radius, 0), _MouseListener.getHotSpot()+CVector (0, -radius, 0), _HotSpotColor, *CNELU::Driver);
1226 CDRU::drawLine (_MouseListener.getHotSpot()+CVector (0, 0, radius), _MouseListener.getHotSpot()+CVector (0, 0, -radius), _HotSpotColor, *CNELU::Driver);
1229 // Test some keys
1230 if (CNELU::AsyncListener.isKeyPushed(KeyF3))
1232 // Change render mode
1233 switch (CNELU::Driver->getPolygonMode())
1235 case IDriver::Filled:
1236 CNELU::Driver->setPolygonMode (IDriver::Line);
1237 break;
1238 case IDriver::Line:
1239 CNELU::Driver->setPolygonMode (IDriver::Point);
1240 break;
1241 case IDriver::Point:
1242 CNELU::Driver->setPolygonMode (IDriver::Filled);
1243 break;
1247 // draw various matrix
1248 if (_FXMatrixVisible) drawFXMatrix();
1249 if (_FXUserMatrixVisible) drawFXUserMatrix();
1250 if (_SceneMatrixVisible) drawSceneMatrix();
1252 // draw Skeleton Scale Dlg selection
1253 if(_SkeletonScaleDlg)
1254 _SkeletonScaleDlg->drawSelection();
1256 // Test Window Keys
1257 bool keyWndOk= false;
1258 if (CNELU::AsyncListener.isKeyPushed(Key1))
1259 _MainFrame->OnWindowAnimation(), keyWndOk= true;
1260 if (CNELU::AsyncListener.isKeyPushed(Key2))
1261 _MainFrame->OnWindowAnimationset(), keyWndOk= true;
1262 if (CNELU::AsyncListener.isKeyPushed(Key3))
1263 _MainFrame->OnWindowMixersslots(), keyWndOk= true;
1264 if (CNELU::AsyncListener.isKeyPushed(Key4))
1265 _MainFrame->OnWindowParticles(), keyWndOk= true;
1266 if (CNELU::AsyncListener.isKeyPushed(Key5))
1267 _MainFrame->OnWindowDayNight(), keyWndOk= true;
1268 if (CNELU::AsyncListener.isKeyPushed(Key6))
1269 _MainFrame->OnWindowWaterPool(), keyWndOk= true;
1270 if (CNELU::AsyncListener.isKeyPushed(Key7))
1271 _MainFrame->OnWindowVegetable(), keyWndOk= true;
1272 if (CNELU::AsyncListener.isKeyPushed(Key8))
1273 _MainFrame->OnWindowGlobalwind(), keyWndOk= true;
1274 if (CNELU::AsyncListener.isKeyPushed(Key9))
1275 _MainFrame->OnWindowSoundAnim(), keyWndOk= true;
1276 if (CNELU::AsyncListener.isKeyPushed(KeyO))
1277 _MainFrame->OnFileOpen(), keyWndOk= true;
1279 // Reload texture ?
1280 if (CNELU::AsyncListener.isKeyPushed(KeyR))
1281 _MainFrame->OnReloadTextures();
1283 // If some window activated, reset the focus to the main wnd.
1284 if(keyWndOk)
1285 _MainFrame->SetActiveWindow();
1287 // Calc FPS
1288 static sint64 lastTime=NLMISC::CTime::getPerformanceTime ();
1289 sint64 newTime=NLMISC::CTime::getPerformanceTime ();
1290 sint64 timeDiff = newTime - lastTime;
1291 float fps = timeDiff > 0 ? (float)(1.0 / NLMISC::CTime::ticksToSecond (newTime-lastTime)) : 1000.0f;
1292 lastTime=newTime;
1293 uint nbPlayingSources, nbSources;
1294 if (CSoundSystem::getAudioMixer())
1296 nbPlayingSources = CSoundSystem::getAudioMixer()->getUsedTracksCount();
1297 nbSources = CSoundSystem::getAudioMixer()->getPlayingSourcesCount();
1299 else
1301 nbPlayingSources = nbSources = NULL;
1304 // Display std info.
1305 std::string msgBar = toString("%s - Nb tri: %u - Texture used (MiB): %5.2f - Texture allocated (MiB): %5.2f - Distance: %5.0f - Sounds: %u/%u - Fps: %03.1f",
1306 _Direct3d ? "Direct3d":"OpenGL",
1307 in.NLines+in.NPoints+in.NQuads*2+in.NTriangles+in.NTriangleStrips,
1308 (float)CNELU::Driver->getUsedTextureMemory () / (float)(1024*1024),
1309 (float)CNELU::Driver->profileAllocatedTextureMemory () / (float)(1024*1024),
1310 (_SceneCenter-CNELU::Camera->getMatrix().getPos()).norm(),
1311 nbPlayingSources,
1312 nbSources,
1316 // Display
1317 _MainFrame->StatusBar.SetWindowText(nlUtf8ToTStr(msgBar));
1319 // Display Vegetable info.
1320 if(_VegetableDlg!=NULL)
1322 if(_VegetableLandscape != NULL)
1324 CString vegetMsgBar;
1325 vegetMsgBar.Format(_T("%u"), _VegetableLandscape->Landscape.getNumVegetableFaceRendered());
1326 _VegetableDlg->StaticPolyCount.SetWindowText(vegetMsgBar);
1328 else
1330 _VegetableDlg->StaticPolyCount.SetWindowText(_T("0"));
1334 // graph disabled for now..
1335 // graph.addValue(CNELU::Scene->getEllapsedTime() * 1000.f);
1336 // graph.renderGraph();
1338 // Swap the buffers
1339 CNELU::swapBuffers();
1341 // Select the good camera
1342 if (_MainFrame->MoveMode == CMainFrame::CameraMode)
1344 sint cameraId = getCurrentCamera ();
1345 if (cameraId != -1)
1347 CInstanceInfo *info = getInstance(getCameraInstance (cameraId));
1348 nlassert (info->Camera);
1349 CNELU::Scene->setCam (info->Camera);
1352 else
1354 CNELU::Scene->setCam (CNELU::Camera);
1357 if (_MainFrame->MoveMode == CMainFrame::ObjectMode)
1359 _MouseListener.setMouseMode (CEvent3dMouseListener::edit3d);
1361 else
1363 _MouseListener.setMouseMode (CEvent3dMouseListener::firstPerson);
1364 _MouseListener.setSpeed (_MainFrame->MoveSpeed);
1369 // Reset camera aspect ratio
1370 initCamera ();
1372 if (_MainFrame->isMoveElement())
1374 // for now we apply a transform on the selected object in the particle system
1375 _ParticleDlg->moveElement(_MouseListener.getModelMatrix());
1377 else if (_MainFrame->isMoveFX())
1379 _ParticleDlg->setPSWorldMatrix(_MouseListener.getModelMatrix());
1381 else if (_MainFrame->isMoveFXUserMatrix())
1383 setFXUserMatrix(_MouseListener.getModelMatrix());
1385 else if (_MainFrame->isMoveObjectLightTest())
1387 _ObjectLightTestMatrix= _MouseListener.getModelMatrix();
1389 else if (_MainFrame->isMoveSceneRoot())
1391 _SceneRoot->setTransformMode (ITransformable::DirectMatrix);
1392 _SceneRoot->setMatrix (_MouseListener.getModelMatrix());
1394 else
1396 nlassert(_MainFrame->isMoveCamera());
1398 // New matrix from camera
1399 CNELU::Camera->setTransformMode (ITransformable::DirectMatrix);
1400 CNELU::Camera->setMatrix (_MouseListener.getViewMatrix());
1402 // Vegetable: manage collision snapping if wanted and possible
1403 if(_VegetableSnapToGround && _VegetableLandscape)
1405 // get matrix from camera.
1406 CMatrix matrix= CNELU::Camera->getMatrix();
1407 // snap To ground.
1408 CVector pos= matrix.getPos();
1409 // if succes to snap to ground
1410 if(_VegetableCollisionEntity->snapToGround(pos))
1412 pos.z+= _VegetableSnapHeight;
1413 matrix.setPos(pos);
1414 // reset the moveListener and the camera.
1415 _MouseListener.setMatrix(matrix);
1416 CNELU::Camera->setMatrix(matrix);
1422 // Update lighting test Dynamic object position
1423 if(_ObjectLightTest && _GlobalRetriever)
1425 // Get the position of the object snapped.
1426 UGlobalPosition gPos= _GlobalRetriever->retrievePosition(_ObjectLightTestMatrix.getPos());
1427 CVector pos= _GlobalRetriever->getGlobalPosition(gPos);
1428 _ObjectLightTest->setPos(pos);
1429 _ObjectLightTest->setRotQuat(_ObjectLightTestMatrix.getRot());
1431 // Update the matrix and the mouseListener.
1432 if (_MainFrame->isMoveObjectLightTest())
1434 _ObjectLightTestMatrix.setPos(pos);
1435 _MouseListener.setModelMatrix(_ObjectLightTestMatrix);
1438 // Update the logicInfo so lighting is well computed.
1439 _ObjectLightTestLogicInfo.GPos= gPos;
1442 // Pump message from the server
1443 CNELU::EventServer.pump();
1445 // Pump others message for the windows
1446 MSG msg;
1447 while ( PeekMessage(&msg, NULL,0,0,PM_REMOVE) )
1449 TranslateMessage(&msg);
1450 DispatchMessage(&msg);
1453 CSoundSystem::setListenerMatrix(_MouseListener.getViewMatrix());
1454 CSoundSystem::poll();
1458 // simulate frame delay
1459 if (_FrameDelay)
1461 NLMISC::nlSleep(_FrameDelay);
1465 // Save last time
1466 _LastTime=_AnimationDlg->getTime();
1467 theApp.OnIdle (0);
1469 else
1471 // Traditionnal message loop
1472 MSG msg;
1473 while (GetMessage( &msg, NULL, 0, 0) == TRUE)
1475 ::TranslateMessage(&msg);
1476 ::DispatchMessage(&msg);
1477 if (!IsWindow (_MainFrame->m_hWnd))
1478 break;
1480 // Get the foreground window
1481 if (isParentWnd(_MainFrame->m_hWnd, GetForegroundWindow()))
1482 break;
1486 while (!CNELU::AsyncListener.isKeyPushed(KeyESCAPE)&&CNELU::Driver->isActive());
1487 _InstanceRunning = false;
1490 // ***************************************************************************
1492 void CObjectViewer::releaseUI ()
1494 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1496 // Release particles
1497 removeWindow(_ChooseFrameDelayDlg);
1498 removeWindow(_ParticleDlg);
1500 // release sound
1501 CSoundSystem::releaseSoundSystem();
1503 if (CNELU::Driver->isActive())
1505 // register window position
1506 if (CNELU::Driver->getDisplay())
1508 setRegisterWindowState (_MainFrame, REGKEY_OBJ_VIEW_OPENGL_WND);
1512 // Write register
1513 if (_MainFrame)
1515 _MainFrame->registerValue (false);
1516 // Remove the main frame
1517 if (::IsWindow(*_MainFrame))
1519 _MainFrame->DestroyWindow();
1521 delete _MainFrame;
1522 _MainFrame = NULL;
1525 // Release the emitter from the server
1526 _MouseListener.removeFromServer (CNELU::EventServer);
1528 // exit
1530 // remove first possibly created collisions objects.
1531 if(_VegetableCollisionEntity)
1533 _VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity);
1534 _VegetableCollisionEntity= NULL;
1536 if(_VegetableCollisionManager)
1538 delete _VegetableCollisionManager;
1539 _VegetableCollisionManager= NULL;
1542 // delete Landscape
1543 if(_VegetableLandscape)
1545 CNELU::Scene->deleteModel(_VegetableLandscape);
1546 _VegetableLandscape= NULL;
1551 // Release all instances and all Igs.
1552 removeAllInstancesFromScene();
1554 // Remove
1556 // Create the cloud scape
1557 delete _CS;
1558 _CS = NULL;
1560 // release Root
1561 CNELU::Scene->deleteModel(_SceneRoot);
1562 _SceneRoot= NULL;
1564 // release other 3D.
1565 CNELU::release();
1570 // ***************************************************************************
1572 void setRegisterWindowState (const CWnd *pWnd, const TCHAR* keyName)
1574 HKEY hKey;
1575 if (RegCreateKey(HKEY_CURRENT_USER, keyName, &hKey)==ERROR_SUCCESS)
1577 RECT rect;
1578 pWnd->GetWindowRect (&rect);
1579 RegSetValueEx(hKey, _T("Left"), 0, REG_DWORD, (LPBYTE)&rect.left, 4);
1580 RegSetValueEx(hKey, _T("Right"), 0, REG_DWORD, (LPBYTE)&rect.right, 4);
1581 RegSetValueEx(hKey, _T("Top"), 0, REG_DWORD, (LPBYTE)&rect.top, 4);
1582 RegSetValueEx(hKey, _T("Bottom"), 0, REG_DWORD, (LPBYTE)&rect.bottom, 4);
1586 // ***************************************************************************
1588 void getRegisterWindowState (CWnd *pWnd, const TCHAR* keyName, bool resize)
1590 HKEY hKey;
1591 if (RegOpenKeyEx(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &hKey)==ERROR_SUCCESS)
1593 DWORD len=4;
1594 DWORD type;
1595 RECT rect;
1596 RegQueryValueEx (hKey, _T("Left"), 0, &type, (LPBYTE)&rect.left, &len);
1597 RegQueryValueEx (hKey, _T("Right"), 0, &type, (LPBYTE)&rect.right, &len);
1598 RegQueryValueEx (hKey, _T("Top"), 0, &type, (LPBYTE)&rect.top, &len);
1599 RegQueryValueEx (hKey, _T("Bottom"), 0, &type, (LPBYTE)&rect.bottom, &len);
1601 // Set window pos
1602 pWnd->SetWindowPos (NULL, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_NOOWNERZORDER|SWP_NOZORDER|
1603 (resize?0:SWP_NOSIZE));
1607 // ***************************************************************************
1609 void CObjectViewer::setAnimTime (float animStart, float animEnd)
1611 // Dispatch the command
1612 _SlotDlg->setAnimTime (animStart, animEnd);
1613 _AnimationDlg->setAnimTime (animStart, animEnd);
1614 _SoundAnimDlg->setAnimTime (animStart, animEnd);
1617 // ***************************************************************************
1620 void CObjectViewer::resetSlots (uint instance)
1622 // Reset the animation set
1623 _ListInstance[instance]->AnimationSet.reset ();
1625 // Set no animation in slot UI
1626 for (uint j=0; j<NL3D::CChannelMixer::NumAnimationSlot; j++)
1627 _ListInstance[instance]->Saved.SlotInfo[j].Animation.clear();
1629 // Reset the animation list
1630 _ListInstance[instance]->Saved.AnimationFileName.clear ();
1632 // Reset the play list
1633 _ListInstance[instance]->Saved.PlayList.clear ();
1635 // Reset the skeleton list
1636 _ListInstance[instance]->Saved.SWTFileName.clear ();
1638 // Update
1639 _AnimationSetDlg->refresh (TRUE);
1640 _SlotDlg->refresh (TRUE);
1641 _SoundAnimDlg->refresh (TRUE);
1644 // ***************************************************************************
1646 void CObjectViewer::reinitChannels ()
1648 // Add all the instance in the channel mixer
1649 for (uint i=0; i<_ListInstance.size(); i++)
1651 // Reset the channels
1652 _ListInstance[i]->ChannelMixer.resetChannels ();
1654 // Setup animation set
1655 _ListInstance[i]->ChannelMixer.setAnimationSet (&(_ListInstance[i]->AnimationSet));
1657 // Register the transform (but not if it has automatic animation, as a channel mixer has been created for us)
1658 bool autoAnim = false;
1659 if (dynamic_cast<CMeshBaseInstance *>(_ListInstance[i]->TransformShape))
1661 CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>( (IShape *) static_cast<CMeshBaseInstance *>(_ListInstance[i]->TransformShape)->Shape );
1662 autoAnim = mb->getAutoAnim();
1665 if (!autoAnim)
1667 if (_ListInstance[i]->TransformShape)
1668 _ListInstance[i]->TransformShape->registerToChannelMixer (&(_ListInstance[i]->ChannelMixer), "");
1669 if (_ListInstance[i]->Camera)
1670 _ListInstance[i]->Camera->registerToChannelMixer (&(_ListInstance[i]->ChannelMixer), "");
1674 // Enable / disable channels
1675 enableChannels ();
1678 // ***************************************************************************
1680 void CObjectViewer::enableChannels ()
1682 // Disable some channels
1683 _AnimationSetDlg->UpdateData ();
1684 bool enable = (_AnimationSetDlg->UseMixer == 1);
1686 // Add all the instance in the channel mixer
1687 for (uint i=0; i<_ListInstance.size(); i++)
1689 // Get the pos and rot channel id
1690 uint posId = _ListInstance[i]->AnimationSet.getChannelIdByName ("pos");
1691 uint rotQuatId = _ListInstance[i]->AnimationSet.getChannelIdByName ("rotquat");
1692 uint rotEulerId = _ListInstance[i]->AnimationSet.getChannelIdByName ("roteuler");
1694 if (posId != CAnimationSet::NotFound)
1695 _ListInstance[i]->ChannelMixer.enableChannel (posId, enable);
1696 if (rotQuatId != CAnimationSet::NotFound)
1697 _ListInstance[i]->ChannelMixer.enableChannel (rotQuatId, enable);
1698 if (rotEulerId != CAnimationSet::NotFound)
1699 _ListInstance[i]->ChannelMixer.enableChannel (rotEulerId, enable);
1703 // ***************************************************************************
1705 float CObjectViewer::getFrameRate ()
1707 return _AnimationDlg->Speed;
1710 // ***************************************************************************
1712 string getFilename (const string &file)
1714 // if the direct file exist, return it
1715 if (NLMISC::CFile::fileExists(file))
1716 return file;
1718 string path = NLMISC::CFile::getFilename(file);
1719 path = CPath::lookup (path, false, false, false);
1720 if (path.empty())
1721 path = file;
1722 return path;
1725 // ***************************************************************************
1727 void CObjectViewer::serial (NLMISC::IStream& f)
1729 // version 4: include particle workspace infos
1730 // serial "OBJV_CFG"
1731 f.serialCheck (NELID("VJBO"));
1732 f.serialCheck (NELID("GFC_"));
1734 // serial the version
1735 int ver=f.serialVersion (4);
1736 if (ver>=4)
1738 f.serial(ParticleWorkspaceFilename);
1740 if (ver>=3)
1742 // Read the configuration file
1743 if (f.isReading())
1745 if (ver <=3)
1747 ParticleWorkspaceFilename.clear();
1749 // First instance
1750 uint firstInstance = (uint)_ListInstance.size();
1752 // Read information
1753 std::vector<CInstanceSave> readed;
1754 f.serialCont (readed);
1756 // Merge
1757 for (uint i=0; i<readed.size(); i++)
1761 // Instance loaded
1762 uint instance = 0xffffffff;
1764 if (readed[i].Camera)
1766 instance = addCamera (readed[i].CameraInfo, readed[i].ShapeFilename.c_str());
1768 else
1770 // Load the shape
1771 CIFile input;
1772 string path = getFilename (readed[i].ShapeFilename);
1773 if (input.open (path))
1775 // Serial a shape
1776 CShapeStream serialShape;
1777 serialShape.serial (input);
1779 // Is a skeleton ?
1780 if (readed[i].IsSkeleton)
1782 // Add the skel
1783 instance = addSkel (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str());
1784 SkeletonUsedForSound = instance;
1786 else
1788 // Add the mesh
1789 if (readed[i].SkeletonId != 0xffffffff)
1790 instance = addMesh (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str(), readed[i].SkeletonId + firstInstance, (readed[i].BindBoneName.empty())?NULL:readed[i].BindBoneName.c_str());
1791 else
1792 instance = addMesh (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str(), 0xffffffff, (readed[i].BindBoneName.empty())?NULL:readed[i].BindBoneName.c_str());
1795 else
1797 // Error message
1798 std::string message = toString("File not found %s", readed[i].ShapeFilename.c_str());
1799 _MainFrame->MessageBox(nlUtf8ToTStr(message), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1801 // Stop loading
1802 break;
1806 // Check instance number
1807 nlassert (instance == (firstInstance+i));
1809 // Load animations
1810 for (uint anim=0; anim<readed[i].AnimationFileName.size(); anim++)
1812 string path = getFilename (readed[i].AnimationFileName[anim]);
1813 loadAnimation (path.c_str(), instance);
1816 // Load SWT
1817 for (uint swt=0; swt<readed[i].SWTFileName.size(); swt++)
1819 string path = getFilename (readed[i].SWTFileName[swt]);
1820 loadSWT (path.c_str(), instance);
1823 // Set the playlist
1824 _ListInstance[instance]->Saved.PlayList = readed[i].PlayList;
1826 // Set the slot information
1827 for (uint slot=0; slot<NL3D::CChannelMixer::NumAnimationSlot; slot++)
1828 _ListInstance[instance]->Saved.SlotInfo[slot] = readed[i].SlotInfo[slot];
1830 catch (const Exception &e)
1832 // Error message
1833 std::string message = toString("Error loading shape %s: %s", readed[i].ShapeFilename.c_str(), e.what());
1834 _MainFrame->MessageBox(nlUtf8ToTStr(message), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1836 // Stop loading
1837 break;
1841 // Init channels
1842 reinitChannels ();
1844 // Read the selection
1845 uint32 selection;
1846 f.serial (selection);
1847 if (selection+firstInstance < _ListInstance.size())
1849 _SelectedObject = selection+firstInstance;
1852 // Invalidate dialogs
1853 _AnimationSetDlg->refresh (TRUE);
1854 _SlotDlg->refresh (TRUE);
1855 _SoundAnimDlg->refresh (TRUE);
1857 else
1859 // Build information
1860 std::vector<CInstanceSave> readed (_ListInstance.size());
1861 for (uint instance=0; instance<_ListInstance.size(); instance++)
1863 // Copy the save information
1864 readed[instance] = _ListInstance[instance]->Saved;
1867 // Save the configuration
1868 f.serialCont (readed);
1870 // Write the selection
1871 f.serial (_SelectedObject);
1876 // ***************************************************************************
1878 bool CObjectViewer::loadInstanceGroup(const std::string &igFilename)
1880 //AFX_MANAGE_STATE(AfxGetStaticModuleState());
1882 // Add search path for the mesh
1883 CPath::addSearchPath (NLMISC::CFile::getPath(igFilename));
1885 // Open a file
1886 CIFile file;
1887 if (file.open (igFilename))
1889 // Shape pointer
1890 NL3D::CInstanceGroup *ig = new NL3D::CInstanceGroup;
1894 // Stream it
1895 file.serial(*ig);
1897 // Append the ig.
1898 addInstanceGroup(ig);
1900 catch (const Exception& e)
1902 // clean
1903 delete ig;
1904 _MainFrame->MessageBox(nlUtf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1905 return false;
1908 else
1910 // Create a message
1911 std::string msg = toString("Can't open the file %s for reading.", igFilename.c_str());
1912 _MainFrame->MessageBox(nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1913 return false;
1918 return true;
1923 // ***************************************************************************
1925 bool CObjectViewer::loadMesh (std::vector<std::string> &meshFilename, const std::string &skeleton)
1927 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1929 // Add to the path
1931 // Add search path for the skeleton
1932 if (skeleton.empty())
1934 CPath::addSearchPath (NLMISC::CFile::getPath(skeleton));
1937 // Open a file
1938 CIFile file;
1940 // Shape pointer
1941 IShape *shapeSkel=NULL;
1942 uint skelIndex = 0xffffffff;
1943 NL3D::CSkeletonModel *transformSkel=NULL;
1945 // Skel error ?
1946 bool skelError=false;
1948 // Continue ?
1949 if (!skeleton.empty())
1952 // Open a file
1953 if (file.open (skeleton))
1955 // Sream a shape
1956 CShapeStream streamShape;
1959 // Stream it
1960 streamShape.serial (file);
1962 // Add the shape
1963 shapeSkel=streamShape.getShapePointer();
1965 catch (const Exception& e)
1967 _MainFrame->MessageBox(nlUtf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1969 // error
1970 skelError=true;
1973 else
1975 // Create a message
1976 std::string msg = NLMISC::toString("Can't open the file %s for reading.", skeleton.c_str());
1977 _MainFrame->MessageBox(nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
1979 // error
1980 skelError=true;
1984 // Skeleton error ?
1985 if (skelError)
1986 return false;
1988 // Skeleton used ?
1989 bool skelUsed = false;
1991 // Index of the shape
1992 uint lastShape = 0xffffffff;
1994 // For each meshes
1995 for (uint i=0; i<meshFilename.size(); i++)
1997 // Filename
1998 const std::string fileName = meshFilename[i];
2000 // Add search path for the mesh
2001 CPath::addSearchPath (NLMISC::CFile::getPath(fileName));
2003 // Shape pointer
2004 IShape *shapeMesh=NULL;
2006 if (file.open (fileName))
2008 // Sream a shape
2009 CShapeStream streamShape;
2012 // Stream it
2013 streamShape.serial (file);
2015 // Add the shape
2016 shapeMesh=streamShape.getShapePointer();
2018 catch (const Exception& e)
2020 _MainFrame->MessageBox(nlUtf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
2021 continue;
2024 else
2026 // Create a message
2027 std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
2028 _MainFrame->MessageBox(nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
2029 continue;
2032 // Add the skel shape
2033 if (shapeSkel&&(!skelUsed))
2035 // Add the skel
2036 skelIndex = addSkel (shapeSkel, skeleton);
2037 if (skelIndex != 0xffffffff)
2039 skelUsed = true;
2040 transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[skelIndex]->TransformShape);
2041 nlassert (transformSkel);
2045 // Add the skel shape
2046 if (shapeMesh)
2048 // Get the object name
2049 lastShape = addMesh (shapeMesh, fileName, skelIndex);
2053 // Skel not used ?
2054 if ((!skelUsed)&&shapeSkel)
2056 // Remove it
2057 delete shapeSkel;
2060 // Select the skeleton
2061 if (skelIndex != 0xffffffff)
2062 _SelectedObject = skelIndex;
2063 else if (lastShape != 0xffffffff)
2064 _SelectedObject = lastShape;
2066 // Update windows
2067 _AnimationSetDlg->refresh (TRUE);
2068 _SlotDlg->refresh (TRUE);
2069 _SoundAnimDlg->refresh (TRUE);
2071 return true;
2074 // ***************************************************************************
2076 void CObjectViewer::resetCamera ()
2078 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2080 _MainFrame->OnResetCamera();
2083 // ***************************************************************************
2085 uint CObjectViewer::addMesh (NL3D::IShape* pMeshShape, const std::string &meshName, uint skelIndex, const char* bindSkelName, bool createInstance)
2087 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2089 // *** Add the shape
2091 // Store the shape pointer
2092 if (CNELU::ShapeBank->getPresentState(meshName)!=CShapeBank::NotPresent)
2094 delete pMeshShape;
2096 else
2097 CNELU::ShapeBank->add (meshName, CSmartPtr<IShape> (pMeshShape));
2099 // Must create the instance?
2100 if(createInstance)
2102 // Create a model and add it to the scene
2103 CTransformShape *pTrShape=CNELU::Scene->createInstance (meshName);
2104 nlassert (pTrShape);
2106 // link to the root for manipulation
2107 _SceneRoot->hrcLinkSon(pTrShape);
2109 // Get the real shape used by the instance.
2110 pMeshShape= pTrShape->Shape;
2112 // Set the rot model
2113 if (_MainFrame->Euler)
2114 pTrShape->setTransformMode (ITransformable::RotEuler);
2115 else
2116 pTrShape->setTransformMode (ITransformable::RotQuat);
2118 // Store the transform shape pointer
2119 CInstanceInfo *iInfo = new CInstanceInfo;
2120 iInfo->TransformShape= pTrShape;
2122 // Store the name of the shape
2123 iInfo->MustDelete = true;
2124 iInfo->Saved.ShapeFilename = meshName;
2125 iInfo->Saved.SkeletonId = skelIndex;
2126 _ListInstance.push_back (iInfo);
2128 // *** Bind to the skeleton
2130 // Get a mesh instance
2131 CMeshBaseInstance *meshInstance=dynamic_cast<CMeshBaseInstance*>(pTrShape);
2133 // Bind the mesh
2134 if (skelIndex != 0xffffffff)
2136 // Get the skeleton
2137 NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[skelIndex]->TransformShape);
2138 nlassert (transformSkel);
2140 // It is a skinned mesh ?
2141 CMesh *mesh = dynamic_cast<CMesh *>(pMeshShape);
2142 CMeshMRM *meshMrm = dynamic_cast<CMeshMRM *>(pMeshShape);
2143 CMeshMRMSkinned *meshMrmSkinned = dynamic_cast<CMeshMRMSkinned *>(pMeshShape);
2144 if ( (mesh && mesh->getMeshGeom().isSkinned()) ||
2145 (meshMrm && meshMrm->getMeshGeom().isSkinned()) ||
2146 meshMrmSkinned)
2148 // Bind to skeleton
2149 transformSkel->bindSkin (meshInstance);
2151 else
2153 // Bind bone name
2154 uint bindBone = 0xffffffff;
2155 std::string boneName;
2157 // Name is passed, look for bone
2158 if (bindSkelName)
2160 // Make a list of bones
2161 uint bone;
2162 for (bone=0; bone<transformSkel->Bones.size(); bone++)
2164 if (transformSkel->Bones[bone].getBoneName() == bindSkelName)
2166 bindBone = bone;
2167 boneName = bindSkelName;
2168 break;
2173 // Found ? No, look for a bind bone
2174 if (bindBone == 0xffffffff)
2176 // Make a list of bones
2177 vector<string> listBones;
2178 uint bone;
2179 for (bone=0; bone<transformSkel->Bones.size(); bone++)
2180 listBones.push_back (transformSkel->Bones[bone].getBoneName());
2182 // Get name of the mesh
2183 std::string nameMesh = NLMISC::CFile::getFilenameWithoutExtension(meshName);
2185 // Select a bones
2186 std::string message = "Select a bone to stick " + string (nameMesh);
2187 CSelectString dialogSelect (listBones, message.c_str(), _MainFrame, false);
2188 if (dialogSelect.DoModal ()==IDOK)
2190 // Select your bones
2191 bindBone = dialogSelect.Selection;
2192 boneName = listBones[dialogSelect.Selection];
2196 // Selected ?
2197 if (bindBone != 0xffffffff)
2199 transformSkel->stickObject (pTrShape, bindBone);
2200 /*meshInstance->setPos (CVector::Null);
2201 meshInstance->setRotQuat (CQuat::Identity);
2202 meshInstance->setScale (1, 1, 1);*/
2205 // Set the bone name
2206 iInfo->Saved.BindBoneName = boneName;
2210 // Return the instance index
2211 return (uint)_ListInstance.size()-1;
2213 else
2214 return 0xffffffff;
2218 // ***************************************************************************
2219 bool CObjectViewer::chooseBone(const std::string &caption, NL3D::CSkeletonModel *&skel, uint &boneIndex, std::string *skelName /*= NULL*/, std::string *boneName /*= NULL*/)
2221 for(uint k = 0; k < _ListInstance.size(); ++k)
2223 NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[k]->TransformShape);
2224 if (transformSkel)
2226 // Make a list of bones
2227 vector<string> listBones;
2228 uint bone;
2229 for (bone=0; bone<transformSkel->Bones.size(); bone++)
2231 listBones.push_back (transformSkel->Bones[bone].getBoneName());
2233 CSelectString dialogSelect (listBones, caption.c_str(), _MainFrame, false);
2234 if (dialogSelect.DoModal ()==IDOK)
2236 boneIndex = dialogSelect.Selection;
2237 skel = transformSkel;
2238 if (skelName)
2240 *skelName = _ListInstance[k]->Saved.ShapeFilename;
2242 if (boneName)
2244 *boneName = safe_cast<NL3D::CSkeletonModel *>(_ListInstance[k]->TransformShape)->Bones[boneIndex].getBoneName();
2246 return true;
2248 return false;
2251 return false;
2254 // ***************************************************************************
2255 bool CObjectViewer::isSkeletonPresent() const
2257 for(uint k = 0; k < _ListInstance.size(); ++k)
2259 NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[k]->TransformShape);
2260 if (transformSkel) return true;
2262 return false;
2265 // ***************************************************************************
2267 uint CObjectViewer::addCamera (const NL3D::CCameraInfo &cameraInfo, const std::string &cameraName)
2269 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2271 // *** Add the shape
2273 // link to the root for manipulation
2274 CCamera *pCamera = (CCamera*)CNELU::Scene->createModel (CameraId);
2275 _SceneRoot->hrcLinkSon(pCamera);
2277 // Build the camera
2278 pCamera->build (cameraInfo);
2280 // Store the transform shape pointer
2281 CInstanceInfo *iInfo = new CInstanceInfo;
2282 iInfo->Camera = pCamera;
2284 // Store the name of the shape
2285 iInfo->MustDelete = true;
2286 iInfo->Saved.ShapeFilename = cameraName;
2287 iInfo->Saved.SkeletonId = 0xffffffff;
2288 iInfo->Saved.CameraInfo = cameraInfo;
2289 iInfo->Saved.Camera = true;
2290 _ListInstance.push_back (iInfo);
2291 _Cameras.push_back ((uint)_ListInstance.size()-1);
2293 // Reinit camera
2294 initCamera ();
2296 // Return the instance index
2297 return (uint)_ListInstance.size()-1;
2300 // ***************************************************************************
2302 uint CObjectViewer::addSkel (NL3D::IShape* pSkelShape, const std::string &skelName)
2304 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2306 // *** Add the shape
2308 // Store the shape pointer
2309 if (CNELU::ShapeBank->getPresentState(skelName)!=CShapeBank::NotPresent)
2311 delete pSkelShape;
2313 else
2314 CNELU::ShapeBank->add (skelName, CSmartPtr<IShape> (pSkelShape));
2316 // Create a model and add it to the scene
2317 CTransformShape *pTrShape=CNELU::Scene->createInstance (skelName);
2318 nlassert (pTrShape);
2320 // link to the root for manipulation
2321 _SceneRoot->hrcLinkSon(pTrShape);
2323 // Get the real shape used by the instance.
2324 pSkelShape= pTrShape->Shape;
2326 // Get a skeleton model
2327 CSkeletonModel *skelModel=dynamic_cast<CSkeletonModel*>(pTrShape);
2329 // Is a skel ?
2330 if (skelModel)
2332 // Set the rot model
2333 if (_MainFrame->Euler)
2334 pTrShape->setTransformMode (ITransformable::RotEuler);
2335 else
2336 pTrShape->setTransformMode (ITransformable::RotQuat);
2338 // Store the transform shape pointer
2339 CInstanceInfo *iInfo = new CInstanceInfo;
2340 iInfo->TransformShape = skelModel;
2342 // Store the name of the shape
2343 iInfo->MustDelete = true;
2344 iInfo->Saved.ShapeFilename = skelName;
2345 iInfo->Saved.IsSkeleton = true;
2346 iInfo->Saved.SkeletonId = 0xffffffff;
2347 _ListInstance.push_back (iInfo);
2349 // set this skeleton for Skeleton Scale edition
2350 _SkeletonScaleDlg->setSkeletonToEdit(skelModel, skelName);
2352 // Return the instance
2353 return (uint)_ListInstance.size()-1;
2355 return 0xffffffff;
2358 // ***************************************************************************
2360 IObjectViewer* IObjectViewer::getInterface (int version)
2362 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2364 // Check version number
2365 if (version!=OBJECT_VIEWER_VERSION)
2367 MessageBox (NULL, _T("Bad version of object_viewer.dll."), _T("NeL object viewer"), MB_ICONEXCLAMATION|MB_OK);
2368 return NULL;
2370 else
2371 return new CObjectViewer;
2374 // ***************************************************************************
2376 void IObjectViewer::releaseInterface (IObjectViewer* view)
2378 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2380 delete view;
2383 // ***************************************************************************
2385 void CObjectViewer::setSingleAnimation (NL3D::CAnimation* pAnim, const std::string &name, uint instance)
2387 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2389 if (instance < _ListInstance.size())
2391 // Set active
2392 _SelectedObject = instance;
2394 // Add the animation
2395 addAnimation (pAnim, name + ".anim", name, instance);
2397 // Add the animation to the animationSet
2398 _AnimationSetDlg->UpdateData (TRUE);
2399 _AnimationSetDlg->UseMixer = 1;
2400 _AnimationSetDlg->UpdateData (FALSE);
2402 // Set the animation in the first slot
2403 _ListInstance[instance]->Saved.SlotInfo[0].Animation = name;
2404 _ListInstance[instance]->Saved.SlotInfo[0].Skeleton.clear();
2405 _ListInstance[instance]->Saved.SlotInfo[0].Offset = 0;
2406 _ListInstance[instance]->Saved.SlotInfo[0].StartTime = (int)(pAnim->getBeginTime()*_AnimationDlg->Speed);
2407 _ListInstance[instance]->Saved.SlotInfo[0].EndTime = (int)(pAnim->getEndTime()*_AnimationDlg->Speed);
2408 _ListInstance[instance]->Saved.SlotInfo[0].StartBlend = 1.f;
2409 _ListInstance[instance]->Saved.SlotInfo[0].EndBlend = 1.f;
2410 _ListInstance[instance]->Saved.SlotInfo[0].Enable = true;
2411 for (uint i=1; i<CChannelMixer::NumAnimationSlot; i++)
2412 _ListInstance[instance]->Saved.SlotInfo[i].Enable = false;
2414 // Update dialog box
2415 _AnimationSetDlg->refresh (TRUE);
2416 _SlotDlg->refresh (TRUE);
2417 _SoundAnimDlg->refresh(TRUE);
2419 // Reinit
2420 reinitChannels ();
2424 // ***************************************************************************
2426 void CObjectViewer::setAutoAnimation (NL3D::CAnimationSet* pAnimSet)
2428 CNELU::Scene->setAutomaticAnimationSet (pAnimSet);
2431 // ***************************************************************************
2433 void CObjectViewer::setAmbientColor (const NLMISC::CRGBA& color)
2435 CNELU::Driver->setAmbientColor (color);
2437 // Setup also Scene lighting system here, even if not used.
2438 CNELU::Scene->setAmbientGlobal(color);
2441 // ***************************************************************************
2443 void CObjectViewer::setLight (unsigned char id, const NL3D::CLight& light)
2445 CNELU::Driver->enableLight (id);
2446 CNELU::Driver->setLight (id, light);
2449 // ***************************************************************************
2452 /** add an object that will be notified each time a frame is processed
2453 * \see removeMainLoopCallBack()
2455 void CObjectViewer::registerMainLoopCallBack(IMainLoopCallBack *i)
2457 // nlassert(std::find(_CallBackList.begin(), _CallBackList.end(), i) == _CallBackList.begin()); // the object was register twice !!
2458 _CallBackList.push_back(i);
2461 /// remove an object that was registered with registerMainLoopCallBack()
2462 void CObjectViewer::removeMainLoopCallBack(IMainLoopCallBack *i)
2464 std::vector<IMainLoopCallBack *>::iterator it = std::find(_CallBackList.begin(), _CallBackList.end(), i);
2465 nlassert(it != _CallBackList.end()); // this object wasn't registered
2466 _CallBackList.erase(it);
2469 // ***************************************************************************
2470 void CObjectViewer::activateTextureSet(uint index)
2472 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2474 std::vector<CInstanceInfo*>::iterator it;
2475 for (it = _ListInstance.begin(); it != _ListInstance.end(); ++it)
2477 NL3D::CTransformShape *trShape= (*it)->TransformShape;
2478 if (dynamic_cast<NL3D::CMeshBaseInstance *>(trShape))
2480 static_cast<NL3D::CMeshBaseInstance *>(trShape)->selectTextureSet(index);
2485 // ***************************************************************************
2486 void CObjectViewer::shuffleTextureSet()
2488 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2490 std::vector<CInstanceInfo*>::iterator it;
2491 for (it = _ListInstance.begin(); it != _ListInstance.end(); ++it)
2493 NL3D::CTransformShape *trShape= (*it)->TransformShape;
2494 if (dynamic_cast<NL3D::CMeshBaseInstance *>(trShape))
2496 static_cast<NL3D::CMeshBaseInstance *>(trShape)->selectTextureSet(rand() % 8);
2502 // ***************************************************************************
2504 void CObjectViewer::removeAllInstancesFromScene()
2506 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2508 // Remove all stand alone TransformShapes.
2509 for(uint instance=0; instance<_ListInstance.size(); instance++)
2511 delete _ListInstance[instance];
2514 // Remove all stand alone TransformShapes.
2515 _ListInstance.clear();
2516 _Cameras.clear();
2517 _CurrentCamera = -1;
2518 _SelectedObject = 0xffffffff;
2520 // Remove added/loaded igs and their instances.
2521 for(uint igId=0; igId<_ListIG.size(); igId++)
2523 // remove instances.
2524 _ListIG[igId]->removeFromScene(*CNELU::Scene);
2525 // free up the ig.
2526 delete _ListIG[igId];
2528 _ListIG.clear();
2530 // clear dynamic lighting test
2531 _GlobalRetriever= NULL;
2532 CNELU::Scene->deleteInstance(_ObjectLightTest);
2533 _ObjectLightTest= NULL;
2535 // Reset mesh cache
2536 CNELU::ShapeBank->reset();
2538 // Invalidate dialogs
2539 if (CNELU::Driver->isActive())
2541 _AnimationSetDlg->refresh (TRUE);
2542 _SlotDlg->refresh (TRUE);
2543 _SoundAnimDlg->refresh (TRUE);
2546 // remove any skeleton edited
2547 if(_InstanceRunning)
2548 _SkeletonScaleDlg->setSkeletonToEdit(NULL, "");
2552 // ***************************************************************************
2553 void CObjectViewer::enableFXs(bool enabled)
2555 // Stand alone fxs
2556 for(uint instance=0; instance<_ListInstance.size(); instance++)
2558 NL3D::CSegRemanence *sr = dynamic_cast<NL3D::CSegRemanence *>(_ListInstance[instance]->TransformShape);
2559 if (sr)
2561 if (enabled) sr->start();
2562 else sr->stop();
2565 // remanences in igs
2566 for(uint igId = 0; igId < _ListIG.size(); ++igId)
2568 for(uint k = 0; k < _ListIG[igId]->_Instances.size(); ++k)
2570 NL3D::CSegRemanence *sr = dynamic_cast<NL3D::CSegRemanence *>(_ListIG[igId]->_Instances[k]);
2571 if (sr)
2573 if (enabled) sr->start();
2574 else sr->stop();
2580 // ***************************************************************************
2582 void CObjectViewer::evalSoundTrack (float lastTime, float currentTime)
2584 // Gor each object
2585 for (uint i = 0; i < _ListInstance.size(); i++)
2587 // Some animation in the list ?
2588 if (!_ListInstance[i]->Saved.PlayList.empty())
2590 // Accumul time
2591 float startTime = 0;
2592 float endTime = 0;
2594 // Get start time of the animation that starts before the current time
2595 for (uint index = 0; index < _ListInstance[i]->Saved.PlayList.size(); index++)
2597 // Pointer on the animation
2598 string& name = _ListInstance[i]->Saved.PlayList[index];
2599 CAnimation *anim = _ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName(name));
2601 // Add start time
2602 startTime = endTime;
2603 endTime = startTime + anim->getEndTime()-anim->getBeginTime();
2605 if ((startTime <= currentTime) && (currentTime < endTime))
2607 // setup the sound context
2609 DWORD tab[] = {IDC_ARG0, IDC_ARG1, IDC_ARG2, IDC_ARG3, };
2611 for (uint i = 0; i < 4; i++)
2613 CEdit *edit = (CEdit*) _SoundAnimDlg->GetDlgItem(tab[i]);
2614 nlassert(edit);
2615 TCHAR str[1024];
2616 edit->GetLine(0, str, 1024);
2617 SoundContext.Args[i] = _ttoi (str);
2620 // get the position of the skel if a skel is available
2621 if (SkeletonUsedForSound != 0xFFFFFFFF)
2623 const CMatrix &m = _ListInstance[SkeletonUsedForSound]->TransformShape->getMatrix();
2624 SoundContext.Position = m.getPos();
2626 else
2628 SoundContext.Position = CVector::Null;
2631 CSoundSystem::playAnimation(name, lastTime - startTime, currentTime - startTime, SoundContext);
2638 // ***************************************************************************
2641 void CObjectViewer::evalSoundTrack (float lastTime, float currentTime)
2643 if (lastTime!=currentTime)
2645 // For each objects
2646 for (uint instance=0; instance<_ListInstance.size(); instance++)
2648 // For each channel of the mixer
2649 for (uint slot=0; slot<CChannelMixer::NumAnimationSlot; slot++)
2651 // Anim id
2652 uint animId=_ListInstance[instance]->Playlist.getAnimation (slot);
2654 // Channel actif ?
2655 if (animId!=CAnimationPlaylist::empty)
2657 // Get the animation
2658 CAnimation *anim=_ListInstance[instance]->AnimationSet.getAnimation (animId);
2659 nlassert (anim);
2661 // Get the sound track
2662 uint trackId=anim->getIdTrackByName ("NoteTrack");
2663 if (trackId!=CAnimation::NotFound)
2665 // Get the track
2666 ITrack *track=anim->getTrack (trackId);
2667 nlassert (track);
2669 // Dynamic cast
2670 UTrackKeyframer *soundTrackKF = dynamic_cast<UTrackKeyframer *>(track);
2671 if (soundTrackKF)
2673 // Sound keys
2674 std::vector<TAnimationTime> result;
2676 // Get local begin and endTime
2677 TAnimationTime localLastTime = _ListInstance[instance]->Playlist.getLocalTime (slot, lastTime, _ListInstance[instance]->AnimationSet);
2678 TAnimationTime localCurrentTime = _ListInstance[instance]->Playlist.getLocalTime (slot, currentTime, _ListInstance[instance]->AnimationSet);
2680 // Good interval
2681 if (localLastTime<=localCurrentTime)
2683 // Get keys in this interval
2684 soundTrackKF->getKeysInRange(localLastTime, localCurrentTime, result);
2686 else
2688 // Get begin and last time
2689 TAnimationTime beginTime=track->getBeginTime ();
2690 TAnimationTime endTime=track->getEndTime ();
2692 // Time must have been clamped
2693 nlassert (localCurrentTime<=endTime);
2694 nlassert (localLastTime>=beginTime);
2696 // Get keys to the end
2697 soundTrackKF->getKeysInRange(localCurrentTime, endTime, result);
2699 // Get keys at the beginning
2700 soundTrackKF->getKeysInRange(beginTime, localLastTime, result);
2703 // Process sounds
2704 NLSOUND::UAudioMixer *audioMixer = CSoundSystem::getAudioMixer ();
2705 if( audioMixer )
2707 vector<TAnimationTime>::iterator itResult;
2708 for( itResult = result.begin(); itResult != result.end(); ++itResult )
2710 string soundName;
2711 double keyTime = *itResult;
2712 nlinfo("keyTime = %f result size : %d",*itResult,result.size());
2714 if( !track->interpolate( *itResult, soundName) )
2716 nlwarning("The key at offset %f is not a string",*itResult);
2718 else
2720 // if there are step sounds
2721 if( soundName == "step" )
2723 // need to spawn a sound linked to the anim
2724 string dummySound = "PAShommecourseappartdur1a";
2725 USource *source = audioMixer->createSource (dummySound.c_str() , true );
2726 if (source)
2728 source->setPos (CVector::Null);
2729 source->play ();
2730 nlinfo ("launching dummy sound %s for the step event", dummySound.c_str());
2732 else
2734 nlwarning ("sound not found for the step event: '%s'", dummySound.c_str());
2737 else if (soundName.find ("snd_") != string::npos)
2739 // need to spawn a sound linked to the anim
2740 USource *source = audioMixer->createSource ( soundName.c_str(), true );
2741 if (source)
2743 source->setPos (CVector::Null);
2744 source->play ();
2745 nlinfo ("launching sound for anim event from notetrack '%s'", soundName.c_str());
2747 else
2749 nlwarning ("sound not found: '%s'", soundName.c_str());
2752 else
2754 nlwarning ("unknown notetrack event: '%s'", soundName.c_str());
2769 // ***************************************************************************
2770 uint CObjectViewer::addInstanceGroup(NL3D::CInstanceGroup *ig)
2772 // First instance
2773 uint first = (uint)_ListInstance.size();
2775 // Add all models to the scene
2776 ig->addToScene(*CNELU::Scene, CNELU::Driver);
2777 // Unfreeze all objects from HRC.
2778 ig->unfreezeHRC();
2780 // link the root of the IG to our root, for scene rotation
2781 ig->linkRoot(*CNELU::Scene, _SceneRoot);
2783 // Keep a reference on them, but they'll be destroyed by IG.
2784 for (uint k = 0; k < ig->getNumInstance(); ++k)
2786 CInstanceInfo *iInfo = new CInstanceInfo;
2787 iInfo->TransformShape = ig->_Instances[k];
2788 iInfo->Saved.ShapeFilename = ig->_InstancesInfos[k].Name;
2789 iInfo->MustDelete = false;
2790 _ListInstance.push_back (iInfo);
2793 // Add the ig to the list.
2794 _ListIG.push_back(ig);
2796 // Return first instance
2797 return first;
2800 // ***************************************************************************
2801 void CObjectViewer::setupSceneLightingSystem(bool enable, const NLMISC::CVector &sunDir, NLMISC::CRGBA sunAmbiant, NLMISC::CRGBA sunDiffuse, NLMISC::CRGBA sunSpecular)
2803 CNELU::Scene->enableLightingSystem(enable);
2805 // Setup sun.
2806 CNELU::Scene->setSunAmbient(sunAmbiant);
2807 CNELU::Scene->setSunDiffuse(sunDiffuse);
2808 CNELU::Scene->setSunSpecular(sunSpecular);
2809 CNELU::Scene->setSunDirection(sunDir);
2813 // ***************************************************************************
2814 void CObjectViewer::enableDynamicObjectLightingTest(NLPACS::CGlobalRetriever *globalRetriever, NL3D::CInstanceGroup *ig)
2816 AFX_MANAGE_STATE(AfxGetStaticModuleState());
2818 // first delete the instance
2819 if(_ObjectLightTest)
2821 CNELU::Scene->deleteInstance(_ObjectLightTest);
2822 _ObjectLightTest= NULL;
2825 _GlobalRetriever= globalRetriever;
2827 // if enabled
2828 if(_GlobalRetriever)
2830 nlassert(ig);
2832 // this mesh is the dynamic one to move around.
2833 _ObjectLightTest= CNELU::Scene->createInstance(_ObjectLightTestShape);
2834 if(_ObjectLightTest!=NULL)
2836 // link to the root for manipulation
2837 _SceneRoot->hrcLinkSon(_ObjectLightTest);
2839 // setup the matrix.
2840 _ObjectLightTestMatrix= _ObjectLightTest->getMatrix();
2841 // setup the logic info.
2842 _ObjectLightTestLogicInfo.GlobalRetriever= _GlobalRetriever;
2843 _ObjectLightTestLogicInfo.Ig= ig;
2844 // Default the GPos to uninitialized
2845 _ObjectLightTestLogicInfo.GPos.InstanceId= -1;
2846 _ObjectLightTest->setLogicInfo(&_ObjectLightTestLogicInfo);
2848 else
2850 if (!_ObjectLightTestShape.empty())
2852 string str= string("Path not found for Light Test Shape: ") + _ObjectLightTestShape;
2853 ::MessageBox(NULL, nlUtf8ToTStr(str.c_str()), _T("Dynamic Object Light Test"), MB_OK | MB_ICONEXCLAMATION);
2855 // disable.
2856 _ObjectLightTest= NULL;
2857 _GlobalRetriever= NULL;
2863 // ***************************************************************************
2864 void CObjectViewer::COVLogicInfo::getStaticLightSetup(NLMISC::CRGBA sunAmbient, std::vector<CPointLightInfluence> &pointLightList, uint8 &sunContribution, CRGBA &ambient)
2866 Ig->getStaticLightSetup(sunAmbient, GlobalRetriever->getLocalRetrieverId(GPos),
2867 GPos.LocalPosition.Surface,
2868 GPos.LocalPosition.Estimation,
2869 pointLightList, sunContribution, ambient);
2873 // ***************************************************************************
2874 // ***************************************************************************
2875 // Vegetable Landscape Part.
2876 // ***************************************************************************
2877 // ***************************************************************************
2880 // ***************************************************************************
2881 void CObjectViewer::loadVegetableLandscapeCfg(NLMISC::CConfigFile &cf)
2883 // vegetable display is true by default.
2884 _VegetableEnabled= true;
2885 _VegetableSnapToGround= true;
2888 // Load landscape setup
2889 // --------------
2892 // tileBank setup.
2893 CConfigFile::CVar &tileBank = cf.getVar("veget_tile_bank");
2894 _VegetableLandscapeTileBank= tileBank.asString();
2895 CConfigFile::CVar &tileFarBank = cf.getVar("veget_tile_far_bank");
2896 _VegetableLandscapeTileFarBank= tileFarBank.asString();
2897 // zone list.
2898 _VegetableLandscapeZoneNames.clear();
2899 CConfigFile::CVar &zones = cf.getVar("veget_landscape_zones");
2900 for (uint i=0; i<(uint)zones.size(); i++)
2901 _VegetableLandscapeZoneNames.push_back(zones.asString(i).c_str());
2903 catch (const EUnknownVar &)
2905 _VegetableLandscapeTileBank.clear();
2906 _VegetableLandscapeTileFarBank.clear();
2907 _VegetableLandscapeZoneNames.clear();
2911 // Load Landscape params.
2912 // --------------
2913 // threshold
2916 CConfigFile::CVar &thre= cf.getVar("veget_landscape_threshold");
2917 _VegetableLandscapeThreshold= thre.asFloat();
2918 // clamp to avoid divide/0.
2919 _VegetableLandscapeThreshold= max(_VegetableLandscapeThreshold, 0.001f);
2921 catch (const EUnknownVar &)
2923 _VegetableLandscapeThreshold= 0.003f;
2925 // tilenear
2928 CConfigFile::CVar &tileNear= cf.getVar("veget_landscape_tile_near");
2929 _VegetableLandscapeTileNear= tileNear.asFloat();
2931 catch (const EUnknownVar &)
2933 _VegetableLandscapeTileNear= 50;
2935 // ambient
2938 CConfigFile::CVar &color= cf.getVar("veget_landscape_ambient");
2939 _VegetableLandscapeAmbient.R= color.asInt(0);
2940 _VegetableLandscapeAmbient.G= color.asInt(1);
2941 _VegetableLandscapeAmbient.B= color.asInt(2);
2943 catch (const EUnknownVar &)
2945 _VegetableLandscapeAmbient.set(80, 80, 80);
2947 // diffuse
2950 CConfigFile::CVar &color= cf.getVar("veget_landscape_diffuse");
2951 _VegetableLandscapeDiffuse.R= color.asInt(0);
2952 _VegetableLandscapeDiffuse.G= color.asInt(1);
2953 _VegetableLandscapeDiffuse.B= color.asInt(2);
2955 catch (const EUnknownVar &)
2957 _VegetableLandscapeDiffuse.set(255, 255, 255);
2959 // Snapping
2962 CConfigFile::CVar &var= cf.getVar("veget_landscape_snap_height");
2963 _VegetableSnapHeight= var.asFloat();
2965 catch (const EUnknownVar &)
2967 _VegetableSnapHeight= 1.70f;
2971 // Load Vegetable params.
2972 // --------------
2974 // vegetable texture
2977 CConfigFile::CVar &var= cf.getVar("veget_texture");
2978 _VegetableTexture= var.asString();
2980 catch (const EUnknownVar &)
2982 _VegetableTexture.clear();
2985 // vegetable ambient
2988 CConfigFile::CVar &color= cf.getVar("veget_ambient");
2989 _VegetableAmbient.R= color.asInt(0);
2990 _VegetableAmbient.G= color.asInt(1);
2991 _VegetableAmbient.B= color.asInt(2);
2993 catch (const EUnknownVar &)
2995 _VegetableAmbient.set(80, 80, 80);
2997 // vegetable diffuse
3000 CConfigFile::CVar &color= cf.getVar("veget_diffuse");
3001 // setup to behave correclty ie as maxLightFactor:
3002 sint R= color.asInt(0) - _VegetableAmbient.R; clamp(R, 0, 255); _VegetableDiffuse.R= R;
3003 sint G= color.asInt(1) - _VegetableAmbient.G; clamp(G, 0, 255); _VegetableDiffuse.G= G;
3004 sint B= color.asInt(2) - _VegetableAmbient.B; clamp(B, 0, 255); _VegetableDiffuse.B= B;
3006 catch (const EUnknownVar &)
3008 sint R= 255 - _VegetableAmbient.R; clamp(R, 0, 255); _VegetableDiffuse.R= R;
3009 sint G= 255 - _VegetableAmbient.G; clamp(G, 0, 255); _VegetableDiffuse.G= G;
3010 sint B= 255 - _VegetableAmbient.B; clamp(B, 0, 255); _VegetableDiffuse.B= B;
3012 // vegetable lightDir
3015 CConfigFile::CVar &var= cf.getVar("veget_light_dir");
3016 _VegetableLightDir.x= var.asFloat(0);
3017 _VegetableLightDir.y= var.asFloat(1);
3018 _VegetableLightDir.z= var.asFloat(2);
3019 _VegetableLightDir.normalize();
3021 catch (const EUnknownVar &)
3023 _VegetableLightDir.set(0, 1, -1);
3024 _VegetableLightDir.normalize();
3027 // windDir
3030 CConfigFile::CVar &var= cf.getVar("veget_wind_dir");
3031 _VegetableWindDir.x= var.asFloat(0);
3032 _VegetableWindDir.y= var.asFloat(1);
3033 _VegetableWindDir.z= var.asFloat(2);
3035 catch (const EUnknownVar &)
3037 _VegetableWindDir.x= 0.5f;
3038 _VegetableWindDir.y= 0.5f;
3039 _VegetableWindDir.z= 0;
3041 // windFreq
3044 CConfigFile::CVar &var= cf.getVar("veget_wind_freq");
3045 _VegetableWindFreq= var.asFloat();
3047 catch (const EUnknownVar &)
3049 _VegetableWindFreq= 0.5;
3051 // windPower
3054 CConfigFile::CVar &var= cf.getVar("veget_wind_power");
3055 _VegetableWindPower= var.asFloat();
3057 catch (const EUnknownVar &)
3059 _VegetableWindPower= 1;
3061 // windBendMin
3064 CConfigFile::CVar &var= cf.getVar("veget_wind_bend_min");
3065 _VegetableWindBendMin= var.asFloat();
3067 catch (const EUnknownVar &)
3069 _VegetableWindBendMin= 0;
3076 // ***************************************************************************
3077 bool CObjectViewer::createVegetableLandscape()
3079 // If not already done.
3080 if(!_VegetableLandscape)
3082 // create the landscape.
3083 _VegetableLandscape= static_cast<CLandscapeModel*>(CNELU::Scene->createModel(LandscapeModelId));
3085 // Create a Progress Dialog.
3086 CDialogProgress dlgProgress;
3087 dlgProgress.Create(CDialogProgress::IDD, _MainFrame);
3088 dlgProgress.ShowWindow(true);
3092 if(_VegetableLandscapeTileBank.empty())
3094 throw Exception("Landscape CFG not fully defined");
3097 // Load The Bank files (copied from CLandscapeUser :) ).
3098 // ================
3099 // progress
3100 dlgProgress.ProgressText.SetWindowText(_T("Loading TileBanks..."));
3101 dlgProgress.ProgressBar.SetPos(0);
3102 // load
3103 CIFile bankFile(CPath::lookup(_VegetableLandscapeTileBank));
3104 _VegetableLandscape->Landscape.TileBank.serial(bankFile);
3105 _VegetableLandscape->Landscape.TileBank.makeAllPathRelative();
3106 _VegetableLandscape->Landscape.TileBank.makeAllExtensionDDS();
3107 _VegetableLandscape->Landscape.TileBank.setAbsPath ("");
3109 // progress
3110 dlgProgress.ProgressBar.SetPos(50);
3111 // load
3112 CIFile farbankFile(CPath::lookup(_VegetableLandscapeTileFarBank));
3113 _VegetableLandscape->Landscape.TileFarBank.serial(farbankFile);
3114 if ( ! _VegetableLandscape->Landscape.initTileBanks() )
3116 nlwarning( "You need to recompute bank.farbank for the far textures" );
3118 bankFile.close();
3119 farbankFile.close();
3122 // flushTiles.
3123 // ================
3124 if(CNELU::Driver)
3126 // progress
3127 dlgProgress.ProgressText.SetWindowText(_T("Loading Tiles..."));
3128 dlgProgress.ProgressBar.SetPos(0);
3130 // count nbText to load.
3131 sint ts;
3132 sint nbTextTotal= 0;
3133 for (ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
3135 CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
3136 nbTextTotal+= tileSet->getNumTile128();
3137 nbTextTotal+= tileSet->getNumTile256();
3138 nbTextTotal+= CTileSet::count;
3141 // load.
3142 sint nbTextDone= 0;
3143 for (ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
3145 CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
3146 sint tl;
3147 for (tl=0; tl<tileSet->getNumTile128(); tl++, nbTextDone++)
3149 _VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTile128(tl), 1);
3150 dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
3152 for (tl=0; tl<tileSet->getNumTile256(); tl++, nbTextDone++)
3154 _VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTile256(tl), 1);
3155 dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
3157 for (tl=0; tl<CTileSet::count; tl++, nbTextDone++)
3159 _VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTransition(tl)->getTile (), 1);
3160 dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
3166 // misc setup.
3167 // ================
3168 _VegetableLandscape->Landscape.setThreshold(_VegetableLandscapeThreshold);
3169 _VegetableLandscape->Landscape.setTileNear(_VegetableLandscapeTileNear);
3170 _VegetableLandscape->Landscape.setupStaticLight(_VegetableLandscapeDiffuse, _VegetableLandscapeAmbient, 1);
3171 _VegetableLandscape->Landscape.loadVegetableTexture(_VegetableTexture);
3172 _VegetableLandscape->Landscape.setupVegetableLighting(_VegetableAmbient, _VegetableDiffuse, _VegetableLightDir);
3173 _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
3176 // Load the zones.
3177 // ================
3178 // landscape recentering.
3179 bool zoneLoaded= false;
3180 CAABBox landscapeBBox;
3181 // progress
3182 dlgProgress.ProgressText.SetWindowText(_T("Loading Zones..."));
3183 dlgProgress.ProgressBar.SetPos(0);
3184 uint nbZones= (uint)_VegetableLandscapeZoneNames.size();
3185 for(uint i=0; i<nbZones;i++)
3187 // open the file
3188 CIFile zoneFile(CPath::lookup(_VegetableLandscapeZoneNames[i]));
3189 CZone zone;
3190 // load
3191 zoneFile.serial(zone);
3192 // append to landscape
3193 _VegetableLandscape->Landscape.addZone(zone);
3194 // progress
3195 dlgProgress.ProgressBar.SetPos(i*100/nbZones);
3197 // Add to the bbox.
3198 if(!zoneLoaded)
3200 zoneLoaded= true;
3201 landscapeBBox.setCenter(zone.getZoneBB().getCenter());
3203 else
3204 landscapeBBox.extend(zone.getZoneBB().getCenter());
3207 // After All zone loaded, recenter the mouse listener on the landscape.
3208 if(zoneLoaded)
3210 CMatrix matrix;
3211 _MouseListener.setHotSpot(landscapeBBox.getCenter());
3212 matrix.setPos(landscapeBBox.getCenter());
3213 matrix.rotateX(-(float)Pi/4);
3214 matrix.translate(CVector(0,-1000,0));
3215 _MouseListener.setMatrix(matrix);
3218 // Create collisions objects.
3219 _VegetableCollisionManager= new CVisualCollisionManager;
3220 _VegetableCollisionManager->setLandscape(&_VegetableLandscape->Landscape);
3221 _VegetableCollisionEntity= _VegetableCollisionManager->createEntity();
3223 catch (const Exception &e)
3225 // close the progress dialog
3226 dlgProgress.DestroyWindow();
3228 MessageBox(_MainFrame->m_hWnd, nlUtf8ToTStr(e.what()), _T("Failed to Load landscape"), MB_OK | MB_APPLMODAL);
3230 // remove first possibly created collisions objects.
3231 if(_VegetableCollisionEntity)
3233 _VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity);
3234 _VegetableCollisionEntity= NULL;
3236 if(_VegetableCollisionManager)
3238 delete _VegetableCollisionManager;
3239 _VegetableCollisionManager= NULL;
3242 // remove the landscape
3243 CNELU::Scene->deleteModel(_VegetableLandscape);
3244 _VegetableLandscape= NULL;
3246 return false;
3249 // close the progress dialog
3250 dlgProgress.DestroyWindow();
3253 return true;
3257 // ***************************************************************************
3258 void CObjectViewer::showVegetableLandscape()
3260 if(_VegetableLandscape)
3262 _VegetableLandscape->show();
3266 // ***************************************************************************
3267 void CObjectViewer::hideVegetableLandscape()
3269 if(_VegetableLandscape)
3271 _VegetableLandscape->hide();
3276 // ***************************************************************************
3277 void CObjectViewer::enableLandscapeVegetable(bool enable)
3279 // update
3280 _VegetableEnabled= enable;
3282 // update view.
3283 if(_VegetableLandscape)
3285 _VegetableLandscape->Landscape.enableVegetable(_VegetableEnabled);
3290 // ***************************************************************************
3291 void CObjectViewer::refreshVegetableLandscape(const NL3D::CTileVegetableDesc &tvdesc)
3293 // if landscape is displayed.
3294 if(_VegetableLandscape)
3296 // first disable the vegetable, to delete any vegetation
3297 _VegetableLandscape->Landscape.enableVegetable(false);
3299 // Then change all the tileSet of all the TileBanks.
3300 for (sint ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
3302 CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
3303 // change the vegetableTileDesc of this tileSet.
3304 tileSet->setTileVegetableDesc(tvdesc);
3307 // re-Enable the vegetable (if wanted).
3308 _VegetableLandscape->Landscape.enableVegetable(_VegetableEnabled);
3313 // ***************************************************************************
3314 void CObjectViewer::setVegetableWindPower(float w)
3316 _VegetableWindPower= w;
3317 if(_VegetableLandscape)
3318 _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
3320 // ***************************************************************************
3321 void CObjectViewer::setVegetableWindBendStart(float w)
3323 _VegetableWindBendMin= w;
3324 if(_VegetableLandscape)
3325 _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
3327 // ***************************************************************************
3328 void CObjectViewer::setVegetableWindFrequency(float w)
3330 _VegetableWindFreq= w;
3331 if(_VegetableLandscape)
3332 _VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
3336 // ***************************************************************************
3337 void CObjectViewer::snapToGroundVegetableLandscape(bool enable)
3339 // update
3340 _VegetableSnapToGround= enable;
3343 // ***************************************************************************
3344 CInstanceInfo::CInstanceInfo ()
3346 TransformShape = NULL;
3347 Camera = NULL;
3348 MustDelete = false;
3351 // ***************************************************************************
3352 CInstanceInfo::~CInstanceInfo ()
3354 if (MustDelete)
3356 if (TransformShape)
3357 CNELU::Scene->deleteInstance (TransformShape);
3358 if (Camera)
3359 CNELU::Scene->deleteModel (Camera);
3363 // ***************************************************************************
3364 CSlotInfo::CSlotInfo ()
3366 StartTime = 0;
3367 EndTime = 0;
3368 Offset = 0;
3369 StartBlend = 1;
3370 EndBlend = 1;
3371 Smoothness = 1;
3372 SpeedFactor = 1;
3373 ClampMode = 0;
3374 SkeletonInverted = false;
3375 Enable = true;
3378 // ***************************************************************************
3379 void CSlotInfo::serial (NLMISC::IStream &f)
3381 f.serialVersion (0);
3382 f.serial (Animation);
3383 f.serial (Skeleton);
3384 f.serial (Offset);
3385 f.serial (StartTime);
3386 f.serial (EndTime);
3387 f.serial (StartBlend);
3388 f.serial (EndBlend);
3389 f.serial (Smoothness);
3390 f.serial (SpeedFactor);
3391 f.serial (ClampMode);
3392 f.serial (SkeletonInverted);
3393 f.serial (Enable);
3396 // ***************************************************************************
3397 uint CObjectViewer::getEditedObject ()
3399 return _SelectedObject;
3402 // ***************************************************************************
3403 void CObjectViewer::setEditedObject (uint selected)
3405 _SelectedObject=selected;
3408 // ***************************************************************************
3409 CInstanceInfo *CObjectViewer::getInstance (uint instance)
3411 return _ListInstance[instance];
3414 // ***************************************************************************
3415 uint CObjectViewer::getNumInstance () const
3417 return (uint)_ListInstance.size ();
3420 // ***************************************************************************
3421 void CInstanceInfo::setAnimationPlaylist (float frameRate)
3423 for (uint id=0; id<NL3D::CChannelMixer::NumAnimationSlot; id++)
3425 if (Saved.SlotInfo[id].Enable)
3427 // Set the animation
3428 uint animId = AnimationSet.getAnimationIdByName (Saved.SlotInfo[id].Animation);
3429 if (animId == CAnimationSet::NotFound)
3430 Playlist.setAnimation (id, CAnimationPlaylist::empty);
3431 else
3432 Playlist.setAnimation (id, animId);
3434 // Set the skeleton weight
3435 uint skelId = AnimationSet.getSkeletonWeightIdByName (Saved.SlotInfo[id].Skeleton);
3436 if (skelId == CAnimationSet::NotFound)
3437 Playlist.setSkeletonWeight (id, CAnimationPlaylist::empty, false);
3438 else
3439 Playlist.setSkeletonWeight (id, skelId, Saved.SlotInfo[id].SkeletonInverted);
3441 // Set others values
3442 Playlist.setTimeOrigin (id, Saved.SlotInfo[id].Offset/frameRate);
3443 Playlist.setSpeedFactor (id, Saved.SlotInfo[id].SpeedFactor);
3444 Playlist.setStartWeight (id, Saved.SlotInfo[id].StartBlend, Saved.SlotInfo[id].StartTime/frameRate);
3445 Playlist.setEndWeight (id, Saved.SlotInfo[id].EndBlend, Saved.SlotInfo[id].EndTime/frameRate);
3446 Playlist.setWeightSmoothness (id, Saved.SlotInfo[id].Smoothness);
3448 // Switch between wrap modes
3449 switch (Saved.SlotInfo[id].ClampMode)
3451 case 0:
3452 Playlist.setWrapMode (id, CAnimationPlaylist::Clamp);
3453 break;
3454 case 1:
3455 Playlist.setWrapMode (id, CAnimationPlaylist::Repeat);
3456 break;
3457 case 2:
3458 Playlist.setWrapMode (id, CAnimationPlaylist::Disable);
3459 break;
3465 // ***************************************************************************
3466 CInstanceSave::CInstanceSave ()
3468 SkeletonId = 0xffffffff;
3469 IsSkeleton = false;
3470 Camera = false;
3473 // ***************************************************************************
3474 void CInstanceSave::serial (NLMISC::IStream &f)
3476 // Serial a version
3477 sint ver = f.serialVersion (1);
3479 // Play list of this object
3480 f.serialCont (PlayList);
3482 // Slot info for this object
3483 nlassert (NL3D::CChannelMixer::NumAnimationSlot == 8);
3484 for (uint slot=0; slot<8; slot++)
3485 // Serial the slot information
3486 f.serial (SlotInfo[slot]);
3488 // Input file
3489 f.serial (ShapeFilename);
3491 // Skeleton id
3492 f.serial (SkeletonId);
3494 // Bind bone name
3495 f.serial (BindBoneName);
3497 // Is a skeleton
3498 f.serial (IsSkeleton);
3500 // Animation input file
3501 f.serialCont (AnimationFileName);
3503 // Skeleton weight input file
3504 f.serialCont (SWTFileName);
3506 // Is a camera
3507 if (ver>=1)
3509 f.serial (Camera);
3510 f.serial (CameraInfo);
3512 else if (f.isReading ())
3513 Camera = false;
3516 // ***************************************************************************
3517 void CObjectViewer::refreshAnimationListeners()
3519 _SoundAnimDlg->refresh (TRUE);
3522 // ***************************************************************************
3523 void CObjectViewer::addAnimation(NL3D::CAnimation* anim, const std::string &filename, const std::string &name, uint instance)
3525 // Add an animation
3526 uint id = _ListInstance[instance]->AnimationSet.addAnimation (name.c_str(), anim);
3527 _ListInstance[instance]->Saved.AnimationFileName.push_back (filename);
3529 // Rebuild the animationSet
3530 _ListInstance[instance]->AnimationSet.build ();
3531 if(CNELU::Driver && CNELU::ShapeBank)
3533 _ListInstance[instance]->AnimationSet.preloadSSSShapes(*CNELU::Driver, *CNELU::ShapeBank);
3536 _SoundAnimDlg->refresh (TRUE);
3539 // ***************************************************************************
3540 void CObjectViewer::loadAnimation(const std::string &fileName, uint instance)
3542 // Open the file
3543 CIFile file;
3544 if (file.open (fileName))
3546 // Get the animation name
3547 std::string name = NLMISC::CFile::getFilenameWithoutExtension(fileName);
3549 // Make an animation
3550 CAnimation *anim=new CAnimation;
3552 // Serial it
3553 anim->serial (file);
3555 // Add the animation
3556 addAnimation (anim, fileName, name, instance);
3558 else
3560 // Create a message
3561 std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
3562 _MainFrame->MessageBox(nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
3566 // ***************************************************************************
3567 void CObjectViewer::loadSWT (const std::string &fileName, uint instance)
3569 // Open the file
3570 CIFile file;
3571 if (file.open (fileName))
3573 // Get the animation name
3574 std::string name = NLMISC::CFile::getFilenameWithoutExtension(fileName);
3576 // Get the skeleton pointer
3577 CSkeletonWeight* skel=new CSkeletonWeight;
3579 // Serial it
3580 skel->serial (file);
3582 // Add an animation
3583 _ListInstance[instance]->AnimationSet.addSkeletonWeight (name.c_str(), skel);
3585 // Add the filename in the list
3586 _ListInstance[instance]->Saved.SWTFileName.push_back (fileName);
3588 else
3590 // Create a message
3591 std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
3592 _MainFrame->MessageBox(nlUtf8ToTStr(msg), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
3596 // ***************************************************************************
3597 CMainDlg *CObjectViewer::getSlotDlg ()
3599 return _SlotDlg;
3602 // ***************************************************************************
3603 void CObjectViewer::reloadTextures ()
3605 // For each instances
3606 uint numInstance = getNumInstance ();
3607 uint instance;
3608 for (instance=0; instance<numInstance; instance++)
3610 // Get the info
3611 CInstanceInfo *info = getInstance (instance);
3613 // For each material
3614 if (info->TransformShape)
3616 uint numMaterial = info->TransformShape->getNumMaterial ();
3617 uint mat;
3618 for (mat=0; mat<numMaterial; mat++)
3620 // Get the material
3621 CMaterial *material = info->TransformShape->getMaterial (mat);
3623 // For each texture
3624 int tex;
3625 for (tex=0; tex<IDRV_MAT_MAXTEXTURES; tex++)
3627 ITexture *texture = material->getTexture (tex);
3629 // Touch it!
3630 if (texture)
3632 CNELU::Driver->invalidateShareTexture (*texture);
3640 // ***************************************************************************
3641 // ***************************************************************************
3642 // Global wind part.
3643 // ***************************************************************************
3644 // ***************************************************************************
3647 // ***************************************************************************
3648 void CObjectViewer::setGlobalWindPower(float w)
3650 if(_MainFrame)
3652 clamp(w, 0.f, 1.f);
3653 _MainFrame->GlobalWindPower= w;
3654 CNELU::Scene->setGlobalWindPower(w);
3659 // ***************************************************************************
3660 float CObjectViewer::getGlobalWindPower() const
3662 if(_MainFrame)
3663 return _MainFrame->GlobalWindPower;
3664 else
3665 return 1.f;
3669 void CObjectViewer::shootScene()
3671 static const TCHAR BASED_CODE szFilter[] = _T("PNG Files (*.png)|*.png|Targa Files (*.tga)|*.tga|Jpeg Files (*.jpg)|*.jpg|All Files (*.*)|*.*||");
3672 CFileDialog fileDlg ( FALSE, _T(".tga"), _T("*.tga"), OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter);
3673 if (fileDlg.DoModal () == IDOK)
3675 // Choose the size
3676 CSelectMovieSize movieSize;
3677 if (movieSize.DoModal () == IDOK)
3679 // Resize the window
3680 RECT window;
3681 _MainFrame->GetWindowRect (&window);
3682 uint32 width;
3683 uint32 height;
3684 CNELU::Driver->getWindowSize (width, height);
3685 window.right += movieSize.Width - width;
3686 window.bottom += movieSize.Height - height;
3687 _MainFrame->SetWindowPos (NULL, 0, 0, window.right-window.left, window.bottom-window.top, SWP_NOMOVE|SWP_NOZORDER);
3690 // Swap the buffers
3691 CNELU::swapBuffers();
3692 CNELU::Driver->setupViewport (CViewport ());
3694 // The file name
3695 string filename = NLMISC::CFile::getFilenameWithoutExtension(tStrToUtf8(fileDlg.GetPathName()));
3696 string extension = NLMISC::CFile::getExtension (tStrToUtf8(fileDlg.GetPathName()));
3698 // The file name without extension
3699 bool jpeg = toLowerAscii (extension) == "jpg";
3701 // Activate the driver
3702 CNELU::Driver->activate ();
3704 // Bitmap for shoot
3705 NLMISC::CBitmap shoot;
3707 // For each frame
3708 sint i;
3709 for (i=(sint)_AnimationDlg->Start; i<=(sint)_AnimationDlg->End; i++)
3711 // Set the time
3712 _AnimationDlg->setCurrentFrame ((float)i);
3714 // Setup the play list
3715 setupPlaylist (_AnimationDlg->getTime());
3717 // Animate the automatic animation in the scene
3718 animateCNELUScene (_CS, (uint64)(1000.f / _AnimationDlg->Speed));
3720 // Eval channel mixer for transform
3721 for (uint j=0; j<_ListInstance.size(); j++)
3722 _ListInstance[j]->ChannelMixer.eval (false);
3724 // Clear the buffers
3725 CNELU::clearBuffers (_BackGroundColor);
3727 // call of callback list
3729 std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
3730 for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
3732 (*it)->goPreRender();
3735 // Render the CS
3736 if (_CS) _CS->render ();
3738 // Draw the scene
3739 CNELU::Scene->render();
3741 // call of callback list
3743 std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
3744 for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
3746 (*it)->goPostRender();
3752 // Swap the buffers
3753 CNELU::swapBuffers();
3755 // Get the buffer
3756 CNELU::Driver->getBuffer (shoot);
3757 shoot.flipV ();
3759 // Save it
3760 char num[12];
3761 smprintf (num, 12, "%04d", i);
3762 string filenamefinal = filename+num+string (".")+extension;
3765 NLMISC::COFile output;
3766 if (output.open (filenamefinal))
3768 if (jpeg)
3769 shoot.writeJPG ( output, 255 );
3770 else
3771 shoot.writeTGA ( output, 32 );
3773 else
3775 std::string message = toString("Can't open the file %s for writing.", filenamefinal.c_str());
3776 _MainFrame->MessageBox(nlUtf8ToTStr(message), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
3777 break;
3780 catch (const Exception &e)
3782 std::string message = toString("Error during writing of the file %s: %s", filenamefinal.c_str(), e.what());
3783 _MainFrame->MessageBox(nlUtf8ToTStr(message), _T("NeL object viewer"), MB_OK | MB_ICONEXCLAMATION);
3784 break;
3791 void CObjectViewer::drawFXUserMatrix()
3794 static std::string fxUserMatrixStr;
3795 static bool stringRetrieved = false;
3796 if (!stringRetrieved)
3798 CString fxUserMatrix;
3799 fxUserMatrix.LoadString(IDS_FX_USER_MATRIX);
3800 fxUserMatrixStr = tStrToUtf8(fxUserMatrix);
3801 stringRetrieved = true;
3803 nlassert(_ParticleDlg);
3804 drawNamedMatrix(getFXUserMatrix(), fxUserMatrixStr, NLMISC::CRGBA::Red, 0.2f, 10.f);
3807 void CObjectViewer::drawFXMatrix()
3809 static std::string fxStr;
3810 static bool stringRetrieved = false;
3811 if (!stringRetrieved)
3813 CString fx;
3814 fx.LoadString(IDS_FX_MATRIX);
3815 fxStr = tStrToUtf8(fx);
3816 stringRetrieved = true;
3818 drawNamedMatrix(_ParticleDlg->getPSWorldMatrix(), fxStr, NLMISC::CRGBA::Blue, -0.2f, 10.f);
3821 void CObjectViewer::drawSceneMatrix()
3823 static std::string sceneMatrixStr;
3824 static bool stringRetrieved = false;
3825 if (!stringRetrieved)
3827 CString sceneMatrix;
3828 sceneMatrix.LoadString(IDS_SCENE_MATRIX);
3829 sceneMatrixStr = tStrToUtf8(sceneMatrix);
3830 stringRetrieved = true;
3832 drawNamedMatrix(_SceneRoot->getMatrix(), sceneMatrixStr, NLMISC::CRGBA::White, 0.f, 10.f);
3836 void CObjectViewer::drawNamedMatrix(const NLMISC::CMatrix &matrix, const std::string &name, NLMISC::CRGBA color, float textZOffset, float testSize)
3838 CPSUtil::displayBasis(CNELU::Driver, matrix, NLMISC::CMatrix::Identity, 1.f, *_FontGenerator, _FontManager);
3839 CPSUtil::print(CNELU::Driver, name, *_FontGenerator, _FontManager, matrix.getPos() + NLMISC::CVector(0.f, 0.f, textZOffset), testSize, color);
3844 sint CObjectViewer::getCurrentCamera () const
3846 return _CurrentCamera;
3849 void CObjectViewer::setCurrentCamera (sint currentCamera)
3851 nlassert ((currentCamera == -1) ||(currentCamera < (sint)_Cameras.size ()));
3852 _CurrentCamera = currentCamera;
3855 uint CObjectViewer::getCameraInstance (uint cameraId) const
3857 return _Cameras[cameraId];
3860 uint CObjectViewer::getNumCamera () const
3862 return (uint)_Cameras.size ();
3865 int localizedMessageBox(HWND parentWindow, int messageStringID, int captionStringID, UINT nType)
3867 CString caption;
3868 CString mess;
3869 caption.LoadString(captionStringID);
3870 mess.LoadString(messageStringID);
3871 return MessageBox(parentWindow, (LPCTSTR) mess, (LPCTSTR) caption, nType);
3872 // TODO : replace older call to ::MessageBox in the object viewer with that function
3875 int localizedMessageBox(HWND parentWindow, const TCHAR *message, int captionStringID, UINT nType)
3877 CString caption;
3878 caption.LoadString(captionStringID);
3879 return MessageBox(parentWindow, message, (LPCTSTR) caption, nType);
3882 CString getStrRsc(uint stringID)
3884 CString str;
3885 str.LoadString(stringID);
3886 return str;
3889 bool browseFolder(const CString &caption, CString &destFolder, HWND parent)
3891 TCHAR chosenPath[MAX_PATH];
3892 // browse folder
3893 BROWSEINFO bi;
3894 bi.hwndOwner = parent;
3895 bi.pidlRoot = NULL;
3896 bi.pszDisplayName = chosenPath;
3897 bi.lpszTitle = (LPCTSTR) caption;
3898 bi.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_EDITBOX;
3899 bi.lpfn = NULL;
3900 bi.lParam = NULL;
3901 bi.iImage = 0;
3902 PIDLIST_ABSOLUTE result = SHBrowseForFolder(&bi);
3903 if (result != NULL && SHGetPathFromIDList(result, chosenPath))
3905 destFolder = chosenPath;
3906 return true;
3908 return false;