khanat-code-old/code/nel/tools/3d/object_viewer/object_viewer.cpp

3909 lines
107 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "std_afx.h"
#undef OBJECT_VIEWER_EXPORT
#define OBJECT_VIEWER_EXPORT __declspec( dllexport )
#include <vector>
#include "object_viewer.h"
#include "nel/3d/nelu.h"
#include "nel/3d/mesh.h"
#include "nel/3d/mesh_mrm.h"
#include "nel/3d/mesh_mrm_skinned.h"
#include "nel/3d/transform_shape.h"
#include "nel/3d/mesh_instance.h"
#include "nel/3d/text_context.h"
#include "nel/3d/skeleton_model.h"
#include "nel/3d/init_3d.h"
#include "nel/3d/scene_group.h"
#include "nel/3d/animation_playlist.h"
#include "nel/3d/track_keyframer.h"
#include "nel/3d/register_3d.h"
#include "nel/3d/seg_remanence.h"
#include "nel/misc/common.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "nel/misc/time_nl.h"
#include "nel/misc/config_file.h"
#include "nel/sound/u_audio_mixer.h"
#include "nel/3d/water_pool_manager.h"
#include "nel/3d/landscape_model.h"
#include "nel/3d/visual_collision_manager.h"
#include "nel/3d/visual_collision_entity.h"
#include "nel/3d/ps_util.h"
#include "nel/pacs/global_retriever.h"
#include "select_movie_size.h"
#include "editable_range.h"
#include "range_manager.h"
#include "located_properties.h"
#include "color_button.h"
#include "particle_dlg.h"
#include "resource.h"
#include "main_frame.h"
#include "sound_system.h"
#include "scheme_manager.h"
#include "day_night_dlg.h"
#include "water_pool_editor.h"
#include "vegetable_dlg.h"
#include "dialog_progress.h"
#include "select_string.h"
#include "global_wind_dlg.h"
#include "sound_anim_dlg.h"
#include "light_group_factor.h"
#include "choose_bg_color_dlg.h"
#include "choose_sun_color_dlg.h"
#include "choose_frame_delay.h"
#include "skeleton_scale_dlg.h"
#include "graph.h"
#include "tune_mrm_dlg.h"
using namespace std;
using namespace NL3D;
using namespace NLMISC;
using namespace NLSOUND;
using namespace NLPACS;
static std::string SPath;
uint SkeletonUsedForSound = 0xFFFFFFFF;
CSoundContext SoundContext;
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CObject_viewerApp
BEGIN_MESSAGE_MAP(CObject_viewerApp, CWinApp)
//{{AFX_MSG_MAP(CObject_viewerApp)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CObject_viewerApp construction
CObject_viewerApp::CObject_viewerApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CObject_viewerApp object
CObject_viewerApp theApp;
bool CObjectViewer::_InstanceRunning = false;
// ***************************************************************************
class CObjView : public CView
{
public:
CObjView()
{
MainFrame=NULL;
};
virtual ~CObjView() {}
virtual void OnDraw (CDC *) {}
afx_msg BOOL OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if ((CNELU::Driver) && MainFrame)
MainFrame->DriverWindowProc (CNELU::Driver, m_hWnd, message, wParam, lParam);
return CView::WindowProc(message, wParam, lParam);
}
DECLARE_DYNCREATE(CObjView)
CMainFrame *MainFrame;
};
// ***************************************************************************
IMPLEMENT_DYNCREATE(CObjView, CView)
// ***************************************************************************
void animateCNELUScene (CCloudScape *cs, uint64 deltaTime = 0)
{
if (!cs) return;
static sint64 firstTime = NLMISC::CTime::getLocalTime();
static sint64 lastTime = NLMISC::CTime::getLocalTime();
if (deltaTime == 0)
{
deltaTime = NLMISC::CTime::getLocalTime() - lastTime;
}
lastTime += deltaTime;
float fdelta = 0.001f * (float) (lastTime - firstTime);
CNELU::Scene->animate ( fdelta);
cs->anim (fdelta, CNELU::Scene->getCam());
}
// ***************************************************************************
CObjectViewer::CObjectViewer ()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
_SceneRoot= NULL;
init3d ();
// vl: is it really useful? i moved it from ov.exe init
CScene::registerBasics ();
registerSerial3d();
_MainFrame = NULL;
_SlotDlg=NULL;
_AnimationSetDlg=NULL;
_AnimationDlg=NULL;
_ParticleDlg = NULL;
_FontGenerator = NULL;
_VegetableLandscape= NULL;
_VegetableCollisionManager= NULL;
_VegetableCollisionEntity= NULL;
_CameraFocal = 75.f; // default value for the focal
_SelectedObject = 0xffffffff;
_LightGroupDlg = NULL;
_ChooseFrameDelayDlg = NULL;
_ChooseBGColorDlg = NULL;
_DayNightDlg = NULL;
_WaterPoolDlg = NULL;
_SoundAnimDlg = NULL;
_VegetableDlg = NULL;
_GlobalWindDlg = NULL;
_SkeletonScaleDlg = NULL;
_TuneMRMDlg= NULL;
// no frame delay is the default
_FrameDelay = 0;
// Hotspot color
_HotSpotColor.R=255;
_HotSpotColor.G=255;
_HotSpotColor.B=0;
_HotSpotColor.A=255;
_BackGroundColor = CRGBA::Black;
// Hotspot size
_HotSpotSize=10.f;
_Wpm = &NL3D::GetWaterPoolManager();
_GlobalRetriever= NULL;
_ObjectLightTest= NULL;
_CharacterScalePos= 1;
_CurrentCamera = -1;
_Direct3d = false;
_Fog = false;
_FogStart = 0;
_FogEnd = 1;
_FogColor = NLMISC::CRGBA::Black;
_FXUserMatrix.identity();
_FXMatrixVisible = false;
_FXUserMatrixVisible = false;
_SceneMatrixVisible = false;
_OcclusionTestMeshsVisible = false;
_CS = NULL;
}
// ***************************************************************************
std::string CObjectViewer::getModulePath() const
{
// Get the configuration file path (located in same directory as module)
HMODULE hModule = AfxGetInstanceHandle();
nlassert(hModule); // shouldn't be null now anymore in any case
nlassert(hModule != GetModuleHandle(NULL)); // if this is dll, the module handle can't be same as exe
TCHAR sModulePath[256];
int res = GetModuleFileName(hModule, sModulePath, 256); nlassert(res);
nldebug("Object viewer module path is '%s'", sModulePath);
SPath = NLMISC::CFile::getPath(tStrToUtf8(sModulePath));
return SPath + "object_viewer.cfg";
}
// ***************************************************************************
void CObjectViewer::loadDriverName()
{
// Load the config file
CConfigFile cf;
cf.load (getModulePath());
CConfigFile::CVar *var = cf.getVarPtr("driver");
_Direct3d = var && (var->asString() == "direct3d");
}
// ***************************************************************************
void CObjectViewer::loadConfigFile()
{
// Load object_viewer.ini
try
{
// Load the config file
CConfigFile cf;
cf.load (getModulePath());
try
{
// Add search pathes
CConfigFile::CVar &search_pathes = cf.getVar ("search_pathes");
for (uint i=0; i<(uint)search_pathes.size(); i++)
CPath::addSearchPath (search_pathes.asString(i));
}
catch(const EUnknownVar &)
{}
try
{
// Add recusrive search pathes
CConfigFile::CVar &recursive_search_pathes = cf.getVar ("recursive_search_pathes");
for (uint i=0; i<(uint)recursive_search_pathes.size(); i++)
CPath::addSearchPath (recursive_search_pathes.asString(i), true, false);
}
catch(const EUnknownVar &)
{}
// Add extension remapping
try
{
CConfigFile::CVar &extensions_remapping = cf.getVar ("extensions_remapping");
if (extensions_remapping.size()%2 != 0)
{
nlwarning ("extensions_remapping must have a multiple of 2 entries (ex: extensions_remapping={\"dds\",\"tga\"};)");
}
else
{
for (uint i=0; i<(uint)extensions_remapping.size(); i+=2)
CPath::remapExtension(extensions_remapping.asString(i), extensions_remapping.asString(i+1), true);
}
}
catch (const EUnknownVar &)
{
}
// debug, display path
//CPath::display();
// set the sound banks and sample banks
try
{
/* CConfigFile::CVar &var = cf.getVar("sound_path");
string soundPath = var.asString();
var = cf.getVar("soundbanks");
for (uint i=0; i<(uint)var.size(); i++)
{
string dir = soundPath;
dir.append("/").append(var.asString(i).c_str());
CSoundSystem::addSoundBank(dir);
}
*/
{
CConfigFile::CVar &var = cf.getVar("sample_path");
string samplePath(var.asString());
CSoundSystem::setSamplePath(samplePath);
}
{
CConfigFile::CVar &var = cf.getVar("packed_sheet_path");
string packedSheetPath(var.asString());
CSoundSystem::setPackedSheetPath(packedSheetPath);
}
/*CConfigFile::CVar var = cf.getVar("samplebanks");
for (uint i=0; i<(uint)var.size(); i++)
CSoundSystem::addSampleBank(var.asString(i).c_str());*/
}
catch (const EUnknownVar &)
{
//::MessageBox(NULL, "warning : 'sample_path' or 'packed_sheet_path' variable not defined.\nSound will not work properly.", "Objectviewer.cfg", MB_OK|MB_ICONEXCLAMATION);
}
// load the camera focal
try
{
CConfigFile::CVar &camera_focal = cf.getVar("camera_focal");
_CameraFocal = camera_focal.asFloat();
}
catch (const EUnknownVar &)
{
}
// load Scene light setup.
try
{
CConfigFile::CVar &var = cf.getVar("scene_light_enabled");
_SceneLightEnabled = var.asInt() !=0 ;
}
catch (const EUnknownVar &)
{
_SceneLightEnabled= false;
}
try
{
CConfigFile::CVar &var = cf.getVar("scene_light_sun_ambiant");
_SceneLightSunAmbiant.R = var.asInt(0);
_SceneLightSunAmbiant.G = var.asInt(1);
_SceneLightSunAmbiant.B = var.asInt(2);
}
catch (const EUnknownVar &)
{
_SceneLightSunAmbiant= NLMISC::CRGBA::Black;
}
try
{
CConfigFile::CVar &var = cf.getVar("scene_light_sun_diffuse");
_SceneLightSunDiffuse.R = var.asInt(0);
_SceneLightSunDiffuse.G = var.asInt(1);
_SceneLightSunDiffuse.B = var.asInt(2);
}
catch (const EUnknownVar &)
{
_SceneLightSunDiffuse= NLMISC::CRGBA::White;
}
try
{
CConfigFile::CVar &var = cf.getVar("scene_light_sun_specular");
_SceneLightSunSpecular.R = var.asInt(0);
_SceneLightSunSpecular.G = var.asInt(1);
_SceneLightSunSpecular.B = var.asInt(2);
}
catch (const EUnknownVar &)
{
_SceneLightSunSpecular= NLMISC::CRGBA::White;
}
try
{
CConfigFile::CVar &var = cf.getVar("scene_light_sun_dir");
_SceneLightSunDir.x = var.asFloat(0);
_SceneLightSunDir.y = var.asFloat(1);
_SceneLightSunDir.z = var.asFloat(2);
_SceneLightSunDir.normalize();
}
catch (const EUnknownVar &)
{
_SceneLightSunDir.set(0, 1, -1);
_SceneLightSunDir.normalize();
}
try
{
CConfigFile::CVar &var = cf.getVar("object_light_test");
_ObjectLightTestShape= var.asString();
}
catch (const EUnknownVar &)
{
}
// Load vegetable Landscape cfg.
loadVegetableLandscapeCfg(cf);
// load automatfic animations
try
{
CConfigFile::CVar &var = cf.getVar("automatic_animation_path");
CUniquePtr<CAnimationSet> as(new CAnimationSet);
//
bool loadingOk = as->loadFromFiles(var.asString(),true ,"anim",true);
//
if (!loadingOk)
{
//::MessageBox(NULL, "Warning : Unable to load all automatic animation", "Error", MB_OK | MB_ICONEXCLAMATION);
nlwarning("Unable to load all automatic animation");
}
CNELU::Scene->setAutomaticAnimationSet(as.release());
}
catch (const EUnknownVar &)
{
//::MessageBox(NULL, "No automatic animation path specified, please set 'automatic_animation_path'", "warning", MB_OK);
nlwarning("No automatic animation path specified");
}
// load CharacterScalePos
try
{
CConfigFile::CVar &var = cf.getVar("character_scale_pos");
_CharacterScalePos= var.asFloat();
}
catch (const EUnknownVar &)
{
}
// Fog
CConfigFile::CVar *var = cf.getVarPtr("fog");
if (var)
_Fog = var->asInt() != 0;
var = cf.getVarPtr("fog_start");
if (var)
_FogStart = var->asFloat();
var = cf.getVarPtr("fog_end");
if (var)
_FogEnd = var->asFloat();
var = cf.getVarPtr("fog_color");
if (var)
_FogColor = CRGBA ((uint8)(var->asInt(0)), (uint8)(var->asInt(1)), (uint8)(var->asInt(2)));
// Clouds
_CSS.NbCloud = 0;
if (var = cf.getVarPtr("cloud_count"))
_CSS.NbCloud = var->asInt();
if (var = cf.getVarPtr("cloud_diffuse"))
{
_CSS.Diffuse.R = var->asInt(0);
_CSS.Diffuse.G = var->asInt(1);
_CSS.Diffuse.B = var->asInt(2);
}
if (var = cf.getVarPtr("cloud_ambient"))
{
_CSS.Ambient.R = var->asInt(0);
_CSS.Ambient.G = var->asInt(1);
_CSS.Ambient.B = var->asInt(2);
}
if (var = cf.getVarPtr("cloud_speed"))
_CSS.CloudSpeed = var->asFloat();
if (var = cf.getVarPtr("cloud_update_period"))
_CSS.TimeToChange = var->asFloat();
if (var = cf.getVarPtr("cloud_wind_speed"))
_CSS.WindSpeed = var->asFloat();
}
catch (const Exception& e)
{
::MessageBox (NULL, utf8ToTStr(e.what()), _T("Objectviewer.cfg"), MB_OK|MB_ICONEXCLAMATION);
}
}
// ***************************************************************************
// properly remove a single window
static void removeWindow(CWnd *wnd)
{
if (!wnd) return;
wnd->DestroyWindow();
delete wnd;
}
// ***************************************************************************
CObjectViewer::~CObjectViewer ()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
removeWindow(_MainFrame);
removeWindow(_SlotDlg);
removeWindow(_AnimationSetDlg);
removeWindow(_AnimationDlg);
removeWindow(_DayNightDlg);
removeWindow(_WaterPoolDlg);
removeWindow(_SoundAnimDlg);
removeWindow(_LightGroupDlg);
removeWindow(_ChooseBGColorDlg);
removeWindow(_VegetableDlg);
removeWindow(_GlobalWindDlg);
removeWindow(_SkeletonScaleDlg);
removeWindow(_TuneMRMDlg);
delete _FontGenerator;
}
// ***************************************************************************
void CObjectViewer::initCamera ()
{
// Camera
CFrustum frustrum;
uint32 width, height;
CNELU::Driver->getWindowSize (width, height);
frustrum.initPerspective( _CameraFocal *(float)Pi/180.f, height != 0 ? (float)width/(float)height : 0.f, 0.1f, 1000.f);
CNELU::Camera->setFrustum (frustrum);
// Others camera
uint i;
for (i=0; i<_Cameras.size (); i++)
{
frustrum.initPerspective( _ListInstance[_Cameras[i]]->Camera->getFov(), height != 0 ? (float)width/(float)height : 0.f, 0.1f, 1000.f);
_ListInstance[_Cameras[i]]->Camera->setFrustum (frustrum);
}
}
// ***************************************************************************
namespace NL3D {
CFontGenerator *newCFontGenerator(const std::string &fontFileName);
}
// ***************************************************************************
bool CObjectViewer::initUI (HWND parent)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// initialize NeL context if needed
if (!NLMISC::INelContext::isContextInitialised())
{
new NLMISC::CApplicationContext();
nldebug("NeL Object Viewer: initUI");
NLMISC::CSheetId::initWithoutSheet();
}
// The fonts manager
_FontManager.setMaxMemory(2000000);
// The windows path
uint dSize = ::GetWindowsDirectory(NULL, 0);
nlverify(dSize);
TCHAR *wd = new TCHAR[dSize];
nlverify(::GetWindowsDirectory(wd, dSize));
_FontPath = tStrToUtf8(wd) + "\\fonts\\arial.ttf";
delete[] wd;
// The font generator
_FontGenerator = NL3D::newCFontGenerator ( _FontPath );
// The viewport
CViewport viewport;
// Create the icon
HICON hIcon = (HICON)LoadImage(theApp.m_hInstance, MAKEINTRESOURCE(IDI_APP_ICON), IMAGE_ICON,
16, 16, 0);
// load name of the driver from the config file
loadDriverName();
// Create a doomy driver
IDriver *driver= _Direct3d?CDRU::createD3DDriver():CDRU::createGlDriver();
// Get parent window
CWnd parentWnd;
CWnd *parentWndPtr=NULL;
if (parent)
{
parentWnd.Attach (parent);
parentWndPtr=&parentWnd;
}
// Create the main frame
_MainFrame = new CMainFrame (this, (winProc) driver->getWindowProc());
// Read register
_MainFrame->registerValue (true);
// Create the window
_MainFrame->CFrameWnd::Create (AfxRegisterWndClass(0, 0, NULL, hIcon),
_T("NeL object viewer"), 0x00cfc000, /*WS_OVERLAPPEDWINDOW,*/ CFrameWnd::rectDefault, parentWndPtr,
MAKEINTRESOURCE(IDR_OBJECT_VIEWER_MENU), 0x00000300 /*WS_EX_ACCEPTFILES*/ /*|WS_EX_CLIENTEDGE*/);
// Detach the hwnd
parentWnd.Detach ();
// Delete doomy driver
delete driver;
// Create a cwnd
getRegisterWindowState (_MainFrame, REGKEY_OBJ_VIEW_OPENGL_WND, true);
_MainFrame->ActivateFrame ();
_MainFrame->ShowWindow (SW_SHOW);
_MainFrame->UpdateWindow();
// Context to open a view
CCreateContext context;
context.m_pCurrentDoc=NULL;
context.m_pCurrentFrame=_MainFrame;
context.m_pLastView=NULL;
context.m_pNewDocTemplate=NULL;
context.m_pNewViewClass=RUNTIME_CLASS(CObjView);
// Create a view
CObjView *view = (CObjView*)_MainFrame->CreateView (&context);
view->ShowWindow (SW_SHOW);
_MainFrame->SetActiveView(view);
view = (CObjView*)_MainFrame->GetActiveView();
view->MainFrame = _MainFrame;
_MainFrame->ShowWindow (SW_SHOW);
RECT viewportRect;
GetClientRect(view->m_hWnd, &viewportRect);
// Init NELU
if (!CNELU::init (viewportRect.right, viewportRect.bottom, viewport, 32, true, view->m_hWnd, false, _Direct3d))
{
return false;
}
//CNELU::init (640, 480, viewport, 32, true, _MainFrame->m_hWnd);
CNELU::Scene->setPolygonBalancingMode(CScene::PolygonBalancingClamp);
// load the config file
loadConfigFile();
// Set the fog
CNELU::Driver->enableFog (_Fog);
CNELU::Driver->setupFog (_FogStart, _FogEnd, _FogColor);
// init sound
CSoundSystem::initSoundSystem ();
// Create a root.
_SceneRoot= (CTransform*)CNELU::Scene->createModel(NL3D::TransformId);
// Init default lighting seutp.
setupSceneLightingSystem(_SceneLightEnabled, _SceneLightSunDir, _SceneLightSunAmbiant, _SceneLightSunDiffuse, _SceneLightSunSpecular);
// Camera
initCamera ();
_MainFrame->OnResetCamera();
// Create animation set dialog
_AnimationSetDlg=new CAnimationSetDlg (this, _MainFrame);
_AnimationSetDlg->Create (IDD_ANIMATION_SET);
getRegisterWindowState (_AnimationSetDlg, REGKEY_OBJ_VIEW_ANIMATION_SET_DLG, false);
// Create animation set dialog
_AnimationDlg=new CAnimationDlg (this, _MainFrame);
_AnimationDlg->Create (IDD_ANIMATION);
getRegisterWindowState (_AnimationDlg, REGKEY_OBJ_VIEW_ANIMATION_DLG, false);
// Create the main dialog
_SlotDlg=new CMainDlg (this, _MainFrame);
_SlotDlg->Create (IDD_MAIN_DLG);
getRegisterWindowState (_SlotDlg, REGKEY_OBJ_VIEW_SLOT_DLG, false);
// Create particle dialog
_ParticleDlg=new CParticleDlg (this, _MainFrame, _MainFrame, _AnimationDlg);
_ParticleDlg->Create (IDD_PARTICLE);
getRegisterWindowState (_ParticleDlg, REGKEY_OBJ_PARTICLE_DLG, false);
// Create water pool editor dialog
_WaterPoolDlg = new CWaterPoolEditor(_Wpm, _MainFrame);
_WaterPoolDlg->Create (IDD_WATER_POOL);
getRegisterWindowState (_WaterPoolDlg, REGKEY_OBJ_WATERPOOL_DLG, false);
// Create day night dialog
_DayNightDlg = new CDayNightDlg (this, _MainFrame);
_DayNightDlg->Create (IDD_DAYNIGHT);
getRegisterWindowState (_DayNightDlg, REGKEY_OBJ_DAYNIGHT_DLG, false);
// Create vegetable dialog
_VegetableDlg=new CVegetableDlg (this, _MainFrame);
_VegetableDlg->Create (IDD_VEGETABLE_DLG);
getRegisterWindowState (_VegetableDlg, REGKEY_OBJ_VIEW_VEGETABLE_DLG, false);
// Create global wind dialog
_GlobalWindDlg= new CGlobalWindDlg (this, _MainFrame);
_GlobalWindDlg->Create(IDD_GLOBAL_WIND);
getRegisterWindowState (_GlobalWindDlg, REGKEY_OBJ_GLOBAL_WIND_DLG, false);
// Create sound animation editor dialog
_SoundAnimDlg = new CSoundAnimDlg(this, _AnimationDlg, _MainFrame);
_SoundAnimDlg->Create (IDD_SOUND_ANIM_DLG, _MainFrame);
getRegisterWindowState (_SoundAnimDlg, REGKEY_OBJ_SOUND_ANIM_DLG, false);
// Create light group editor dialog
_LightGroupDlg = new CLightGroupFactor(_MainFrame);
_LightGroupDlg->Create (IDD_LIGHT_GROUP_FACTOR, _MainFrame);
getRegisterWindowState (_LightGroupDlg, REGKEY_OBJ_LIGHT_GROUP_DLG, false);
// Create frame delay window
_ChooseFrameDelayDlg = new CChooseFrameDelay(this, _MainFrame);
_ChooseFrameDelayDlg->Create(IDD_CHOOSE_FRAME_DELAY, _MainFrame);
getRegisterWindowState (_ChooseFrameDelayDlg, REGKEY_CHOOSE_FRAME_DELAY_DLG, false);
// Set backgroupnd color
setBackGroundColor(_MainFrame->BgColor);
// Create bg color window (must create after the background color has been set)
_ChooseBGColorDlg = new CChooseBGColorDlg(this, _MainFrame);
_ChooseBGColorDlg->Create(IDD_CHOOSE_BG_COLOR, _MainFrame);
getRegisterWindowState (_ChooseBGColorDlg, REGKEY_CHOOSE_BG_COLOR_DLG, false);
// Create bg color window (must create after the background color has been set)
_ChooseSunColorDlg = new CChooseSunColorDlg(CNELU::Scene, _MainFrame);
_ChooseSunColorDlg->Create(IDD_CHOOSE_SUN_COLOR, _MainFrame);
getRegisterWindowState (_ChooseSunColorDlg, REGKEY_CHOOSE_SUN_COLOR_DLG, false);
// Create skeleton scale dlg
_SkeletonScaleDlg = new CSkeletonScaleDlg(this, _MainFrame);
_SkeletonScaleDlg->Create(IDD_SKELETON_SCALE_DLG, _MainFrame);
getRegisterWindowState (_SkeletonScaleDlg, REGKEY_SKELETON_SCALE_DLG, false);
// Create tune mrm dlg
_TuneMRMDlg = new CTuneMrmDlg(this, CNELU::Scene, _MainFrame);
_TuneMRMDlg->Create(IDD_TUNE_MRM_DLG, _MainFrame);
getRegisterWindowState (_TuneMRMDlg, REGKEY_TUNE_MRM_DLG, false);
_MainFrame->update ();
// Set current frame
setAnimTime (0.f, 100.f);
// Add mouse listener to event server
_MouseListener.addToServer(CNELU::EventServer);
CNELU::Driver->activate ();
// Enable sum of vram
CNELU::Driver->enableUsedTextureMemorySum ();
// load the scheme bank if one is present
CIFile iF;
std::string path = SPath + "default.scb";
if (iF.open(path))
{
try
{
iF.serial(SchemeManager);
}
catch (const NLMISC::EStream &e)
{
std::string msg = toString("Unable to load the default scheme bank file : %s", e.what());
::MessageBox(NULL, utf8ToTStr(msg), _T("Object Viewer"), MB_ICONEXCLAMATION);
}
}
iF.close();
// try to load a default config file for the viewer (for anitmation and particle edition setup)
path = SPath + "default.ovcgf";
if (iF.open (path))
{
try
{
serial (iF);
}
catch (const Exception& e)
{
std::string msg = toString("Error while loading default.ovcgf : %s", e.what());
::MessageBox (NULL, utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
}
}
// Create the cloud scape
_CS = new CCloudScape(CNELU::Driver);
_CS->init (&_CSS);
return true;
}
// ***************************************************************************
void CObjectViewer::addTransformation (CMatrix &current, CAnimation *anim, float begin, float end, ITrack *posTrack, ITrack *rotquatTrack,
ITrack *nextPosTrack, ITrack *nextRotquatTrack, bool removeLast)
{
// In place ?
if (_AnimationDlg->Inplace)
{
// Just identity
current.identity();
}
else
{
// Remove the start of the animation
CQuat rotEnd (0,0,0,1);
CVector posEnd (0,0,0);
if (rotquatTrack)
{
// Interpolate the rotation
rotquatTrack->interpolate (end, rotEnd);
}
if (posTrack)
{
// Interpolate the position
posTrack->interpolate (end, posEnd);
}
// Add the final rotation and position
CMatrix tmp;
tmp.identity ();
tmp.setRot (rotEnd);
tmp.setPos (posEnd);
// Incremental ?
if (_AnimationDlg->IncPos)
current *= tmp;
else
current = tmp;
if (removeLast)
{
CQuat rotStart (0,0,0,1);
CVector posStart (0,0,0);
if (nextRotquatTrack)
{
// Interpolate the rotation
nextRotquatTrack->interpolate (begin, rotStart);
}
if (nextPosTrack)
{
// Interpolate the position
nextPosTrack->interpolate (begin, posStart);
}
// Remove the init rotation and position of the next animation
tmp.identity ();
tmp.setRot (rotStart);
tmp.setPos (posStart);
tmp.invert ();
current *= tmp;
// Normalize the mt
CVector I = current.getI ();
CVector J = current.getJ ();
I.z = 0;
J.z = 0;
J.normalize ();
CVector K = I^J;
K.normalize ();
I = J^K;
I.normalize ();
tmp.setRot (I, J, K);
tmp.setPos (current.getPos ());
current = tmp;
}
}
}
// ***************************************************************************
void CObjectViewer::setupPlaylist (float time)
{
// Update animation dlg
// Gor each object
uint i;
for (i=0; i<_ListInstance.size(); i++)
{
// Empty with playlist
uint j;
for (j=0; j<CChannelMixer::NumAnimationSlot; j++)
{
// Empty slot
_ListInstance[i]->Playlist.setAnimation (j, CAnimationPlaylist::empty);
}
// With channel mixer ?
if (_AnimationSetDlg->UseMixer)
{
// Setup from slots
_ListInstance[i]->setAnimationPlaylist (getFrameRate ());
// A playlist
_ListInstance[i]->Playlist.setupMixer (_ListInstance[i]->ChannelMixer, _AnimationDlg->getTime());
}
else
{
// Some animation in the list ?
if (_ListInstance[i]->Saved.PlayList.size()>0)
{
// Index choosed
uint choosedIndex = 0xffffffff;
// Track here
bool there = false;
// Current matrix
CMatrix current;
current.identity ();
// Current animation
CAnimation *anim = NULL;
ITrack *posTrack = NULL;
ITrack *rotquatTrack = NULL;
// Try channel animationset
anim = _ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[0]));
if (anim)
{
posTrack = (ITrack *)anim->getTrackByName ("pos");
rotquatTrack = (ITrack *)anim->getTrackByName ("rotquat");
}
there = posTrack || rotquatTrack;
// Accumul time
float startTime=0;
float endTime=anim->getEndTime()-anim->getBeginTime();
// Animation index
uint index = 0;
// Get animation used in the list
while (time>=endTime)
{
// Next animation
index++;
if (index<_ListInstance[i]->Saved.PlayList.size())
{
// Pointer on the animation
CAnimation *newAnim=_ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName(_ListInstance[i]->Saved.PlayList[index]));
ITrack *newPosTrack = (ITrack *)newAnim->getTrackByName ("pos");
ITrack *newRotquatTrack = (ITrack *)newAnim->getTrackByName ("rotquat");
// Add the transformation
addTransformation (current, anim, newAnim->getBeginTime(), anim->getEndTime(), posTrack, rotquatTrack, newPosTrack, newRotquatTrack, true);
// Pointer on the animation
anim = newAnim;
posTrack = newPosTrack;
rotquatTrack = newRotquatTrack;
// Add start time
startTime = endTime;
endTime = startTime + anim->getEndTime()-anim->getBeginTime();
}
else
{
// Add the transformation
addTransformation (current, anim, 0, anim->getEndTime(), posTrack, rotquatTrack, NULL, NULL, false);
break;
}
}
// Time cropped ?
if (index>=_ListInstance[i]->Saved.PlayList.size())
{
// Yes
index--;
// Good index
choosedIndex = _ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[index]);
anim=_ListInstance[i]->AnimationSet.getAnimation (choosedIndex);
// End time for last anim
startTime = anim->getEndTime () - time;
}
else
{
// No
// Add the transformation
addTransformation (current, anim, 0, anim->getBeginTime() + time - startTime, posTrack, rotquatTrack, NULL, NULL, false);
// Good index
choosedIndex = _ListInstance[i]->AnimationSet.getAnimationIdByName (_ListInstance[i]->Saved.PlayList[index]);
// Get the animation
anim=_ListInstance[i]->AnimationSet.getAnimation (choosedIndex);
// Final time
startTime -= anim->getBeginTime ();
}
// Set the slot
_ListInstance[i]->Playlist.setTimeOrigin (0, startTime);
_ListInstance[i]->Playlist.setWrapMode (0, CAnimationPlaylist::Clamp);
_ListInstance[i]->Playlist.setStartWeight (0, 1, 0);
_ListInstance[i]->Playlist.setEndWeight (0, 1, 1);
_ListInstance[i]->Playlist.setAnimation (0, choosedIndex);
// Setup the channel
_ListInstance[i]->Playlist.setupMixer (_ListInstance[i]->ChannelMixer, _AnimationDlg->getTime());
// Setup the pos and rot for this shape
if (there)
{
CVector pos= current.getPos();
// Get a skeleton model
CSkeletonModel *skelModel=dynamic_cast<CSkeletonModel*>(_ListInstance[i]->TransformShape);
// If a skeleton model
if(skelModel)
{
// scale animated pos value with the CFG scale
pos*= _CharacterScalePos;
}
if (_ListInstance[i]->TransformShape)
{
_ListInstance[i]->TransformShape->setPos (pos);
_ListInstance[i]->TransformShape->setRotQuat (current.getRot());
}
if (_ListInstance[i]->Camera)
{
_ListInstance[i]->Camera->setPos (pos);
_ListInstance[i]->Camera->setRotQuat (current.getRot());
}
}
}
else
{
if (_ListInstance[i]->TransformShape)
{
CMeshBase *meshBase = dynamic_cast<CMeshBase *> ((IShape*)_ListInstance[i]->TransformShape->Shape);
if (meshBase)
{
_ListInstance[i]->TransformShape->setPos (meshBase->getDefaultPos ()->getDefaultValue ());
_ListInstance[i]->TransformShape->setRotQuat (meshBase->getDefaultRotQuat ()->getDefaultValue ());
_ListInstance[i]->TransformShape->setScale (meshBase->getDefaultScale ()->getDefaultValue ());
}
else
{
/*_ListInstance[i]->TransformShape->setPos (CVector::Null);
_ListInstance[i]->TransformShape->setRotQuat (CQuat::Identity);
_ListInstance[i]->TransformShape->setScale (1, 1, 1);*/
}
}
if (_ListInstance[i]->Camera)
{
_ListInstance[i]->Camera->setPos (_ListInstance[i]->Camera->getDefaultPos ()->getDefaultValue ());
_ListInstance[i]->Camera->setTargetPos (_ListInstance[i]->Camera->getDefaultTargetPos ()->getDefaultValue ());
}
}
}
}
}
// tool funct : this if a window has another window as a parent (recursive)
// if parent == true, this return true
static bool isParentWnd(HWND parent, HWND son)
{
if (parent == son) return true;
HWND directParent = GetParent (son);
if (!directParent) return false;
if (directParent == parent) return true;
return isParentWnd(parent, directParent);
}
// ***************************************************************************
void CObjectViewer::go ()
{
nlassert(!_InstanceRunning); // this shouldn't be called if an instance of the viewer is running.
AFX_MANAGE_STATE(AfxGetStaticModuleState());
_InstanceRunning = true;
CGraph graph("ms", 10, 10, 200, 100, CRGBA(64, 64, 64), 20, 200);
do
{
_CrtCheckMemory();
if (isParentWnd(_MainFrame->m_hWnd, GetForegroundWindow()))
{
CNELU::Driver->activate ();
// Handle animation
_AnimationDlg->handle ();
// Handle sound animation
_SoundAnimDlg->handle ();
// Handle sound animation
_LightGroupDlg->handle ();
// Setup the channel mixer
_AnimationSetDlg->UpdateData ();
// Setup the play list
setupPlaylist (_AnimationDlg->getTime());
// Eval sound tracks
evalSoundTrack (_AnimationDlg->getLastTime(), _AnimationDlg->getTime());
// Animate the automatic animation in the scene
//CNELU::Scene->animate( (float) + NLMISC::CTime::ticksToSecond( NLMISC::CTime::getPerformanceTime() ) );
// Eval channel mixer for transform
for (uint i=0; i<_ListInstance.size(); i++)
_ListInstance[i]->ChannelMixer.eval (false);
animateCNELUScene (_CS);
// Clear the buffers
CNELU::clearBuffers(_BackGroundColor);
//if (_CS) _CS->setDebugQuad(true);
// call of callback list
{
std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
{
(*it)->goPreRender();
}
}
// Render the CS
if (_CS) _CS->render ();
// Draw the scene
CNELU::Scene->render();
// call of callback list
{
std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
{
(*it)->goPostRender();
}
}
if (_OcclusionTestMeshsVisible)
{
CNELU::Scene->renderOcclusionTestMeshs();
}
// Profile polygon count
CPrimitiveProfile in, out;
CNELU::Driver->profileRenderedPrimitives (in, out);
// Draw the hotSpot
if (_MainFrame->MoveMode == CMainFrame::ObjectMode)
{
float radius=_HotSpotSize/2.f;
CNELU::Driver->setupModelMatrix (CMatrix::Identity);
CDRU::drawLine (_MouseListener.getHotSpot()+CVector (radius, 0, 0), _MouseListener.getHotSpot()+CVector (-radius, 0, 0), _HotSpotColor, *CNELU::Driver);
CDRU::drawLine (_MouseListener.getHotSpot()+CVector (0, radius, 0), _MouseListener.getHotSpot()+CVector (0, -radius, 0), _HotSpotColor, *CNELU::Driver);
CDRU::drawLine (_MouseListener.getHotSpot()+CVector (0, 0, radius), _MouseListener.getHotSpot()+CVector (0, 0, -radius), _HotSpotColor, *CNELU::Driver);
}
// Test some keys
if (CNELU::AsyncListener.isKeyPushed(KeyF3))
{
// Change render mode
switch (CNELU::Driver->getPolygonMode())
{
case IDriver::Filled:
CNELU::Driver->setPolygonMode (IDriver::Line);
break;
case IDriver::Line:
CNELU::Driver->setPolygonMode (IDriver::Point);
break;
case IDriver::Point:
CNELU::Driver->setPolygonMode (IDriver::Filled);
break;
}
}
// draw various matrix
if (_FXMatrixVisible) drawFXMatrix();
if (_FXUserMatrixVisible) drawFXUserMatrix();
if (_SceneMatrixVisible) drawSceneMatrix();
// draw Skeleton Scale Dlg selection
if(_SkeletonScaleDlg)
_SkeletonScaleDlg->drawSelection();
// Test Window Keys
bool keyWndOk= false;
if (CNELU::AsyncListener.isKeyPushed(Key1))
_MainFrame->OnWindowAnimation(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key2))
_MainFrame->OnWindowAnimationset(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key3))
_MainFrame->OnWindowMixersslots(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key4))
_MainFrame->OnWindowParticles(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key5))
_MainFrame->OnWindowDayNight(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key6))
_MainFrame->OnWindowWaterPool(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key7))
_MainFrame->OnWindowVegetable(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key8))
_MainFrame->OnWindowGlobalwind(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(Key9))
_MainFrame->OnWindowSoundAnim(), keyWndOk= true;
if (CNELU::AsyncListener.isKeyPushed(KeyO))
_MainFrame->OnFileOpen(), keyWndOk= true;
// Reload texture ?
if (CNELU::AsyncListener.isKeyPushed(KeyR))
_MainFrame->OnReloadTextures();
// If some window activated, reset the focus to the main wnd.
if(keyWndOk)
_MainFrame->SetActiveWindow();
// Calc FPS
static sint64 lastTime=NLMISC::CTime::getPerformanceTime ();
sint64 newTime=NLMISC::CTime::getPerformanceTime ();
sint64 timeDiff = newTime - lastTime;
float fps = timeDiff > 0 ? (float)(1.0 / NLMISC::CTime::ticksToSecond (newTime-lastTime)) : 1000.0f;
lastTime=newTime;
uint nbPlayingSources, nbSources;
if (CSoundSystem::getAudioMixer())
{
nbPlayingSources = CSoundSystem::getAudioMixer()->getUsedTracksCount();
nbSources = CSoundSystem::getAudioMixer()->getPlayingSourcesCount();
}
else
{
nbPlayingSources = nbSources = NULL;
}
// Display std info.
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",
_Direct3d ? "Direct3d":"OpenGL",
in.NLines+in.NPoints+in.NQuads*2+in.NTriangles+in.NTriangleStrips,
(float)CNELU::Driver->getUsedTextureMemory () / (float)(1024*1024),
(float)CNELU::Driver->profileAllocatedTextureMemory () / (float)(1024*1024),
(_SceneCenter-CNELU::Camera->getMatrix().getPos()).norm(),
nbPlayingSources,
nbSources,
fps
);
// Display
_MainFrame->StatusBar.SetWindowText (utf8ToTStr(msgBar));
// Display Vegetable info.
if(_VegetableDlg!=NULL)
{
if(_VegetableLandscape != NULL)
{
CString vegetMsgBar;
vegetMsgBar.Format(_T("%u"), _VegetableLandscape->Landscape.getNumVegetableFaceRendered());
_VegetableDlg->StaticPolyCount.SetWindowText(vegetMsgBar);
}
else
{
_VegetableDlg->StaticPolyCount.SetWindowText(_T("0"));
}
}
// graph disabled for now..
// graph.addValue(CNELU::Scene->getEllapsedTime() * 1000.f);
// graph.renderGraph();
// Swap the buffers
CNELU::swapBuffers();
// Select the good camera
if (_MainFrame->MoveMode == CMainFrame::CameraMode)
{
sint cameraId = getCurrentCamera ();
if (cameraId != -1)
{
CInstanceInfo *info = getInstance(getCameraInstance (cameraId));
nlassert (info->Camera);
CNELU::Scene->setCam (info->Camera);
}
}
else
{
CNELU::Scene->setCam (CNELU::Camera);
}
if (_MainFrame->MoveMode == CMainFrame::ObjectMode)
{
_MouseListener.setMouseMode (CEvent3dMouseListener::edit3d);
}
else
{
_MouseListener.setMouseMode (CEvent3dMouseListener::firstPerson);
_MouseListener.setSpeed (_MainFrame->MoveSpeed);
}
// Reset camera aspect ratio
initCamera ();
if (_MainFrame->isMoveElement())
{
// for now we apply a transform on the selected object in the particle system
_ParticleDlg->moveElement(_MouseListener.getModelMatrix());
}
else if (_MainFrame->isMoveFX())
{
_ParticleDlg->setPSWorldMatrix(_MouseListener.getModelMatrix());
}
else if (_MainFrame->isMoveFXUserMatrix())
{
setFXUserMatrix(_MouseListener.getModelMatrix());
}
else if (_MainFrame->isMoveObjectLightTest())
{
_ObjectLightTestMatrix= _MouseListener.getModelMatrix();
}
else if (_MainFrame->isMoveSceneRoot())
{
_SceneRoot->setTransformMode (ITransformable::DirectMatrix);
_SceneRoot->setMatrix (_MouseListener.getModelMatrix());
}
else
{
nlassert(_MainFrame->isMoveCamera());
// New matrix from camera
CNELU::Camera->setTransformMode (ITransformable::DirectMatrix);
CNELU::Camera->setMatrix (_MouseListener.getViewMatrix());
// Vegetable: manage collision snapping if wanted and possible
if(_VegetableSnapToGround && _VegetableLandscape)
{
// get matrix from camera.
CMatrix matrix= CNELU::Camera->getMatrix();
// snap To ground.
CVector pos= matrix.getPos();
// if succes to snap to ground
if(_VegetableCollisionEntity->snapToGround(pos))
{
pos.z+= _VegetableSnapHeight;
matrix.setPos(pos);
// reset the moveListener and the camera.
_MouseListener.setMatrix(matrix);
CNELU::Camera->setMatrix(matrix);
}
}
}
// Update lighting test Dynamic object position
if(_ObjectLightTest && _GlobalRetriever)
{
// Get the position of the object snapped.
UGlobalPosition gPos= _GlobalRetriever->retrievePosition(_ObjectLightTestMatrix.getPos());
CVector pos= _GlobalRetriever->getGlobalPosition(gPos);
_ObjectLightTest->setPos(pos);
_ObjectLightTest->setRotQuat(_ObjectLightTestMatrix.getRot());
// Update the matrix and the mouseListener.
if (_MainFrame->isMoveObjectLightTest())
{
_ObjectLightTestMatrix.setPos(pos);
_MouseListener.setModelMatrix(_ObjectLightTestMatrix);
}
// Update the logicInfo so lighting is well computed.
_ObjectLightTestLogicInfo.GPos= gPos;
}
// Pump message from the server
CNELU::EventServer.pump();
// Pump others message for the windows
MSG msg;
while ( PeekMessage(&msg, NULL,0,0,PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CSoundSystem::setListenerMatrix(_MouseListener.getViewMatrix());
CSoundSystem::poll();
// simulate frame delay
if (_FrameDelay)
{
NLMISC::nlSleep(_FrameDelay);
}
// Save last time
_LastTime=_AnimationDlg->getTime();
theApp.OnIdle (0);
}
else
{
// Traditionnal message loop
MSG msg;
while (GetMessage( &msg, NULL, 0, 0) == TRUE)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
if (!IsWindow (_MainFrame->m_hWnd))
break;
// Get the foreground window
if (isParentWnd(_MainFrame->m_hWnd, GetForegroundWindow()))
break;
}
}
}
while (!CNELU::AsyncListener.isKeyPushed(KeyESCAPE)&&CNELU::Driver->isActive());
_InstanceRunning = false;
}
// ***************************************************************************
void CObjectViewer::releaseUI ()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Release particles
removeWindow(_ChooseFrameDelayDlg);
removeWindow(_ParticleDlg);
// release sound
CSoundSystem::releaseSoundSystem();
if (CNELU::Driver->isActive())
{
// register window position
if (CNELU::Driver->getDisplay())
{
setRegisterWindowState (_MainFrame, REGKEY_OBJ_VIEW_OPENGL_WND);
}
}
// Write register
if (_MainFrame)
{
_MainFrame->registerValue (false);
// Remove the main frame
if (::IsWindow(*_MainFrame))
{
_MainFrame->DestroyWindow();
}
delete _MainFrame;
_MainFrame = NULL;
}
// Release the emitter from the server
_MouseListener.removeFromServer (CNELU::EventServer);
// exit
// remove first possibly created collisions objects.
if(_VegetableCollisionEntity)
{
_VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity);
_VegetableCollisionEntity= NULL;
}
if(_VegetableCollisionManager)
{
delete _VegetableCollisionManager;
_VegetableCollisionManager= NULL;
}
// delete Landscape
if(_VegetableLandscape)
{
CNELU::Scene->deleteModel(_VegetableLandscape);
_VegetableLandscape= NULL;
}
// Release all instances and all Igs.
removeAllInstancesFromScene();
// Remove
// Create the cloud scape
delete _CS;
_CS = NULL;
// release Root
CNELU::Scene->deleteModel(_SceneRoot);
_SceneRoot= NULL;
// release other 3D.
CNELU::release();
}
// ***************************************************************************
void setRegisterWindowState (const CWnd *pWnd, const TCHAR* keyName)
{
HKEY hKey;
if (RegCreateKey(HKEY_CURRENT_USER, keyName, &hKey)==ERROR_SUCCESS)
{
RECT rect;
pWnd->GetWindowRect (&rect);
RegSetValueEx(hKey, _T("Left"), 0, REG_DWORD, (LPBYTE)&rect.left, 4);
RegSetValueEx(hKey, _T("Right"), 0, REG_DWORD, (LPBYTE)&rect.right, 4);
RegSetValueEx(hKey, _T("Top"), 0, REG_DWORD, (LPBYTE)&rect.top, 4);
RegSetValueEx(hKey, _T("Bottom"), 0, REG_DWORD, (LPBYTE)&rect.bottom, 4);
}
}
// ***************************************************************************
void getRegisterWindowState (CWnd *pWnd, const TCHAR* keyName, bool resize)
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, keyName, 0, KEY_READ, &hKey)==ERROR_SUCCESS)
{
DWORD len=4;
DWORD type;
RECT rect;
RegQueryValueEx (hKey, _T("Left"), 0, &type, (LPBYTE)&rect.left, &len);
RegQueryValueEx (hKey, _T("Right"), 0, &type, (LPBYTE)&rect.right, &len);
RegQueryValueEx (hKey, _T("Top"), 0, &type, (LPBYTE)&rect.top, &len);
RegQueryValueEx (hKey, _T("Bottom"), 0, &type, (LPBYTE)&rect.bottom, &len);
// Set window pos
pWnd->SetWindowPos (NULL, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_NOOWNERZORDER|SWP_NOZORDER|
(resize?0:SWP_NOSIZE));
}
}
// ***************************************************************************
void CObjectViewer::setAnimTime (float animStart, float animEnd)
{
// Dispatch the command
_SlotDlg->setAnimTime (animStart, animEnd);
_AnimationDlg->setAnimTime (animStart, animEnd);
_SoundAnimDlg->setAnimTime (animStart, animEnd);
}
// ***************************************************************************
void CObjectViewer::resetSlots (uint instance)
{
// Reset the animation set
_ListInstance[instance]->AnimationSet.reset ();
// Set no animation in slot UI
for (uint j=0; j<NL3D::CChannelMixer::NumAnimationSlot; j++)
_ListInstance[instance]->Saved.SlotInfo[j].Animation.clear();
// Reset the animation list
_ListInstance[instance]->Saved.AnimationFileName.clear ();
// Reset the play list
_ListInstance[instance]->Saved.PlayList.clear ();
// Reset the skeleton list
_ListInstance[instance]->Saved.SWTFileName.clear ();
// Update
_AnimationSetDlg->refresh (TRUE);
_SlotDlg->refresh (TRUE);
_SoundAnimDlg->refresh (TRUE);
}
// ***************************************************************************
void CObjectViewer::reinitChannels ()
{
// Add all the instance in the channel mixer
for (uint i=0; i<_ListInstance.size(); i++)
{
// Reset the channels
_ListInstance[i]->ChannelMixer.resetChannels ();
// Setup animation set
_ListInstance[i]->ChannelMixer.setAnimationSet (&(_ListInstance[i]->AnimationSet));
// Register the transform (but not if it has automatic animation, as a channel mixer has been created for us)
bool autoAnim = false;
if (dynamic_cast<CMeshBaseInstance *>(_ListInstance[i]->TransformShape))
{
CMeshBase *mb = NLMISC::safe_cast<CMeshBase *>( (IShape *) static_cast<CMeshBaseInstance *>(_ListInstance[i]->TransformShape)->Shape );
autoAnim = mb->getAutoAnim();
}
if (!autoAnim)
{
if (_ListInstance[i]->TransformShape)
_ListInstance[i]->TransformShape->registerToChannelMixer (&(_ListInstance[i]->ChannelMixer), "");
if (_ListInstance[i]->Camera)
_ListInstance[i]->Camera->registerToChannelMixer (&(_ListInstance[i]->ChannelMixer), "");
}
}
// Enable / disable channels
enableChannels ();
}
// ***************************************************************************
void CObjectViewer::enableChannels ()
{
// Disable some channels
_AnimationSetDlg->UpdateData ();
bool enable = (_AnimationSetDlg->UseMixer == 1);
// Add all the instance in the channel mixer
for (uint i=0; i<_ListInstance.size(); i++)
{
// Get the pos and rot channel id
uint posId = _ListInstance[i]->AnimationSet.getChannelIdByName ("pos");
uint rotQuatId = _ListInstance[i]->AnimationSet.getChannelIdByName ("rotquat");
uint rotEulerId = _ListInstance[i]->AnimationSet.getChannelIdByName ("roteuler");
if (posId != CAnimationSet::NotFound)
_ListInstance[i]->ChannelMixer.enableChannel (posId, enable);
if (rotQuatId != CAnimationSet::NotFound)
_ListInstance[i]->ChannelMixer.enableChannel (rotQuatId, enable);
if (rotEulerId != CAnimationSet::NotFound)
_ListInstance[i]->ChannelMixer.enableChannel (rotEulerId, enable);
}
}
// ***************************************************************************
float CObjectViewer::getFrameRate ()
{
return _AnimationDlg->Speed;
}
// ***************************************************************************
string getFilename (const string &file)
{
// if the direct file exist, return it
if (NLMISC::CFile::fileExists(file))
return file;
string path = NLMISC::CFile::getFilename(file);
path = CPath::lookup (path, false, false, false);
if (path.empty())
path = file;
return path;
}
// ***************************************************************************
void CObjectViewer::serial (NLMISC::IStream& f)
{
// version 4: include particle workspace infos
// serial "OBJV_CFG"
f.serialCheck (NELID("VJBO"));
f.serialCheck (NELID("GFC_"));
// serial the version
int ver=f.serialVersion (4);
if (ver>=4)
{
f.serial(ParticleWorkspaceFilename);
}
if (ver>=3)
{
// Read the configuration file
if (f.isReading())
{
if (ver <=3)
{
ParticleWorkspaceFilename.clear();
}
// First instance
uint firstInstance = (uint)_ListInstance.size();
// Read information
std::vector<CInstanceSave> readed;
f.serialCont (readed);
// Merge
for (uint i=0; i<readed.size(); i++)
{
try
{
// Instance loaded
uint instance = 0xffffffff;
if (readed[i].Camera)
{
instance = addCamera (readed[i].CameraInfo, readed[i].ShapeFilename.c_str());
}
else
{
// Load the shape
CIFile input;
string path = getFilename (readed[i].ShapeFilename);
if (input.open (path))
{
// Serial a shape
CShapeStream serialShape;
serialShape.serial (input);
// Is a skeleton ?
if (readed[i].IsSkeleton)
{
// Add the skel
instance = addSkel (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str());
SkeletonUsedForSound = instance;
}
else
{
// Add the mesh
if (readed[i].SkeletonId != 0xffffffff)
instance = addMesh (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str(), readed[i].SkeletonId + firstInstance, (readed[i].BindBoneName.empty())?NULL:readed[i].BindBoneName.c_str());
else
instance = addMesh (serialShape.getShapePointer(), readed[i].ShapeFilename.c_str(), 0xffffffff, (readed[i].BindBoneName.empty())?NULL:readed[i].BindBoneName.c_str());
}
}
else
{
// Error message
std::string message = toString("File not found %s", readed[i].ShapeFilename.c_str());
_MainFrame->MessageBox (utf8ToTStr(message), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
// Stop loading
break;
}
}
// Check instance number
nlassert (instance == (firstInstance+i));
// Load animations
for (uint anim=0; anim<readed[i].AnimationFileName.size(); anim++)
{
string path = getFilename (readed[i].AnimationFileName[anim]);
loadAnimation (path.c_str(), instance);
}
// Load SWT
for (uint swt=0; swt<readed[i].SWTFileName.size(); swt++)
{
string path = getFilename (readed[i].SWTFileName[swt]);
loadSWT (path.c_str(), instance);
}
// Set the playlist
_ListInstance[instance]->Saved.PlayList = readed[i].PlayList;
// Set the slot information
for (uint slot=0; slot<NL3D::CChannelMixer::NumAnimationSlot; slot++)
_ListInstance[instance]->Saved.SlotInfo[slot] = readed[i].SlotInfo[slot];
}
catch (const Exception &e)
{
// Error message
std::string message = toString("Error loading shape %s: %s", readed[i].ShapeFilename.c_str(), e.what());
_MainFrame->MessageBox (utf8ToTStr(message), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
// Stop loading
break;
}
}
// Init channels
reinitChannels ();
// Read the selection
uint32 selection;
f.serial (selection);
if (selection+firstInstance < _ListInstance.size())
{
_SelectedObject = selection+firstInstance;
}
// Invalidate dialogs
_AnimationSetDlg->refresh (TRUE);
_SlotDlg->refresh (TRUE);
_SoundAnimDlg->refresh (TRUE);
}
else
{
// Build information
std::vector<CInstanceSave> readed (_ListInstance.size());
for (uint instance=0; instance<_ListInstance.size(); instance++)
{
// Copy the save information
readed[instance] = _ListInstance[instance]->Saved;
}
// Save the configuration
f.serialCont (readed);
// Write the selection
f.serial (_SelectedObject);
}
}
}
// ***************************************************************************
bool CObjectViewer::loadInstanceGroup(const std::string &igFilename)
{
//AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Add search path for the mesh
CPath::addSearchPath (NLMISC::CFile::getPath(igFilename));
// Open a file
CIFile file;
if (file.open (igFilename))
{
// Shape pointer
NL3D::CInstanceGroup *ig = new NL3D::CInstanceGroup;
try
{
// Stream it
file.serial(*ig);
// Append the ig.
addInstanceGroup(ig);
}
catch (const Exception& e)
{
// clean
delete ig;
_MainFrame->MessageBox (utf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
return false;
}
}
else
{
// Create a message
std::string msg = toString("Can't open the file %s for reading.", igFilename.c_str());
_MainFrame->MessageBox (utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
return false;
}
return true;
}
// ***************************************************************************
bool CObjectViewer::loadMesh (std::vector<std::string> &meshFilename, const std::string &skeleton)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Add to the path
// Add search path for the skeleton
if (skeleton.empty())
{
CPath::addSearchPath (NLMISC::CFile::getPath(skeleton));
}
// Open a file
CIFile file;
// Shape pointer
IShape *shapeSkel=NULL;
uint skelIndex = 0xffffffff;
NL3D::CSkeletonModel *transformSkel=NULL;
// Skel error ?
bool skelError=false;
// Continue ?
if (!skeleton.empty())
{
// Open a file
if (file.open (skeleton))
{
// Sream a shape
CShapeStream streamShape;
try
{
// Stream it
streamShape.serial (file);
// Add the shape
shapeSkel=streamShape.getShapePointer();
}
catch (const Exception& e)
{
_MainFrame->MessageBox (utf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
// error
skelError=true;
}
}
else
{
// Create a message
std::string msg = NLMISC::toString("Can't open the file %s for reading.", skeleton.c_str());
_MainFrame->MessageBox (utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
// error
skelError=true;
}
}
// Skeleton error ?
if (skelError)
return false;
// Skeleton used ?
bool skelUsed = false;
// Index of the shape
uint lastShape = 0xffffffff;
// For each meshes
for (uint i=0; i<meshFilename.size(); i++)
{
// Filename
const std::string fileName = meshFilename[i];
// Add search path for the mesh
CPath::addSearchPath (NLMISC::CFile::getPath(fileName));
// Shape pointer
IShape *shapeMesh=NULL;
if (file.open (fileName))
{
// Sream a shape
CShapeStream streamShape;
try
{
// Stream it
streamShape.serial (file);
// Add the shape
shapeMesh=streamShape.getShapePointer();
}
catch (const Exception& e)
{
_MainFrame->MessageBox (utf8ToTStr(e.what()), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
continue;
}
}
else
{
// Create a message
std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
_MainFrame->MessageBox (utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
continue;
}
// Add the skel shape
if (shapeSkel&&(!skelUsed))
{
// Add the skel
skelIndex = addSkel (shapeSkel, skeleton);
if (skelIndex != 0xffffffff)
{
skelUsed = true;
transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[skelIndex]->TransformShape);
nlassert (transformSkel);
}
}
// Add the skel shape
if (shapeMesh)
{
// Get the object name
lastShape = addMesh (shapeMesh, fileName, skelIndex);
}
}
// Skel not used ?
if ((!skelUsed)&&shapeSkel)
{
// Remove it
delete shapeSkel;
}
// Select the skeleton
if (skelIndex != 0xffffffff)
_SelectedObject = skelIndex;
else if (lastShape != 0xffffffff)
_SelectedObject = lastShape;
// Update windows
_AnimationSetDlg->refresh (TRUE);
_SlotDlg->refresh (TRUE);
_SoundAnimDlg->refresh (TRUE);
return true;
}
// ***************************************************************************
void CObjectViewer::resetCamera ()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
_MainFrame->OnResetCamera();
}
// ***************************************************************************
uint CObjectViewer::addMesh (NL3D::IShape* pMeshShape, const std::string &meshName, uint skelIndex, const char* bindSkelName, bool createInstance)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// *** Add the shape
// Store the shape pointer
if (CNELU::ShapeBank->getPresentState(meshName)!=CShapeBank::NotPresent)
{
delete pMeshShape;
}
else
CNELU::ShapeBank->add (meshName, CSmartPtr<IShape> (pMeshShape));
// Must create the instance?
if(createInstance)
{
// Create a model and add it to the scene
CTransformShape *pTrShape=CNELU::Scene->createInstance (meshName);
nlassert (pTrShape);
// link to the root for manipulation
_SceneRoot->hrcLinkSon(pTrShape);
// Get the real shape used by the instance.
pMeshShape= pTrShape->Shape;
// Set the rot model
if (_MainFrame->Euler)
pTrShape->setTransformMode (ITransformable::RotEuler);
else
pTrShape->setTransformMode (ITransformable::RotQuat);
// Store the transform shape pointer
CInstanceInfo *iInfo = new CInstanceInfo;
iInfo->TransformShape= pTrShape;
// Store the name of the shape
iInfo->MustDelete = true;
iInfo->Saved.ShapeFilename = meshName;
iInfo->Saved.SkeletonId = skelIndex;
_ListInstance.push_back (iInfo);
// *** Bind to the skeleton
// Get a mesh instance
CMeshBaseInstance *meshInstance=dynamic_cast<CMeshBaseInstance*>(pTrShape);
// Bind the mesh
if (skelIndex != 0xffffffff)
{
// Get the skeleton
NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[skelIndex]->TransformShape);
nlassert (transformSkel);
// It is a skinned mesh ?
CMesh *mesh = dynamic_cast<CMesh *>(pMeshShape);
CMeshMRM *meshMrm = dynamic_cast<CMeshMRM *>(pMeshShape);
CMeshMRMSkinned *meshMrmSkinned = dynamic_cast<CMeshMRMSkinned *>(pMeshShape);
if ( (mesh && mesh->getMeshGeom().isSkinned()) ||
(meshMrm && meshMrm->getMeshGeom().isSkinned()) ||
meshMrmSkinned)
{
// Bind to skeleton
transformSkel->bindSkin (meshInstance);
}
else
{
// Bind bone name
uint bindBone = 0xffffffff;
std::string boneName;
// Name is passed, look for bone
if (bindSkelName)
{
// Make a list of bones
uint bone;
for (bone=0; bone<transformSkel->Bones.size(); bone++)
{
if (transformSkel->Bones[bone].getBoneName() == bindSkelName)
{
bindBone = bone;
boneName = bindSkelName;
break;
}
}
}
// Found ? No, look for a bind bone
if (bindBone == 0xffffffff)
{
// Make a list of bones
vector<string> listBones;
uint bone;
for (bone=0; bone<transformSkel->Bones.size(); bone++)
listBones.push_back (transformSkel->Bones[bone].getBoneName());
// Get name of the mesh
std::string nameMesh = NLMISC::CFile::getFilenameWithoutExtension(meshName);
// Select a bones
std::string message = "Select a bone to stick " + string (nameMesh);
CSelectString dialogSelect (listBones, message.c_str(), _MainFrame, false);
if (dialogSelect.DoModal ()==IDOK)
{
// Select your bones
bindBone = dialogSelect.Selection;
boneName = listBones[dialogSelect.Selection];
}
}
// Selected ?
if (bindBone != 0xffffffff)
{
transformSkel->stickObject (pTrShape, bindBone);
/*meshInstance->setPos (CVector::Null);
meshInstance->setRotQuat (CQuat::Identity);
meshInstance->setScale (1, 1, 1);*/
}
// Set the bone name
iInfo->Saved.BindBoneName = boneName;
}
}
// Return the instance index
return (uint)_ListInstance.size()-1;
}
else
return 0xffffffff;
}
// ***************************************************************************
bool CObjectViewer::chooseBone(const std::string &caption, NL3D::CSkeletonModel *&skel, uint &boneIndex, std::string *skelName /*= NULL*/, std::string *boneName /*= NULL*/)
{
for(uint k = 0; k < _ListInstance.size(); ++k)
{
NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[k]->TransformShape);
if (transformSkel)
{
// Make a list of bones
vector<string> listBones;
uint bone;
for (bone=0; bone<transformSkel->Bones.size(); bone++)
{
listBones.push_back (transformSkel->Bones[bone].getBoneName());
}
CSelectString dialogSelect (listBones, caption.c_str(), _MainFrame, false);
if (dialogSelect.DoModal ()==IDOK)
{
boneIndex = dialogSelect.Selection;
skel = transformSkel;
if (skelName)
{
*skelName = _ListInstance[k]->Saved.ShapeFilename;
}
if (boneName)
{
*boneName = safe_cast<NL3D::CSkeletonModel *>(_ListInstance[k]->TransformShape)->Bones[boneIndex].getBoneName();
}
return true;
}
return false;
}
}
return false;
}
// ***************************************************************************
bool CObjectViewer::isSkeletonPresent() const
{
for(uint k = 0; k < _ListInstance.size(); ++k)
{
NL3D::CSkeletonModel *transformSkel = dynamic_cast<CSkeletonModel*>(_ListInstance[k]->TransformShape);
if (transformSkel) return true;
}
return false;
}
// ***************************************************************************
uint CObjectViewer::addCamera (const NL3D::CCameraInfo &cameraInfo, const std::string &cameraName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// *** Add the shape
// link to the root for manipulation
CCamera *pCamera = (CCamera*)CNELU::Scene->createModel (CameraId);
_SceneRoot->hrcLinkSon(pCamera);
// Build the camera
pCamera->build (cameraInfo);
// Store the transform shape pointer
CInstanceInfo *iInfo = new CInstanceInfo;
iInfo->Camera = pCamera;
// Store the name of the shape
iInfo->MustDelete = true;
iInfo->Saved.ShapeFilename = cameraName;
iInfo->Saved.SkeletonId = 0xffffffff;
iInfo->Saved.CameraInfo = cameraInfo;
iInfo->Saved.Camera = true;
_ListInstance.push_back (iInfo);
_Cameras.push_back ((uint)_ListInstance.size()-1);
// Reinit camera
initCamera ();
// Return the instance index
return (uint)_ListInstance.size()-1;
}
// ***************************************************************************
uint CObjectViewer::addSkel (NL3D::IShape* pSkelShape, const std::string &skelName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// *** Add the shape
// Store the shape pointer
if (CNELU::ShapeBank->getPresentState(skelName)!=CShapeBank::NotPresent)
{
delete pSkelShape;
}
else
CNELU::ShapeBank->add (skelName, CSmartPtr<IShape> (pSkelShape));
// Create a model and add it to the scene
CTransformShape *pTrShape=CNELU::Scene->createInstance (skelName);
nlassert (pTrShape);
// link to the root for manipulation
_SceneRoot->hrcLinkSon(pTrShape);
// Get the real shape used by the instance.
pSkelShape= pTrShape->Shape;
// Get a skeleton model
CSkeletonModel *skelModel=dynamic_cast<CSkeletonModel*>(pTrShape);
// Is a skel ?
if (skelModel)
{
// Set the rot model
if (_MainFrame->Euler)
pTrShape->setTransformMode (ITransformable::RotEuler);
else
pTrShape->setTransformMode (ITransformable::RotQuat);
// Store the transform shape pointer
CInstanceInfo *iInfo = new CInstanceInfo;
iInfo->TransformShape = skelModel;
// Store the name of the shape
iInfo->MustDelete = true;
iInfo->Saved.ShapeFilename = skelName;
iInfo->Saved.IsSkeleton = true;
iInfo->Saved.SkeletonId = 0xffffffff;
_ListInstance.push_back (iInfo);
// set this skeleton for Skeleton Scale edition
_SkeletonScaleDlg->setSkeletonToEdit(skelModel, skelName);
// Return the instance
return (uint)_ListInstance.size()-1;
}
return 0xffffffff;
}
// ***************************************************************************
IObjectViewer* IObjectViewer::getInterface (int version)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Check version number
if (version!=OBJECT_VIEWER_VERSION)
{
MessageBox (NULL, _T("Bad version of object_viewer.dll."), _T("NeL object viewer"), MB_ICONEXCLAMATION|MB_OK);
return NULL;
}
else
return new CObjectViewer;
}
// ***************************************************************************
void IObjectViewer::releaseInterface (IObjectViewer* view)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
delete view;
}
// ***************************************************************************
void CObjectViewer::setSingleAnimation (NL3D::CAnimation* pAnim, const std::string &name, uint instance)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (instance < _ListInstance.size())
{
// Set active
_SelectedObject = instance;
// Add the animation
addAnimation (pAnim, name + ".anim", name, instance);
// Add the animation to the animationSet
_AnimationSetDlg->UpdateData (TRUE);
_AnimationSetDlg->UseMixer = 1;
_AnimationSetDlg->UpdateData (FALSE);
// Set the animation in the first slot
_ListInstance[instance]->Saved.SlotInfo[0].Animation = name;
_ListInstance[instance]->Saved.SlotInfo[0].Skeleton.clear();
_ListInstance[instance]->Saved.SlotInfo[0].Offset = 0;
_ListInstance[instance]->Saved.SlotInfo[0].StartTime = (int)(pAnim->getBeginTime()*_AnimationDlg->Speed);
_ListInstance[instance]->Saved.SlotInfo[0].EndTime = (int)(pAnim->getEndTime()*_AnimationDlg->Speed);
_ListInstance[instance]->Saved.SlotInfo[0].StartBlend = 1.f;
_ListInstance[instance]->Saved.SlotInfo[0].EndBlend = 1.f;
_ListInstance[instance]->Saved.SlotInfo[0].Enable = true;
for (uint i=1; i<CChannelMixer::NumAnimationSlot; i++)
_ListInstance[instance]->Saved.SlotInfo[i].Enable = false;
// Update dialog box
_AnimationSetDlg->refresh (TRUE);
_SlotDlg->refresh (TRUE);
_SoundAnimDlg->refresh(TRUE);
// Reinit
reinitChannels ();
}
}
// ***************************************************************************
void CObjectViewer::setAutoAnimation (NL3D::CAnimationSet* pAnimSet)
{
CNELU::Scene->setAutomaticAnimationSet (pAnimSet);
}
// ***************************************************************************
void CObjectViewer::setAmbientColor (const NLMISC::CRGBA& color)
{
CNELU::Driver->setAmbientColor (color);
// Setup also Scene lighting system here, even if not used.
CNELU::Scene->setAmbientGlobal(color);
}
// ***************************************************************************
void CObjectViewer::setLight (unsigned char id, const NL3D::CLight& light)
{
CNELU::Driver->enableLight (id);
CNELU::Driver->setLight (id, light);
}
// ***************************************************************************
/** add an object that will be notified each time a frame is processed
* \see removeMainLoopCallBack()
*/
void CObjectViewer::registerMainLoopCallBack(IMainLoopCallBack *i)
{
// nlassert(std::find(_CallBackList.begin(), _CallBackList.end(), i) == _CallBackList.begin()); // the object was register twice !!
_CallBackList.push_back(i);
}
/// remove an object that was registered with registerMainLoopCallBack()
void CObjectViewer::removeMainLoopCallBack(IMainLoopCallBack *i)
{
std::vector<IMainLoopCallBack *>::iterator it = std::find(_CallBackList.begin(), _CallBackList.end(), i);
nlassert(it != _CallBackList.end()); // this object wasn't registered
_CallBackList.erase(it);
}
// ***************************************************************************
void CObjectViewer::activateTextureSet(uint index)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
std::vector<CInstanceInfo*>::iterator it;
for (it = _ListInstance.begin(); it != _ListInstance.end(); ++it)
{
NL3D::CTransformShape *trShape= (*it)->TransformShape;
if (dynamic_cast<NL3D::CMeshBaseInstance *>(trShape))
{
static_cast<NL3D::CMeshBaseInstance *>(trShape)->selectTextureSet(index);
}
}
}
// ***************************************************************************
void CObjectViewer::shuffleTextureSet()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
std::vector<CInstanceInfo*>::iterator it;
for (it = _ListInstance.begin(); it != _ListInstance.end(); ++it)
{
NL3D::CTransformShape *trShape= (*it)->TransformShape;
if (dynamic_cast<NL3D::CMeshBaseInstance *>(trShape))
{
static_cast<NL3D::CMeshBaseInstance *>(trShape)->selectTextureSet(rand() % 8);
}
}
}
// ***************************************************************************
void CObjectViewer::removeAllInstancesFromScene()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// Remove all stand alone TransformShapes.
for(uint instance=0; instance<_ListInstance.size(); instance++)
{
delete _ListInstance[instance];
}
// Remove all stand alone TransformShapes.
_ListInstance.clear();
_Cameras.clear();
_CurrentCamera = -1;
_SelectedObject = 0xffffffff;
// Remove added/loaded igs and their instances.
for(uint igId=0; igId<_ListIG.size(); igId++)
{
// remove instances.
_ListIG[igId]->removeFromScene(*CNELU::Scene);
// free up the ig.
delete _ListIG[igId];
}
_ListIG.clear();
// clear dynamic lighting test
_GlobalRetriever= NULL;
CNELU::Scene->deleteInstance(_ObjectLightTest);
_ObjectLightTest= NULL;
// Reset mesh cache
CNELU::ShapeBank->reset();
// Invalidate dialogs
if (CNELU::Driver->isActive())
{
_AnimationSetDlg->refresh (TRUE);
_SlotDlg->refresh (TRUE);
_SoundAnimDlg->refresh (TRUE);
}
// remove any skeleton edited
if(_InstanceRunning)
_SkeletonScaleDlg->setSkeletonToEdit(NULL, "");
}
// ***************************************************************************
void CObjectViewer::enableFXs(bool enabled)
{
// Stand alone fxs
for(uint instance=0; instance<_ListInstance.size(); instance++)
{
NL3D::CSegRemanence *sr = dynamic_cast<NL3D::CSegRemanence *>(_ListInstance[instance]->TransformShape);
if (sr)
{
if (enabled) sr->start();
else sr->stop();
}
}
// remanences in igs
for(uint igId = 0; igId < _ListIG.size(); ++igId)
{
for(uint k = 0; k < _ListIG[igId]->_Instances.size(); ++k)
{
NL3D::CSegRemanence *sr = dynamic_cast<NL3D::CSegRemanence *>(_ListIG[igId]->_Instances[k]);
if (sr)
{
if (enabled) sr->start();
else sr->stop();
}
}
}
}
// ***************************************************************************
void CObjectViewer::evalSoundTrack (float lastTime, float currentTime)
{
// Gor each object
for (uint i = 0; i < _ListInstance.size(); i++)
{
// Some animation in the list ?
if (_ListInstance[i]->Saved.PlayList.size() > 0)
{
// Accumul time
float startTime = 0;
float endTime = 0;
// Get start time of the animation that starts before the current time
for (uint index = 0; index < _ListInstance[i]->Saved.PlayList.size(); index++)
{
// Pointer on the animation
string& name = _ListInstance[i]->Saved.PlayList[index];
CAnimation *anim = _ListInstance[i]->AnimationSet.getAnimation (_ListInstance[i]->AnimationSet.getAnimationIdByName(name));
// Add start time
startTime = endTime;
endTime = startTime + anim->getEndTime()-anim->getBeginTime();
if ((startTime <= currentTime) && (currentTime < endTime))
{
// setup the sound context
DWORD tab[] = {IDC_ARG0, IDC_ARG1, IDC_ARG2, IDC_ARG3, };
for (uint i = 0; i < 4; i++)
{
CEdit *edit = (CEdit*) _SoundAnimDlg->GetDlgItem(tab[i]);
nlassert(edit);
TCHAR str[1024];
edit->GetLine(0, str, 1024);
SoundContext.Args[i] = _ttoi (str);
}
// get the position of the skel if a skel is available
if (SkeletonUsedForSound != 0xFFFFFFFF)
{
const CMatrix &m = _ListInstance[SkeletonUsedForSound]->TransformShape->getMatrix();
SoundContext.Position = m.getPos();
}
else
{
SoundContext.Position = CVector::Null;
}
CSoundSystem::playAnimation(name, lastTime - startTime, currentTime - startTime, SoundContext);
}
}
}
}
}
// ***************************************************************************
/*
void CObjectViewer::evalSoundTrack (float lastTime, float currentTime)
{
if (lastTime!=currentTime)
{
// For each objects
for (uint instance=0; instance<_ListInstance.size(); instance++)
{
// For each channel of the mixer
for (uint slot=0; slot<CChannelMixer::NumAnimationSlot; slot++)
{
// Anim id
uint animId=_ListInstance[instance]->Playlist.getAnimation (slot);
// Channel actif ?
if (animId!=CAnimationPlaylist::empty)
{
// Get the animation
CAnimation *anim=_ListInstance[instance]->AnimationSet.getAnimation (animId);
nlassert (anim);
// Get the sound track
uint trackId=anim->getIdTrackByName ("NoteTrack");
if (trackId!=CAnimation::NotFound)
{
// Get the track
ITrack *track=anim->getTrack (trackId);
nlassert (track);
// Dynamic cast
UTrackKeyframer *soundTrackKF = dynamic_cast<UTrackKeyframer *>(track);
if (soundTrackKF)
{
// Sound keys
std::vector<TAnimationTime> result;
// Get local begin and endTime
TAnimationTime localLastTime = _ListInstance[instance]->Playlist.getLocalTime (slot, lastTime, _ListInstance[instance]->AnimationSet);
TAnimationTime localCurrentTime = _ListInstance[instance]->Playlist.getLocalTime (slot, currentTime, _ListInstance[instance]->AnimationSet);
// Good interval
if (localLastTime<=localCurrentTime)
{
// Get keys in this interval
soundTrackKF->getKeysInRange(localLastTime, localCurrentTime, result);
}
else
{
// Get begin and last time
TAnimationTime beginTime=track->getBeginTime ();
TAnimationTime endTime=track->getEndTime ();
// Time must have been clamped
nlassert (localCurrentTime<=endTime);
nlassert (localLastTime>=beginTime);
// Get keys to the end
soundTrackKF->getKeysInRange(localCurrentTime, endTime, result);
// Get keys at the beginning
soundTrackKF->getKeysInRange(beginTime, localLastTime, result);
}
// Process sounds
NLSOUND::UAudioMixer *audioMixer = CSoundSystem::getAudioMixer ();
if( audioMixer )
{
vector<TAnimationTime>::iterator itResult;
for( itResult = result.begin(); itResult != result.end(); ++itResult )
{
string soundName;
double keyTime = *itResult;
nlinfo("keyTime = %f result size : %d",*itResult,result.size());
if( !track->interpolate( *itResult, soundName) )
{
nlwarning("The key at offset %f is not a string",*itResult);
}
else
{
// if there are step sounds
if( soundName == "step" )
{
// need to spawn a sound linked to the anim
string dummySound = "PAShommecourseappartdur1a";
USource *source = audioMixer->createSource (dummySound.c_str() , true );
if (source)
{
source->setPos (CVector::Null);
source->play ();
nlinfo ("launching dummy sound %s for the step event", dummySound.c_str());
}
else
{
nlwarning ("sound not found for the step event: '%s'", dummySound.c_str());
}
}
else if (soundName.find ("snd_") != string::npos)
{
// need to spawn a sound linked to the anim
USource *source = audioMixer->createSource ( soundName.c_str(), true );
if (source)
{
source->setPos (CVector::Null);
source->play ();
nlinfo ("launching sound for anim event from notetrack '%s'", soundName.c_str());
}
else
{
nlwarning ("sound not found: '%s'", soundName.c_str());
}
}
else
{
nlwarning ("unknown notetrack event: '%s'", soundName.c_str());
}
}
}
}
}
}
}
}
}
}
}
*/
// ***************************************************************************
uint CObjectViewer::addInstanceGroup(NL3D::CInstanceGroup *ig)
{
// First instance
uint first = (uint)_ListInstance.size();
// Add all models to the scene
ig->addToScene(*CNELU::Scene, CNELU::Driver);
// Unfreeze all objects from HRC.
ig->unfreezeHRC();
// link the root of the IG to our root, for scene rotation
ig->linkRoot(*CNELU::Scene, _SceneRoot);
// Keep a reference on them, but they'll be destroyed by IG.
for (uint k = 0; k < ig->getNumInstance(); ++k)
{
CInstanceInfo *iInfo = new CInstanceInfo;
iInfo->TransformShape = ig->_Instances[k];
iInfo->Saved.ShapeFilename = ig->_InstancesInfos[k].Name;
iInfo->MustDelete = false;
_ListInstance.push_back (iInfo);
}
// Add the ig to the list.
_ListIG.push_back(ig);
// Return first instance
return first;
}
// ***************************************************************************
void CObjectViewer::setupSceneLightingSystem(bool enable, const NLMISC::CVector &sunDir, NLMISC::CRGBA sunAmbiant, NLMISC::CRGBA sunDiffuse, NLMISC::CRGBA sunSpecular)
{
CNELU::Scene->enableLightingSystem(enable);
// Setup sun.
CNELU::Scene->setSunAmbient(sunAmbiant);
CNELU::Scene->setSunDiffuse(sunDiffuse);
CNELU::Scene->setSunSpecular(sunSpecular);
CNELU::Scene->setSunDirection(sunDir);
}
// ***************************************************************************
void CObjectViewer::enableDynamicObjectLightingTest(NLPACS::CGlobalRetriever *globalRetriever, NL3D::CInstanceGroup *ig)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// first delete the instance
if(_ObjectLightTest)
{
CNELU::Scene->deleteInstance(_ObjectLightTest);
_ObjectLightTest= NULL;
}
_GlobalRetriever= globalRetriever;
// if enabled
if(_GlobalRetriever)
{
nlassert(ig);
// this mesh is the dynamic one to move around.
_ObjectLightTest= CNELU::Scene->createInstance(_ObjectLightTestShape);
if(_ObjectLightTest!=NULL)
{
// link to the root for manipulation
_SceneRoot->hrcLinkSon(_ObjectLightTest);
// setup the matrix.
_ObjectLightTestMatrix= _ObjectLightTest->getMatrix();
// setup the logic info.
_ObjectLightTestLogicInfo.GlobalRetriever= _GlobalRetriever;
_ObjectLightTestLogicInfo.Ig= ig;
// Default the GPos to uninitialized
_ObjectLightTestLogicInfo.GPos.InstanceId= -1;
_ObjectLightTest->setLogicInfo(&_ObjectLightTestLogicInfo);
}
else
{
if (!_ObjectLightTestShape.empty())
{
string str= string("Path not found for Light Test Shape: ") + _ObjectLightTestShape;
::MessageBox(NULL, utf8ToTStr(str.c_str()), _T("Dynamic Object Light Test"), MB_OK|MB_ICONEXCLAMATION);
}
// disable.
_ObjectLightTest= NULL;
_GlobalRetriever= NULL;
}
}
}
// ***************************************************************************
void CObjectViewer::COVLogicInfo::getStaticLightSetup(NLMISC::CRGBA sunAmbient, std::vector<CPointLightInfluence> &pointLightList, uint8 &sunContribution, CRGBA &ambient)
{
Ig->getStaticLightSetup(sunAmbient, GlobalRetriever->getLocalRetrieverId(GPos),
GPos.LocalPosition.Surface,
GPos.LocalPosition.Estimation,
pointLightList, sunContribution, ambient);
}
// ***************************************************************************
// ***************************************************************************
// Vegetable Landscape Part.
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
void CObjectViewer::loadVegetableLandscapeCfg(NLMISC::CConfigFile &cf)
{
// vegetable display is true by default.
_VegetableEnabled= true;
_VegetableSnapToGround= true;
// Load landscape setup
// --------------
try
{
// tileBank setup.
CConfigFile::CVar &tileBank = cf.getVar("veget_tile_bank");
_VegetableLandscapeTileBank= tileBank.asString();
CConfigFile::CVar &tileFarBank = cf.getVar("veget_tile_far_bank");
_VegetableLandscapeTileFarBank= tileFarBank.asString();
// zone list.
_VegetableLandscapeZoneNames.clear();
CConfigFile::CVar &zones = cf.getVar("veget_landscape_zones");
for (uint i=0; i<(uint)zones.size(); i++)
_VegetableLandscapeZoneNames.push_back(zones.asString(i).c_str());
}
catch (const EUnknownVar &)
{
_VegetableLandscapeTileBank.clear();
_VegetableLandscapeTileFarBank.clear();
_VegetableLandscapeZoneNames.clear();
}
// Load Landscape params.
// --------------
// threshold
try
{
CConfigFile::CVar &thre= cf.getVar("veget_landscape_threshold");
_VegetableLandscapeThreshold= thre.asFloat();
// clamp to avoid divide/0.
_VegetableLandscapeThreshold= max(_VegetableLandscapeThreshold, 0.001f);
}
catch (const EUnknownVar &)
{
_VegetableLandscapeThreshold= 0.003f;
}
// tilenear
try
{
CConfigFile::CVar &tileNear= cf.getVar("veget_landscape_tile_near");
_VegetableLandscapeTileNear= tileNear.asFloat();
}
catch (const EUnknownVar &)
{
_VegetableLandscapeTileNear= 50;
}
// ambient
try
{
CConfigFile::CVar &color= cf.getVar("veget_landscape_ambient");
_VegetableLandscapeAmbient.R= color.asInt(0);
_VegetableLandscapeAmbient.G= color.asInt(1);
_VegetableLandscapeAmbient.B= color.asInt(2);
}
catch (const EUnknownVar &)
{
_VegetableLandscapeAmbient.set(80, 80, 80);
}
// diffuse
try
{
CConfigFile::CVar &color= cf.getVar("veget_landscape_diffuse");
_VegetableLandscapeDiffuse.R= color.asInt(0);
_VegetableLandscapeDiffuse.G= color.asInt(1);
_VegetableLandscapeDiffuse.B= color.asInt(2);
}
catch (const EUnknownVar &)
{
_VegetableLandscapeDiffuse.set(255, 255, 255);
}
// Snapping
try
{
CConfigFile::CVar &var= cf.getVar("veget_landscape_snap_height");
_VegetableSnapHeight= var.asFloat();
}
catch (const EUnknownVar &)
{
_VegetableSnapHeight= 1.70f;
}
// Load Vegetable params.
// --------------
// vegetable texture
try
{
CConfigFile::CVar &var= cf.getVar("veget_texture");
_VegetableTexture= var.asString();
}
catch (const EUnknownVar &)
{
_VegetableTexture.clear();
}
// vegetable ambient
try
{
CConfigFile::CVar &color= cf.getVar("veget_ambient");
_VegetableAmbient.R= color.asInt(0);
_VegetableAmbient.G= color.asInt(1);
_VegetableAmbient.B= color.asInt(2);
}
catch (const EUnknownVar &)
{
_VegetableAmbient.set(80, 80, 80);
}
// vegetable diffuse
try
{
CConfigFile::CVar &color= cf.getVar("veget_diffuse");
// setup to behave correclty ie as maxLightFactor:
sint R= color.asInt(0) - _VegetableAmbient.R; clamp(R, 0, 255); _VegetableDiffuse.R= R;
sint G= color.asInt(1) - _VegetableAmbient.G; clamp(G, 0, 255); _VegetableDiffuse.G= G;
sint B= color.asInt(2) - _VegetableAmbient.B; clamp(B, 0, 255); _VegetableDiffuse.B= B;
}
catch (const EUnknownVar &)
{
sint R= 255 - _VegetableAmbient.R; clamp(R, 0, 255); _VegetableDiffuse.R= R;
sint G= 255 - _VegetableAmbient.G; clamp(G, 0, 255); _VegetableDiffuse.G= G;
sint B= 255 - _VegetableAmbient.B; clamp(B, 0, 255); _VegetableDiffuse.B= B;
}
// vegetable lightDir
try
{
CConfigFile::CVar &var= cf.getVar("veget_light_dir");
_VegetableLightDir.x= var.asFloat(0);
_VegetableLightDir.y= var.asFloat(1);
_VegetableLightDir.z= var.asFloat(2);
_VegetableLightDir.normalize();
}
catch (const EUnknownVar &)
{
_VegetableLightDir.set(0, 1, -1);
_VegetableLightDir.normalize();
}
// windDir
try
{
CConfigFile::CVar &var= cf.getVar("veget_wind_dir");
_VegetableWindDir.x= var.asFloat(0);
_VegetableWindDir.y= var.asFloat(1);
_VegetableWindDir.z= var.asFloat(2);
}
catch (const EUnknownVar &)
{
_VegetableWindDir.x= 0.5f;
_VegetableWindDir.y= 0.5f;
_VegetableWindDir.z= 0;
}
// windFreq
try
{
CConfigFile::CVar &var= cf.getVar("veget_wind_freq");
_VegetableWindFreq= var.asFloat();
}
catch (const EUnknownVar &)
{
_VegetableWindFreq= 0.5;
}
// windPower
try
{
CConfigFile::CVar &var= cf.getVar("veget_wind_power");
_VegetableWindPower= var.asFloat();
}
catch (const EUnknownVar &)
{
_VegetableWindPower= 1;
}
// windBendMin
try
{
CConfigFile::CVar &var= cf.getVar("veget_wind_bend_min");
_VegetableWindBendMin= var.asFloat();
}
catch (const EUnknownVar &)
{
_VegetableWindBendMin= 0;
}
}
// ***************************************************************************
bool CObjectViewer::createVegetableLandscape()
{
// If not already done.
if(!_VegetableLandscape)
{
// create the landscape.
_VegetableLandscape= static_cast<CLandscapeModel*>(CNELU::Scene->createModel(LandscapeModelId));
// Create a Progress Dialog.
CDialogProgress dlgProgress;
dlgProgress.Create(CDialogProgress::IDD, _MainFrame);
dlgProgress.ShowWindow(true);
try
{
if(_VegetableLandscapeTileBank.empty())
{
throw Exception("Landscape CFG not fully defined");
}
// Load The Bank files (copied from CLandscapeUser :) ).
// ================
// progress
dlgProgress.ProgressText.SetWindowText(_T("Loading TileBanks..."));
dlgProgress.ProgressBar.SetPos(0);
// load
CIFile bankFile(CPath::lookup(_VegetableLandscapeTileBank));
_VegetableLandscape->Landscape.TileBank.serial(bankFile);
_VegetableLandscape->Landscape.TileBank.makeAllPathRelative();
_VegetableLandscape->Landscape.TileBank.makeAllExtensionDDS();
_VegetableLandscape->Landscape.TileBank.setAbsPath ("");
// progress
dlgProgress.ProgressBar.SetPos(50);
// load
CIFile farbankFile(CPath::lookup(_VegetableLandscapeTileFarBank));
_VegetableLandscape->Landscape.TileFarBank.serial(farbankFile);
if ( ! _VegetableLandscape->Landscape.initTileBanks() )
{
nlwarning( "You need to recompute bank.farbank for the far textures" );
}
bankFile.close();
farbankFile.close();
// flushTiles.
// ================
if(CNELU::Driver)
{
// progress
dlgProgress.ProgressText.SetWindowText(_T("Loading Tiles..."));
dlgProgress.ProgressBar.SetPos(0);
// count nbText to load.
sint ts;
sint nbTextTotal= 0;
for (ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
{
CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
nbTextTotal+= tileSet->getNumTile128();
nbTextTotal+= tileSet->getNumTile256();
nbTextTotal+= CTileSet::count;
}
// load.
sint nbTextDone= 0;
for (ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
{
CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
sint tl;
for (tl=0; tl<tileSet->getNumTile128(); tl++, nbTextDone++)
{
_VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTile128(tl), 1);
dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
}
for (tl=0; tl<tileSet->getNumTile256(); tl++, nbTextDone++)
{
_VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTile256(tl), 1);
dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
}
for (tl=0; tl<CTileSet::count; tl++, nbTextDone++)
{
_VegetableLandscape->Landscape.flushTiles (CNELU::Driver, (uint16)tileSet->getTransition(tl)->getTile (), 1);
dlgProgress.ProgressBar.SetPos(nbTextDone*100/nbTextTotal);
}
}
}
// misc setup.
// ================
_VegetableLandscape->Landscape.setThreshold(_VegetableLandscapeThreshold);
_VegetableLandscape->Landscape.setTileNear(_VegetableLandscapeTileNear);
_VegetableLandscape->Landscape.setupStaticLight(_VegetableLandscapeDiffuse, _VegetableLandscapeAmbient, 1);
_VegetableLandscape->Landscape.loadVegetableTexture(_VegetableTexture);
_VegetableLandscape->Landscape.setupVegetableLighting(_VegetableAmbient, _VegetableDiffuse, _VegetableLightDir);
_VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
// Load the zones.
// ================
// landscape recentering.
bool zoneLoaded= false;
CAABBox landscapeBBox;
// progress
dlgProgress.ProgressText.SetWindowText(_T("Loading Zones..."));
dlgProgress.ProgressBar.SetPos(0);
uint nbZones= (uint)_VegetableLandscapeZoneNames.size();
for(uint i=0; i<nbZones;i++)
{
// open the file
CIFile zoneFile(CPath::lookup(_VegetableLandscapeZoneNames[i]));
CZone zone;
// load
zoneFile.serial(zone);
// append to landscape
_VegetableLandscape->Landscape.addZone(zone);
// progress
dlgProgress.ProgressBar.SetPos(i*100/nbZones);
// Add to the bbox.
if(!zoneLoaded)
{
zoneLoaded= true;
landscapeBBox.setCenter(zone.getZoneBB().getCenter());
}
else
landscapeBBox.extend(zone.getZoneBB().getCenter());
}
// After All zone loaded, recenter the mouse listener on the landscape.
if(zoneLoaded)
{
CMatrix matrix;
_MouseListener.setHotSpot(landscapeBBox.getCenter());
matrix.setPos(landscapeBBox.getCenter());
matrix.rotateX(-(float)Pi/4);
matrix.translate(CVector(0,-1000,0));
_MouseListener.setMatrix(matrix);
}
// Create collisions objects.
_VegetableCollisionManager= new CVisualCollisionManager;
_VegetableCollisionManager->setLandscape(&_VegetableLandscape->Landscape);
_VegetableCollisionEntity= _VegetableCollisionManager->createEntity();
}
catch (const Exception &e)
{
// close the progress dialog
dlgProgress.DestroyWindow();
MessageBox(_MainFrame->m_hWnd, utf8ToTStr(e.what()), _T("Failed to Load landscape"), MB_OK | MB_APPLMODAL);
// remove first possibly created collisions objects.
if(_VegetableCollisionEntity)
{
_VegetableCollisionManager->deleteEntity(_VegetableCollisionEntity);
_VegetableCollisionEntity= NULL;
}
if(_VegetableCollisionManager)
{
delete _VegetableCollisionManager;
_VegetableCollisionManager= NULL;
}
// remove the landscape
CNELU::Scene->deleteModel(_VegetableLandscape);
_VegetableLandscape= NULL;
return false;
}
// close the progress dialog
dlgProgress.DestroyWindow();
}
return true;
}
// ***************************************************************************
void CObjectViewer::showVegetableLandscape()
{
if(_VegetableLandscape)
{
_VegetableLandscape->show();
}
}
// ***************************************************************************
void CObjectViewer::hideVegetableLandscape()
{
if(_VegetableLandscape)
{
_VegetableLandscape->hide();
}
}
// ***************************************************************************
void CObjectViewer::enableLandscapeVegetable(bool enable)
{
// update
_VegetableEnabled= enable;
// update view.
if(_VegetableLandscape)
{
_VegetableLandscape->Landscape.enableVegetable(_VegetableEnabled);
}
}
// ***************************************************************************
void CObjectViewer::refreshVegetableLandscape(const NL3D::CTileVegetableDesc &tvdesc)
{
// if landscape is displayed.
if(_VegetableLandscape)
{
// first disable the vegetable, to delete any vegetation
_VegetableLandscape->Landscape.enableVegetable(false);
// Then change all the tileSet of all the TileBanks.
for (sint ts=0; ts<_VegetableLandscape->Landscape.TileBank.getTileSetCount (); ts++)
{
CTileSet *tileSet=_VegetableLandscape->Landscape.TileBank.getTileSet (ts);
// change the vegetableTileDesc of this tileSet.
tileSet->setTileVegetableDesc(tvdesc);
}
// re-Enable the vegetable (if wanted).
_VegetableLandscape->Landscape.enableVegetable(_VegetableEnabled);
}
}
// ***************************************************************************
void CObjectViewer::setVegetableWindPower(float w)
{
_VegetableWindPower= w;
if(_VegetableLandscape)
_VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
}
// ***************************************************************************
void CObjectViewer::setVegetableWindBendStart(float w)
{
_VegetableWindBendMin= w;
if(_VegetableLandscape)
_VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
}
// ***************************************************************************
void CObjectViewer::setVegetableWindFrequency(float w)
{
_VegetableWindFreq= w;
if(_VegetableLandscape)
_VegetableLandscape->Landscape.setVegetableWind(_VegetableWindDir, _VegetableWindFreq, _VegetableWindPower, _VegetableWindBendMin);
}
// ***************************************************************************
void CObjectViewer::snapToGroundVegetableLandscape(bool enable)
{
// update
_VegetableSnapToGround= enable;
}
// ***************************************************************************
CInstanceInfo::CInstanceInfo ()
{
TransformShape = NULL;
Camera = NULL;
MustDelete = false;
}
// ***************************************************************************
CInstanceInfo::~CInstanceInfo ()
{
if (MustDelete)
{
if (TransformShape)
CNELU::Scene->deleteInstance (TransformShape);
if (Camera)
CNELU::Scene->deleteModel (Camera);
}
}
// ***************************************************************************
CSlotInfo::CSlotInfo ()
{
StartTime = 0;
EndTime = 0;
Offset = 0;
StartBlend = 1;
EndBlend = 1;
Smoothness = 1;
SpeedFactor = 1;
ClampMode = 0;
SkeletonInverted = false;
Enable = true;
}
// ***************************************************************************
void CSlotInfo::serial (NLMISC::IStream &f)
{
f.serialVersion (0);
f.serial (Animation);
f.serial (Skeleton);
f.serial (Offset);
f.serial (StartTime);
f.serial (EndTime);
f.serial (StartBlend);
f.serial (EndBlend);
f.serial (Smoothness);
f.serial (SpeedFactor);
f.serial (ClampMode);
f.serial (SkeletonInverted);
f.serial (Enable);
}
// ***************************************************************************
uint CObjectViewer::getEditedObject ()
{
return _SelectedObject;
}
// ***************************************************************************
void CObjectViewer::setEditedObject (uint selected)
{
_SelectedObject=selected;
}
// ***************************************************************************
CInstanceInfo *CObjectViewer::getInstance (uint instance)
{
return _ListInstance[instance];
}
// ***************************************************************************
uint CObjectViewer::getNumInstance () const
{
return (uint)_ListInstance.size ();
}
// ***************************************************************************
void CInstanceInfo::setAnimationPlaylist (float frameRate)
{
for (uint id=0; id<NL3D::CChannelMixer::NumAnimationSlot; id++)
{
if (Saved.SlotInfo[id].Enable)
{
// Set the animation
uint animId = AnimationSet.getAnimationIdByName (Saved.SlotInfo[id].Animation);
if (animId == CAnimationSet::NotFound)
Playlist.setAnimation (id, CAnimationPlaylist::empty);
else
Playlist.setAnimation (id, animId);
// Set the skeleton weight
uint skelId = AnimationSet.getSkeletonWeightIdByName (Saved.SlotInfo[id].Skeleton);
if (skelId == CAnimationSet::NotFound)
Playlist.setSkeletonWeight (id, CAnimationPlaylist::empty, false);
else
Playlist.setSkeletonWeight (id, skelId, Saved.SlotInfo[id].SkeletonInverted);
// Set others values
Playlist.setTimeOrigin (id, Saved.SlotInfo[id].Offset/frameRate);
Playlist.setSpeedFactor (id, Saved.SlotInfo[id].SpeedFactor);
Playlist.setStartWeight (id, Saved.SlotInfo[id].StartBlend, Saved.SlotInfo[id].StartTime/frameRate);
Playlist.setEndWeight (id, Saved.SlotInfo[id].EndBlend, Saved.SlotInfo[id].EndTime/frameRate);
Playlist.setWeightSmoothness (id, Saved.SlotInfo[id].Smoothness);
// Switch between wrap modes
switch (Saved.SlotInfo[id].ClampMode)
{
case 0:
Playlist.setWrapMode (id, CAnimationPlaylist::Clamp);
break;
case 1:
Playlist.setWrapMode (id, CAnimationPlaylist::Repeat);
break;
case 2:
Playlist.setWrapMode (id, CAnimationPlaylist::Disable);
break;
}
}
}
}
// ***************************************************************************
CInstanceSave::CInstanceSave ()
{
SkeletonId = 0xffffffff;
IsSkeleton = false;
Camera = false;
}
// ***************************************************************************
void CInstanceSave::serial (NLMISC::IStream &f)
{
// Serial a version
sint ver = f.serialVersion (1);
// Play list of this object
f.serialCont (PlayList);
// Slot info for this object
nlassert (NL3D::CChannelMixer::NumAnimationSlot == 8);
for (uint slot=0; slot<8; slot++)
// Serial the slot information
f.serial (SlotInfo[slot]);
// Input file
f.serial (ShapeFilename);
// Skeleton id
f.serial (SkeletonId);
// Bind bone name
f.serial (BindBoneName);
// Is a skeleton
f.serial (IsSkeleton);
// Animation input file
f.serialCont (AnimationFileName);
// Skeleton weight input file
f.serialCont (SWTFileName);
// Is a camera
if (ver>=1)
{
f.serial (Camera);
f.serial (CameraInfo);
}
else if (f.isReading ())
Camera = false;
}
// ***************************************************************************
void CObjectViewer::refreshAnimationListeners()
{
_SoundAnimDlg->refresh (TRUE);
}
// ***************************************************************************
void CObjectViewer::addAnimation(NL3D::CAnimation* anim, const std::string &filename, const std::string &name, uint instance)
{
// Add an animation
uint id = _ListInstance[instance]->AnimationSet.addAnimation (name.c_str(), anim);
_ListInstance[instance]->Saved.AnimationFileName.push_back (filename);
// Rebuild the animationSet
_ListInstance[instance]->AnimationSet.build ();
if(CNELU::Driver && CNELU::ShapeBank)
{
_ListInstance[instance]->AnimationSet.preloadSSSShapes(*CNELU::Driver, *CNELU::ShapeBank);
}
_SoundAnimDlg->refresh (TRUE);
}
// ***************************************************************************
void CObjectViewer::loadAnimation(const std::string &fileName, uint instance)
{
// Open the file
CIFile file;
if (file.open (fileName))
{
// Get the animation name
std::string name = NLMISC::CFile::getFilenameWithoutExtension(fileName);
// Make an animation
CAnimation *anim=new CAnimation;
// Serial it
anim->serial (file);
// Add the animation
addAnimation (anim, fileName, name, instance);
}
else
{
// Create a message
std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
_MainFrame->MessageBox (utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
}
}
// ***************************************************************************
void CObjectViewer::loadSWT (const std::string &fileName, uint instance)
{
// Open the file
CIFile file;
if (file.open (fileName))
{
// Get the animation name
std::string name = NLMISC::CFile::getFilenameWithoutExtension(fileName);
// Get the skeleton pointer
CSkeletonWeight* skel=new CSkeletonWeight;
// Serial it
skel->serial (file);
// Add an animation
_ListInstance[instance]->AnimationSet.addSkeletonWeight (name.c_str(), skel);
// Add the filename in the list
_ListInstance[instance]->Saved.SWTFileName.push_back (fileName);
}
else
{
// Create a message
std::string msg = NLMISC::toString("Can't open the file %s for reading.", fileName.c_str());
_MainFrame->MessageBox (utf8ToTStr(msg), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
}
}
// ***************************************************************************
CMainDlg *CObjectViewer::getSlotDlg ()
{
return _SlotDlg;
}
// ***************************************************************************
void CObjectViewer::reloadTextures ()
{
// For each instances
uint numInstance = getNumInstance ();
uint instance;
for (instance=0; instance<numInstance; instance++)
{
// Get the info
CInstanceInfo *info = getInstance (instance);
// For each material
if (info->TransformShape)
{
uint numMaterial = info->TransformShape->getNumMaterial ();
uint mat;
for (mat=0; mat<numMaterial; mat++)
{
// Get the material
CMaterial *material = info->TransformShape->getMaterial (mat);
// For each texture
int tex;
for (tex=0; tex<IDRV_MAT_MAXTEXTURES; tex++)
{
ITexture *texture = material->getTexture (tex);
// Touch it!
if (texture)
{
CNELU::Driver->invalidateShareTexture (*texture);
}
}
}
}
}
}
// ***************************************************************************
// ***************************************************************************
// Global wind part.
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
void CObjectViewer::setGlobalWindPower(float w)
{
if(_MainFrame)
{
clamp(w, 0.f, 1.f);
_MainFrame->GlobalWindPower= w;
CNELU::Scene->setGlobalWindPower(w);
}
}
// ***************************************************************************
float CObjectViewer::getGlobalWindPower() const
{
if(_MainFrame)
return _MainFrame->GlobalWindPower;
else
return 1.f;
}
void CObjectViewer::shootScene()
{
static const TCHAR BASED_CODE szFilter[] = _T("PNG Files (*.png)|*.png|Targa Files (*.tga)|*.tga|Jpeg Files (*.jpg)|*.jpg|All Files (*.*)|*.*||");
CFileDialog fileDlg ( FALSE, _T(".tga"), _T("*.tga"), OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter);
if (fileDlg.DoModal () == IDOK)
{
// Choose the size
CSelectMovieSize movieSize;
if (movieSize.DoModal () == IDOK)
{
// Resize the window
RECT window;
_MainFrame->GetWindowRect (&window);
uint32 width;
uint32 height;
CNELU::Driver->getWindowSize (width, height);
window.right += movieSize.Width - width;
window.bottom += movieSize.Height - height;
_MainFrame->SetWindowPos (NULL, 0, 0, window.right-window.left, window.bottom-window.top, SWP_NOMOVE|SWP_NOZORDER);
// Swap the buffers
CNELU::swapBuffers();
CNELU::Driver->setupViewport (CViewport ());
// The file name
string filename = NLMISC::CFile::getFilenameWithoutExtension(tStrToUtf8(fileDlg.GetPathName()));
string extension = NLMISC::CFile::getExtension (tStrToUtf8(fileDlg.GetPathName()));
// The file name without extension
bool jpeg = toLower (extension) == "jpg";
// Activate the driver
CNELU::Driver->activate ();
// Bitmap for shoot
NLMISC::CBitmap shoot;
// For each frame
sint i;
for (i=(sint)_AnimationDlg->Start; i<=(sint)_AnimationDlg->End; i++)
{
// Set the time
_AnimationDlg->setCurrentFrame ((float)i);
// Setup the play list
setupPlaylist (_AnimationDlg->getTime());
// Animate the automatic animation in the scene
animateCNELUScene (_CS, (uint64)(1000.f / _AnimationDlg->Speed));
// Eval channel mixer for transform
for (uint j=0; j<_ListInstance.size(); j++)
_ListInstance[j]->ChannelMixer.eval (false);
// Clear the buffers
CNELU::clearBuffers (_BackGroundColor);
// call of callback list
{
std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
{
(*it)->goPreRender();
}
}
// Render the CS
if (_CS) _CS->render ();
// Draw the scene
CNELU::Scene->render();
// call of callback list
{
std::vector<IMainLoopCallBack *> copyVect(_CallBackList.begin(), _CallBackList.end());
for (std::vector<IMainLoopCallBack *>::iterator it = _CallBackList.begin(); it != _CallBackList.end(); ++it)
{
(*it)->goPostRender();
}
}
// Swap the buffers
CNELU::swapBuffers();
// Get the buffer
CNELU::Driver->getBuffer (shoot);
shoot.flipV ();
// Save it
char num[12];
smprintf (num, 12, "%04d", i);
string filenamefinal = filename+num+string (".")+extension;
try
{
NLMISC::COFile output;
if (output.open (filenamefinal))
{
if (jpeg)
shoot.writeJPG ( output, 255 );
else
shoot.writeTGA ( output, 32 );
}
else
{
std::string message = toString("Can't open the file %s for writing.", filenamefinal.c_str());
_MainFrame->MessageBox (utf8ToTStr(message), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
break;
}
}
catch (const Exception &e)
{
std::string message = toString("Error during writing of the file %s: %s", filenamefinal.c_str(), e.what());
_MainFrame->MessageBox (utf8ToTStr(message), _T("NeL object viewer"), MB_OK|MB_ICONEXCLAMATION);
break;
}
}
}
}
}
void CObjectViewer::drawFXUserMatrix()
{
static std::string fxUserMatrixStr;
static bool stringRetrieved = false;
if (!stringRetrieved)
{
CString fxUserMatrix;
fxUserMatrix.LoadString(IDS_FX_USER_MATRIX);
fxUserMatrixStr = tStrToUtf8(fxUserMatrix);
stringRetrieved = true;
}
nlassert(_ParticleDlg);
drawNamedMatrix(getFXUserMatrix(), fxUserMatrixStr, NLMISC::CRGBA::Red, 0.2f, 10.f);
}
void CObjectViewer::drawFXMatrix()
{
static std::string fxStr;
static bool stringRetrieved = false;
if (!stringRetrieved)
{
CString fx;
fx.LoadString(IDS_FX_MATRIX);
fxStr = tStrToUtf8(fx);
stringRetrieved = true;
}
drawNamedMatrix(_ParticleDlg->getPSWorldMatrix(), fxStr, NLMISC::CRGBA::Blue, -0.2f, 10.f);
}
void CObjectViewer::drawSceneMatrix()
{
static std::string sceneMatrixStr;
static bool stringRetrieved = false;
if (!stringRetrieved)
{
CString sceneMatrix;
sceneMatrix.LoadString(IDS_SCENE_MATRIX);
sceneMatrixStr = tStrToUtf8(sceneMatrix);
stringRetrieved = true;
}
drawNamedMatrix(_SceneRoot->getMatrix(), sceneMatrixStr, NLMISC::CRGBA::White, 0.f, 10.f);
}
void CObjectViewer::drawNamedMatrix(const NLMISC::CMatrix &matrix, const std::string &name, NLMISC::CRGBA color, float textZOffset, float testSize)
{
CPSUtil::displayBasis(CNELU::Driver, matrix, NLMISC::CMatrix::Identity, 1.f, *_FontGenerator, _FontManager);
CPSUtil::print(CNELU::Driver, name, *_FontGenerator, _FontManager, matrix.getPos() + NLMISC::CVector(0.f, 0.f, textZOffset), testSize, color);
}
sint CObjectViewer::getCurrentCamera () const
{
return _CurrentCamera;
}
void CObjectViewer::setCurrentCamera (sint currentCamera)
{
nlassert ((currentCamera == -1) ||(currentCamera < (sint)_Cameras.size ()));
_CurrentCamera = currentCamera;
}
uint CObjectViewer::getCameraInstance (uint cameraId) const
{
return _Cameras[cameraId];
}
uint CObjectViewer::getNumCamera () const
{
return (uint)_Cameras.size ();
}
int localizedMessageBox(HWND parentWindow, int messageStringID, int captionStringID, UINT nType)
{
CString caption;
CString mess;
caption.LoadString(captionStringID);
mess.LoadString(messageStringID);
return MessageBox(parentWindow, (LPCTSTR) mess, (LPCTSTR) caption, nType);
// TODO : replace older call to ::MessageBox in the object viewer with that function
}
int localizedMessageBox(HWND parentWindow, const TCHAR *message, int captionStringID, UINT nType)
{
CString caption;
caption.LoadString(captionStringID);
return MessageBox(parentWindow, message, (LPCTSTR) caption, nType);
}
CString getStrRsc(uint stringID)
{
CString str;
str.LoadString(stringID);
return str;
}
bool browseFolder(const CString &caption, CString &destFolder, HWND parent)
{
TCHAR chosenPath[MAX_PATH];
// browse folder
BROWSEINFO bi;
bi.hwndOwner = parent;
bi.pidlRoot = NULL;
bi.pszDisplayName = chosenPath;
bi.lpszTitle = (LPCTSTR) caption;
bi.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_EDITBOX;
bi.lpfn = NULL;
bi.lParam = NULL;
bi.iImage = 0;
LPITEMIDLIST result = SHBrowseForFolder(&bi);
if (result != NULL && SHGetPathFromIDList(result, chosenPath))
{
destFolder = chosenPath;
return true;
}
return false;
}